diff --git a/Code Burner/Podfile b/Code Burner/Podfile new file mode 100644 index 0000000..8d9d0a4 --- /dev/null +++ b/Code Burner/Podfile @@ -0,0 +1,7 @@ +inhibit_all_warnings! + +target "Task Burner" do +pod 'Firebase/Core' +pod 'Firebase/Database' +pod 'Firebase/Auth' +end \ No newline at end of file diff --git a/Code Burner/Podfile.lock b/Code Burner/Podfile.lock new file mode 100644 index 0000000..bfb37b9 --- /dev/null +++ b/Code Burner/Podfile.lock @@ -0,0 +1,61 @@ +PODS: + - Firebase/Auth (3.8.0): + - Firebase/Core + - FirebaseAuth (= 3.0.6) + - Firebase/Core (3.8.0): + - FirebaseAnalytics (= 3.5.1) + - FirebaseCore (= 3.4.4) + - Firebase/Database (3.8.0): + - Firebase/Core + - FirebaseDatabase (= 3.1.0) + - FirebaseAnalytics (3.5.1): + - FirebaseCore (~> 3.4) + - FirebaseInstanceID (~> 1.0) + - GoogleInterchangeUtilities (~> 1.2) + - GoogleSymbolUtilities (~> 1.1) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseAuth (3.0.6): + - FirebaseAnalytics (~> 3.4) + - GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1) + - GTMSessionFetcher/Core (~> 1.1) + - FirebaseCore (3.4.4): + - GoogleInterchangeUtilities (~> 1.2) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseDatabase (3.1.0): + - FirebaseAnalytics (~> 3.4) + - FirebaseInstanceID (1.0.8) + - GoogleInterchangeUtilities (1.2.2): + - GoogleSymbolUtilities (~> 1.1) + - GoogleSymbolUtilities (1.1.2) + - GoogleToolboxForMac/DebugUtils (2.1.0): + - GoogleToolboxForMac/Defines (= 2.1.0) + - GoogleToolboxForMac/Defines (2.1.0) + - GoogleToolboxForMac/NSData+zlib (2.1.0): + - GoogleToolboxForMac/Defines (= 2.1.0) + - GoogleToolboxForMac/NSDictionary+URLArguments (2.1.0): + - GoogleToolboxForMac/DebugUtils (= 2.1.0) + - GoogleToolboxForMac/Defines (= 2.1.0) + - GoogleToolboxForMac/NSString+URLArguments (= 2.1.0) + - GoogleToolboxForMac/NSString+URLArguments (2.1.0) + - GTMSessionFetcher/Core (1.1.7) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Core + - Firebase/Database + +SPEC CHECKSUMS: + Firebase: fdbecadb7b5cbef2774852d4fa659b9daf11f2af + FirebaseAnalytics: 6e58fc9b397664369ac7617fb0ba93fab6ba7b5b + FirebaseAuth: 96e9674ff31d6e1f826d53e26aa003a57cab0295 + FirebaseCore: d0ed25f27b6f9158eccc439f1be6f92e81207e28 + FirebaseDatabase: 3ebb2edb6007c3f0f87b248f3fa212bde56a1468 + FirebaseInstanceID: ba1e640935235e5fac39dfa816fe7660e72e1a8a + GoogleInterchangeUtilities: d5bc4d88d5b661ab72f9d70c58d02ca8c27ad1f7 + GoogleSymbolUtilities: 631ee17048aa5e9ab133470d768ea997a5ef9b96 + GoogleToolboxForMac: 2b2596cbb7186865e98cadf2b1e262d851c2b168 + GTMSessionFetcher: a1f8ed39e4fe21c68957daed472c7afbcdf29166 + +PODFILE CHECKSUM: bcd164b21736a3888ce41a62ba7c1654aa2135cd + +COCOAPODS: 1.1.1 diff --git a/Code Burner/Pods/Firebase/Core/Sources/Firebase.h b/Code Burner/Pods/Firebase/Core/Sources/Firebase.h new file mode 100755 index 0000000..90798a6 --- /dev/null +++ b/Code Burner/Pods/Firebase/Core/Sources/Firebase.h @@ -0,0 +1,52 @@ +#import +#import + +#if !defined(__has_include) + #error "Firebase.h won't import anything if your compiler doesn't support __has_include. Please \ + import the headers individually." +#else + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + +#endif // defined(__has_include) diff --git a/Code Burner/Pods/Firebase/Core/Sources/module.modulemap b/Code Burner/Pods/Firebase/Core/Sources/module.modulemap new file mode 100755 index 0000000..3685b54 --- /dev/null +++ b/Code Burner/Pods/Firebase/Core/Sources/module.modulemap @@ -0,0 +1,4 @@ +module Firebase { + export * + header "Firebase.h" +} \ No newline at end of file diff --git a/Code Burner/Pods/Firebase/README.md b/Code Burner/Pods/Firebase/README.md new file mode 100755 index 0000000..bfc5419 --- /dev/null +++ b/Code Burner/Pods/Firebase/README.md @@ -0,0 +1,76 @@ +# Firebase APIs for iOS + +Simplify your iOS development, grow your user base, and monetize more +effectively with Firebase services. + +Much more information can be found at [https://firebase.google.com](https://firebase.google.com). + +## Install a Firebase SDK using CocoaPods + +Firebase distributes several iOS specific APIs and SDKs via CocoaPods. +You can install the CocoaPods tool on OS X by running the following command from +the terminal. Detailed information is available in the [Getting Started +guide](https://guides.cocoapods.org/using/getting-started.html#getting-started). + +``` +$ sudo gem install cocoapods +``` + +## Try out an SDK + +You can try any of the SDKs with `pod try`. Run the following command and select +the SDK you are interested in when prompted: + +``` +$ pod try Firebase +``` + +Note that some SDKs may require credentials. More information is available in +the SDK-specific documentation at [https://firebase.google.com/docs/](https://firebase.google.com/docs/). + +## Add a Firebase SDK to your iOS app + +CocoaPods is used to install and manage dependencies in existing Xcode projects. + +1. Create an Xcode project, and save it to your local machine. +2. Create a file named `Podfile` in your project directory. This file defines + your project's dependencies, and is commonly referred to as a Podspec. +3. Open `Podfile`, and add your dependencies. A simple Podspec is shown here: + + ``` + platform :ios, '7.0' + pod 'Firebase' + ``` + +4. Save the file. +5. Open a terminal and `cd` to the directory containing the Podfile. + + ``` + $ cd /project/ + ``` + +6. Run the `pod install` command. This will install the SDKs specified in the + Podspec, along with any dependencies they may have. + + ``` + $ pod install + ``` + +7. Open your app's `.xcworkspace` file to launch Xcode. + Use this file for all development on your app. +8. You can also install other Firebase SDKs by adding the subspecs in the + Podfile. + + ``` + pod 'Firebase/AdMob' + pod 'Firebase/Analytics' + pod 'Firebase/AppIndexing' + pod 'Firebase/Auth' + pod 'Firebase/Crash' + pod 'Firebase/Database' + pod 'Firebase/DynamicLinks' + pod 'Firebase/Invites' + pod 'Firebase/Messaging' + pod 'Firebase/RemoteConfig' + pod 'Firebase/Storage' + ``` diff --git a/Code Burner/Pods/FirebaseAuth/CHANGELOG.md b/Code Burner/Pods/FirebaseAuth/CHANGELOG.md new file mode 100755 index 0000000..99d2873 --- /dev/null +++ b/Code Burner/Pods/FirebaseAuth/CHANGELOG.md @@ -0,0 +1,23 @@ +# 2016-10-24 -- v3.0.6 +- Switches to depend on open sourced GoogleToolboxForMac and GTMSessionFetcher. +- Improves logging of keychain error when initializing. + +# 2016-09-14 -- v3.0.5 +- Works around a keychain issue in iOS 10 simulator. +- Reports the correct error for invalid email when signing in with email and + password. + +# 2016-07-18 -- v3.0.4 +- Fixes a race condition bug that could crash the app with an exception from + NSURLSession on iOS 9. + +# 2016-06-20 -- v3.0.3 +- Adds documentation for all possible errors returned by each method. +- Improves error handling and messages for a variety of error conditions. +- Whether or not an user is considered anonymous is now consistent with other + platforms. +- A saved signed in user is now siloed between different Firebase projects + within the same app. + +# 2016-05-18 -- v3.0.2 +- Initial public release. diff --git a/Code Burner/Pods/FirebaseAuth/README.md b/Code Burner/Pods/FirebaseAuth/README.md new file mode 100755 index 0000000..e766949 --- /dev/null +++ b/Code Burner/Pods/FirebaseAuth/README.md @@ -0,0 +1,8 @@ +# Firebase Auth for iOS + +Firebase Auth enables apps to easily support multiple authentication options +for their end users. + +Please visit [our developer site](https://developers.google.com/) for +integration instructions, documentation, support information, and terms of +service. diff --git a/Code Burner/Pods/FirebaseInstanceID/Sources/FIRInstanceID.h b/Code Burner/Pods/FirebaseInstanceID/Sources/FIRInstanceID.h new file mode 100755 index 0000000..e3782f8 --- /dev/null +++ b/Code Burner/Pods/FirebaseInstanceID/Sources/FIRInstanceID.h @@ -0,0 +1,237 @@ +#import + +/** + * @memberof FIRInstanceID + * + * The scope to be used when fetching/deleting a token for Firebase Messaging. + */ +FOUNDATION_EXPORT NSString * __nonnull const kFIRInstanceIDScopeFirebaseMessaging; + +/** + * Called when the system determines that tokens need to be refreshed. + * This method is also called if Instance ID has been reset in which + * case, tokens and FCM topic subscriptions also need to be refreshed. + * + * Instance ID service will throttle the refresh event across all devices + * to control the rate of token updates on application servers. + */ +FOUNDATION_EXPORT NSString * __nonnull const kFIRInstanceIDTokenRefreshNotification; + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the InstanceID token returns. If + * the call fails we return the appropriate `error code` as described below. + * + * @param token The valid token as returned by InstanceID backend. + * + * @param error The error describing why generating a new token + * failed. See the error codes below for a more detailed + * description. + */ +typedef void(^FIRInstanceIDTokenHandler)(NSString * __nullable token, NSError * __nullable error); + + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the InstanceID `deleteToken` returns. If + * the call fails we return the appropriate `error code` as described below + * + * @param error The error describing why deleting the token failed. + * See the error codes below for a more detailed description. + */ +typedef void(^FIRInstanceIDDeleteTokenHandler)(NSError * __nullable error); + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the app identity is created. If the + * identity wasn't created for some reason we return the appropriate error code. + * + * @param identity A valid identity for the app instance, nil if there was an error + * while creating an identity. + * @param error The error if fetching the identity fails else nil. + */ +typedef void(^FIRInstanceIDHandler)(NSString * __nullable identity, NSError * __nullable error); + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the app identity and all the tokens associated + * with it are deleted. Returns a valid error object in case of failure else nil. + * + * @param error The error if deleting the identity and all the tokens associated with + * it fails else nil. + */ +typedef void(^FIRInstanceIDDeleteHandler)(NSError * __nullable error); + +/** + * @enum FIRInstanceIDError + */ +typedef NS_ENUM(NSUInteger, FIRInstanceIDError) { + /// Unknown error. + FIRInstanceIDErrorUnknown = 0, + + /// Auth Error -- FCM couldn't validate request from this client. + FIRInstanceIDErrorAuthentication = 1, + + /// NoAccess -- InstanceID service cannot be accessed. + FIRInstanceIDErrorNoAccess = 2, + + /// Timeout -- Request to InstanceID backend timed out. + FIRInstanceIDErrorTimeout = 3, + + /// Network -- No network available to reach the servers. + FIRInstanceIDErrorNetwork = 4, + + /// OperationInProgress -- Another similar operation in progress, + /// bailing this one. + FIRInstanceIDErrorOperationInProgress = 5, + + /// InvalidRequest -- Some parameters of the request were invalid. + FIRInstanceIDErrorInvalidRequest = 7, +}; + +/** + * The APNS token type for the app. If the token type is set to `UNKNOWN` + * InstanceID will implicitly try to figure out what the actual token type + * is from the provisioning profile. + */ +typedef NS_ENUM(NSInteger, FIRInstanceIDAPNSTokenType) { + /// Unknown token type. + FIRInstanceIDAPNSTokenTypeUnknown, + /// Sandbox token type. + FIRInstanceIDAPNSTokenTypeSandbox, + /// Production token type. + FIRInstanceIDAPNSTokenTypeProd, +}; + +/** + * Instance ID provides a unique identifier for each app instance and a mechanism + * to authenticate and authorize actions (for example, sending a GCM message). + * + * Instance ID is long lived but, may be reset if the device is not used for + * a long time or the Instance ID service detects a problem. + * If Instance ID is reset, the app will be notified with a `com.firebase.iid.token-refresh` + * notification. + * + * If the Instance ID has become invalid, the app can request a new one and + * send it to the app server. + * To prove ownership of Instance ID and to allow servers to access data or + * services associated with the app, call + * `[FIRInstanceID tokenWithAuthorizedEntity:scope:options:handler]`. + */ +@interface FIRInstanceID : NSObject + +/** + * FIRInstanceID. + * + * @return A shared instance of FIRInstanceID. + */ ++ (nonnull instancetype)instanceID; + +/** + * Set APNS token for the application. This APNS token will be used to register + * with Firebase Messaging using `token` or + * `tokenWithAuthorizedEntity:scope:options:handler`. If the token type is set to + * `FIRInstanceIDAPNSTokenTypeUnknown` InstanceID will read the provisioning profile + * to find out the token type. + * + * @param token The APNS token for the application. + * @param type The APNS token type for the above token. + */ +- (void)setAPNSToken:(nonnull NSData *)token type:(FIRInstanceIDAPNSTokenType)type; + +#pragma mark - Tokens + +/** + * Returns a Firebase Messaging scoped token for the firebase app. + * + * @return Null Returns null if the device has not yet been registerd with + * Firebase Message else returns a valid token. + */ +- (nullable NSString *)token; + +/** + * Returns a token that authorizes an Entity (example: cloud service) to perform + * an action on behalf of the application identified by Instance ID. + * + * This is similar to an OAuth2 token except, it applies to the + * application instance instead of a user. + * + * This is an asynchronous call. If the token fetching fails for some reason + * we invoke the completion callback with nil `token` and the appropriate + * error. + * + * Note, you can only have one `token` or `deleteToken` call for a given + * authorizedEntity and scope at any point of time. Making another such call with the + * same authorizedEntity and scope before the last one finishes will result in an + * error with code `OperationInProgress`. + * + * @see FIRInstanceID deleteTokenWithAuthorizedEntity:scope:handler: + * + * @param authorizedEntity Entity authorized by the token. + * @param scope Action authorized for authorizedEntity. + * @param options The extra options to be sent with your token request. The + * value for the `apns_token` should be the NSData object + * passed to UIApplication's + * `didRegisterForRemoteNotificationsWithDeviceToken` method. + * All other keys and values in the options dict need to be + * instances of NSString or else they will be discarded. Bundle + * keys starting with 'GCM.' and 'GOOGLE.' are reserved. + * @param handler The callback handler which is invoked when the token is + * successfully fetched. In case of success a valid `token` and + * `nil` error are returned. In case of any error the `token` + * is nil and a valid `error` is returned. The valid error + * codes have been documented above. + */ +- (void)tokenWithAuthorizedEntity:(nonnull NSString *)authorizedEntity + scope:(nonnull NSString *)scope + options:(nonnull NSDictionary *)options + handler:(nonnull FIRInstanceIDTokenHandler)handler; + +/** + * Revokes access to a scope (action) for an entity previously + * authorized by `[FIRInstanceID tokenWithAuthorizedEntity:scope:options:handler]`. + * + * This is an asynchronous call. Call this on the main thread since InstanceID lib + * is not thread safe. In case token deletion fails for some reason we invoke the + * `handler` callback passed in with the appropriate error code. + * + * Note, you can only have one `token` or `deleteToken` call for a given + * authorizedEntity and scope at a point of time. Making another such call with the + * same authorizedEntity and scope before the last one finishes will result in an error + * with code `OperationInProgress`. + * + * @param authorizedEntity Entity that must no longer have access. + * @param scope Action that entity is no longer authorized to perform. + * @param handler The handler that is invoked once the unsubscribe call ends. + * In case of error an appropriate error object is returned + * else error is nil. + */ +- (void)deleteTokenWithAuthorizedEntity:(nonnull NSString *)authorizedEntity + scope:(nonnull NSString *)scope + handler:(nonnull FIRInstanceIDDeleteTokenHandler)handler; + +#pragma mark - Identity + +/** + * Asynchronously fetch a stable identifier that uniquely identifies the app + * instance. If the identifier has been revoked or has expired, this method will + * return a new identifier. + * + * + * @param handler The handler to invoke once the identifier has been fetched. + * In case of error an appropriate error object is returned else + * a valid identifier is returned and a valid identifier for the + * application instance. + */ +- (void)getIDWithHandler:(nonnull FIRInstanceIDHandler)handler; + +/** + * Resets Instance ID and revokes all tokens. + */ +- (void)deleteIDWithHandler:(nonnull FIRInstanceIDDeleteHandler)handler; + +@end diff --git a/Code Burner/Pods/GTMSessionFetcher/LICENSE b/Code Burner/Pods/GTMSessionFetcher/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Code Burner/Pods/GTMSessionFetcher/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Code Burner/Pods/GTMSessionFetcher/README.md b/Code Burner/Pods/GTMSessionFetcher/README.md new file mode 100644 index 0000000..9c0d345 --- /dev/null +++ b/Code Burner/Pods/GTMSessionFetcher/README.md @@ -0,0 +1,23 @@ +# Google Toolbox for Mac - Session Fetcher # + +**Project site**
+**Discussion group** + +[![Build Status](https://travis-ci.org/google/gtm-session-fetcher.svg?branch=master)](https://travis-ci.org/google/gtm-session-fetcher) + +`GTMSessionFetcher` makes it easy for Cocoa applications to perform http +operations. The fetcher is implemented as a wrapper on `NSURLSession`, so its +behavior is asynchronous and uses operating-system settings on iOS and Mac OS X. + +Features include: +- Simple to build; only one source/header file pair is required +- Simple to use: takes just two lines of code to fetch a request +- Supports upload and download sessions +- Flexible cookie storage +- Automatic retry on errors, with exponential backoff +- Support for generating multipart MIME upload streams +- Easy, convenient logging of http requests and responses +- Supports plug-in authentication such as with gtm-oauth2 +- Easily testable; self-mocking +- Automatic rate limiting when created by the `GTMSessionFetcherService` factory class +- Fully independent of other projects diff --git a/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h new file mode 100644 index 0000000..83d766b --- /dev/null +++ b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h @@ -0,0 +1,1310 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// GTMSessionFetcher is a wrapper around NSURLSession for http operations. +// +// What does this offer on top of of NSURLSession? +// +// - Block-style callbacks for useful functionality like progress rather +// than delegate methods. +// - Out-of-process uploads and downloads using NSURLSession, including +// management of fetches after relaunch. +// - Integration with GTMOAuth2 for invisible management and refresh of +// authorization tokens. +// - Pretty-printed http logging. +// - Cookies handling that does not interfere with or get interfered with +// by WebKit cookies or on Mac by Safari and other apps. +// - Credentials handling for the http operation. +// - Rate-limiting and cookie grouping when fetchers are created with +// GTMSessionFetcherService. +// +// If the bodyData or bodyFileURL property is set, then a POST request is assumed. +// +// Each fetcher is assumed to be for a one-shot fetch request; don't reuse the object +// for a second fetch. +// +// The fetcher will be self-retained as long as a connection is pending. +// +// To keep user activity private, URLs must have an https scheme (unless the property +// allowedInsecureSchemes is set to permit the scheme.) +// +// Callbacks will be released when the fetch completes or is stopped, so there is no need +// to use weak self references in the callback blocks. +// +// Sample usage: +// +// _fetcherService = [[GTMSessionFetcherService alloc] init]; +// +// GTMSessionFetcher *myFetcher = [_fetcherService fetcherWithURLString:myURLString]; +// myFetcher.retryEnabled = YES; +// myFetcher.comment = @"First profile image"; +// +// // Optionally specify a file URL or NSData for the request body to upload. +// myFetcher.bodyData = [postString dataUsingEncoding:NSUTF8StringEncoding]; +// +// [myFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { +// if (error != nil) { +// // Server status code or network error. +// // +// // If the domain is kGTMSessionFetcherStatusDomain then the error code +// // is a failure status from the server. +// } else { +// // Fetch succeeded. +// } +// }]; +// +// There is also a beginFetch call that takes a pointer and selector for the completion handler; +// a pointer and selector is a better style when the callback is a substantial, separate method. +// +// NOTE: Fetches may retrieve data from the server even though the server +// returned an error, so the criteria for success is a non-nil error. +// The completion handler is called when the server status is >= 300 with an NSError +// having domain kGTMSessionFetcherStatusDomain and code set to the server status. +// +// Status codes are at +// +// +// Background session support: +// +// Out-of-process uploads and downloads may be created by setting the fetcher's +// useBackgroundSession property. Data to be uploaded should be provided via +// the uploadFileURL property; the download destination should be specified with +// the destinationFileURL. NOTE: Background upload files should be in a location +// that will be valid even after the device is restarted, so the file should not +// be uploaded from a system temporary or cache directory. +// +// Background session transfers are slower, and should typically be used only +// for very large downloads or uploads (hundreds of megabytes). +// +// When background sessions are used in iOS apps, the application delegate must +// pass through the parameters from UIApplicationDelegate's +// application:handleEventsForBackgroundURLSession:completionHandler: to the +// fetcher class. +// +// When the application has been relaunched, it may also create a new fetcher +// instance to handle completion of the transfers. +// +// - (void)application:(UIApplication *)application +// handleEventsForBackgroundURLSession:(NSString *)identifier +// completionHandler:(void (^)())completionHandler { +// // Application was re-launched on completing an out-of-process download. +// +// // Pass the URLSession info related to this re-launch to the fetcher class. +// [GTMSessionFetcher application:application +// handleEventsForBackgroundURLSession:identifier +// completionHandler:completionHandler]; +// +// // Get a fetcher related to this re-launch and re-hook up a completionHandler to it. +// GTMSessionFetcher *fetcher = [GTMSessionFetcher fetcherWithSessionIdentifier:identifier]; +// NSURL *destinationFileURL = fetcher.destinationFileURL; +// fetcher.completionHandler = ^(NSData *data, NSError *error) { +// [self downloadCompletedToFile:destinationFileURL error:error]; +// }; +// } +// +// +// Threading and queue support: +// +// Networking always happens on a background thread; there is no advantage to +// changing thread or queue to create or start a fetcher. +// +// Callbacks are run on the main thread; alternatively, the app may set the +// fetcher's callbackQueue to a dispatch queue. +// +// Once the fetcher's beginFetch method has been called, the fetcher's methods and +// properties may be accessed from any thread. +// +// Downloading to disk: +// +// To have downloaded data saved directly to disk, specify a file URL for the +// destinationFileURL property. +// +// HTTP methods and headers: +// +// Alternative HTTP methods, like PUT, and custom headers can be specified by +// creating the fetcher with an appropriate NSMutableURLRequest. +// +// +// Caching: +// +// The fetcher avoids caching. That is best for API requests, but may hurt +// repeat fetches of static data. Apps may enable a persistent disk cache by +// customizing the config: +// +// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher, +// NSURLSessionConfiguration *config) { +// config.URLCache = [NSURLCache sharedURLCache]; +// }; +// +// Or use the standard system config to share cookie storage with web views +// and to enable disk caching: +// +// fetcher.configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; +// +// +// Cookies: +// +// There are three supported mechanisms for remembering cookies between fetches. +// +// By default, a standalone GTMSessionFetcher uses a mutable array held +// statically to track cookies for all instantiated fetchers. This avoids +// cookies being set by servers for the application from interfering with +// Safari and WebKit cookie settings, and vice versa. +// The fetcher cookies are lost when the application quits. +// +// To rely instead on WebKit's global NSHTTPCookieStorage, set the fetcher's +// cookieStorage property: +// myFetcher.cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; +// +// To share cookies with other apps, use the method introduced in iOS 9/OS X 10.11: +// myFetcher.cookieStorage = +// [NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:kMyCompanyContainedID]; +// +// To ignore existing cookies and only have cookies related to the single fetch +// be applied, make a temporary cookie storage object: +// myFetcher.cookieStorage = [[GTMSessionCookieStorage alloc] init]; +// +// Note: cookies set while following redirects will be sent to the server, as +// the redirects are followed by the fetcher. +// +// To completely disable cookies, similar to setting cookieStorageMethod to +// kGTMHTTPFetcherCookieStorageMethodNone, adjust the session configuration +// appropriately in the fetcher or fetcher service: +// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher, +// NSURLSessionConfiguration *config) { +// config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever; +// config.HTTPShouldSetCookies = NO; +// }; +// +// If the fetcher is created from a GTMSessionFetcherService object +// then the cookie storage mechanism is set to use the cookie storage in the +// service object rather than the static storage. Disabling cookies in the +// session configuration set on a service object will disable cookies for all +// fetchers created from that GTMSessionFetcherService object, since the session +// configuration is propagated to the fetcher. +// +// +// Monitoring data transfers. +// +// The fetcher supports a variety of properties for progress monitoring +// progress with callback blocks. +// GTMSessionFetcherSendProgressBlock sendProgressBlock +// GTMSessionFetcherReceivedProgressBlock receivedProgressBlock +// GTMSessionFetcherDownloadProgressBlock downloadProgressBlock +// +// If supplied by the server, the anticipated total download size is available +// as [[myFetcher response] expectedContentLength] (and may be -1 for unknown +// download sizes.) +// +// +// Automatic retrying of fetches +// +// The fetcher can optionally create a timer and reattempt certain kinds of +// fetch failures (status codes 408, request timeout; 502, gateway failure; +// 503, service unavailable; 504, gateway timeout; networking errors +// NSURLErrorTimedOut and NSURLErrorNetworkConnectionLost.) The user may +// set a retry selector to customize the type of errors which will be retried. +// +// Retries are done in an exponential-backoff fashion (that is, after 1 second, +// 2, 4, 8, and so on.) +// +// Enabling automatic retries looks like this: +// myFetcher.retryEnabled = YES; +// +// With retries enabled, the completion callbacks are called only +// when no more retries will be attempted. Calling the fetcher's stopFetching +// method will terminate the retry timer, without the finished or failure +// selectors being invoked. +// +// Optionally, the client may set the maximum retry interval: +// myFetcher.maxRetryInterval = 60.0; // in seconds; default is 60 seconds +// // for downloads, 600 for uploads +// +// Servers should never send a 400 or 500 status for errors that are retryable +// by clients, as those values indicate permanent failures. In nearly all +// cases, the default standard retry behavior is correct for clients, and no +// custom client retry behavior is needed or appropriate. Servers that send +// non-retryable status codes and expect the client to retry the request are +// faulty. +// +// Still, the client may provide a block to determine if a status code or other +// error should be retried. The block returns YES to set the retry timer or NO +// to fail without additional fetch attempts. +// +// The retry method may return the |suggestedWillRetry| argument to get the +// default retry behavior. Server status codes are present in the +// error argument, and have the domain kGTMSessionFetcherStatusDomain. The +// user's method may look something like this: +// +// myFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *error, +// GTMSessionFetcherRetryResponse response) { +// // Perhaps examine error.domain and error.code, or fetcher.retryCount +// // +// // Respond with YES to start the retry timer, NO to proceed to the failure +// // callback, or suggestedWillRetry to get default behavior for the +// // current error domain and code values. +// response(suggestedWillRetry); +// }; + + +#import + +#if TARGET_OS_IPHONE +#import +#endif + +// By default it is stripped from non DEBUG builds. Developers can override +// this in their project settings. +#ifndef STRIP_GTM_FETCH_LOGGING + #if !DEBUG + #define STRIP_GTM_FETCH_LOGGING 1 + #else + #define STRIP_GTM_FETCH_LOGGING 0 + #endif +#endif + +// Logs in debug builds. +#ifndef GTMSESSION_LOG_DEBUG + #if DEBUG + #define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__) + #else + #define GTMSESSION_LOG_DEBUG(...) do { } while (0) + #endif +#endif + +// Asserts in debug builds (or logs in debug builds if GTMSESSION_ASSERT_AS_LOG +// or NS_BLOCK_ASSERTIONS are defined.) +#ifndef GTMSESSION_ASSERT_DEBUG + #if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG + #undef GTMSESSION_ASSERT_AS_LOG + #define GTMSESSION_ASSERT_AS_LOG 1 + #endif + + #if DEBUG && !GTMSESSION_ASSERT_AS_LOG + #define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__) + #elif DEBUG + #define GTMSESSION_ASSERT_DEBUG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); } + #else + #define GTMSESSION_ASSERT_DEBUG(pred, ...) do { } while (0) + #endif +#endif + +// Asserts in debug builds, logs in release builds (or logs in debug builds if +// GTMSESSION_ASSERT_AS_LOG is defined.) +#ifndef GTMSESSION_ASSERT_DEBUG_OR_LOG + #if DEBUG && !GTMSESSION_ASSERT_AS_LOG + #define GTMSESSION_ASSERT_DEBUG_OR_LOG(...) NSAssert(__VA_ARGS__) + #else + #define GTMSESSION_ASSERT_DEBUG_OR_LOG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); } + #endif +#endif + +// Macro useful for examining messages from NSURLSession during debugging. +#if 0 +#define GTM_LOG_SESSION_DELEGATE(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__) +#else +#define GTM_LOG_SESSION_DELEGATE(...) +#endif + +#ifndef GTM_NULLABLE + #if __has_feature(nullability) // Available starting in Xcode 6.3 + #define GTM_NULLABLE_TYPE __nullable + #define GTM_NONNULL_TYPE __nonnull + #define GTM_NULLABLE nullable + #define GTM_NONNULL_DECL nonnull // GTM_NONNULL is used by GTMDefines.h + #define GTM_NULL_RESETTABLE null_resettable + + #define GTM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN + #define GTM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END + #else + #define GTM_NULLABLE_TYPE + #define GTM_NONNULL_TYPE + #define GTM_NULLABLE + #define GTM_NONNULL_DECL + #define GTM_NULL_RESETTABLE + #define GTM_ASSUME_NONNULL_BEGIN + #define GTM_ASSUME_NONNULL_END + #endif // __has_feature(nullability) +#endif // GTM_NULLABLE + +#if ((!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0)) +#define GTMSESSION_DEPRECATE_ON_2016_SDKS(_MSG) __attribute__((deprecated("" _MSG))) +#else +#define GTMSESSION_DEPRECATE_ON_2016_SDKS(_MSG) +#endif + +#ifndef GTM_DECLARE_GENERICS + #if __has_feature(objc_generics) \ + && ((!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0)) + #define GTM_DECLARE_GENERICS 1 + #else + #define GTM_DECLARE_GENERICS 0 + #endif +#endif + +#ifndef GTM_NSArrayOf + #if GTM_DECLARE_GENERICS + #define GTM_NSArrayOf(value) NSArray + #define GTM_NSDictionaryOf(key, value) NSDictionary + #else + #define GTM_NSArrayOf(value) NSArray + #define GTM_NSDictionaryOf(key, value) NSDictionary + #endif // __has_feature(objc_generics) +#endif // GTM_NSArrayOf + +// For iOS, the fetcher can declare itself a background task to allow fetches +// to finish when the app leaves the foreground. +// +// (This is unrelated to providing a background configuration, which allows +// out-of-process uploads and downloads.) +// +// To disallow use of background tasks during fetches, the target should define +// GTM_BACKGROUND_TASK_FETCHING to 0, or alternatively may set the +// skipBackgroundTask property to YES. +#if TARGET_OS_IPHONE && !defined(GTM_BACKGROUND_TASK_FETCHING) + #define GTM_BACKGROUND_TASK_FETCHING 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0) + #ifndef GTM_USE_SESSION_FETCHER + #define GTM_USE_SESSION_FETCHER 1 + #endif + + #define GTMSESSION_DEPRECATE_OLD_ENUMS 1 +#endif + +#if !defined(GTMBridgeFetcher) + // These bridge macros should be identical in GTMHTTPFetcher.h and GTMSessionFetcher.h + #if GTM_USE_SESSION_FETCHER + // Macros to new fetcher class. + #define GTMBridgeFetcher GTMSessionFetcher + #define GTMBridgeFetcherService GTMSessionFetcherService + #define GTMBridgeFetcherServiceProtocol GTMSessionFetcherServiceProtocol + #define GTMBridgeAssertValidSelector GTMSessionFetcherAssertValidSelector + #define GTMBridgeCookieStorage GTMSessionCookieStorage + #define GTMBridgeCleanedUserAgentString GTMFetcherCleanedUserAgentString + #define GTMBridgeSystemVersionString GTMFetcherSystemVersionString + #define GTMBridgeApplicationIdentifier GTMFetcherApplicationIdentifier + #define kGTMBridgeFetcherStatusDomain kGTMSessionFetcherStatusDomain + #define kGTMBridgeFetcherStatusBadRequest GTMSessionFetcherStatusBadRequest + #else + // Macros to old fetcher class. + #define GTMBridgeFetcher GTMHTTPFetcher + #define GTMBridgeFetcherService GTMHTTPFetcherService + #define GTMBridgeFetcherServiceProtocol GTMHTTPFetcherServiceProtocol + #define GTMBridgeAssertValidSelector GTMAssertSelectorNilOrImplementedWithArgs + #define GTMBridgeCookieStorage GTMCookieStorage + #define GTMBridgeCleanedUserAgentString GTMCleanedUserAgentString + #define GTMBridgeSystemVersionString GTMSystemVersionString + #define GTMBridgeApplicationIdentifier GTMApplicationIdentifier + #define kGTMBridgeFetcherStatusDomain kGTMHTTPFetcherStatusDomain + #define kGTMBridgeFetcherStatusBadRequest kGTMHTTPFetcherStatusBadRequest + #endif // GTM_USE_SESSION_FETCHER +#endif + +GTM_ASSUME_NONNULL_BEGIN + +// Notifications +// +// Fetch started and stopped, and fetch retry delay started and stopped. +extern NSString *const kGTMSessionFetcherStartedNotification; +extern NSString *const kGTMSessionFetcherStoppedNotification; +extern NSString *const kGTMSessionFetcherRetryDelayStartedNotification; +extern NSString *const kGTMSessionFetcherRetryDelayStoppedNotification; + +// Completion handler notification. This is intended for use by code capturing +// and replaying fetch requests and results for testing. For fetches where +// destinationFileURL or accumulateDataBlock is set for the fetcher, the data +// will be nil for successful fetches. +// +// This notification is posted on the main thread. +extern NSString *const kGTMSessionFetcherCompletionInvokedNotification; +extern NSString *const kGTMSessionFetcherCompletionDataKey; +extern NSString *const kGTMSessionFetcherCompletionErrorKey; + +// Constants for NSErrors created by the fetcher (excluding server status errors, +// and error objects originating in the OS.) +extern NSString *const kGTMSessionFetcherErrorDomain; + +// The fetcher turns server error status values (3XX, 4XX, 5XX) into NSErrors +// with domain kGTMSessionFetcherStatusDomain. +// +// Any server response body data accompanying the status error is added to the +// userInfo dictionary with key kGTMSessionFetcherStatusDataKey. +extern NSString *const kGTMSessionFetcherStatusDomain; +extern NSString *const kGTMSessionFetcherStatusDataKey; + +// When a fetch fails with an error, these keys are included in the error userInfo +// dictionary if retries were attempted. +extern NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey; +extern NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey; + +// Background session support requires access to NSUserDefaults. +// If [NSUserDefaults standardUserDefaults] doesn't yield the correct NSUserDefaults for your usage, +// ie for an App Extension, then implement this class/method to return the correct NSUserDefaults. +// https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW6 +@interface GTMSessionFetcherUserDefaultsFactory : NSObject + ++ (NSUserDefaults *)fetcherUserDefaults; + +@end + +#ifdef __cplusplus +} +#endif + +typedef NS_ENUM(NSInteger, GTMSessionFetcherError) { + GTMSessionFetcherErrorDownloadFailed = -1, + GTMSessionFetcherErrorUploadChunkUnavailable = -2, + GTMSessionFetcherErrorBackgroundExpiration = -3, + GTMSessionFetcherErrorBackgroundFetchFailed = -4, + GTMSessionFetcherErrorInsecureRequest = -5, + GTMSessionFetcherErrorTaskCreationFailed = -6, +}; + +typedef NS_ENUM(NSInteger, GTMSessionFetcherStatus) { + // Standard http status codes. + GTMSessionFetcherStatusNotModified = 304, + GTMSessionFetcherStatusBadRequest = 400, + GTMSessionFetcherStatusUnauthorized = 401, + GTMSessionFetcherStatusForbidden = 403, + GTMSessionFetcherStatusPreconditionFailed = 412 +}; + +#if !GTMSESSION_DEPRECATE_OLD_ENUMS +#define kGTMSessionFetcherErrorDownloadFailed GTMSessionFetcherErrorDownloadFailed +#define kGTMSessionFetcherErrorUploadChunkUnavailable GTMSessionFetcherErrorUploadChunkUnavailable +#define kGTMSessionFetcherErrorBackgroundExpiration GTMSessionFetcherErrorBackgroundExpiration +#define kGTMSessionFetcherErrorBackgroundFetchFailed GTMSessionFetcherErrorBackgroundFetchFailed +#define kGTMSessionFetcherErrorInsecureRequest GTMSessionFetcherErrorInsecureRequest +#define kGTMSessionFetcherErrorTaskCreationFailed GTMSessionFetcherErrorTaskCreationFailed + +#define kGTMSessionFetcherStatusNotModified GTMSessionFetcherStatusNotModified +#define kGTMSessionFetcherStatusBadRequest GTMSessionFetcherStatusBadRequest +#define kGTMSessionFetcherStatusUnauthorized GTMSessionFetcherStatusUnauthorized +#define kGTMSessionFetcherStatusForbidden GTMSessionFetcherStatusForbidden +#define kGTMSessionFetcherStatusPreconditionFailed GTMSessionFetcherStatusPreconditionFailed +#endif // !GTMSESSION_DEPRECATE_OLD_ENUMS + +#ifdef __cplusplus +extern "C" { +#endif + +@class GTMSessionCookieStorage; +@class GTMSessionFetcher; + +// The configuration block is for modifying the NSURLSessionConfiguration only. +// DO NOT change any fetcher properties in the configuration block. +typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher, + NSURLSessionConfiguration *configuration); +typedef void (^GTMSessionFetcherSystemCompletionHandler)(void); +typedef void (^GTMSessionFetcherCompletionHandler)(NSData * GTM_NULLABLE_TYPE data, + NSError * GTM_NULLABLE_TYPE error); +typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream); +typedef void (^GTMSessionFetcherBodyStreamProvider)(GTMSessionFetcherBodyStreamProviderResponse response); +typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)(NSURLSessionResponseDisposition disposition); +typedef void (^GTMSessionFetcherDidReceiveResponseBlock)(NSURLResponse *response, + GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock); +typedef void (^GTMSessionFetcherChallengeDispositionBlock)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential); +typedef void (^GTMSessionFetcherChallengeBlock)(GTMSessionFetcher *fetcher, + NSURLAuthenticationChallenge *challenge, + GTMSessionFetcherChallengeDispositionBlock dispositionBlock); +typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest * GTM_NULLABLE_TYPE redirectedRequest); +typedef void (^GTMSessionFetcherWillRedirectBlock)(NSHTTPURLResponse *redirectResponse, + NSURLRequest *redirectRequest, + GTMSessionFetcherWillRedirectResponse response); +typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData * GTM_NULLABLE_TYPE buffer); +typedef void (^GTMSessionFetcherReceivedProgressBlock)(int64_t bytesWritten, + int64_t totalBytesWritten); +typedef void (^GTMSessionFetcherDownloadProgressBlock)(int64_t bytesWritten, + int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite); +typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent, + int64_t totalBytesSent, + int64_t totalBytesExpectedToSend); +typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)(NSCachedURLResponse * GTM_NULLABLE_TYPE cachedResponse); +typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)(NSCachedURLResponse *proposedResponse, + GTMSessionFetcherWillCacheURLResponseResponse responseBlock); +typedef void (^GTMSessionFetcherRetryResponse)(BOOL shouldRetry); +typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry, + NSError * GTM_NULLABLE_TYPE error, + GTMSessionFetcherRetryResponse response); + +typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse * GTM_NULLABLE_TYPE response, + NSData * GTM_NULLABLE_TYPE data, + NSError * GTM_NULLABLE_TYPE error); +typedef void (^GTMSessionFetcherTestBlock)(GTMSessionFetcher *fetcherToTest, + GTMSessionFetcherTestResponse testResponse); + +void GTMSessionFetcherAssertValidSelector(id GTM_NULLABLE_TYPE obj, SEL GTM_NULLABLE_TYPE sel, ...); + +// Utility functions for applications self-identifying to servers via a +// user-agent header + +// The "standard" user agent includes the application identifier, taken from the bundle, +// followed by a space and the system version string. Pass nil to use +mainBundle as the source +// of the bundle identifier. +// +// Applications may use this as a starting point for their own user agent strings, perhaps +// with additional sections appended. Use GTMFetcherCleanedUserAgentString() below to +// clean up any string being added to the user agent. +NSString *GTMFetcherStandardUserAgentString(NSBundle * GTM_NULLABLE_TYPE bundle); + +// Make a generic name and version for the current application, like +// com.example.MyApp/1.2.3 relying on the bundle identifier and the +// CFBundleShortVersionString or CFBundleVersion. +// +// The bundle ID may be overridden as the base identifier string by +// adding to the bundle's Info.plist a "GTMUserAgentID" key. +// +// If no bundle ID or override is available, the process name preceded +// by "proc_" is used. +NSString *GTMFetcherApplicationIdentifier(NSBundle * GTM_NULLABLE_TYPE bundle); + +// Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1 hw/iPod1_1" +NSString *GTMFetcherSystemVersionString(void); + +// Make a parseable user-agent identifier from the given string, replacing whitespace +// and commas with underscores, and removing other characters that may interfere +// with parsing of the full user-agent string. +// +// For example, @"[My App]" would become @"My_App" +NSString *GTMFetcherCleanedUserAgentString(NSString *str); + +// Grab the data from an input stream. Since streams cannot be assumed to be rewindable, +// this may be destructive; the caller can try to rewind the stream (by setting the +// NSStreamFileCurrentOffsetKey property) or can just use the NSData to make a new +// NSInputStream. This function is intended to facilitate testing rather than be used in +// production. +// +// This function operates synchronously on the current thread. Depending on how the +// input stream is implemented, it may be appropriate to dispatch to a different +// queue before calling this function. +// +// Failure is indicated by a returned data value of nil. +NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError); + +#ifdef __cplusplus +} // extern "C" +#endif + + +#if !GTM_USE_SESSION_FETCHER +@protocol GTMHTTPFetcherServiceProtocol; +#endif + +// This protocol allows abstract references to the fetcher service, primarily for +// fetchers (which may be compiled without the fetcher service class present.) +// +// Apps should not need to use this protocol. +@protocol GTMSessionFetcherServiceProtocol +// This protocol allows us to call into the service without requiring +// GTMSessionFetcherService sources in this project + +@property(atomic, strong) dispatch_queue_t callbackQueue; + +- (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher; + +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request; +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher; + +@property(atomic, assign) BOOL reuseSession; +- (GTM_NULLABLE NSURLSession *)session; +- (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation; +- (GTM_NULLABLE id)sessionDelegate; +- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate; + +// Methods for compatibility with the old GTMHTTPFetcher. +@property(readonly, strong, GTM_NULLABLE) NSOperationQueue *delegateQueue; + +@end // @protocol GTMSessionFetcherServiceProtocol + +#ifndef GTM_FETCHER_AUTHORIZATION_PROTOCOL +#define GTM_FETCHER_AUTHORIZATION_PROTOCOL 1 +@protocol GTMFetcherAuthorizationProtocol +@required +// This protocol allows us to call the authorizer without requiring its sources +// in this project. +- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request + delegate:(id)delegate + didFinishSelector:(SEL)sel; + +- (void)stopAuthorization; + +- (void)stopAuthorizationForRequest:(NSURLRequest *)request; + +- (BOOL)isAuthorizingRequest:(NSURLRequest *)request; + +- (BOOL)isAuthorizedRequest:(NSURLRequest *)request; + +@property(strong, readonly, GTM_NULLABLE) NSString *userEmail; + +@optional + +// Indicate if authorization may be attempted. Even if this succeeds, +// authorization may fail if the user's permissions have been revoked. +@property(readonly) BOOL canAuthorize; + +// For development only, allow authorization of non-SSL requests, allowing +// transmission of the bearer token unencrypted. +@property(assign) BOOL shouldAuthorizeAllRequests; + +- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request + completionHandler:(void (^)(NSError * GTM_NULLABLE_TYPE error))handler; + +#if GTM_USE_SESSION_FETCHER +@property (weak, GTM_NULLABLE) id fetcherService; +#else +@property (weak, GTM_NULLABLE) id fetcherService; +#endif + +- (BOOL)primeForRefresh; + +@end +#endif // GTM_FETCHER_AUTHORIZATION_PROTOCOL + +#if TARGET_OS_IPHONE +// A protocol for an alternative target for messages from GTMSessionFetcher to UIApplication. +// Set the target using +[GTMSessionFetcher setSubstituteUIApplication:] +@protocol GTMUIApplicationProtocol +- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName + expirationHandler:(void(^ __nullable)(void))handler; +- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier; +@end +#endif + +#pragma mark - + +// GTMSessionFetcher objects are used for async retrieval of an http get or post +// +// See additional comments at the beginning of this file +@interface GTMSessionFetcher : NSObject + +// Create a fetcher +// +// fetcherWithRequest will return an autoreleased fetcher, but if +// the connection is successfully created, the connection should retain the +// fetcher for the life of the connection as well. So the caller doesn't have +// to retain the fetcher explicitly unless they want to be able to cancel it. ++ (instancetype)fetcherWithRequest:(GTM_NULLABLE NSURLRequest *)request; + +// Convenience methods that make a request, like +fetcherWithRequest ++ (instancetype)fetcherWithURL:(NSURL *)requestURL; ++ (instancetype)fetcherWithURLString:(NSString *)requestURLString; + +// Methods for creating fetchers to continue previous fetches. ++ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData; ++ (GTM_NULLABLE instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier; + +// Returns an array of currently active fetchers for background sessions, +// both restarted and newly created ones. ++ (GTM_NSArrayOf(GTMSessionFetcher *) *)fetchersForBackgroundSessions; + +// Designated initializer. +// +// Applications should create fetchers with a "fetcherWith..." method on a fetcher +// service or a class method, not with this initializer. +// +// The configuration should typically be nil. Applications needing to customize +// the configuration may do so by setting the configurationBlock property. +- (instancetype)initWithRequest:(GTM_NULLABLE NSURLRequest *)request + configuration:(GTM_NULLABLE NSURLSessionConfiguration *)configuration; + +// The fetcher's request. This may not be set after beginFetch has been invoked. The request +// may change due to redirects. +@property(strong, GTM_NULLABLE) NSURLRequest *request; + +// Set a header field value on the request. Header field value changes will not +// affect a fetch after the fetch has begun. +- (void)setRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field; + +// The fetcher's request (deprecated.) +// +// Exposing a mutable object in the interface was convenient but a bad design decision due +// to thread-safety requirements. Clients should use the request property and +// setRequestValue:forHTTPHeaderField: instead. +@property(atomic, readonly, GTM_NULLABLE) NSMutableURLRequest *mutableRequest + GTMSESSION_DEPRECATE_ON_2016_SDKS("use 'request' or '-setRequestValue:forHTTPHeaderField:'"); + +// Data used for resuming a download task. +@property(atomic, readonly, GTM_NULLABLE) NSData *downloadResumeData; + +// The configuration; this must be set before the fetch begins. If no configuration is +// set or inherited from the fetcher service, then the fetcher uses an ephemeral config. +// +// NOTE: This property should typically be nil. Applications needing to customize +// the configuration should do so by setting the configurationBlock property. +// That allows the fetcher to pick an appropriate base configuration, with the +// application setting only the configuration properties it needs to customize. +@property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration; + +// A block the client may use to customize the configuration used to create the session. +// +// This is called synchronously, either on the thread that begins the fetch or, during a retry, +// on the main thread. The configuration block may be called repeatedly if multiple fetchers are +// created. +// +// The configuration block is for modifying the NSURLSessionConfiguration only. +// DO NOT change any fetcher properties in the configuration block. Fetcher properties +// may be set in the fetcher service prior to fetcher creation, or on the fetcher prior +// to invoking beginFetch. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock; + +// A session is created as needed by the fetcher. A fetcher service object +// may maintain sessions for multiple fetches to the same host. +@property(atomic, strong, GTM_NULLABLE) NSURLSession *session; + +// The task in flight. +@property(atomic, readonly, GTM_NULLABLE) NSURLSessionTask *sessionTask; + +// The background session identifier. +@property(atomic, readonly, GTM_NULLABLE) NSString *sessionIdentifier; + +// Indicates a fetcher created to finish a background session task. +@property(atomic, readonly) BOOL wasCreatedFromBackgroundSession; + +// Additional user-supplied data to encode into the session identifier. Since session identifier +// length limits are unspecified, this should be kept small. Key names beginning with an underscore +// are reserved for use by the fetcher. +@property(atomic, strong, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *sessionUserInfo; + +// The human-readable description to be assigned to the task. +@property(atomic, copy, GTM_NULLABLE) NSString *taskDescription; + +// The priority assigned to the task, if any. Use NSURLSessionTaskPriorityLow, +// NSURLSessionTaskPriorityDefault, or NSURLSessionTaskPriorityHigh. +@property(atomic, assign) float taskPriority; + +// The fetcher encodes information used to resume a session in the session identifier. +// This method, intended for internal use returns the encoded information. The sessionUserInfo +// dictionary is stored as identifier metadata. +- (GTM_NULLABLE GTM_NSDictionaryOf(NSString *, NSString *) *)sessionIdentifierMetadata; + +#if TARGET_OS_IPHONE +// The app should pass to this method the completion handler passed in the app delegate method +// application:handleEventsForBackgroundURLSession:completionHandler: ++ (void)application:(UIApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler; +#endif + +// Indicate that a newly created session should be a background session. +// A new session identifier will be created by the fetcher. +// +// Warning: The only thing background sessions are for is rare download +// of huge, batched files of data. And even just for those, there's a lot +// of pain and hackery needed to get transfers to actually happen reliably +// with background sessions. +// +// Don't try to upload or download in many background sessions, since the system +// will impose an exponentially increasing time penalty to prevent the app from +// getting too much background execution time. +// +// References: +// +// "Moving to Fewer, Larger Transfers" +// https://forums.developer.apple.com/thread/14853 +// +// "NSURLSession’s Resume Rate Limiter" +// https://forums.developer.apple.com/thread/14854 +// +// "Background Session Task state persistence" +// https://forums.developer.apple.com/thread/11554 +// +@property(assign) BOOL useBackgroundSession; + +// Indicates if the fetcher was started using a background session. +@property(atomic, readonly, getter=isUsingBackgroundSession) BOOL usingBackgroundSession; + +// Indicates if uploads should use an upload task. This is always set for file or stream-provider +// bodies, but may be set explicitly for NSData bodies. +@property(atomic, assign) BOOL useUploadTask; + +// Indicates that the fetcher is using a session that may be shared with other fetchers. +@property(atomic, readonly) BOOL canShareSession; + +// By default, the fetcher allows only secure (https) schemes unless this +// property is set, or the GTM_ALLOW_INSECURE_REQUESTS build flag is set. +// +// For example, during debugging when fetching from a development server that lacks SSL support, +// this may be set to @[ @"http" ], or when the fetcher is used to retrieve local files, +// this may be set to @[ @"file" ]. +// +// This should be left as nil for release builds to avoid creating the opportunity for +// leaking private user behavior and data. If a server is providing insecure URLs +// for fetching by the client app, report the problem as server security & privacy bug. +// +// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when +// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist. +@property(atomic, copy, GTM_NULLABLE) GTM_NSArrayOf(NSString *) *allowedInsecureSchemes; + +// By default, the fetcher prohibits localhost requests unless this property is set, +// or the GTM_ALLOW_INSECURE_REQUESTS build flag is set. +// +// For localhost requests, the URL scheme is not checked when this property is set. +// +// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when +// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist. +@property(atomic, assign) BOOL allowLocalhostRequest; + +// By default, the fetcher requires valid server certs. This may be bypassed +// temporarily for development against a test server with an invalid cert. +@property(atomic, assign) BOOL allowInvalidServerCertificates; + +// Cookie storage object for this fetcher. If nil, the fetcher will use a static cookie +// storage instance shared among fetchers. If this fetcher was created by a fetcher service +// object, it will be set to use the service object's cookie storage. See Cookies section above for +// the full discussion. +// +// Because as of Jan 2014 standalone instances of NSHTTPCookieStorage do not actually +// store any cookies (Radar 15735276) we use our own subclass, GTMSessionCookieStorage, +// to hold cookies in memory. +@property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage; + +// Setting the credential is optional; it is used if the connection receives +// an authentication challenge. +@property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential; + +// Setting the proxy credential is optional; it is used if the connection +// receives an authentication challenge from a proxy. +@property(atomic, strong, GTM_NULLABLE) NSURLCredential *proxyCredential; + +// If body data, body file URL, or body stream provider is not set, then a GET request +// method is assumed. +@property(atomic, strong, GTM_NULLABLE) NSData *bodyData; + +// File to use as the request body. This forces use of an upload task. +@property(atomic, strong, GTM_NULLABLE) NSURL *bodyFileURL; + +// Length of body to send, expected or actual. +@property(atomic, readonly) int64_t bodyLength; + +// The body stream provider may be called repeatedly to provide a body. +// Setting a body stream provider forces use of an upload task. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherBodyStreamProvider bodyStreamProvider; + +// Object to add authorization to the request, if needed. +// +// This may not be changed once beginFetch has been invoked. +@property(atomic, strong, GTM_NULLABLE) id authorizer; + +// The service object that created and monitors this fetcher, if any. +@property(atomic, strong) id service; + +// The host, if any, used to classify this fetcher in the fetcher service. +@property(atomic, copy, GTM_NULLABLE) NSString *serviceHost; + +// The priority, if any, used for starting fetchers in the fetcher service. +// +// Lower values are higher priority; the default is 0, and values may +// be negative or positive. This priority affects only the start order of +// fetchers that are being delayed by a fetcher service when the running fetchers +// exceeds the service's maxRunningFetchersPerHost. A priority of NSIntegerMin will +// exempt this fetcher from delay. +@property(atomic, assign) NSInteger servicePriority; + +// The delegate's optional didReceiveResponse block may be used to inspect or alter +// the session task response. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock; + +// The delegate's optional challenge block may be used to inspect or alter +// the session task challenge. +// +// If this block is not set, the fetcher's default behavior for the NSURLSessionTask +// didReceiveChallenge: delegate method is to use the fetcher's respondToChallenge: method +// which relies on the fetcher's credential and proxyCredential properties. +// +// Warning: This may be called repeatedly if the challenge fails. Check +// challenge.previousFailureCount to identify repeated invocations. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock; + +// The delegate's optional willRedirect block may be used to inspect or alter +// the redirection. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillRedirectBlock willRedirectBlock; + +// The optional send progress block reports body bytes uploaded. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherSendProgressBlock sendProgressBlock; + +// The optional accumulate block may be set by clients wishing to accumulate data +// themselves rather than let the fetcher append each buffer to an NSData. +// +// When this is called with nil data (such as on redirect) the client +// should empty its accumulation buffer. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherAccumulateDataBlock accumulateDataBlock; + +// The optional received progress block may be used to monitor data +// received from a data task. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherReceivedProgressBlock receivedProgressBlock; + +// The delegate's optional downloadProgress block may be used to monitor download +// progress in writing to disk. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDownloadProgressBlock downloadProgressBlock; + +// The delegate's optional willCacheURLResponse block may be used to alter the cached +// NSURLResponse. The user may prevent caching by passing nil to the block's response. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock; + +// Enable retrying; see comments at the top of this file. Setting +// retryEnabled=YES resets the min and max retry intervals. +@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled; + +// Retry block is optional for retries. +// +// If present, this block should call the response block with YES to cause a retry or NO to end the +// fetch. +// See comments at the top of this file. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherRetryBlock retryBlock; + +// Retry intervals must be strictly less than maxRetryInterval, else +// they will be limited to maxRetryInterval and no further retries will +// be attempted. Setting maxRetryInterval to 0.0 will reset it to the +// default value, 60 seconds for downloads and 600 seconds for uploads. +@property(atomic, assign) NSTimeInterval maxRetryInterval; + +// Starting retry interval. Setting minRetryInterval to 0.0 will reset it +// to a random value between 1.0 and 2.0 seconds. Clients should normally not +// set this except for unit testing. +@property(atomic, assign) NSTimeInterval minRetryInterval; + +// Multiplier used to increase the interval between retries, typically 2.0. +// Clients should not need to set this. +@property(atomic, assign) double retryFactor; + +// Number of retries attempted. +@property(atomic, readonly) NSUInteger retryCount; + +// Interval delay to precede next retry. +@property(atomic, readonly) NSTimeInterval nextRetryInterval; + +#if GTM_BACKGROUND_TASK_FETCHING +// Skip use of a UIBackgroundTask, thus requiring fetches to complete when the app is in the +// foreground. +// +// Targets should define GTM_BACKGROUND_TASK_FETCHING to 0 to avoid use of a UIBackgroundTask +// on iOS to allow fetches to complete in the background. This property is available when +// it's not practical to set the preprocessor define. +@property(atomic, assign) BOOL skipBackgroundTask; +#endif // GTM_BACKGROUND_TASK_FETCHING + +// Begin fetching the request +// +// The delegate may optionally implement the callback or pass nil for the selector or handler. +// +// The delegate and all callback blocks are retained between the beginFetch call until after the +// finish callback, or until the fetch is stopped. +// +// An error is passed to the callback for server statuses 300 or +// higher, with the status stored as the error object's code. +// +// finishedSEL has a signature like: +// - (void)fetcher:(GTMSessionFetcher *)fetcher +// finishedWithData:(NSData *)data +// error:(NSError *)error; +// +// If the application has specified a destinationFileURL or an accumulateDataBlock +// for the fetcher, the data parameter passed to the callback will be nil. + +- (void)beginFetchWithDelegate:(GTM_NULLABLE id)delegate + didFinishSelector:(GTM_NULLABLE SEL)finishedSEL; + +- (void)beginFetchWithCompletionHandler:(GTM_NULLABLE GTMSessionFetcherCompletionHandler)handler; + +// Returns YES if this fetcher is in the process of fetching a URL. +@property(atomic, readonly, getter=isFetching) BOOL fetching; + +// Cancel the fetch of the request that's currently in progress. The completion handler +// will not be called. +- (void)stopFetching; + +// A block to be called when the fetch completes. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherCompletionHandler completionHandler; + +// A block to be called if download resume data becomes available. +@property(atomic, strong, GTM_NULLABLE) void (^resumeDataBlock)(NSData *); + +// Return the status code from the server response. +@property(atomic, readonly) NSInteger statusCode; + +// Return the http headers from the response. +@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *responseHeaders; + +// The response, once it's been received. +@property(atomic, strong, readonly, GTM_NULLABLE) NSURLResponse *response; + +// Bytes downloaded so far. +@property(atomic, readonly) int64_t downloadedLength; + +// Buffer of currently-downloaded data, if available. +@property(atomic, readonly, strong, GTM_NULLABLE) NSData *downloadedData; + +// Local path to which the downloaded file will be moved. +// +// If a file already exists at the path, it will be overwritten. +// Will create the enclosing folders if they are not present. +@property(atomic, strong, GTM_NULLABLE) NSURL *destinationFileURL; + +// The time this fetcher originally began fetching. This is useful as a time +// barrier for ignoring irrelevant fetch notifications or callbacks. +@property(atomic, strong, readonly, GTM_NULLABLE) NSDate *initialBeginFetchDate; + +// userData is retained solely for the convenience of the client. +@property(atomic, strong, GTM_NULLABLE) id userData; + +// Stored property values are retained solely for the convenience of the client. +@property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties; + +- (void)setProperty:(GTM_NULLABLE id)obj forKey:(NSString *)key; // Pass nil for obj to remove the property. +- (GTM_NULLABLE id)propertyForKey:(NSString *)key; + +- (void)addPropertiesFromDictionary:(GTM_NSDictionaryOf(NSString *, id) *)dict; + +// Comments are useful for logging, so are strongly recommended for each fetcher. +@property(atomic, copy, GTM_NULLABLE) NSString *comment; + +- (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2); + +// Log of request and response, if logging is enabled +@property(atomic, copy, GTM_NULLABLE) NSString *log; + +// Callbacks are run on this queue. If none is supplied, the main queue is used. +@property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue; + +// The queue used internally by the session to invoke its delegate methods in the fetcher. +// +// Application callbacks are always called by the fetcher on the callbackQueue above, +// not on this queue. Apps should generally not change this queue. +// +// The default delegate queue is the main queue. +// +// This value is ignored after the session has been created, so this +// property should be set in the fetcher service rather in the fetcher as it applies +// to a shared session. +@property(atomic, strong, GTM_NULL_RESETTABLE) NSOperationQueue *sessionDelegateQueue; + +// Spin the run loop or sleep the thread, discarding events, until the fetch has completed. +// +// This is only for use in testing or in tools without a user interface. +// +// Note: Synchronous fetches should never be used by shipping apps; they are +// sufficient reason for rejection from the app store. +// +// Returns NO if timed out. +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds; + +// Test block is optional for testing. +// +// If present, this block will cause the fetcher to skip starting the session, and instead +// use the test block response values when calling the completion handler and delegate code. +// +// Test code can set this on the fetcher or on the fetcher service. For testing libraries +// that use a fetcher without exposing either the fetcher or the fetcher service, the global +// method setGlobalTestBlock: will set the block for all fetchers that do not have a test +// block set. +// +// The test code can pass nil for all response parameters to indicate that the fetch +// should proceed. +// +// Applications can exclude test block support by setting GTM_DISABLE_FETCHER_TEST_BLOCK. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock; + ++ (void)setGlobalTestBlock:(GTM_NULLABLE GTMSessionFetcherTestBlock)block; + +#if TARGET_OS_IPHONE +// For testing or to override UIApplication invocations, apps may specify an alternative +// target for messages to UIApplication. ++ (void)setSubstituteUIApplication:(nullable id)substituteUIApplication; ++ (nullable id)substituteUIApplication; +#endif // TARGET_OS_IPHONE + +// Exposed for testing. ++ (GTMSessionCookieStorage *)staticCookieStorage; ++ (BOOL)appAllowsInsecureRequests; + +#if STRIP_GTM_FETCH_LOGGING +// If logging is stripped, provide a stub for the main method +// for controlling logging. ++ (void)setLoggingEnabled:(BOOL)flag; ++ (BOOL)isLoggingEnabled; + +#else + +// These methods let an application log specific body text, such as the text description of a binary +// request or response. The application should set the fetcher to defer response body logging until +// the response has been received and the log response body has been set by the app. For example: +// +// fetcher.logRequestBody = [binaryObject stringDescription]; +// fetcher.deferResponseBodyLogging = YES; +// [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { +// if (error == nil) { +// fetcher.logResponseBody = [[[MyThing alloc] initWithData:data] stringDescription]; +// } +// fetcher.deferResponseBodyLogging = NO; +// }]; + +@property(atomic, copy, GTM_NULLABLE) NSString *logRequestBody; +@property(atomic, assign) BOOL deferResponseBodyLogging; +@property(atomic, copy, GTM_NULLABLE) NSString *logResponseBody; + +// Internal logging support. +@property(atomic, readonly) NSData *loggedStreamData; +@property(atomic, assign) BOOL hasLoggedError; +@property(atomic, strong, GTM_NULLABLE) NSURL *redirectedFromURL; +- (void)appendLoggedStreamData:(NSData *)dataToAdd; +- (void)clearLoggedStreamData; + +#endif // STRIP_GTM_FETCH_LOGGING + +@end + +@interface GTMSessionFetcher (BackwardsCompatibilityOnly) +// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves. +// This method is just for compatibility with the old GTMHTTPFetcher class. +- (void)setCookieStorageMethod:(NSInteger)method; +@end + +// Until we can just instantiate NSHTTPCookieStorage for local use, we'll +// implement all the public methods ourselves. This stores cookies only in +// memory. Additional methods are provided for testing. +// +// iOS 9/OS X 10.11 added +[NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:] +// which may also be used to create cookie storage. +@interface GTMSessionCookieStorage : NSHTTPCookieStorage + +// Add the array off cookies to the storage, replacing duplicates. +// Also removes expired cookies from the storage. +- (void)setCookies:(GTM_NULLABLE GTM_NSArrayOf(NSHTTPCookie *) *)cookies; + +- (void)removeAllCookies; + +@end + +// Macros to monitor synchronization blocks in debug builds. +// These report problems using GTMSessionCheckDebug. +// +// GTMSessionMonitorSynchronized Start monitoring a top-level-only +// @sync scope. +// GTMSessionMonitorRecursiveSynchronized Start monitoring a top-level or +// recursive @sync scope. +// GTMSessionCheckSynchronized Verify that the current execution +// is inside a @sync scope. +// GTMSessionCheckNotSynchronized Verify that the current execution +// is not inside a @sync scope. +// +// Example usage: +// +// - (void)myExternalMethod { +// @synchronized(self) { +// GTMSessionMonitorSynchronized(self) +// +// - (void)myInternalMethod { +// GTMSessionCheckSynchronized(self); +// +// - (void)callMyCallbacks { +// GTMSessionCheckNotSynchronized(self); +// +// GTMSessionCheckNotSynchronized is available for verifying the code isn't +// in a deadlockable @sync state when posting notifications and invoking +// callbacks. Don't use GTMSessionCheckNotSynchronized immediately before a +// @sync scope; the normal recursiveness check of GTMSessionMonitorSynchronized +// can catch those. + +#ifdef __OBJC__ +#if DEBUG + #define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) \ + varname ## counter + #define __GTMSessionMonitorSynchronizedVariable(varname, counter) \ + __GTMSessionMonitorSynchronizedVariableInner(varname, counter) + + #define GTMSessionMonitorSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id \ + __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:NO \ + functionName:__func__] + + #define GTMSessionMonitorRecursiveSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id \ + __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:YES \ + functionName:__func__] + + #define GTMSessionCheckSynchronized(obj) { \ + GTMSESSION_ASSERT_DEBUG( \ + [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \ + @" on " #obj " in %s. Call stack:\n%@", \ + __func__, [NSThread callStackSymbols]); \ + } + + #define GTMSessionCheckNotSynchronized(obj) { \ + GTMSESSION_ASSERT_DEBUG( \ + ![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \ + @" on " #obj " in %s by %@. Call stack:\n%@", __func__, \ + [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + [NSThread callStackSymbols]); \ + } + +// GTMSessionSyncMonitorInternal is a private class that keeps track of the +// beginning and end of synchronized scopes. +// +// This class should not be used directly, but only via the +// GTMSessionMonitorSynchronized macro. +@interface GTMSessionSyncMonitorInternal : NSObject +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName; +// Return the names of the functions that hold sync on the object, or nil if none. ++ (NSArray *)functionsHoldingSynchronizationOnObject:(id)object; +@end + +#else + #define GTMSessionMonitorSynchronized(obj) do { } while (0) + #define GTMSessionMonitorRecursiveSynchronized(obj) do { } while (0) + #define GTMSessionCheckSynchronized(obj) do { } while (0) + #define GTMSessionCheckNotSynchronized(obj) do { } while (0) +#endif // !DEBUG +#endif // __OBJC__ + + +GTM_ASSUME_NONNULL_END diff --git a/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m new file mode 100644 index 0000000..54b217a --- /dev/null +++ b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m @@ -0,0 +1,4457 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcher.h" + +#import + +#ifndef STRIP_GTM_FETCH_LOGGING + #error GTMSessionFetcher headers should have defaulted this if it wasn't already defined. +#endif + +GTM_ASSUME_NONNULL_BEGIN + +NSString *const kGTMSessionFetcherStartedNotification = @"kGTMSessionFetcherStartedNotification"; +NSString *const kGTMSessionFetcherStoppedNotification = @"kGTMSessionFetcherStoppedNotification"; +NSString *const kGTMSessionFetcherRetryDelayStartedNotification = @"kGTMSessionFetcherRetryDelayStartedNotification"; +NSString *const kGTMSessionFetcherRetryDelayStoppedNotification = @"kGTMSessionFetcherRetryDelayStoppedNotification"; + +NSString *const kGTMSessionFetcherCompletionInvokedNotification = @"kGTMSessionFetcherCompletionInvokedNotification"; +NSString *const kGTMSessionFetcherCompletionDataKey = @"data"; +NSString *const kGTMSessionFetcherCompletionErrorKey = @"error"; + +NSString *const kGTMSessionFetcherErrorDomain = @"com.google.GTMSessionFetcher"; +NSString *const kGTMSessionFetcherStatusDomain = @"com.google.HTTPStatus"; +NSString *const kGTMSessionFetcherStatusDataKey = @"data"; // data returned with a kGTMSessionFetcherStatusDomain error + +NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey = @"kGTMSessionFetcherNumberOfRetriesDoneKey"; +NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey = @"kGTMSessionFetcherElapsedIntervalWithRetriesKey"; + +static NSString *const kGTMSessionIdentifierPrefix = @"com.google.GTMSessionFetcher"; +static NSString *const kGTMSessionIdentifierDestinationFileURLMetadataKey = @"_destURL"; +static NSString *const kGTMSessionIdentifierBodyFileURLMetadataKey = @"_bodyURL"; + +// The default max retry interview is 10 minutes for uploads (POST/PUT/PATCH), +// 1 minute for downloads. +static const NSTimeInterval kUnsetMaxRetryInterval = -1.0; +static const NSTimeInterval kDefaultMaxDownloadRetryInterval = 60.0; +static const NSTimeInterval kDefaultMaxUploadRetryInterval = 60.0 * 10.; + +#ifdef GTMSESSION_PERSISTED_DESTINATION_KEY +// Projects using unique class names should also define a unique persisted destination key. +static NSString * const kGTMSessionFetcherPersistedDestinationKey = + GTMSESSION_PERSISTED_DESTINATION_KEY; +#else +static NSString * const kGTMSessionFetcherPersistedDestinationKey = + @"com.google.GTMSessionFetcher.downloads"; +#endif + +GTM_ASSUME_NONNULL_END + +// +// GTMSessionFetcher +// + +#if 0 +#define GTM_LOG_BACKGROUND_SESSION(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__) +#else +#define GTM_LOG_BACKGROUND_SESSION(...) +#endif + +#ifndef GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY + #if (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0) + #define GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY 1 + #endif +#endif + +@interface GTMSessionFetcher () + +@property(atomic, strong, readwrite, GTM_NULLABLE) NSData *downloadedData; +@property(atomic, strong, readwrite, GTM_NULLABLE) NSData *downloadResumeData; + +#if GTM_BACKGROUND_TASK_FETCHING +@property(assign, atomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier; +#endif + +@property(atomic, readwrite, getter=isUsingBackgroundSession) BOOL usingBackgroundSession; + +@end + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (GTMSessionFetcherLoggingInternal) +- (void)logFetchWithError:(NSError *)error; +- (void)logNowWithError:(GTM_NULLABLE NSError *)error; +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream; +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider; +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +GTM_ASSUME_NONNULL_BEGIN + +static NSTimeInterval InitialMinRetryInterval(void) { + return 1.0 + ((double)(arc4random_uniform(0x0FFFF)) / (double) 0x0FFFF); +} + +static BOOL IsLocalhost(NSString * GTM_NULLABLE_TYPE host) { + // We check if there's host, and then make the comparisons. + if (host == nil) return NO; + return ([host caseInsensitiveCompare:@"localhost"] == NSOrderedSame + || [host isEqual:@"::1"] + || [host isEqual:@"127.0.0.1"]); +} + +static GTMSessionFetcherTestBlock GTM_NULLABLE_TYPE gGlobalTestBlock; + +@implementation GTMSessionFetcher { + NSMutableURLRequest *_request; // after beginFetch, changed only in delegate callbacks + BOOL _useUploadTask; // immutable after beginFetch + NSURL *_bodyFileURL; // immutable after beginFetch + GTMSessionFetcherBodyStreamProvider _bodyStreamProvider; // immutable after beginFetch + NSURLSession *_session; + BOOL _shouldInvalidateSession; // immutable after beginFetch + NSURLSession *_sessionNeedingInvalidation; + NSURLSessionConfiguration *_configuration; + NSURLSessionTask *_sessionTask; + NSString *_taskDescription; + float _taskPriority; + NSURLResponse *_response; + NSString *_sessionIdentifier; + BOOL _wasCreatedFromBackgroundSession; + BOOL _didCreateSessionIdentifier; + NSString *_sessionIdentifierUUID; + BOOL _userRequestedBackgroundSession; + BOOL _usingBackgroundSession; + NSMutableData * GTM_NULLABLE_TYPE _downloadedData; + NSError *_downloadFinishedError; + NSData *_downloadResumeData; // immutable after construction + NSURL *_destinationFileURL; + int64_t _downloadedLength; + NSURLCredential *_credential; // username & password + NSURLCredential *_proxyCredential; // credential supplied to proxy servers + BOOL _isStopNotificationNeeded; // set when start notification has been sent + BOOL _isUsingTestBlock; // set when a test block was provided (remains set when the block is released) + id _userData; // retained, if set by caller + NSMutableDictionary *_properties; // more data retained for caller + dispatch_queue_t _callbackQueue; + dispatch_group_t _callbackGroup; // read-only after creation + NSOperationQueue *_delegateQueue; // immutable after beginFetch + + id _authorizer; // immutable after beginFetch + + // The service object that created and monitors this fetcher, if any. + id _service; // immutable; set by the fetcher service upon creation + NSString *_serviceHost; + NSInteger _servicePriority; // immutable after beginFetch + BOOL _hasStoppedFetching; // counterpart to _initialBeginFetchDate + BOOL _userStoppedFetching; + + BOOL _isRetryEnabled; // user wants auto-retry + NSTimer *_retryTimer; + NSUInteger _retryCount; + NSTimeInterval _maxRetryInterval; // default 60 (download) or 600 (upload) seconds + NSTimeInterval _minRetryInterval; // random between 1 and 2 seconds + NSTimeInterval _retryFactor; // default interval multiplier is 2 + NSTimeInterval _lastRetryInterval; + NSDate *_initialBeginFetchDate; // date that beginFetch was first invoked; immutable after initial beginFetch + NSDate *_initialRequestDate; // date of first request to the target server (ignoring auth) + BOOL _hasAttemptedAuthRefresh; // accessed only in shouldRetryNowForStatus: + + NSString *_comment; // comment for log + NSString *_log; +#if !STRIP_GTM_FETCH_LOGGING + NSMutableData *_loggedStreamData; + NSURL *_redirectedFromURL; + NSString *_logRequestBody; + NSString *_logResponseBody; + BOOL _hasLoggedError; + BOOL _deferResponseBodyLogging; +#endif +} + +#if !GTMSESSION_UNIT_TESTING ++ (void)load { + [self fetchersForBackgroundSessions]; +} +#endif + ++ (instancetype)fetcherWithRequest:(GTM_NULLABLE NSURLRequest *)request { + return [[self alloc] initWithRequest:request configuration:nil]; +} + ++ (instancetype)fetcherWithURL:(NSURL *)requestURL { + return [self fetcherWithRequest:[NSURLRequest requestWithURL:requestURL]]; +} + ++ (instancetype)fetcherWithURLString:(NSString *)requestURLString { + return [self fetcherWithURL:(NSURL *)[NSURL URLWithString:requestURLString]]; +} + ++ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData { + GTMSessionFetcher *fetcher = [self fetcherWithRequest:nil]; + fetcher.comment = @"Resuming download"; + fetcher.downloadResumeData = resumeData; + return fetcher; +} + ++ (GTM_NULLABLE instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (!fetcher && [sessionIdentifier hasPrefix:kGTMSessionIdentifierPrefix]) { + fetcher = [self fetcherWithRequest:nil]; + [fetcher setSessionIdentifier:sessionIdentifier]; + [sessionIdentifierToFetcherMap setObject:fetcher forKey:sessionIdentifier]; + fetcher->_wasCreatedFromBackgroundSession = YES; + [fetcher setCommentWithFormat:@"Resuming %@", + fetcher && fetcher->_sessionIdentifierUUID ? fetcher->_sessionIdentifierUUID : @"?"]; + } + return fetcher; +} + ++ (NSMapTable *)sessionIdentifierToFetcherMap { + // TODO: What if a service is involved in creating the fetcher? Currently, when re-creating + // fetchers, if a service was involved, it is not re-created. Should the service maintain a map? + static NSMapTable *gSessionIdentifierToFetcherMap = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gSessionIdentifierToFetcherMap = [NSMapTable strongToWeakObjectsMapTable]; + }); + return gSessionIdentifierToFetcherMap; +} + +#if !GTM_ALLOW_INSECURE_REQUESTS ++ (BOOL)appAllowsInsecureRequests { + // If the main bundle Info.plist key NSAppTransportSecurity is present, and it specifies + // NSAllowsArbitraryLoads, then we need to explicitly enforce secure schemes. +#if GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY + static BOOL allowsInsecureRequests; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSBundle *mainBundle = [NSBundle mainBundle]; + NSDictionary *appTransportSecurity = + [mainBundle objectForInfoDictionaryKey:@"NSAppTransportSecurity"]; + allowsInsecureRequests = + [[appTransportSecurity objectForKey:@"NSAllowsArbitraryLoads"] boolValue]; + }); + return allowsInsecureRequests; +#else + // For builds targeting iOS 8 or 10.10 and earlier, we want to require fetcher + // security checks. + return YES; +#endif // GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY +} +#else // GTM_ALLOW_INSECURE_REQUESTS ++ (BOOL)appAllowsInsecureRequests { + return YES; +} +#endif // !GTM_ALLOW_INSECURE_REQUESTS + + +- (instancetype)init { + return [self initWithRequest:nil configuration:nil]; +} + +- (instancetype)initWithRequest:(NSURLRequest *)request { + return [self initWithRequest:request configuration:nil]; +} + +- (instancetype)initWithRequest:(GTM_NULLABLE NSURLRequest *)request + configuration:(GTM_NULLABLE NSURLSessionConfiguration *)configuration { + self = [super init]; + if (self) { + if (![NSURLSession class]) { + Class oldFetcherClass = NSClassFromString(@"GTMHTTPFetcher"); + if (oldFetcherClass && request) { + self = [[oldFetcherClass alloc] initWithRequest:(NSURLRequest *)request]; + } else { + self = nil; + } + return self; + } +#if GTM_BACKGROUND_TASK_FETCHING + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; +#endif + _request = [request mutableCopy]; + _configuration = configuration; + + NSData *bodyData = request.HTTPBody; + if (bodyData) { + _bodyLength = (int64_t)bodyData.length; + } else { + _bodyLength = NSURLSessionTransferSizeUnknown; + } + + _callbackQueue = dispatch_get_main_queue(); + _callbackGroup = dispatch_group_create(); + _delegateQueue = [NSOperationQueue mainQueue]; + + _minRetryInterval = InitialMinRetryInterval(); + _maxRetryInterval = kUnsetMaxRetryInterval; + + _taskPriority = -1.0f; // Valid values if set are 0.0...1.0. + +#if !STRIP_GTM_FETCH_LOGGING + // Encourage developers to set the comment property or use + // setCommentWithFormat: by providing a default string. + _comment = @"(No fetcher comment set)"; +#endif + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + // disallow use of fetchers in a copy property + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (NSString *)description { + NSString *requestStr = self.request.URL.description; + if (requestStr.length == 0) { + if (self.downloadResumeData.length > 0) { + requestStr = @""; + } else if (_wasCreatedFromBackgroundSession) { + requestStr = @""; + } else { + requestStr = @""; + } + } + return [NSString stringWithFormat:@"%@ %p (%@)", [self class], self, requestStr]; +} + +- (void)dealloc { + GTMSESSION_ASSERT_DEBUG(!_isStopNotificationNeeded, + @"unbalanced fetcher notification for %@", _request.URL); + [self forgetSessionIdentifierForFetcherWithoutSyncCheck]; + + // Note: if a session task or a retry timer was pending, then this instance + // would be retained by those so it wouldn't be getting dealloc'd, + // hence we don't need to stopFetch here +} + +#pragma mark - + +// Begin fetching the URL (or begin a retry fetch). The delegate is retained +// for the duration of the fetch connection. + +- (void)beginFetchWithCompletionHandler:(GTM_NULLABLE GTMSessionFetcherCompletionHandler)handler { + GTMSessionCheckNotSynchronized(self); + + _completionHandler = [handler copy]; + + // The user may have called setDelegate: earlier if they want to use other + // delegate-style callbacks during the fetch; otherwise, the delegate is nil, + // which is fine. + [self beginFetchMayDelay:YES mayAuthorize:YES]; +} + +- (GTMSessionFetcherCompletionHandler)completionHandlerWithTarget:(GTM_NULLABLE_TYPE id)target + didFinishSelector:(GTM_NULLABLE_TYPE SEL)finishedSelector { + GTMSessionFetcherAssertValidSelector(target, finishedSelector, @encode(GTMSessionFetcher *), + @encode(NSData *), @encode(NSError *), 0); + GTMSessionFetcherCompletionHandler completionHandler = ^(NSData *data, NSError *error) { + if (target && finishedSelector) { + id selfArg = self; // Placate ARC. + NSMethodSignature *sig = [target methodSignatureForSelector:finishedSelector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setSelector:(SEL)finishedSelector]; + [invocation setTarget:target]; + [invocation setArgument:&selfArg atIndex:2]; + [invocation setArgument:&data atIndex:3]; + [invocation setArgument:&error atIndex:4]; + [invocation invoke]; + } + }; + return completionHandler; +} + +- (void)beginFetchWithDelegate:(GTM_NULLABLE_TYPE id)target + didFinishSelector:(GTM_NULLABLE_TYPE SEL)finishedSelector { + GTMSessionCheckNotSynchronized(self); + + GTMSessionFetcherCompletionHandler handler = [self completionHandlerWithTarget:target + didFinishSelector:finishedSelector]; + [self beginFetchWithCompletionHandler:handler]; +} + +- (void)beginFetchMayDelay:(BOOL)mayDelay + mayAuthorize:(BOOL)mayAuthorize { + // This is the internal entry point for re-starting fetches. + GTMSessionCheckNotSynchronized(self); + + NSMutableURLRequest *fetchRequest = _request; // The request property is now externally immutable. + NSURL *fetchRequestURL = fetchRequest.URL; + NSString *priorSessionIdentifier = self.sessionIdentifier; + + // A utility block for creating error objects when we fail to start the fetch. + NSError *(^beginFailureError)(NSInteger) = ^(NSInteger code){ + NSString *urlString = fetchRequestURL.absoluteString; + NSDictionary *userInfo = @{ + NSURLErrorFailingURLStringErrorKey : (urlString ? urlString : @"(missing URL)") + }; + return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:code + userInfo:userInfo]; + }; + + // Catch delegate queue maxConcurrentOperationCount values other than 1, particularly + // NSOperationQueueDefaultMaxConcurrentOperationCount (-1), to avoid the additional complexity + // of simultaneous or out-of-order delegate callbacks. + GTMSESSION_ASSERT_DEBUG(_delegateQueue.maxConcurrentOperationCount == 1, + @"delegate queue %@ should support one concurrent operation, not %zd", + _delegateQueue.name, _delegateQueue.maxConcurrentOperationCount); + + if (!_initialBeginFetchDate) { + // This ivar is set only here on the initial beginFetch so need not be synchronized. + _initialBeginFetchDate = [[NSDate alloc] init]; + } + + if (self.sessionTask != nil) { + // If cached fetcher returned through fetcherWithSessionIdentifier:, then it's + // already begun, but don't consider this a failure, since the user need not know this. + if (self.sessionIdentifier != nil) { + return; + } + GTMSESSION_ASSERT_DEBUG(NO, @"Fetch object %@ being reused; this should never happen", self); + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorDownloadFailed)]; + return; + } + + if (fetchRequestURL == nil && !_downloadResumeData && !priorSessionIdentifier) { + GTMSESSION_ASSERT_DEBUG(NO, @"Beginning a fetch requires a request with a URL"); + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorDownloadFailed)]; + return; + } + + // We'll respect the user's request for a background session (unless this is + // an upload fetcher, which does its initial request foreground.) + self.usingBackgroundSession = self.useBackgroundSession && [self canFetchWithBackgroundSession]; + + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSError *fileCheckError; + if (![bodyFileURL checkResourceIsReachableAndReturnError:&fileCheckError]) { + // This assert fires when the file being uploaded no longer exists once + // the fetcher is ready to start the upload. + GTMSESSION_ASSERT_DEBUG_OR_LOG(0, @"Body file is unreachable: %@\n %@", + bodyFileURL.path, fileCheckError); + [self failToBeginFetchWithError:fileCheckError]; + return; + } + } + + NSString *requestScheme = fetchRequestURL.scheme; + BOOL isDataRequest = [requestScheme isEqual:@"data"]; + if (isDataRequest) { + // NSURLSession does not support data URLs in background sessions. +#if DEBUG + if (priorSessionIdentifier || self.sessionIdentifier) { + GTMSESSION_LOG_DEBUG(@"Converting background to foreground session for %@", + fetchRequest); + } +#endif + [self setSessionIdentifierInternal:nil]; + self.useBackgroundSession = NO; + } + +#if GTM_ALLOW_INSECURE_REQUESTS + BOOL shouldCheckSecurity = NO; +#else + BOOL shouldCheckSecurity = (fetchRequestURL != nil + && !isDataRequest + && [[self class] appAllowsInsecureRequests]); +#endif + + if (shouldCheckSecurity) { + // Allow https only for requests, unless overridden by the client. + // + // Non-https requests may too easily be snooped, so we disallow them by default. + // + // file: and data: schemes are usually safe if they are hardcoded in the client or provided + // by a trusted source, but since it's fairly rare to need them, it's safest to make clients + // explicitly whitelist them. + BOOL isSecure = + requestScheme != nil && [requestScheme caseInsensitiveCompare:@"https"] == NSOrderedSame; + if (!isSecure) { + BOOL allowRequest = NO; + NSString *host = fetchRequestURL.host; + + // Check schemes first. A file scheme request may be allowed here, or as a localhost request. + for (NSString *allowedScheme in _allowedInsecureSchemes) { + if (requestScheme != nil && + [requestScheme caseInsensitiveCompare:allowedScheme] == NSOrderedSame) { + allowRequest = YES; + break; + } + } + if (!allowRequest) { + // Check for localhost requests. Security checks only occur for non-https requests, so + // this check won't happen for an https request to localhost. + BOOL isLocalhostRequest = (host.length == 0 && [fetchRequestURL isFileURL]) || IsLocalhost(host); + if (isLocalhostRequest) { + if (self.allowLocalhostRequest) { + allowRequest = YES; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Fetch request for localhost but fetcher" + @" allowLocalhostRequest is not set: %@", fetchRequestURL); + } + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Insecure fetch request has a scheme (%@)" + @" not found in fetcher allowedInsecureSchemes (%@): %@", + requestScheme, _allowedInsecureSchemes ?: @" @[] ", fetchRequestURL); + } + } + + if (!allowRequest) { +#if !DEBUG + NSLog(@"Insecure fetch disallowed for %@", fetchRequestURL.description ?: @"nil request URL"); +#endif + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorInsecureRequest)]; + return; + } + } // !isSecure + } // (requestURL != nil) && !isDataRequest + + if (self.cookieStorage == nil) { + self.cookieStorage = [[self class] staticCookieStorage]; + } + + BOOL isRecreatingSession = (self.sessionIdentifier != nil) && (fetchRequest == nil); + + self.canShareSession = !isRecreatingSession && !self.usingBackgroundSession; + + if (!self.session && self.canShareSession) { + self.session = [_service sessionForFetcherCreation]; + // If _session is nil, then the service's session creation semaphore will block + // until this fetcher invokes fetcherDidCreateSession: below, so this *must* invoke + // that method, even if the session fails to be created. + } + + if (!self.session) { + // Create a session. + if (!_configuration) { + if (priorSessionIdentifier || self.usingBackgroundSession) { + NSString *sessionIdentifier = priorSessionIdentifier; + if (!sessionIdentifier) { + sessionIdentifier = [self createSessionIdentifierWithMetadata:nil]; + } + NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap]; + [sessionIdentifierToFetcherMap setObject:self forKey:self.sessionIdentifier]; + +#if (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0) + // iOS 8/10.10 builds require the new backgroundSessionConfiguration method name. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionIdentifier]; +#elif (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0) + // Do a runtime check to avoid a deprecation warning about using + // +backgroundSessionConfiguration: on iOS 8. + if ([NSURLSessionConfiguration respondsToSelector:@selector(backgroundSessionConfigurationWithIdentifier:)]) { + // Running on iOS 8+/OS X 10.10+. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionIdentifier]; + } else { + // Running on iOS 7/OS X 10.9. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier]; + } +#else + // Building with an SDK earlier than iOS 8/OS X 10.10. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier]; +#endif + self.usingBackgroundSession = YES; + self.canShareSession = NO; + } else { + _configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + } +#if !GTM_ALLOW_INSECURE_REQUESTS + _configuration.TLSMinimumSupportedProtocol = kTLSProtocol12; +#endif + } // !_configuration + _configuration.HTTPCookieStorage = self.cookieStorage; + + if (_configurationBlock) { + _configurationBlock(self, _configuration); + } + + id delegate = [_service sessionDelegate]; + if (!delegate || !self.canShareSession) { + delegate = self; + } + self.session = [NSURLSession sessionWithConfiguration:_configuration + delegate:delegate + delegateQueue:self.sessionDelegateQueue]; + GTMSESSION_ASSERT_DEBUG(self.session, @"Couldn't create session"); + + // Tell the service about the session created by this fetcher. This also signals the + // service's semaphore to allow other fetchers to request this session. + [_service fetcherDidCreateSession:self]; + + // If this assertion fires, the client probably tried to use a session identifier that was + // already used. The solution is to make the client use a unique identifier (or better yet let + // the session fetcher assign the identifier). + GTMSESSION_ASSERT_DEBUG(self.session.delegate == delegate, @"Couldn't assign delegate."); + + if (self.session) { + BOOL isUsingSharedDelegate = (delegate != self); + if (!isUsingSharedDelegate) { + _shouldInvalidateSession = YES; + } + } + } + + if (isRecreatingSession) { + _shouldInvalidateSession = YES; + + // Let's make sure there are tasks still running or if not that we get a callback from a + // completed one; otherwise, we assume the tasks failed. + // This is the observed behavior perhaps 25% of the time within the Simulator running 7.0.3 on + // exiting the app after starting an upload and relaunching the app if we manage to relaunch + // after the task has completed, but before the system relaunches us in the background. + [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, + NSArray *downloadTasks) { + if (dataTasks.count == 0 && uploadTasks.count == 0 && downloadTasks.count == 0) { + double const kDelayInSeconds = 1.0; // We should get progress indication or completion soon + dispatch_time_t checkForFeedbackDelay = + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelayInSeconds * NSEC_PER_SEC)); + dispatch_after(checkForFeedbackDelay, dispatch_get_main_queue(), ^{ + if (!self.sessionTask && !fetchRequest) { + // If our task and/or request haven't been restored, then we assume task feedback lost. + [self removePersistedBackgroundSessionFromDefaults]; + NSError *sessionError = + [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorBackgroundFetchFailed + userInfo:nil]; + [self failToBeginFetchWithError:sessionError]; + } + }); + } + }]; + return; + } + + self.downloadedData = nil; + self.downloadedLength = 0; + + if (_servicePriority == NSIntegerMin) { + mayDelay = NO; + } + if (mayDelay && _service) { + BOOL shouldFetchNow = [_service fetcherShouldBeginFetching:self]; + if (!shouldFetchNow) { + // The fetch is deferred, but will happen later. + // + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after the fetcher is restarted. + if (self.canShareSession) { + self.session = nil; + } + return; + } + } + + NSString *effectiveHTTPMethod = [fetchRequest valueForHTTPHeaderField:@"X-HTTP-Method-Override"]; + if (effectiveHTTPMethod == nil) { + effectiveHTTPMethod = fetchRequest.HTTPMethod; + } + BOOL isEffectiveHTTPGet = (effectiveHTTPMethod == nil + || [effectiveHTTPMethod isEqual:@"GET"]); + + BOOL needsUploadTask = (self.useUploadTask || self.bodyFileURL || self.bodyStreamProvider); + if (_bodyData || self.bodyStreamProvider || fetchRequest.HTTPBodyStream) { + if (isEffectiveHTTPGet) { + fetchRequest.HTTPMethod = @"POST"; + isEffectiveHTTPGet = NO; + } + + if (_bodyData) { + if (!needsUploadTask) { + fetchRequest.HTTPBody = _bodyData; + } +#if !STRIP_GTM_FETCH_LOGGING + } else if (fetchRequest.HTTPBodyStream) { + if ([self respondsToSelector:@selector(loggedInputStreamForInputStream:)]) { + fetchRequest.HTTPBodyStream = + [self performSelector:@selector(loggedInputStreamForInputStream:) + withObject:fetchRequest.HTTPBodyStream]; + } +#endif + } + } + + // We authorize after setting up the http method and body in the request + // because OAuth 1 may need to sign the request body + if (mayAuthorize && _authorizer && !isDataRequest) { + BOOL isAuthorized = [_authorizer isAuthorizedRequest:fetchRequest]; + if (!isAuthorized) { + // Authorization needed. + // + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after authorization completes. + if (self.canShareSession) { + self.session = nil; + } + + // Authorizing the request will recursively call this beginFetch:mayDelay: + // or failToBeginFetchWithError:. + [self authorizeRequest]; + return; + } + } + + // set the default upload or download retry interval, if necessary + if ([self isRetryEnabled] && self.maxRetryInterval <= 0) { + if (isEffectiveHTTPGet || [effectiveHTTPMethod isEqual:@"HEAD"]) { + [self setMaxRetryInterval:kDefaultMaxDownloadRetryInterval]; + } else { + [self setMaxRetryInterval:kDefaultMaxUploadRetryInterval]; + } + } + + // finally, start the connection + NSURLSessionTask *newSessionTask; + BOOL needsDataAccumulator = NO; + if (_downloadResumeData) { + newSessionTask = [_session downloadTaskWithResumeData:_downloadResumeData]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed downloadTaskWithResumeData for %@, resume data %tu bytes", + _session, _downloadResumeData.length); + } else if (_destinationFileURL && !isDataRequest) { + newSessionTask = [_session downloadTaskWithRequest:fetchRequest]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, @"Failed downloadTaskWithRequest for %@, %@", + _session, fetchRequest); + } else if (needsUploadTask) { + if (bodyFileURL) { + newSessionTask = [_session uploadTaskWithRequest:fetchRequest + fromFile:bodyFileURL]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithRequest for %@, %@, file %@", + _session, fetchRequest, bodyFileURL.path); + } else if (self.bodyStreamProvider) { + newSessionTask = [_session uploadTaskWithStreamedRequest:fetchRequest]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithStreamedRequest for %@, %@", + _session, fetchRequest); + } else { + GTMSESSION_ASSERT_DEBUG_OR_LOG(_bodyData != nil, + @"Upload task needs body data, %@", fetchRequest); + newSessionTask = [_session uploadTaskWithRequest:fetchRequest + fromData:(NSData * GTM_NONNULL_TYPE)_bodyData]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithRequest for %@, %@, body data %tu bytes", + _session, fetchRequest, _bodyData.length); + } + needsDataAccumulator = YES; + } else { + newSessionTask = [_session dataTaskWithRequest:fetchRequest]; + needsDataAccumulator = YES; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, @"Failed dataTaskWithRequest for %@, %@", + _session, fetchRequest); + } + self.sessionTask = newSessionTask; + + if (!newSessionTask) { + // We shouldn't get here; if we're here, an earlier assertion should have fired to explain + // which session task creation failed. + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorTaskCreationFailed)]; + return; + } + + if (needsDataAccumulator && _accumulateDataBlock == nil) { + self.downloadedData = [NSMutableData data]; + } + if (_taskDescription) { + newSessionTask.taskDescription = _taskDescription; + } + if (_taskPriority >= 0) { +#if (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0) + BOOL hasTaskPriority = YES; +#else + BOOL hasTaskPriority = [newSessionTask respondsToSelector:@selector(setPriority:)]; +#endif + if (hasTaskPriority) { + newSessionTask.priority = _taskPriority; + } + } + +#if GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSESSION_ASSERT_DEBUG(_testBlock == nil && gGlobalTestBlock == nil, @"test blocks disabled"); + _testBlock = nil; +#else + if (!_testBlock) { + if (gGlobalTestBlock) { + // Note that the test block may pass nil for all of its response parameters, + // indicating that the fetch should actually proceed. This is useful when the + // global test block has been set, and the app is only testing a specific + // fetcher. The block simulation code will then resume the task. + _testBlock = gGlobalTestBlock; + } + } + _isUsingTestBlock = (_testBlock != nil); +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK + +#if GTM_BACKGROUND_TASK_FETCHING + // Background tasks seem to interfere with out-of-process uploads and downloads. + if (!self.skipBackgroundTask && !self.useBackgroundSession) { + // Tell UIApplication that we want to continue even when the app is in the + // background. + id app = [[self class] fetcherUIApplication]; +#if DEBUG + NSString *bgTaskName = [NSString stringWithFormat:@"%@-%@", + [self class], fetchRequest.URL.host]; +#else + NSString *bgTaskName = @"GTMSessionFetcher"; +#endif + __block UIBackgroundTaskIdentifier bgTaskID = [app beginBackgroundTaskWithName:bgTaskName + expirationHandler:^{ + // Background task expiration callback - this block is always invoked by + // UIApplication on the main thread. + if (bgTaskID != UIBackgroundTaskInvalid) { + if (bgTaskID == self.backgroundTaskIdentifier) { + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + [app endBackgroundTask:bgTaskID]; + } + }]; + self.backgroundTaskIdentifier = bgTaskID; + } +#endif + + if (!_initialRequestDate) { + _initialRequestDate = [[NSDate alloc] init]; + } + + // We don't expect to reach here even on retry or auth until a stop notification has been sent + // for the previous task, but we should ensure that we don't unbalance that. + GTMSESSION_ASSERT_DEBUG(!_isStopNotificationNeeded, @"Start notification without a prior stop"); + [self sendStopNotificationIfNeeded]; + + [self addPersistedBackgroundSessionToDefaults]; + + [self setStopNotificationNeeded:YES]; + + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherStartedNotification + userInfo:nil + requireAsync:NO]; + + // The service needs to know our task if it is serving as NSURLSession delegate. + [_service fetcherDidBeginFetching:self]; + + if (_testBlock) { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + [self simulateFetchForTestBlock]; +#endif + } else { + // We resume the session task after posting the notification since the + // delegate callbacks may happen immediately if the fetch is started off + // the main thread or the session delegate queue is on a background thread, + // and we don't want to post a start notification after a premature finish + // of the session task. + [newSessionTask resume]; + } +} + +NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError) { + NSMutableData *data = [NSMutableData data]; + + [inputStream open]; + NSInteger numberOfBytesRead = 0; + while ([inputStream hasBytesAvailable]) { + uint8_t buffer[512]; + numberOfBytesRead = [inputStream read:buffer maxLength:sizeof(buffer)]; + if (numberOfBytesRead > 0) { + [data appendBytes:buffer length:(NSUInteger)numberOfBytesRead]; + } else { + break; + } + } + [inputStream close]; + NSError *streamError = inputStream.streamError; + + if (streamError) { + data = nil; + } + if (outError) { + *outError = streamError; + } + return data; +} + +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + +- (void)simulateFetchForTestBlock { + // This is invoked on the same thread as the beginFetch method was. + // + // Callbacks will all occur on the callback queue. + _testBlock(self, ^(NSURLResponse *response, NSData *responseData, NSError *error) { + // Callback from test block. + if (response == nil && responseData == nil && error == nil) { + // Assume the fetcher should execute rather than be tested. + _testBlock = nil; + _isUsingTestBlock = NO; + [_sessionTask resume]; + return; + } + + GTMSessionFetcherBodyStreamProvider bodyStreamProvider = self.bodyStreamProvider; + if (bodyStreamProvider) { + bodyStreamProvider(^(NSInputStream *bodyStream){ + // Read from the input stream into an NSData buffer. We'll drain the stream + // explicitly on a background queue. + [self invokeOnCallbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) + afterUserStopped:NO + block:^{ + NSError *streamError; + NSData *streamedData = GTMDataFromInputStream(bodyStream, &streamError); + + dispatch_async(dispatch_get_main_queue(), ^{ + // Continue callbacks on the main thread, since serial behavior + // is more reliable for tests. + [self simulateDataCallbacksForTestBlockWithBodyData:streamedData + response:response + responseData:responseData + error:(error ?: streamError)]; + }); + }]; + }); + } else { + // No input stream; use the supplied data or file URL. + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSError *readError; + _bodyData = [NSData dataWithContentsOfURL:bodyFileURL + options:NSDataReadingMappedIfSafe + error:&readError]; + error = readError; + } + + // No stream provider. + + // In real fetches, nothing happens until the run loop spins, so apps have leeway to + // set callbacks after they call beginFetch. We'll mirror that fetcher behavior by + // delaying callbacks here at least to the next spin of the run loop. That keeps + // immediate, synchronous setting of callback blocks after beginFetch working in tests. + dispatch_async(dispatch_get_main_queue(), ^{ + [self simulateDataCallbacksForTestBlockWithBodyData:_bodyData + response:response + responseData:responseData + error:error]; + }); + } + }); +} + +- (void)simulateByteTransferReportWithDataLength:(int64_t)totalDataLength + block:(GTMSessionFetcherSendProgressBlock)block { + // This utility method simulates transfer progress with up to three callbacks. + // It is used to call back to any of the progress blocks. + int64_t sendReportSize = totalDataLength / 3 + 1; + int64_t totalSent = 0; + while (totalSent < totalDataLength) { + int64_t bytesRemaining = totalDataLength - totalSent; + sendReportSize = MIN(sendReportSize, bytesRemaining); + totalSent += sendReportSize; + [self invokeOnCallbackQueueUnlessStopped:^{ + block(sendReportSize, totalSent, totalDataLength); + }]; + } +} + +- (void)simulateDataCallbacksForTestBlockWithBodyData:(NSData * GTM_NULLABLE_TYPE)bodyData + response:(NSURLResponse *)response + responseData:(NSData *)suppliedData + error:(NSError *)suppliedError { + __block NSData *responseData = suppliedData; + __block NSError *responseError = suppliedError; + + // This method does the test simulation of callbacks once the upload + // and download data are known. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Get copies of ivars we'll access in async invocations. This simulation assumes + // they won't change during fetcher execution. + NSURL *destinationFileURL = _destinationFileURL; + GTMSessionFetcherWillRedirectBlock willRedirectBlock = _willRedirectBlock; + GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock = _didReceiveResponseBlock; + GTMSessionFetcherSendProgressBlock sendProgressBlock = _sendProgressBlock; + GTMSessionFetcherDownloadProgressBlock downloadProgressBlock = _downloadProgressBlock; + GTMSessionFetcherAccumulateDataBlock accumulateDataBlock = _accumulateDataBlock; + GTMSessionFetcherReceivedProgressBlock receivedProgressBlock = _receivedProgressBlock; + GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock = + _willCacheURLResponseBlock; + + // Simulate receipt of redirection. + if (willRedirectBlock) { + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + willRedirectBlock((NSHTTPURLResponse *)response, _request, + ^(NSURLRequest *redirectRequest) { + // For simulation, we'll assume the app will just continue. + }); + }]; + } + + // If the fetcher has a challenge block, simulate a challenge. + // + // It might be nice to eventually let the user determine which testBlock + // fetches get challenged rather than always executing the supplied + // challenge block. + if (_challengeBlock) { + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + if (_challengeBlock) { + NSURL *requestURL = _request.URL; + NSString *host = requestURL.host; + NSURLProtectionSpace *pspace = + [[NSURLProtectionSpace alloc] initWithHost:host + port:requestURL.port.integerValue + protocol:requestURL.scheme + realm:nil + authenticationMethod:NSURLAuthenticationMethodHTTPBasic]; + id unusedSender = + (id)[NSNull null]; + NSURLAuthenticationChallenge *challenge = + [[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:pspace + proposedCredential:nil + previousFailureCount:0 + failureResponse:nil + error:nil + sender:unusedSender]; + _challengeBlock(self, challenge, ^(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential){ + // We could change the responseData and responseError based on the disposition, + // but it's easier for apps to just supply the expected data and error + // directly to the test block. So this simulation ignores the disposition. + }); + } + }]; + } + + // Simulate receipt of an initial response. + if (didReceiveResponseBlock) { + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + didReceiveResponseBlock(response, ^(NSURLSessionResponseDisposition desiredDisposition) { + // For simulation, we'll assume the disposition is to continue. + }); + }]; + } + + // Simulate reporting send progress. + if (sendProgressBlock) { + [self simulateByteTransferReportWithDataLength:(int64_t)bodyData.length + block:^(int64_t bytesSent, + int64_t totalBytesSent, + int64_t totalBytesExpectedToSend) { + // This is invoked on the callback queue unless stopped. + sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpectedToSend); + }]; + } + + if (destinationFileURL) { + // Simulate download to file progress. + if (downloadProgressBlock) { + [self simulateByteTransferReportWithDataLength:(int64_t)responseData.length + block:^(int64_t bytesDownloaded, + int64_t totalBytesDownloaded, + int64_t totalBytesExpectedToDownload) { + // This is invoked on the callback queue unless stopped. + downloadProgressBlock(bytesDownloaded, totalBytesDownloaded, + totalBytesExpectedToDownload); + }]; + } + + NSError *writeError; + [responseData writeToURL:destinationFileURL + options:NSDataWritingAtomic + error:&writeError]; + if (writeError) { + // Tell the test code that writing failed. + responseError = writeError; + } + } else { + // Simulate download to NSData progress. + if (accumulateDataBlock) { + if (responseData) { + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateDataBlock(responseData); + }]; + } + } else { + _downloadedData = [responseData mutableCopy]; + } + + if (receivedProgressBlock) { + [self simulateByteTransferReportWithDataLength:(int64_t)responseData.length + block:^(int64_t bytesReceived, + int64_t totalBytesReceived, + int64_t totalBytesExpectedToReceive) { + // This is invoked on the callback queue unless stopped. + receivedProgressBlock(bytesReceived, totalBytesReceived); + }]; + } + + if (willCacheURLResponseBlock) { + // Simulate letting the client inspect and alter the cached response. + NSData *cachedData = responseData ?: [[NSData alloc] init]; // Always have non-nil data. + NSCachedURLResponse *cachedResponse = + [[NSCachedURLResponse alloc] initWithResponse:response + data:cachedData]; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + willCacheURLResponseBlock(cachedResponse, ^(NSCachedURLResponse *responseToCache){ + // The app may provide an alternative response, or nil to defeat caching. + }); + }]; + } + } + _response = response; + } // @synchronized(self) + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + // Rather than invoke failToBeginFetchWithError: we want to simulate completion of + // a connection that started and ended, so we'll call down to finishWithError: + NSInteger status = responseError ? responseError.code : 200; + if (status >= 200 && status <= 399) { + [self finishWithError:nil shouldRetry:NO]; + } else { + [self shouldRetryNowForStatus:status + error:responseError + forceAssumeRetry:NO + response:^(BOOL shouldRetry) { + [self finishWithError:responseError shouldRetry:shouldRetry]; + }]; + } + }]; +} + +#endif // !GTM_DISABLE_FETCHER_TEST_BLOCK + +- (void)setSessionTask:(NSURLSessionTask *)sessionTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionTask != sessionTask) { + _sessionTask = sessionTask; + if (_sessionTask) { + // Request could be nil on restoring this fetcher from a background session. + if (!_request) { + _request = [_sessionTask.originalRequest mutableCopy]; + } + } + } + } // @synchronized(self) +} + +- (NSURLSessionTask * GTM_NULLABLE_TYPE)sessionTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionTask; + } // @synchronized(self) +} + ++ (NSUserDefaults *)fetcherUserDefaults { + static NSUserDefaults *gFetcherUserDefaults = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class fetcherUserDefaultsClass = NSClassFromString(@"GTMSessionFetcherUserDefaultsFactory"); + if (fetcherUserDefaultsClass) { + gFetcherUserDefaults = [fetcherUserDefaultsClass fetcherUserDefaults]; + } else { + gFetcherUserDefaults = [NSUserDefaults standardUserDefaults]; + } + }); + return gFetcherUserDefaults; +} + +- (void)addPersistedBackgroundSessionToDefaults { + NSString *sessionIdentifier = self.sessionIdentifier; + if (!sessionIdentifier) { + return; + } + NSArray *oldBackgroundSessions = [[self class] activePersistedBackgroundSessions]; + if ([oldBackgroundSessions containsObject:_sessionIdentifier]) { + return; + } + NSMutableArray *newBackgroundSessions = + [NSMutableArray arrayWithArray:oldBackgroundSessions]; + [newBackgroundSessions addObject:sessionIdentifier]; + GTM_LOG_BACKGROUND_SESSION(@"Add to background sessions: %@", newBackgroundSessions); + + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + [userDefaults setObject:newBackgroundSessions + forKey:kGTMSessionFetcherPersistedDestinationKey]; + [userDefaults synchronize]; +} + +- (void)removePersistedBackgroundSessionFromDefaults { + NSString *sessionIdentifier = self.sessionIdentifier; + if (!sessionIdentifier) return; + + NSArray *oldBackgroundSessions = [[self class] activePersistedBackgroundSessions]; + if (!oldBackgroundSessions) { + return; + } + NSMutableArray *newBackgroundSessions = + [NSMutableArray arrayWithArray:oldBackgroundSessions]; + NSUInteger sessionIndex = [newBackgroundSessions indexOfObject:sessionIdentifier]; + if (sessionIndex == NSNotFound) { + return; + } + [newBackgroundSessions removeObjectAtIndex:sessionIndex]; + GTM_LOG_BACKGROUND_SESSION(@"Remove from background sessions: %@", newBackgroundSessions); + + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + if (newBackgroundSessions.count == 0) { + [userDefaults removeObjectForKey:kGTMSessionFetcherPersistedDestinationKey]; + } else { + [userDefaults setObject:newBackgroundSessions + forKey:kGTMSessionFetcherPersistedDestinationKey]; + } + [userDefaults synchronize]; +} + ++ (GTM_NULLABLE NSArray *)activePersistedBackgroundSessions { + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + NSArray *oldBackgroundSessions = + [userDefaults arrayForKey:kGTMSessionFetcherPersistedDestinationKey]; + if (oldBackgroundSessions.count == 0) { + return nil; + } + NSMutableArray *activeBackgroundSessions = nil; + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + for (NSString *sessionIdentifier in oldBackgroundSessions) { + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (fetcher) { + if (!activeBackgroundSessions) { + activeBackgroundSessions = [[NSMutableArray alloc] init]; + } + [activeBackgroundSessions addObject:sessionIdentifier]; + } + } + return activeBackgroundSessions; +} + ++ (NSArray *)fetchersForBackgroundSessions { + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + NSArray *backgroundSessions = + [userDefaults arrayForKey:kGTMSessionFetcherPersistedDestinationKey]; + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + NSMutableArray *fetchers = [NSMutableArray array]; + for (NSString *sessionIdentifier in backgroundSessions) { + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (!fetcher) { + fetcher = [self fetcherWithSessionIdentifier:sessionIdentifier]; + GTMSESSION_ASSERT_DEBUG(fetcher != nil, + @"Unexpected invalid session identifier: %@", sessionIdentifier); + [fetcher beginFetchWithCompletionHandler:nil]; + } + GTM_LOG_BACKGROUND_SESSION(@"%@ restoring session %@ by creating fetcher %@ %p", + [self class], sessionIdentifier, fetcher, fetcher); + if (fetcher != nil) { + [fetchers addObject:fetcher]; + } + } + return fetchers; +} + +#if TARGET_OS_IPHONE ++ (void)application:(UIApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler { + GTMSessionFetcher *fetcher = [self fetcherWithSessionIdentifier:identifier]; + if (fetcher != nil) { + fetcher.systemCompletionHandler = completionHandler; + } else { + GTM_LOG_BACKGROUND_SESSION(@"%@ did not create background session identifier: %@", + [self class], identifier); + } +} +#endif + +- (NSString * GTM_NULLABLE_TYPE)sessionIdentifier { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionIdentifier; + } // @synchronized(self) +} + +- (void)setSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(!_session, @"Unable to set session identifier after session created"); + _sessionIdentifier = [sessionIdentifier copy]; + _usingBackgroundSession = YES; + _canShareSession = NO; + [self restoreDefaultStateForSessionIdentifierMetadata]; + } // @synchronized(self) +} + +- (void)setSessionIdentifierInternal:(GTM_NULLABLE NSString *)sessionIdentifier { + // This internal method only does a synchronized set of the session identifier. + // It does not have side effects on the background session, shared session, or + // session identifier metadata. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _sessionIdentifier = [sessionIdentifier copy]; + } // @synchronized(self) +} + +- (NSDictionary * GTM_NULLABLE_TYPE)sessionUserInfo { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionUserInfo == nil) { + // We'll return the metadata dictionary with internal keys removed. This avoids the user + // re-using the userInfo dictionary later and accidentally including the internal keys. + NSMutableDictionary *metadata = [[self sessionIdentifierMetadataUnsynchronized] mutableCopy]; + NSSet *keysToRemove = [metadata keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) { + return [key hasPrefix:@"_"]; + }]; + [metadata removeObjectsForKeys:[keysToRemove allObjects]]; + if (metadata.count > 0) { + _sessionUserInfo = metadata; + } + } + return _sessionUserInfo; + } // @synchronized(self) +} + +- (void)setSessionUserInfo:(NSDictionary * GTM_NULLABLE_TYPE)dictionary { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(_sessionIdentifier == nil, @"Too late to assign userInfo"); + _sessionUserInfo = dictionary; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSDictionary *)sessionIdentifierDefaultMetadata { + GTMSessionCheckSynchronized(self); + + NSMutableDictionary *defaultUserInfo = [[NSMutableDictionary alloc] init]; + if (_destinationFileURL) { + defaultUserInfo[kGTMSessionIdentifierDestinationFileURLMetadataKey] = + [_destinationFileURL absoluteString]; + } + if (_bodyFileURL) { + defaultUserInfo[kGTMSessionIdentifierBodyFileURLMetadataKey] = [_bodyFileURL absoluteString]; + } + return (defaultUserInfo.count > 0) ? defaultUserInfo : nil; +} + +- (void)restoreDefaultStateForSessionIdentifierMetadata { + GTMSessionCheckSynchronized(self); + + NSDictionary *metadata = [self sessionIdentifierMetadataUnsynchronized]; + NSString *destinationFileURLString = metadata[kGTMSessionIdentifierDestinationFileURLMetadataKey]; + if (destinationFileURLString) { + _destinationFileURL = [NSURL URLWithString:destinationFileURLString]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring destination file URL: %@", _destinationFileURL); + } + NSString *bodyFileURLString = metadata[kGTMSessionIdentifierBodyFileURLMetadataKey]; + if (bodyFileURLString) { + _bodyFileURL = [NSURL URLWithString:bodyFileURLString]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring body file URL: %@", _bodyFileURL); + } +} + +- (NSDictionary * GTM_NULLABLE_TYPE)sessionIdentifierMetadata { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [self sessionIdentifierMetadataUnsynchronized]; + } +} + +- (NSDictionary * GTM_NULLABLE_TYPE)sessionIdentifierMetadataUnsynchronized { + GTMSessionCheckSynchronized(self); + + // Session Identifier format: "com.google.__ + if (!_sessionIdentifier) { + return nil; + } + NSScanner *metadataScanner = [NSScanner scannerWithString:_sessionIdentifier]; + [metadataScanner setCharactersToBeSkipped:nil]; + NSString *metadataString; + NSString *uuid; + if ([metadataScanner scanUpToString:@"_" intoString:NULL] && + [metadataScanner scanString:@"_" intoString:NULL] && + [metadataScanner scanUpToString:@"_" intoString:&uuid] && + [metadataScanner scanString:@"_" intoString:NULL] && + [metadataScanner scanUpToString:@"\n" intoString:&metadataString]) { + _sessionIdentifierUUID = uuid; + NSData *metadataData = [metadataString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *error; + NSDictionary *metadataDict = + [NSJSONSerialization JSONObjectWithData:metadataData + options:0 + error:&error]; + GTM_LOG_BACKGROUND_SESSION(@"User Info from session identifier: %@ %@", + metadataDict, error ? error : @""); + return metadataDict; + } + return nil; +} + +- (NSString *)createSessionIdentifierWithMetadata:(NSDictionary * GTM_NULLABLE_TYPE)metadataToInclude { + NSString *result; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Session Identifier format: "com.google.__ + GTMSESSION_ASSERT_DEBUG(!_sessionIdentifier, @"Session identifier already created"); + _sessionIdentifierUUID = [[NSUUID UUID] UUIDString]; + _sessionIdentifier = + [NSString stringWithFormat:@"%@_%@", kGTMSessionIdentifierPrefix, _sessionIdentifierUUID]; + // Start with user-supplied keys so they cannot accidentally override the fetcher's keys. + NSMutableDictionary *metadataDict = + [NSMutableDictionary dictionaryWithDictionary:(NSDictionary * GTM_NONNULL_TYPE)_sessionUserInfo]; + + if (metadataToInclude) { + [metadataDict addEntriesFromDictionary:(NSDictionary *)metadataToInclude]; + } + NSDictionary *defaultMetadataDict = [self sessionIdentifierDefaultMetadata]; + if (defaultMetadataDict) { + [metadataDict addEntriesFromDictionary:defaultMetadataDict]; + } + if (metadataDict.count > 0) { + NSData *metadataData = [NSJSONSerialization dataWithJSONObject:metadataDict + options:0 + error:NULL]; + GTMSESSION_ASSERT_DEBUG(metadataData != nil, + @"Session identifier user info failed to convert to JSON"); + if (metadataData.length > 0) { + NSString *metadataString = [[NSString alloc] initWithData:metadataData + encoding:NSUTF8StringEncoding]; + _sessionIdentifier = + [_sessionIdentifier stringByAppendingFormat:@"_%@", metadataString]; + } + } + _didCreateSessionIdentifier = YES; + result = _sessionIdentifier; + } // @synchronized(self) + return result; +} + +- (void)failToBeginFetchWithError:(NSError *)error { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _hasStoppedFetching = YES; + } + + if (error == nil) { + error = [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorDownloadFailed + userInfo:nil]; + } + + [self invokeFetchCallbacksOnCallbackQueueWithData:nil + error:error]; + [self releaseCallbacks]; + + [_service fetcherDidStop:self]; + + self.authorizer = nil; +} + ++ (GTMSessionCookieStorage *)staticCookieStorage { + static GTMSessionCookieStorage *gCookieStorage = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gCookieStorage = [[GTMSessionCookieStorage alloc] init]; + }); + return gCookieStorage; +} + +#if GTM_BACKGROUND_TASK_FETCHING + +- (void)endBackgroundTask { + // Whenever the connection stops or background execution expires, + // we need to tell UIApplication we're done. + // + // We'll wait on _callbackGroup to ensure that any callbacks in flight have executed, + // and that we access backgroundTaskIdentifier on the main thread, as happens when the + // task has expired. + UIBackgroundTaskIdentifier bgTaskID = self.backgroundTaskIdentifier; + if (bgTaskID != UIBackgroundTaskInvalid) { + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + + id app = [[self class] fetcherUIApplication]; + [app endBackgroundTask:bgTaskID]; + } +} + +#endif // GTM_BACKGROUND_TASK_FETCHING + +- (void)authorizeRequest { + GTMSessionCheckNotSynchronized(self); + + id authorizer = self.authorizer; + SEL asyncAuthSel = @selector(authorizeRequest:delegate:didFinishSelector:); + if ([authorizer respondsToSelector:asyncAuthSel]) { + SEL callbackSel = @selector(authorizer:request:finishedWithError:); + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + [authorizer authorizeRequest:mutableRequest + delegate:self + didFinishSelector:callbackSel]; + } else { + GTMSESSION_ASSERT_DEBUG(authorizer == nil, @"invalid authorizer for fetch"); + + // No authorizing possible, and authorizing happens only after any delay; + // just begin fetching + [self beginFetchMayDelay:NO + mayAuthorize:NO]; + } +} + +- (void)authorizer:(id)auth + request:(NSMutableURLRequest *)authorizedRequest + finishedWithError:(NSError *)error { + GTMSessionCheckNotSynchronized(self); + + if (error != nil) { + // We can't fetch without authorization + [self failToBeginFetchWithError:error]; + } else { + @synchronized(self) { + _request = authorizedRequest; + } + [self beginFetchMayDelay:NO + mayAuthorize:NO]; + } +} + + +- (BOOL)canFetchWithBackgroundSession { + // Subclasses may override. + return YES; +} + +// Returns YES if the fetcher has been started and has not yet stopped. +// +// Fetching includes waiting for authorization or for retry, waiting to be allowed by the +// service object to start the request, and actually fetching the request. +- (BOOL)isFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [self isFetchingUnsynchronized]; + } +} + +- (BOOL)isFetchingUnsynchronized { + GTMSessionCheckSynchronized(self); + + BOOL hasBegun = (_initialBeginFetchDate != nil); + return hasBegun && !_hasStoppedFetching; +} + +- (NSURLResponse * GTM_NULLABLE_TYPE)response { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + return response; + } // @synchronized(self) +} + +- (NSURLResponse * GTM_NULLABLE_TYPE)responseUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = _sessionTask.response; + if (!response) response = _response; + return response; +} + +- (NSInteger)statusCode { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSInteger statusCode = [self statusCodeUnsynchronized]; + return statusCode; + } // @synchronized(self) +} + +- (NSInteger)statusCodeUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + NSInteger statusCode; + + if ([response respondsToSelector:@selector(statusCode)]) { + statusCode = [(NSHTTPURLResponse *)response statusCode]; + } else { + // Default to zero, in hopes of hinting "Unknown" (we can't be + // sure that things are OK enough to use 200). + statusCode = 0; + } + return statusCode; +} + +- (NSDictionary * GTM_NULLABLE_TYPE)responseHeaders { + GTMSessionCheckNotSynchronized(self); + + NSURLResponse *response = self.response; + if ([response respondsToSelector:@selector(allHeaderFields)]) { + NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; + return headers; + } + return nil; +} + +- (NSDictionary * GTM_NULLABLE_TYPE)responseHeadersUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + if ([response respondsToSelector:@selector(allHeaderFields)]) { + NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; + return headers; + } + return nil; +} + +- (void)releaseCallbacks { + // Avoid releasing blocks in the sync section since objects dealloc'd by + // the blocks being released may call back into the fetcher or fetcher + // service. + dispatch_queue_t NS_VALID_UNTIL_END_OF_SCOPE holdCallbackQueue; + GTMSessionFetcherCompletionHandler NS_VALID_UNTIL_END_OF_SCOPE holdCompletionHandler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + holdCallbackQueue = _callbackQueue; + holdCompletionHandler = _completionHandler; + + _callbackQueue = nil; + _completionHandler = nil; // Setter overridden in upload. Setter assumed to be used externally. + } + + // Set local callback pointers to nil here rather than let them release at the end of the scope + // to make any problems due to the blocks being released be a bit more obvious in a stack trace. + holdCallbackQueue = nil; + holdCompletionHandler = nil; + + self.configurationBlock = nil; + self.didReceiveResponseBlock = nil; + self.challengeBlock = nil; + self.willRedirectBlock = nil; + self.sendProgressBlock = nil; + self.receivedProgressBlock = nil; + self.downloadProgressBlock = nil; + self.accumulateDataBlock = nil; + self.willCacheURLResponseBlock = nil; + self.retryBlock = nil; + self.testBlock = nil; + self.resumeDataBlock = nil; +} + +- (void)forgetSessionIdentifierForFetcher { + GTMSessionCheckSynchronized(self); + [self forgetSessionIdentifierForFetcherWithoutSyncCheck]; +} + +- (void)forgetSessionIdentifierForFetcherWithoutSyncCheck { + // This should be called inside a @synchronized block (except during dealloc.) + if (_sessionIdentifier) { + NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap]; + [sessionIdentifierToFetcherMap removeObjectForKey:_sessionIdentifier]; + _sessionIdentifier = nil; + _didCreateSessionIdentifier = NO; + } +} + +// External stop method +- (void)stopFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Prevent enqueued callbacks from executing. + _userStoppedFetching = YES; + } // @synchronized(self) + [self stopFetchReleasingCallbacks:YES]; +} + +// Cancel the fetch of the URL that's currently in progress. +// +// If shouldReleaseCallbacks is NO then the fetch will be retried so the callbacks +// need to still be retained. +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks { + [self removePersistedBackgroundSessionFromDefaults]; + + id service; + NSMutableURLRequest *request; + + // If the task or the retry timer is all that's retaining the fetcher, + // we want to be sure this instance survives stopping at least long enough for + // the stack to unwind. + __autoreleasing GTMSessionFetcher *holdSelf = self; + + BOOL hasCanceledTask = NO; + + [holdSelf destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _hasStoppedFetching = YES; + + service = _service; + request = _request; + + if (_sessionTask) { + // In case cancelling the task or session calls this recursively, we want + // to ensure that we'll only release the task and delegate once, + // so first set _sessionTask to nil + // + // This may be called in a callback from the task, so use autorelease to avoid + // releasing the task in its own callback. + __autoreleasing NSURLSessionTask *oldTask = _sessionTask; + if (!_isUsingTestBlock) { + _response = _sessionTask.response; + } + _sessionTask = nil; + + if ([oldTask state] != NSURLSessionTaskStateCompleted) { + // For download tasks, when the fetch is stopped, we may provide resume data that can + // be used to create a new session. + BOOL mayResume = (_resumeDataBlock + && [oldTask respondsToSelector:@selector(cancelByProducingResumeData:)]); + if (!mayResume) { + [oldTask cancel]; + // A side effect of stopping the task is that URLSession:task:didCompleteWithError: + // will be invoked asynchronously on the delegate queue. + } else { + void (^resumeBlock)(NSData *) = _resumeDataBlock; + _resumeDataBlock = nil; + + // Save callbackQueue since releaseCallbacks clears it. + dispatch_queue_t callbackQueue = _callbackQueue; + dispatch_group_enter(_callbackGroup); + [(NSURLSessionDownloadTask *)oldTask cancelByProducingResumeData:^(NSData *resumeData) { + [self invokeOnCallbackQueue:callbackQueue + afterUserStopped:YES + block:^{ + resumeBlock(resumeData); + dispatch_group_leave(_callbackGroup); + }]; + }]; + } + hasCanceledTask = YES; + } + } + + // If the task was canceled, wait until the URLSession:task:didCompleteWithError: to call + // finishTasksAndInvalidate, since calling it immediately tends to crash, see radar 18471901. + if (_session) { + BOOL shouldInvalidate = _shouldInvalidateSession; +#if TARGET_OS_IPHONE + // Don't invalidate if we've got a systemCompletionHandler, since + // URLSessionDidFinishEventsForBackgroundURLSession: won't be called if invalidated. + shouldInvalidate = shouldInvalidate && !self.systemCompletionHandler; +#endif + if (shouldInvalidate) { + __autoreleasing NSURLSession *oldSession = _session; + _session = nil; + + if (!hasCanceledTask) { + [oldSession finishTasksAndInvalidate]; + } else { + _sessionNeedingInvalidation = oldSession; + } + } + } + } // @synchronized(self) + + // send the stopped notification + [self sendStopNotificationIfNeeded]; + + [_authorizer stopAuthorizationForRequest:request]; + + if (shouldReleaseCallbacks) { + [self releaseCallbacks]; + + self.authorizer = nil; + } + + [service fetcherDidStop:self]; + +#if GTM_BACKGROUND_TASK_FETCHING + [self endBackgroundTask]; +#endif +} + +- (void)setStopNotificationNeeded:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _isStopNotificationNeeded = flag; + } // @synchronized(self) +} + +- (void)sendStopNotificationIfNeeded { + BOOL sendNow = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_isStopNotificationNeeded) { + _isStopNotificationNeeded = NO; + sendNow = YES; + } + } // @synchronized(self) + + if (sendNow) { + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherStoppedNotification + userInfo:nil + requireAsync:NO]; + } +} + +- (void)retryFetch { + [self stopFetchReleasingCallbacks:NO]; + + GTMSessionFetcherCompletionHandler completionHandler; + + // A retry will need a configuration with a fresh session identifier. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionIdentifier && _didCreateSessionIdentifier) { + [self forgetSessionIdentifierForFetcher]; + _configuration = nil; + } + + if (_canShareSession) { + // Force a grab of the current session from the fetcher service in case + // the service's old one has become invalid. + _session = nil; + } + + completionHandler = _completionHandler; + } // @synchronized(self) + + [self beginFetchWithCompletionHandler:completionHandler]; +} + +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds { + // Uncovered in upload fetcher testing, because the chunk fetcher is being waited on, and gets + // released by the upload code. The uploader just holds onto it with an ivar, and that gets + // nilled in the chunk fetcher callback. + // Used once in while loop just to avoid unused variable compiler warning. + __autoreleasing GTMSessionFetcher *holdSelf = self; + + NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + + BOOL shouldSpinRunLoop = ([NSThread isMainThread] && + (!self.callbackQueue + || self.callbackQueue == dispatch_get_main_queue())); + BOOL expired = NO; + + // Loop until the callbacks have been called and released, and until + // the connection is no longer pending, until there are no callback dispatches + // in flight, or until the timeout has expired. + int64_t delta = (int64_t)(100 * NSEC_PER_MSEC); // 100 ms + while (1) { + BOOL isTaskInProgress = (holdSelf->_sessionTask + && [_sessionTask state] != NSURLSessionTaskStateCompleted); + BOOL needsToCallCompletion = (_completionHandler != nil); + BOOL isCallbackInProgress = (_callbackGroup + && dispatch_group_wait(_callbackGroup, dispatch_time(DISPATCH_TIME_NOW, delta))); + + if (!isTaskInProgress && !needsToCallCompletion && !isCallbackInProgress) break; + + expired = ([giveUpDate timeIntervalSinceNow] < 0); + if (expired) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher waitForCompletionWithTimeout:%0.1f expired -- " + @"%@%@%@", timeoutInSeconds, + isTaskInProgress ? @"taskInProgress " : @"", + needsToCallCompletion ? @"needsToCallCompletion " : @"", + isCallbackInProgress ? @"isCallbackInProgress" : @""); + break; + } + + // Run the current run loop 1/1000 of a second to give the networking + // code a chance to work + const NSTimeInterval kSpinInterval = 0.001; + if (shouldSpinRunLoop) { + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:kSpinInterval]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + [NSThread sleepForTimeInterval:kSpinInterval]; + } + } + return !expired; +} + ++ (void)setGlobalTestBlock:(GTMSessionFetcherTestBlock GTM_NULLABLE_TYPE)block { +#if GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSESSION_ASSERT_DEBUG(block == nil, @"test blocks disabled"); +#endif + gGlobalTestBlock = [block copy]; +} + +#if TARGET_OS_IPHONE + +static GTM_NULLABLE_TYPE id gSubstituteUIApp; + ++ (void)setSubstituteUIApplication:(nullable id)app { + gSubstituteUIApp = app; +} + ++ (nullable id)substituteUIApplication { + return gSubstituteUIApp; +} + ++ (nullable id)fetcherUIApplication { + id app = gSubstituteUIApp; + if (app) return app; + + // Some projects use GTM_BACKGROUND_TASK_FETCHING to avoid compile-time references + // to UIApplication. +#if GTM_BACKGROUND_TASK_FETCHING + return (id) [UIApplication sharedApplication]; +#else + return nil; +#endif +} +#endif // TARGET_OS_IPHONE + +#pragma mark NSURLSession Delegate Methods + +// NSURLSession documentation indicates that redirectRequest can be passed to the handler +// but empirically redirectRequest lacks the HTTP body, so passing it will break POSTs. +// Instead, we construct a new request, a copy of the original, with overrides from the +// redirect. + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +willPerformHTTPRedirection:(NSHTTPURLResponse *)redirectResponse + newRequest:(NSURLRequest *)redirectRequest + completionHandler:(void (^)(NSURLRequest * GTM_NULLABLE_TYPE))handler { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ willPerformHTTPRedirection:%@ newRequest:%@", + [self class], self, session, task, redirectResponse, redirectRequest); + + if ([self userStoppedFetching]) { + handler(nil); + return; + } + if (redirectRequest && redirectResponse) { + // Copy the original request, including the body. + NSURLRequest *originalRequest = self.request; + NSMutableURLRequest *newRequest = [originalRequest mutableCopy]; + + // Disallow scheme changes (say, from https to http). + NSURL *originalRequestURL = originalRequest.URL; + NSURL *redirectRequestURL = redirectRequest.URL; + + NSString *originalScheme = originalRequestURL.scheme; + NSString *redirectScheme = redirectRequestURL.scheme; + + if (originalScheme != nil + && [originalScheme caseInsensitiveCompare:@"http"] == NSOrderedSame + && redirectScheme != nil + && [redirectScheme caseInsensitiveCompare:@"https"] == NSOrderedSame) { + // Allow the change from http to https. + } else { + // Disallow any other scheme changes. + redirectScheme = originalScheme; + } + // The new requests's URL overrides the original's URL. + NSURLComponents *components = [NSURLComponents componentsWithURL:redirectRequestURL + resolvingAgainstBaseURL:NO]; + components.scheme = redirectScheme; + NSURL *newURL = components.URL; + [newRequest setURL:newURL]; + + // Any headers in the redirect override headers in the original. + NSDictionary *redirectHeaders = redirectRequest.allHTTPHeaderFields; + for (NSString *key in redirectHeaders) { + NSString *value = [redirectHeaders objectForKey:key]; + [newRequest setValue:value forHTTPHeaderField:key]; + } + + redirectRequest = newRequest; + + // Log the response we just received + [self setResponse:redirectResponse]; + [self logNowWithError:nil]; + + GTMSessionFetcherWillRedirectBlock willRedirectBlock = self.willRedirectBlock; + if (willRedirectBlock) { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + willRedirectBlock(redirectResponse, redirectRequest, ^(NSURLRequest *clientRequest) { + + // Update the request for future logging. + [self updateMutableRequest:[clientRequest mutableCopy]]; + + handler(clientRequest); + }); + }]; + } // @synchronized(self) + return; + } + // Continues here if the client did not provide a redirect block. + + // Update the request for future logging. + [self updateMutableRequest:[redirectRequest mutableCopy]]; + } + handler(redirectRequest); +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))handler { + [self setSessionTask:dataTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didReceiveResponse:%@", + [self class], self, session, dataTask, response); + void (^accumulateAndFinish)(NSURLSessionResponseDisposition) = + ^(NSURLSessionResponseDisposition dispositionValue) { + // This method is called when the server has determined that it + // has enough information to create the NSURLResponse + // it can be called multiple times, for example in the case of a + // redirect, so each time we reset the data. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL hadPreviousData = _downloadedLength > 0; + + [_downloadedData setLength:0]; + _downloadedLength = 0; + + if (hadPreviousData && (dispositionValue != NSURLSessionResponseCancel)) { + // Tell the accumulate block to discard prior data. + GTMSessionFetcherAccumulateDataBlock accumulateBlock = _accumulateDataBlock; + if (accumulateBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateBlock(nil); + }]; + } + } + } // @synchronized(self) + handler(dispositionValue); + }; + + GTMSessionFetcherDidReceiveResponseBlock receivedResponseBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + receivedResponseBlock = _didReceiveResponseBlock; + if (receivedResponseBlock) { + // We will ultimately need to call back to NSURLSession's handler with the disposition value + // for this delegate method even if the user has stopped the fetcher. + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + receivedResponseBlock(response, ^(NSURLSessionResponseDisposition desiredDisposition) { + accumulateAndFinish(desiredDisposition); + }); + }]; + } + } // @synchronized(self) + + if (receivedResponseBlock == nil) { + accumulateAndFinish(NSURLSessionResponseAllow); + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didBecomeDownloadTask:%@", + [self class], self, session, dataTask, downloadTask); + [self setSessionTask:downloadTask]; +} + + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential))handler { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didReceiveChallenge:%@", + [self class], self, session, task, challenge); + + GTMSessionFetcherChallengeBlock challengeBlock = self.challengeBlock; + if (challengeBlock) { + // The fetcher user has provided custom challenge handling. + // + // We will ultimately need to call back to NSURLSession's handler with the disposition value + // for this delegate method even if the user has stopped the fetcher. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + challengeBlock(self, challenge, handler); + }]; + } + } else { + // No challenge block was provided by the client. + [self respondToChallenge:challenge + completionHandler:handler]; + } +} + +- (void)respondToChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential))handler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSInteger previousFailureCount = [challenge previousFailureCount]; + if (previousFailureCount <= 2) { + NSURLProtectionSpace *protectionSpace = [challenge protectionSpace]; + NSString *authenticationMethod = [protectionSpace authenticationMethod]; + if ([authenticationMethod isEqual:NSURLAuthenticationMethodServerTrust]) { + // SSL. + // + // Background sessions seem to require an explicit check of the server trust object + // rather than default handling. + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + if (serverTrust == NULL) { + // No server trust information is available. + handler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } else { + // Server trust information is available. + void (^callback)(SecTrustRef, BOOL) = ^(SecTrustRef trustRef, BOOL allow){ + if (allow) { + NSURLCredential *trustCredential = [NSURLCredential credentialForTrust:trustRef]; + handler(NSURLSessionAuthChallengeUseCredential, trustCredential); + } else { + GTMSESSION_LOG_DEBUG(@"Cancelling authentication challenge for %@", _request.URL); + handler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + }; + if (_allowInvalidServerCertificates) { + callback(serverTrust, YES); + } else { + [[self class] evaluateServerTrust:serverTrust + forRequest:_request + completionHandler:callback]; + } + } + return; + } + + NSURLCredential *credential = _credential; + + if ([[challenge protectionSpace] isProxy] && _proxyCredential != nil) { + credential = _proxyCredential; + } + + if (credential) { + handler(NSURLSessionAuthChallengeUseCredential, credential); + } else { + // The credential is still nil; tell the OS to use the default handling. This is needed + // for things that can come out of the keychain (proxies, client certificates, etc.). + // + // Note: Looking up a credential with NSURLCredentialStorage's + // defaultCredentialForProtectionSpace: is *not* the same invoking the handler with + // NSURLSessionAuthChallengePerformDefaultHandling. In the case of + // NSURLAuthenticationMethodClientCertificate, you can get nil back from + // NSURLCredentialStorage, while using this code path instead works. + handler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } + + } else { + // We've failed auth 3 times. The completion handler will be called with code + // NSURLErrorCancelled. + handler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + } // @synchronized(self) +} + +// Validate the certificate chain. +// +// This may become a public method if it appears to be useful to users. ++ (void)evaluateServerTrust:(SecTrustRef)serverTrust + forRequest:(NSURLRequest *)request + completionHandler:(void (^)(SecTrustRef trustRef, BOOL allow))handler { + // Retain the trust object to avoid a SecTrustEvaluate() crash on iOS 7. + CFRetain(serverTrust); + + // Evaluate the certificate chain. + // + // The delegate queue may be the main thread. Trust evaluation could cause some + // blocking network activity, so we must evaluate async, as documented at + // https://developer.apple.com/library/ios/technotes/tn2232/ + // + // We must also avoid multiple uses of the trust object, per docs: + // "It is not safe to call this function concurrently with any other function that uses + // the same trust management object, or to re-enter this function for the same trust + // management object." + // + // SecTrustEvaluateAsync both does sync execution of Evaluate and calls back on the + // queue passed to it, according to at sources in + // http://www.opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-55050.9/lib/SecTrust.cpp + // It would require a global serial queue to ensure the evaluate happens only on a + // single thread at a time, so we'll stick with using SecTrustEvaluate on a background + // thread. + dispatch_queue_t evaluateBackgroundQueue = + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(evaluateBackgroundQueue, ^{ + // It looks like the implementation of SecTrustEvaluate() on Mac grabs a global lock, + // so it may be redundant for us to also lock, but it's easy to synchronize here + // anyway. + SecTrustResultType trustEval = kSecTrustResultInvalid; + BOOL shouldAllow; + OSStatus trustError; + @synchronized([GTMSessionFetcher class]) { + GTMSessionMonitorSynchronized([GTMSessionFetcher class]); + + trustError = SecTrustEvaluate(serverTrust, &trustEval); + } + if (trustError != errSecSuccess) { + GTMSESSION_LOG_DEBUG(@"Error %d evaluating trust for %@", + (int)trustError, request); + shouldAllow = NO; + } else { + // Having a trust level "unspecified" by the user is the usual result, described at + // https://developer.apple.com/library/mac/qa/qa1360 + if (trustEval == kSecTrustResultUnspecified + || trustEval == kSecTrustResultProceed) { + shouldAllow = YES; + } else { + shouldAllow = NO; + GTMSESSION_LOG_DEBUG(@"Challenge SecTrustResultType %u for %@, properties: %@", + trustEval, request.URL.host, + CFBridgingRelease(SecTrustCopyProperties(serverTrust))); + } + } + handler(serverTrust, shouldAllow); + + CFRelease(serverTrust); + }); +} + +- (void)invokeOnCallbackQueueUnlessStopped:(void (^)(void))block { + [self invokeOnCallbackQueueAfterUserStopped:NO + block:block]; +} + +- (void)invokeOnCallbackQueueAfterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + GTMSessionCheckSynchronized(self); + + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:afterStopped + block:block]; +} + +- (void)invokeOnCallbackUnsynchronizedQueueAfterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + // testBlock simulation code may not be synchronizing when this is invoked. + [self invokeOnCallbackQueue:_callbackQueue + afterUserStopped:afterStopped + block:block]; +} + +- (void)invokeOnCallbackQueue:(dispatch_queue_t)callbackQueue + afterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + if (callbackQueue) { + dispatch_group_async(_callbackGroup, callbackQueue, ^{ + if (!afterStopped) { + NSDate *serviceStoppedAllDate = [_service stoppedAllFetchersDate]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Avoid a race between stopFetching and the callback. + if (_userStoppedFetching) { + return; + } + + // Also avoid calling back if the service has stopped all fetchers + // since this one was created. The fetcher may have stopped before + // stopAllFetchers was invoked, so _userStoppedFetching wasn't set, + // but the app still won't expect the callback to fire after + // the service's stopAllFetchers was invoked. + if (serviceStoppedAllDate + && [_initialBeginFetchDate compare:serviceStoppedAllDate] != NSOrderedDescending) { + // stopAllFetchers was called after this fetcher began. + return; + } + } // @synchronized(self) + } + block(); + }); + } +} + +- (void)invokeFetchCallbacksOnCallbackQueueWithData:(GTM_NULLABLE NSData *)data + error:(GTM_NULLABLE NSError *)error { + // Callbacks will be released in the method stopFetchReleasingCallbacks: + GTMSessionFetcherCompletionHandler handler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + handler = _completionHandler; + + if (handler) { + [self invokeOnCallbackQueueUnlessStopped:^{ + handler(data, error); + + // Post a notification, primarily to allow code to collect responses for + // testing. + // + // The observing code is not likely on the fetcher's callback + // queue, so this posts explicitly to the main queue. + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (data) { + userInfo[kGTMSessionFetcherCompletionDataKey] = data; + } + if (error) { + userInfo[kGTMSessionFetcherCompletionErrorKey] = error; + } + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherCompletionInvokedNotification + userInfo:userInfo + requireAsync:NO]; + }]; + } + } // @synchronized(self) +} + +- (void)postNotificationOnMainThreadWithName:(NSString *)noteName + userInfo:(GTM_NULLABLE NSDictionary *)userInfo + requireAsync:(BOOL)requireAsync { + dispatch_block_t postBlock = ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:noteName + object:self + userInfo:userInfo]; + }; + + if ([NSThread isMainThread] && !requireAsync) { + // Post synchronously for compatibility with older code using the fetcher. + + // Avoid calling out to other code from inside a sync block to avoid risk + // of a deadlock or of recursive sync. + GTMSessionCheckNotSynchronized(self); + + postBlock(); + } else { + dispatch_async(dispatch_get_main_queue(), postBlock); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)uploadTask + needNewBodyStream:(void (^)(NSInputStream * GTM_NULLABLE_TYPE bodyStream))completionHandler { + [self setSessionTask:uploadTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ needNewBodyStream:", + [self class], self, session, uploadTask); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSessionFetcherBodyStreamProvider provider = _bodyStreamProvider; +#if !STRIP_GTM_FETCH_LOGGING + if ([self respondsToSelector:@selector(loggedStreamProviderForStreamProvider:)]) { + provider = [self performSelector:@selector(loggedStreamProviderForStreamProvider:) + withObject:provider]; + } +#endif + if (provider) { + [self invokeOnCallbackQueueUnlessStopped:^{ + provider(completionHandler); + }]; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"NSURLSession expects a stream provider"); + + completionHandler(nil); + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didSendBodyData:%lld" + @" totalBytesSent:%lld totalBytesExpectedToSend:%lld", + [self class], self, session, task, bytesSent, totalBytesSent, + totalBytesExpectedToSend); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (!_sendProgressBlock) { + return; + } + // We won't hold on to send progress block; it's ok to not send it if the upload finishes. + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherSendProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = _sendProgressBlock; + } + if (progressBlock) { + progressBlock(bytesSent, totalBytesSent, totalBytesExpectedToSend); + } + }]; + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + [self setSessionTask:dataTask]; + NSUInteger bufferLength = data.length; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didReceiveData:%p (%llu bytes)", + [self class], self, session, dataTask, data, + (unsigned long long)bufferLength); + if (bufferLength == 0) { + // Observed on completing an out-of-process upload. + return; + } + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSessionFetcherAccumulateDataBlock accumulateBlock = _accumulateDataBlock; + if (accumulateBlock) { + // Let the client accumulate the data. + _downloadedLength += bufferLength; + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateBlock(data); + }]; + } else if (!_userStoppedFetching) { + // Append to the mutable data buffer unless the fetch has been cancelled. + + // Resumed upload tasks may not yet have a data buffer. + if (_downloadedData == nil) { + // Using NSClassFromString for iOS 6 compatibility. + GTMSESSION_ASSERT_DEBUG( + ![dataTask isKindOfClass:NSClassFromString(@"NSURLSessionDownloadTask")], + @"Resumed download tasks should not receive data bytes"); + _downloadedData = [[NSMutableData alloc] init]; + } + + [_downloadedData appendData:data]; + _downloadedLength = (int64_t)_downloadedData.length; + + // We won't hold on to receivedProgressBlock here; it's ok to not send + // it if the transfer finishes. + if (_receivedProgressBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherReceivedProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = _receivedProgressBlock; + } + if (progressBlock) { + progressBlock((int64_t)bufferLength, _downloadedLength); + } + }]; + } + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ willCacheResponse:%@ %@", + [self class], self, session, dataTask, + proposedResponse, proposedResponse.response); + GTMSessionFetcherWillCacheURLResponseBlock callback; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + callback = _willCacheURLResponseBlock; + + if (callback) { + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + callback(proposedResponse, completionHandler); + }]; + } + } // @synchronized(self) + if (!callback) { + completionHandler(proposedResponse); + } +} + + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalBytesWritten +totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didWriteData:%lld" + @" bytesWritten:%lld totalBytesExpectedToWrite:%lld", + [self class], self, session, downloadTask, bytesWritten, + totalBytesWritten, totalBytesExpectedToWrite); + [self setSessionTask:downloadTask]; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if ((totalBytesExpectedToWrite != NSURLSessionTransferSizeUnknown) && + (totalBytesExpectedToWrite < totalBytesWritten)) { + // Have observed cases were bytesWritten == totalBytesExpectedToWrite, + // but totalBytesWritten > totalBytesExpectedToWrite, so setting to unkown in these cases. + totalBytesExpectedToWrite = NSURLSessionTransferSizeUnknown; + } + // We won't hold on to download progress block during the enqueue; + // it's ok to not send it if the upload finishes. + + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherDownloadProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = _downloadProgressBlock; + } + if (progressBlock) { + progressBlock(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + } + }]; + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset +expectedTotalBytes:(int64_t)expectedTotalBytes { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didResumeAtOffset:%lld" + @" expectedTotalBytes:%lld", + [self class], self, session, downloadTask, fileOffset, + expectedTotalBytes); + [self setSessionTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask +didFinishDownloadingToURL:(NSURL *)downloadLocationURL { + // Download may have relaunched app, so update _sessionTask. + [self setSessionTask:downloadTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didFinishDownloadingToURL:%@", + [self class], self, session, downloadTask, downloadLocationURL); + NSNumber *fileSizeNum; + [downloadLocationURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:NULL]; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURL *destinationURL = _destinationFileURL; + + _downloadedLength = fileSizeNum.longLongValue; + + // Overwrite any previous file at the destination URL. + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSError *removeError; + if (![fileMgr removeItemAtURL:destinationURL error:&removeError] + && removeError.code != NSFileNoSuchFileError) { + GTMSESSION_LOG_DEBUG(@"Could not remove previous file at %@ due to %@", + downloadLocationURL.path, removeError); + } + + NSInteger statusCode = [self statusCodeUnsynchronized]; + if (statusCode < 200 || statusCode > 399) { + // In OS X 10.11, the response body is written to a file even on a server + // status error. For convenience of the fetcher client, we'll skip saving the + // downloaded body to the destination URL so that clients do not need to know + // to delete the file following fetch errors. A downside of this is that + // the server may have included error details in the response body, and + // abandoning the downloaded file here means that the details from the + // body are not available to the fetcher client. + GTMSESSION_LOG_DEBUG(@"Abandoning download due to status %zd, file %@", + statusCode, downloadLocationURL.path); + } else { + NSError *moveError; + NSURL *destinationFolderURL = [destinationURL URLByDeletingLastPathComponent]; + BOOL didMoveDownload = NO; + if ([fileMgr createDirectoryAtURL:destinationFolderURL + withIntermediateDirectories:YES + attributes:nil + error:&moveError]) { + didMoveDownload = [fileMgr moveItemAtURL:downloadLocationURL + toURL:destinationURL + error:&moveError]; + } + if (!didMoveDownload) { + _downloadFinishedError = moveError; + } + GTM_LOG_BACKGROUND_SESSION(@"%@ %p Moved download from \"%@\" to \"%@\" %@", + [self class], self, + downloadLocationURL.path, destinationURL.path, + error ? error : @""); + } + } // @synchronized(self) +} + +/* Sent as the last message related to a specific task. Error may be + * nil, which implies that no error occurred and this task is complete. + */ +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didCompleteWithError:%@", + [self class], self, session, task, error); + + NSInteger status = self.statusCode; + BOOL forceAssumeRetry = NO; + BOOL succeeded = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + // The task is never resumed when a testBlock is used. When the session is destroyed, + // we should ignore the callback, since the testBlock support code itself invokes + // shouldRetryNowForStatus: and finishWithError:shouldRetry: + if (_isUsingTestBlock) return; +#endif + + if (error == nil) { + error = _downloadFinishedError; + } + succeeded = (error == nil && status >= 0 && status < 300); + if (succeeded) { + // Succeeded. + _bodyLength = task.countOfBytesSent; + } + } // @synchronized(self) + + if (succeeded) { + [self finishWithError:nil shouldRetry:NO]; + return; + } + // For background redirects, no delegate method is called, so we cannot restore a stripped + // Authorization header, so if a 403 ("Forbidden") was generated due to a missing OAuth 2 header, + // set the current request's URL to the redirected URL, so we in effect restore the Authorization + // header. + if ((status == 403) && self.usingBackgroundSession) { + NSURL *redirectURL = self.response.URL; + NSURLRequest *request = self.request; + if (![request.URL isEqual:redirectURL]) { + NSString *authorizationHeader = [request.allHTTPHeaderFields objectForKey:@"Authorization"]; + if (authorizationHeader != nil) { + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + mutableRequest.URL = redirectURL; + [self updateMutableRequest:mutableRequest]; + // Avoid assuming the session is still valid. + self.session = nil; + forceAssumeRetry = YES; + } + } + } + + // If invalidating the session was deferred in stopFetchReleasingCallbacks: then do it now. + NSURLSession *oldSession = self.sessionNeedingInvalidation; + if (oldSession) { + [self setSessionNeedingInvalidation:NULL]; + [oldSession finishTasksAndInvalidate]; + } + + // Failed. + [self shouldRetryNowForStatus:status + error:error + forceAssumeRetry:forceAssumeRetry + response:^(BOOL shouldRetry) { + [self finishWithError:error shouldRetry:shouldRetry]; + }]; +} + +#if TARGET_OS_IPHONE +- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSessionDidFinishEventsForBackgroundURLSession:%@", + [self class], self, session); + [self removePersistedBackgroundSessionFromDefaults]; + + GTMSessionFetcherSystemCompletionHandler handler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + handler = self.systemCompletionHandler; + self.systemCompletionHandler = nil; + } // @synchronized(self) + if (handler) { + GTM_LOG_BACKGROUND_SESSION(@"%@ %p Calling system completionHandler", [self class], self); + handler(); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLSession *oldSession = _session; + _session = nil; + if (_shouldInvalidateSession) { + [oldSession finishTasksAndInvalidate]; + } + } // @synchronized(self) + } +} +#endif + +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(GTM_NULLABLE NSError *)error { + // This may happen repeatedly for retries. On authentication callbacks, the retry + // may begin before the prior session sends the didBecomeInvalid delegate message. + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", + [self class], self, session, error); + if (session == (NSURLSession *)self.session) { + GTM_LOG_SESSION_DELEGATE(@" Unexpected retained invalid session: %@", session); + self.session = nil; + } +} + +- (void)finishWithError:(GTM_NULLABLE NSError *)error shouldRetry:(BOOL)shouldRetry { + [self removePersistedBackgroundSessionFromDefaults]; + + BOOL shouldStopFetching = YES; + NSData *downloadedData = nil; +#if !STRIP_GTM_FETCH_LOGGING + BOOL shouldDeferLogging = NO; +#endif + BOOL shouldBeginRetryTimer = NO; + NSInteger status = [self statusCode]; + NSURL *destinationURL = self.destinationFileURL; + + BOOL fetchSucceeded = (error == nil && status >= 0 && status < 300); + +#if !STRIP_GTM_FETCH_LOGGING + if (!fetchSucceeded) { + if (!shouldDeferLogging && !self.hasLoggedError) { + [self logNowWithError:error]; + self.hasLoggedError = YES; + } + } +#endif // !STRIP_GTM_FETCH_LOGGING + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if !STRIP_GTM_FETCH_LOGGING + shouldDeferLogging = _deferResponseBodyLogging; +#endif + if (fetchSucceeded) { + // Success + if ((_downloadedData.length > 0) && (destinationURL != nil)) { + // Overwrite any previous file at the destination URL. + NSFileManager *fileMgr = [NSFileManager defaultManager]; + [fileMgr removeItemAtURL:destinationURL + error:NULL]; + NSURL *destinationFolderURL = [destinationURL URLByDeletingLastPathComponent]; + BOOL didMoveDownload = NO; + if ([fileMgr createDirectoryAtURL:destinationFolderURL + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + didMoveDownload = [_downloadedData writeToURL:destinationURL + options:NSDataWritingAtomic + error:&error]; + } + if (didMoveDownload) { + _downloadedData = nil; + } else { + _downloadFinishedError = error; + } + } + downloadedData = _downloadedData; + } else { + // Unsuccessful with error or status over 300. Retry or notify the delegate of failure + if (shouldRetry) { + // Retrying. + shouldBeginRetryTimer = YES; + shouldStopFetching = NO; + } else { + if (error == nil) { + // Create an error. + NSDictionary *userInfo = nil; + if (_downloadedData.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : _downloadedData }; + } + error = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:status + userInfo:userInfo]; + } else { + // If the error had resume data, and the client supplied a resume block, pass the + // data to the client. + void (^resumeBlock)(NSData *) = _resumeDataBlock; + _resumeDataBlock = nil; + if (resumeBlock) { + NSData *resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]; + if (resumeData) { + [self invokeOnCallbackQueueAfterUserStopped:YES block:^{ + resumeBlock(resumeData); + }]; + } + } + } + if (_downloadedData.length > 0) { + downloadedData = _downloadedData; + } + // If the error occurred after retries, report the number and duration of the + // retries. This provides a clue to a developer looking at the error description + // that the fetcher did retry before failing with this error. + if (_retryCount > 0) { + NSMutableDictionary *userInfoWithRetries = + [NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)error.userInfo]; + NSTimeInterval timeSinceInitialRequest = -[_initialRequestDate timeIntervalSinceNow]; + [userInfoWithRetries setObject:@(timeSinceInitialRequest) + forKey:kGTMSessionFetcherElapsedIntervalWithRetriesKey]; + [userInfoWithRetries setObject:@(_retryCount) + forKey:kGTMSessionFetcherNumberOfRetriesDoneKey]; + error = [NSError errorWithDomain:(NSString *)error.domain + code:error.code + userInfo:userInfoWithRetries]; + } + } + } + } // @synchronized(self) + + if (shouldBeginRetryTimer) { + [self beginRetryTimer]; + } + + // We want to send the stop notification before calling the delegate's + // callback selector, since the callback selector may release all of + // the fetcher properties that the client is using to track the fetches. + // + // We'll also stop now so that, to any observers watching the notifications, + // it doesn't look like our wait for a retry (which may be long, + // 30 seconds or more) is part of the network activity. + [self sendStopNotificationIfNeeded]; + + if (shouldStopFetching) { + [self invokeFetchCallbacksOnCallbackQueueWithData:downloadedData + error:error]; + // The upload subclass doesn't want to release callbacks until upload chunks have completed. + BOOL shouldRelease = [self shouldReleaseCallbacksUponCompletion]; + [self stopFetchReleasingCallbacks:shouldRelease]; + } + +#if !STRIP_GTM_FETCH_LOGGING + // _hasLoggedError is only set by this method + if (!shouldDeferLogging && !_hasLoggedError) { + [self logNowWithError:error]; + } +#endif +} + +- (BOOL)shouldReleaseCallbacksUponCompletion { + // A subclass can override this to keep callbacks around after the + // connection has finished successfully + return YES; +} + +- (void)logNowWithError:(GTM_NULLABLE NSError *)error { + GTMSessionCheckNotSynchronized(self); + + // If the logging category is available, then log the current request, + // response, data, and error + if ([self respondsToSelector:@selector(logFetchWithError:)]) { + [self performSelector:@selector(logFetchWithError:) withObject:error]; + } +} + +#pragma mark Retries + +- (BOOL)isRetryError:(NSError *)error { + struct RetryRecord { + __unsafe_unretained NSString *const domain; + NSInteger code; + }; + + struct RetryRecord retries[] = { + { kGTMSessionFetcherStatusDomain, 408 }, // request timeout + { kGTMSessionFetcherStatusDomain, 502 }, // failure gatewaying to another server + { kGTMSessionFetcherStatusDomain, 503 }, // service unavailable + { kGTMSessionFetcherStatusDomain, 504 }, // request timeout + { NSURLErrorDomain, NSURLErrorTimedOut }, + { NSURLErrorDomain, NSURLErrorNetworkConnectionLost }, + { nil, 0 } + }; + + // NSError's isEqual always returns false for equal but distinct instances + // of NSError, so we have to compare the domain and code values explicitly + NSString *domain = error.domain; + NSInteger code = error.code; + for (int idx = 0; retries[idx].domain != nil; idx++) { + if (code == retries[idx].code && [domain isEqual:retries[idx].domain]) { + return YES; + } + } + return NO; +} + +// shouldRetryNowForStatus:error: responds with YES if the user has enabled retries +// and the status or error is one that is suitable for retrying. "Suitable" +// means either the isRetryError:'s list contains the status or error, or the +// user's retry block is present and returns YES when called, or the +// authorizer may be able to fix. +- (void)shouldRetryNowForStatus:(NSInteger)status + error:(NSError *)error + forceAssumeRetry:(BOOL)forceAssumeRetry + response:(GTMSessionFetcherRetryResponse)response { + // Determine if a refreshed authorizer may avoid an authorization error + BOOL willRetry = NO; + + // We assume _authorizer is immutable after beginFetch, and _hasAttemptedAuthRefresh is modified + // only in this method, and this method is invoked on the serial delegate queue. + // + // We want to avoid calling the authorizer from inside a sync block. + BOOL isFirstAuthError = (_authorizer != nil + && !_hasAttemptedAuthRefresh + && status == GTMSessionFetcherStatusUnauthorized); // 401 + + BOOL hasPrimed = NO; + if (isFirstAuthError) { + if ([_authorizer respondsToSelector:@selector(primeForRefresh)]) { + hasPrimed = [_authorizer primeForRefresh]; + } + } + + BOOL shouldRetryForAuthRefresh = NO; + if (hasPrimed) { + shouldRetryForAuthRefresh = YES; + _hasAttemptedAuthRefresh = YES; + [self updateRequestValue:nil forHTTPHeaderField:@"Authorization"]; + } + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL shouldDoRetry = [self isRetryEnabledUnsynchronized]; + if (shouldDoRetry && ![self hasRetryAfterInterval]) { + + // Determine if we're doing exponential backoff retries + shouldDoRetry = [self nextRetryIntervalUnsynchronized] < _maxRetryInterval; + + if (shouldDoRetry) { + // If an explicit max retry interval was set, we expect repeated backoffs to take + // up to roughly twice that for repeated fast failures. If the initial attempt is + // already more than 3 times the max retry interval, then failures have taken a long time + // (such as from network timeouts) so don't retry again to avoid the app becoming + // unexpectedly unresponsive. + if (_maxRetryInterval > 0) { + NSTimeInterval maxAllowedIntervalBeforeRetry = _maxRetryInterval * 3; + NSTimeInterval timeSinceInitialRequest = -[_initialRequestDate timeIntervalSinceNow]; + if (timeSinceInitialRequest > maxAllowedIntervalBeforeRetry) { + shouldDoRetry = NO; + } + } + } + } + BOOL canRetry = shouldRetryForAuthRefresh || forceAssumeRetry || shouldDoRetry; + if (canRetry) { + NSDictionary *userInfo = nil; + if (_downloadedData.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : _downloadedData }; + } + NSError *statusError = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:status + userInfo:userInfo]; + if (error == nil) { + error = statusError; + } + willRetry = shouldRetryForAuthRefresh || + forceAssumeRetry || + [self isRetryError:error] || + ((error != statusError) && [self isRetryError:statusError]); + + // If the user has installed a retry callback, consult that. + GTMSessionFetcherRetryBlock retryBlock = _retryBlock; + if (retryBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + retryBlock(willRetry, error, response); + }]; + return; + } + } + } // @synchronized(self) + response(willRetry); +} + +- (BOOL)hasRetryAfterInterval { + GTMSessionCheckSynchronized(self); + + NSDictionary *responseHeaders = [self responseHeadersUnsynchronized]; + NSString *retryAfterValue = [responseHeaders valueForKey:@"Retry-After"]; + return (retryAfterValue != nil); +} + +- (NSTimeInterval)retryAfterInterval { + GTMSessionCheckSynchronized(self); + + NSDictionary *responseHeaders = [self responseHeadersUnsynchronized]; + NSString *retryAfterValue = [responseHeaders valueForKey:@"Retry-After"]; + if (retryAfterValue == nil) { + return 0; + } + // Retry-After formatted as HTTP-date | delta-seconds + // Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + NSDateFormatter *rfc1123DateFormatter = [[NSDateFormatter alloc] init]; + rfc1123DateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; + rfc1123DateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + rfc1123DateFormatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss z"; + NSDate *retryAfterDate = [rfc1123DateFormatter dateFromString:retryAfterValue]; + NSTimeInterval retryAfterInterval = (retryAfterDate != nil) ? + retryAfterDate.timeIntervalSinceNow : retryAfterValue.intValue; + retryAfterInterval = MAX(0, retryAfterInterval); + return retryAfterInterval; +} + +- (void)beginRetryTimer { + if (![NSThread isMainThread]) { + // Defer creating and starting the timer until we're on the main thread to ensure it has + // a run loop. + dispatch_group_async(_callbackGroup, dispatch_get_main_queue(), ^{ + [self beginRetryTimer]; + }); + return; + } + + [self destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval nextInterval = [self nextRetryIntervalUnsynchronized]; + NSTimeInterval maxInterval = _maxRetryInterval; + NSTimeInterval newInterval = MIN(nextInterval, (maxInterval > 0 ? maxInterval : DBL_MAX)); + NSTimeInterval newIntervalTolerance = (newInterval / 10) > 1.0 ?: 1.0; + + _lastRetryInterval = newInterval; + + _retryTimer = [NSTimer timerWithTimeInterval:newInterval + target:self + selector:@selector(retryTimerFired:) + userInfo:nil + repeats:NO]; + _retryTimer.tolerance = newIntervalTolerance; + [[NSRunLoop mainRunLoop] addTimer:_retryTimer + forMode:NSDefaultRunLoopMode]; + } // @synchronized(self) + + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherRetryDelayStartedNotification + userInfo:nil + requireAsync:NO]; +} + +- (void)retryTimerFired:(NSTimer *)timer { + [self destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _retryCount++; + } // @synchronized(self) + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + [self retryFetch]; + }]; +} + +- (void)destroyRetryTimer { + BOOL shouldNotify = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_retryTimer) { + [_retryTimer invalidate]; + _retryTimer = nil; + shouldNotify = YES; + } + } + + if (shouldNotify) { + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherRetryDelayStoppedNotification + userInfo:nil + requireAsync:NO]; + } +} + +- (NSUInteger)retryCount { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _retryCount; + } // @synchronized(self) +} + +- (NSTimeInterval)nextRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval interval = [self nextRetryIntervalUnsynchronized]; + return interval; + } // @synchronized(self) +} + +- (NSTimeInterval)nextRetryIntervalUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSInteger statusCode = [self statusCodeUnsynchronized]; + if ((statusCode == 503) && [self hasRetryAfterInterval]) { + NSTimeInterval secs = [self retryAfterInterval]; + return secs; + } + // The next wait interval is the factor (2.0) times the last interval, + // but never less than the minimum interval. + NSTimeInterval secs = _lastRetryInterval * _retryFactor; + if (_maxRetryInterval > 0) { + secs = MIN(secs, _maxRetryInterval); + } + secs = MAX(secs, _minRetryInterval); + + return secs; +} + +- (NSTimer *)retryTimer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _retryTimer; + } // @synchronized(self) +} + +- (BOOL)isRetryEnabled { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isRetryEnabled; + } // @synchronized(self) +} + +- (BOOL)isRetryEnabledUnsynchronized { + GTMSessionCheckSynchronized(self); + + return _isRetryEnabled; +} + +- (void)setRetryEnabled:(BOOL)flag { + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag && !_isRetryEnabled) { + // We defer initializing these until the user calls setRetryEnabled + // to avoid using the random number generator if it's not needed. + // However, this means min and max intervals for this fetcher are reset + // as a side effect of calling setRetryEnabled. + // + // Make an initial retry interval random between 1.0 and 2.0 seconds + _minRetryInterval = InitialMinRetryInterval(); + _maxRetryInterval = kUnsetMaxRetryInterval; + _retryFactor = 2.0; + _lastRetryInterval = 0.0; + } + _isRetryEnabled = flag; + } // @synchronized(self) +}; + +- (NSTimeInterval)maxRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _maxRetryInterval; + } // @synchronized(self) +} + +- (void)setMaxRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _maxRetryInterval = secs; + } else { + _maxRetryInterval = kUnsetMaxRetryInterval; + } + } // @synchronized(self) +} + +- (double)minRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _minRetryInterval; + } // @synchronized(self) +} + +- (void)setMinRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _minRetryInterval = secs; + } else { + // Set min interval to a random value between 1.0 and 2.0 seconds + // so that if multiple clients start retrying at the same time, they'll + // repeat at different times and avoid overloading the server + _minRetryInterval = InitialMinRetryInterval(); + } + } // @synchronized(self) + +} + +#pragma mark iOS System Completion Handlers + +#if TARGET_OS_IPHONE +static NSMutableDictionary *gSystemCompletionHandlers = nil; + +- (GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler { + return [[self class] systemCompletionHandlerForSessionIdentifier:_sessionIdentifier]; +} + +- (void)setSystemCompletionHandler:(GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler { + [[self class] setSystemCompletionHandler:systemCompletionHandler + forSessionIdentifier:_sessionIdentifier]; +} + ++ (void)setSystemCompletionHandler:(GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler + forSessionIdentifier:(NSString *)sessionIdentifier { + if (!sessionIdentifier) { + NSLog(@"%s with nil identifier", __PRETTY_FUNCTION__); + return; + } + + @synchronized([GTMSessionFetcher class]) { + if (gSystemCompletionHandlers == nil && systemCompletionHandler != nil) { + gSystemCompletionHandlers = [[NSMutableDictionary alloc] init]; + } + // Use setValue: to remove the object if completionHandler is nil. + [gSystemCompletionHandlers setValue:systemCompletionHandler + forKey:sessionIdentifier]; + } +} + ++ (GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandlerForSessionIdentifier:(NSString *)sessionIdentifier { + if (!sessionIdentifier) { + return nil; + } + @synchronized([GTMSessionFetcher class]) { + return [gSystemCompletionHandlers objectForKey:sessionIdentifier]; + } +} +#endif // TARGET_OS_IPHONE + +#pragma mark Getters and Setters + +@synthesize downloadResumeData = _downloadResumeData, + configuration = _configuration, + configurationBlock = _configurationBlock, + sessionTask = _sessionTask, + wasCreatedFromBackgroundSession = _wasCreatedFromBackgroundSession, + sessionUserInfo = _sessionUserInfo, + taskDescription = _taskDescription, + taskPriority = _taskPriority, + usingBackgroundSession = _usingBackgroundSession, + canShareSession = _canShareSession, + completionHandler = _completionHandler, + credential = _credential, + proxyCredential = _proxyCredential, + bodyData = _bodyData, + bodyLength = _bodyLength, + service = _service, + serviceHost = _serviceHost, + accumulateDataBlock = _accumulateDataBlock, + receivedProgressBlock = _receivedProgressBlock, + downloadProgressBlock = _downloadProgressBlock, + resumeDataBlock = _resumeDataBlock, + didReceiveResponseBlock = _didReceiveResponseBlock, + challengeBlock = _challengeBlock, + willRedirectBlock = _willRedirectBlock, + sendProgressBlock = _sendProgressBlock, + willCacheURLResponseBlock = _willCacheURLResponseBlock, + retryBlock = _retryBlock, + retryFactor = _retryFactor, + allowedInsecureSchemes = _allowedInsecureSchemes, + allowLocalhostRequest = _allowLocalhostRequest, + allowInvalidServerCertificates = _allowInvalidServerCertificates, + cookieStorage = _cookieStorage, + callbackQueue = _callbackQueue, + initialBeginFetchDate = _initialBeginFetchDate, + testBlock = _testBlock, + comment = _comment, + log = _log; + +#if !STRIP_GTM_FETCH_LOGGING +@synthesize redirectedFromURL = _redirectedFromURL, + logRequestBody = _logRequestBody, + logResponseBody = _logResponseBody, + hasLoggedError = _hasLoggedError; +#endif + +#if GTM_BACKGROUND_TASK_FETCHING +@synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier, + skipBackgroundTask = _skipBackgroundTask; +#endif + +- (GTM_NULLABLE NSURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_request copy]; + } // @synchronized(self) +} + +- (void)setRequest:(GTM_NULLABLE NSURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (![self isFetchingUnsynchronized]) { + _request = [request mutableCopy]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"request may not be set after beginFetch has been invoked"); + } + } // @synchronized(self) +} + +- (GTM_NULLABLE NSMutableURLRequest *)mutableRequestForTesting { + // Allow tests only to modify the request, useful during retries. + return _request; +} + +- (GTM_NULLABLE NSMutableURLRequest *)mutableRequest { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_LOG_DEBUG(@"[GTMSessionFetcher mutableRequest] is deprecated; use -request or" + @" -setRequestVaue:forHTTPHeaderField:"); + + return _request; + } // @synchronized(self) +} + +- (void)setMutableRequest:(GTM_NULLABLE NSMutableURLRequest *)request { + GTMSESSION_LOG_DEBUG(@"[GTMSessionFetcher setMutableRequest:] is deprecated; use -request or" + @" -setRequestVaue:forHTTPHeaderField:"); + + GTMSESSION_ASSERT_DEBUG(![self isFetching], + @"mutableRequest should not change after beginFetch has been invoked"); + [self updateMutableRequest:request]; +} + +// Internal method for updating the request property such as on redirects. +- (void)updateMutableRequest:(GTM_NULLABLE NSMutableURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _request = request; + } // @synchronized(self) +} + +// Set a header field value on the request. Header field value changes will not +// affect a fetch after the fetch has begun. +- (void)setRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field { + if (![self isFetching]) { + [self updateRequestValue:value forHTTPHeaderField:field]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"request may not be set after beginFetch has been invoked"); + } +} + +// Internal method for updating request headers. +- (void)updateRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_request setValue:value forHTTPHeaderField:field]; + } // @synchronized(self) +} + +- (void)setResponse:(GTM_NULLABLE NSURLResponse *)response { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _response = response; + } // @synchronized(self) +} + +- (int64_t)bodyLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_bodyLength == NSURLSessionTransferSizeUnknown) { + if (_bodyData) { + _bodyLength = (int64_t)_bodyData.length; + } else if (_bodyFileURL) { + NSNumber *fileSizeNum = nil; + NSError *fileSizeError = nil; + if ([_bodyFileURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:&fileSizeError]) { + _bodyLength = [fileSizeNum longLongValue]; + } + } + } + return _bodyLength; + } // @synchronized(self) +} + +- (BOOL)useUploadTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _useUploadTask; + } // @synchronized(self) +} + +- (void)setUseUploadTask:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag != _useUploadTask) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"useUploadTask should not change after beginFetch has been invoked"); + _useUploadTask = flag; + } + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURL *)bodyFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _bodyFileURL; + } // @synchronized(self) +} + +- (void)setBodyFileURL:(GTM_NULLABLE NSURL *)fileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // The comparison here is a trivial optimization and forgiveness for any client that + // repeatedly sets the property, so it just uses pointer comparison rather than isEqual:. + if (fileURL != _bodyFileURL) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"fileURL should not change after beginFetch has been invoked"); + + _bodyFileURL = fileURL; + } + } // @synchronized(self) +} + +- (GTM_NULLABLE GTMSessionFetcherBodyStreamProvider)bodyStreamProvider { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _bodyStreamProvider; + } // @synchronized(self) +} + +- (void)setBodyStreamProvider:(GTM_NULLABLE GTMSessionFetcherBodyStreamProvider)block { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"stream provider should not change after beginFetch has been invoked"); + + _bodyStreamProvider = [block copy]; + } // @synchronized(self) +} + +- (GTM_NULLABLE id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _authorizer; + } // @synchronized(self) +} + +- (void)setAuthorizer:(GTM_NULLABLE id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (authorizer != _authorizer) { + if ([self isFetchingUnsynchronized]) { + GTMSESSION_ASSERT_DEBUG(0, @"authorizer should not change after beginFetch has been invoked"); + } else { + _authorizer = authorizer; + } + } + } // @synchronized(self) +} + +- (GTM_NULLABLE NSData *)downloadedData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _downloadedData; + } // @synchronized(self) +} + +- (void)setDownloadedData:(GTM_NULLABLE NSData *)data { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _downloadedData = [data mutableCopy]; + } // @synchronized(self) +} + +- (int64_t)downloadedLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _downloadedLength; + } // @synchronized(self) +} + +- (void)setDownloadedLength:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _downloadedLength = length; + } // @synchronized(self) +} + +- (dispatch_queue_t GTM_NONNULL_TYPE)callbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _callbackQueue; + } // @synchronized(self) +} + +- (void)setCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _callbackQueue = queue ?: dispatch_get_main_queue(); + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _session; + } // @synchronized(self) +} + +- (NSInteger)servicePriority { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _servicePriority; + } // @synchronized(self) +} + +- (void)setServicePriority:(NSInteger)value { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (value != _servicePriority) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"servicePriority should not change after beginFetch has been invoked"); + + _servicePriority = value; + } + } // @synchronized(self) +} + + +- (void)setSession:(GTM_NULLABLE NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = session; + } // @synchronized(self) +} + +- (BOOL)canShareSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _canShareSession; + } // @synchronized(self) +} + +- (void)setCanShareSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _canShareSession = flag; + } // @synchronized(self) +} + +- (BOOL)useBackgroundSession { + // This reflects if the user requested a background session, not necessarily + // if one was created. That is tracked with _usingBackgroundSession. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userRequestedBackgroundSession; + } // @synchronized(self) +} + +- (void)setUseBackgroundSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag != _userRequestedBackgroundSession) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"useBackgroundSession should not change after beginFetch has been invoked"); + + _userRequestedBackgroundSession = flag; + } + } // @synchronized(self) +} + +- (BOOL)isUsingBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _usingBackgroundSession; + } // @synchronized(self) +} + +- (void)setUsingBackgroundSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _usingBackgroundSession = flag; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURLSession *)sessionNeedingInvalidation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionNeedingInvalidation; + } // @synchronized(self) +} + +- (void)setSessionNeedingInvalidation:(GTM_NULLABLE NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _sessionNeedingInvalidation = session; + } // @synchronized(self) +} + +- (NSOperationQueue * GTM_NONNULL_TYPE)sessionDelegateQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateQueue; + } // @synchronized(self) +} + +- (void)setSessionDelegateQueue:(NSOperationQueue * GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (queue != _delegateQueue) { + if ([self isFetchingUnsynchronized]) { + GTMSESSION_ASSERT_DEBUG(0, @"sessionDelegateQueue should not change after fetch begins"); + } else { + _delegateQueue = queue ?: [NSOperationQueue mainQueue]; + } + } + } // @synchronized(self) +} + +- (BOOL)userStoppedFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userStoppedFetching; + } // @synchronized(self) +} + +- (GTM_NULLABLE id)userData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userData; + } // @synchronized(self) +} + +- (void)setUserData:(GTM_NULLABLE id)theObj { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _userData = theObj; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURL *)destinationFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _destinationFileURL; + } // @synchronized(self) +} + +- (void)setDestinationFileURL:(GTM_NULLABLE NSURL *)destinationFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (((_destinationFileURL == nil) && (destinationFileURL == nil)) || + [_destinationFileURL isEqual:destinationFileURL]) { + return; + } + if (_sessionIdentifier) { + // This is something we don't expect to happen in production. + // However if it ever happen, leave a system log. + NSLog(@"%@: Destination File URL changed from (%@) to (%@) after session identifier has " + @"been created.", + [self class], _destinationFileURL, destinationFileURL); +#if DEBUG + // On both the simulator and devices, the path can change to the download file, but the name + // shouldn't change. Technically, this isn't supported in the fetcher, but the change of + // URL is expected to happen only across development runs through Xcode. + NSString *oldFilename = [_destinationFileURL lastPathComponent]; + NSString *newFilename = [destinationFileURL lastPathComponent]; + #pragma unused(oldFilename) + #pragma unused(newFilename) + GTMSESSION_ASSERT_DEBUG([oldFilename isEqualToString:newFilename], + @"Destination File URL cannot be changed after session identifier has been created"); +#endif + } + _destinationFileURL = destinationFileURL; + } // @synchronized(self) +} + +- (void)setProperties:(GTM_NULLABLE NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _properties = [dict mutableCopy]; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSDictionary *)properties { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _properties; + } // @synchronized(self) +} + +- (void)setProperty:(GTM_NULLABLE id)obj forKey:(NSString *)key { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_properties == nil && obj != nil) { + _properties = [[NSMutableDictionary alloc] init]; + } + [_properties setValue:obj forKey:key]; + } // @synchronized(self) +} + +- (GTM_NULLABLE id)propertyForKey:(NSString *)key { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_properties objectForKey:key]; + } // @synchronized(self) +} + +- (void)addPropertiesFromDictionary:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_properties == nil && dict != nil) { + [self setProperties:[dict mutableCopy]]; + } else { + [_properties addEntriesFromDictionary:dict]; + } + } // @synchronized(self) +} + +- (void)setCommentWithFormat:(id)format, ... { +#if !STRIP_GTM_FETCH_LOGGING + NSString *result = format; + if (format) { + va_list argList; + va_start(argList, format); + + result = [[NSString alloc] initWithFormat:format + arguments:argList]; + va_end(argList); + } + [self setComment:result]; +#endif +} + +#if !STRIP_GTM_FETCH_LOGGING +- (NSData *)loggedStreamData { + return _loggedStreamData; +} + +- (void)appendLoggedStreamData:dataToAdd { + if (!_loggedStreamData) { + _loggedStreamData = [NSMutableData data]; + } + [_loggedStreamData appendData:dataToAdd]; +} + +- (void)clearLoggedStreamData { + _loggedStreamData = nil; +} + +- (void)setDeferResponseBodyLogging:(BOOL)deferResponseBodyLogging { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (deferResponseBodyLogging != _deferResponseBodyLogging) { + _deferResponseBodyLogging = deferResponseBodyLogging; + if (!deferResponseBodyLogging && !self.hasLoggedError) { + [_delegateQueue addOperationWithBlock:^{ + [self logNowWithError:nil]; + }]; + } + } + } // @synchronized(self) +} + +- (BOOL)deferResponseBodyLogging { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _deferResponseBodyLogging; + } // @synchronized(self) +} + +#else ++ (void)setLoggingEnabled:(BOOL)flag { +} + ++ (BOOL)isLoggingEnabled { + return NO; +} +#endif // STRIP_GTM_FETCH_LOGGING + +@end + +@implementation GTMSessionFetcher (BackwardsCompatibilityOnly) + +- (void)setCookieStorageMethod:(NSInteger)method { + // For backwards compatibility with the old fetcher, we'll support the old constants. + // + // Clients using the GTMSessionFetcher class should set the cookie storage explicitly + // themselves. + NSHTTPCookieStorage *storage = nil; + switch(method) { + case 0: // kGTMHTTPFetcherCookieStorageMethodStatic + // nil storage will use [[self class] staticCookieStorage] when the fetch begins. + break; + case 1: // kGTMHTTPFetcherCookieStorageMethodFetchHistory + // Do nothing; use whatever was set by the fetcher service. + return; + case 2: // kGTMHTTPFetcherCookieStorageMethodSystemDefault + storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + break; + case 3: // kGTMHTTPFetcherCookieStorageMethodNone + // Create temporary storage for this fetcher only. + storage = [[GTMSessionCookieStorage alloc] init]; + break; + default: + GTMSESSION_ASSERT_DEBUG(0, @"Invalid cookie storage method: %d", (int)method); + } + self.cookieStorage = storage; +} + +@end + +@implementation GTMSessionCookieStorage { + NSMutableArray *_cookies; + NSHTTPCookieAcceptPolicy _policy; +} + +- (id)init { + self = [super init]; + if (self != nil) { + _cookies = [[NSMutableArray alloc] init]; + } + return self; +} + +- (GTM_NULLABLE NSArray *)cookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_cookies copy]; + } // @synchronized(self) +} + +- (void)setCookie:(NSHTTPCookie *)cookie { + if (!cookie) return; + if (_policy == NSHTTPCookieAcceptPolicyNever) return; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self internalSetCookie:cookie]; + } // @synchronized(self) +} + +// Note: this should only be called from inside a @synchronized(self) block. +- (void)internalSetCookie:(NSHTTPCookie *)newCookie { + GTMSessionCheckSynchronized(self); + + if (_policy == NSHTTPCookieAcceptPolicyNever) return; + + BOOL isValidCookie = (newCookie.name.length > 0 + && newCookie.domain.length > 0 + && newCookie.path.length > 0); + GTMSESSION_ASSERT_DEBUG(isValidCookie, @"invalid cookie: %@", newCookie); + + if (isValidCookie) { + // Remove the cookie if it's currently in the array. + NSHTTPCookie *oldCookie = [self cookieMatchingCookie:newCookie]; + if (oldCookie) { + [_cookies removeObjectIdenticalTo:oldCookie]; + } + + if (![[self class] hasCookieExpired:newCookie]) { + [_cookies addObject:newCookie]; + } + } +} + +// Add all cookies in the new cookie array to the storage, +// replacing stored cookies as appropriate. +// +// Side effect: removes expired cookies from the storage array. +- (void)setCookies:(GTM_NULLABLE NSArray *)newCookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self removeExpiredCookies]; + + for (NSHTTPCookie *newCookie in newCookies) { + [self internalSetCookie:newCookie]; + } + } // @synchronized(self) +} + +- (void)setCookies:(NSArray *)cookies forURL:(GTM_NULLABLE NSURL *)URL mainDocumentURL:(GTM_NULLABLE NSURL *)mainDocumentURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_policy == NSHTTPCookieAcceptPolicyNever) { + return; + } + + if (_policy == NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain) { + NSString *mainHost = mainDocumentURL.host; + NSString *associatedHost = URL.host; + if (!mainHost || ![associatedHost hasSuffix:mainHost]) { + return; + } + } + } // @synchronized(self) + [self setCookies:cookies]; +} + +- (void)deleteCookie:(NSHTTPCookie *)cookie { + if (!cookie) return; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSHTTPCookie *foundCookie = [self cookieMatchingCookie:cookie]; + if (foundCookie) { + [_cookies removeObjectIdenticalTo:foundCookie]; + } + } // @synchronized(self) +} + +// Retrieve all cookies appropriate for the given URL, considering +// domain, path, cookie name, expiration, security setting. +// Side effect: removed expired cookies from the storage array. +- (GTM_NULLABLE NSArray *)cookiesForURL:(NSURL *)theURL { + NSMutableArray *foundCookies = nil; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self removeExpiredCookies]; + + // We'll prepend "." to the desired domain, since we want the + // actual domain "nytimes.com" to still match the cookie domain + // ".nytimes.com" when we check it below with hasSuffix. + NSString *host = theURL.host.lowercaseString; + NSString *path = theURL.path; + NSString *scheme = [theURL scheme]; + + NSString *requestingDomain = nil; + BOOL isLocalhostRetrieval = NO; + + if (IsLocalhost(host)) { + isLocalhostRetrieval = YES; + } else { + if (host.length > 0) { + requestingDomain = [@"." stringByAppendingString:host]; + } + } + + for (NSHTTPCookie *storedCookie in _cookies) { + NSString *cookieDomain = storedCookie.domain.lowercaseString; + NSString *cookiePath = storedCookie.path; + BOOL cookieIsSecure = [storedCookie isSecure]; + + BOOL isDomainOK; + + if (isLocalhostRetrieval) { + // Prior to 10.5.6, the domain stored into NSHTTPCookies for localhost + // is "localhost.local" + isDomainOK = (IsLocalhost(cookieDomain) + || [cookieDomain isEqual:@"localhost.local"]); + } else { + // Ensure we're matching exact domain names. We prepended a dot to the + // requesting domain, so we can also prepend one here if needed before + // checking if the request contains the cookie domain. + if (![cookieDomain hasPrefix:@"."]) { + cookieDomain = [@"." stringByAppendingString:cookieDomain]; + } + isDomainOK = [requestingDomain hasSuffix:cookieDomain]; + } + + BOOL isPathOK = [cookiePath isEqual:@"/"] || [path hasPrefix:cookiePath]; + BOOL isSecureOK = (!cookieIsSecure + || [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame); + + if (isDomainOK && isPathOK && isSecureOK) { + if (foundCookies == nil) { + foundCookies = [NSMutableArray array]; + } + [foundCookies addObject:storedCookie]; + } + } + } // @synchronized(self) + return foundCookies; +} + +// Override methods from the NSHTTPCookieStorage (NSURLSessionTaskAdditions) category. +- (void)storeCookies:(NSArray *)cookies forTask:(NSURLSessionTask *)task { + NSURLRequest *currentRequest = task.currentRequest; + [self setCookies:cookies forURL:currentRequest.URL mainDocumentURL:nil]; +} + +- (void)getCookiesForTask:(NSURLSessionTask *)task + completionHandler:(void (^)(GTM_NSArrayOf(NSHTTPCookie *) *))completionHandler { + if (completionHandler) { + NSURLRequest *currentRequest = task.currentRequest; + NSURL *currentRequestURL = currentRequest.URL; + NSArray *cookies = [self cookiesForURL:currentRequestURL]; + completionHandler(cookies); + } +} + +// Return a cookie from the array with the same name, domain, and path as the +// given cookie, or else return nil if none found. +// +// Both the cookie being tested and all cookies in the storage array should +// be valid (non-nil name, domains, paths). +// +// Note: this should only be called from inside a @synchronized(self) block +- (GTM_NULLABLE NSHTTPCookie *)cookieMatchingCookie:(NSHTTPCookie *)cookie { + GTMSessionCheckSynchronized(self); + + NSString *name = cookie.name; + NSString *domain = cookie.domain; + NSString *path = cookie.path; + + GTMSESSION_ASSERT_DEBUG(name && domain && path, + @"Invalid stored cookie (name:%@ domain:%@ path:%@)", name, domain, path); + + for (NSHTTPCookie *storedCookie in _cookies) { + if ([storedCookie.name isEqual:name] + && [storedCookie.domain isEqual:domain] + && [storedCookie.path isEqual:path]) { + return storedCookie; + } + } + return nil; +} + +// Internal routine to remove any expired cookies from the array, excluding +// cookies with nil expirations. +// +// Note: this should only be called from inside a @synchronized(self) block +- (void)removeExpiredCookies { + GTMSessionCheckSynchronized(self); + + // Count backwards since we're deleting items from the array + for (NSInteger idx = (NSInteger)_cookies.count - 1; idx >= 0; idx--) { + NSHTTPCookie *storedCookie = [_cookies objectAtIndex:(NSUInteger)idx]; + if ([[self class] hasCookieExpired:storedCookie]) { + [_cookies removeObjectAtIndex:(NSUInteger)idx]; + } + } +} + ++ (BOOL)hasCookieExpired:(NSHTTPCookie *)cookie { + NSDate *expiresDate = [cookie expiresDate]; + if (expiresDate == nil) { + // Cookies seem to have a Expires property even when the expiresDate method returns nil. + id expiresVal = [[cookie properties] objectForKey:NSHTTPCookieExpires]; + if ([expiresVal isKindOfClass:[NSDate class]]) { + expiresDate = expiresVal; + } + } + BOOL hasExpired = (expiresDate != nil && [expiresDate timeIntervalSinceNow] < 0); + return hasExpired; +} + +- (void)removeAllCookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_cookies removeAllObjects]; + } // @synchronized(self) +} + +- (NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _policy; + } // @synchronized(self) +} + +- (void)setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _policy = cookieAcceptPolicy; + } // @synchronized(self) +} + +@end + +void GTMSessionFetcherAssertValidSelector(id GTM_NULLABLE_TYPE obj, SEL GTM_NULLABLE_TYPE sel, ...) { + // Verify that the object's selector is implemented with the proper + // number and type of arguments +#if DEBUG + va_list argList; + va_start(argList, sel); + + if (obj && sel) { + // Check that the selector is implemented + if (![obj respondsToSelector:sel]) { + NSLog(@"\"%@\" selector \"%@\" is unimplemented or misnamed", + NSStringFromClass([(id)obj class]), + NSStringFromSelector((SEL)sel)); + NSCAssert(0, @"callback selector unimplemented or misnamed"); + } else { + const char *expectedArgType; + unsigned int argCount = 2; // skip self and _cmd + NSMethodSignature *sig = [obj methodSignatureForSelector:sel]; + + // Check that each expected argument is present and of the correct type + while ((expectedArgType = va_arg(argList, const char*)) != 0) { + + if ([sig numberOfArguments] > argCount) { + const char *foundArgType = [sig getArgumentTypeAtIndex:argCount]; + + if (0 != strncmp(foundArgType, expectedArgType, strlen(expectedArgType))) { + NSLog(@"\"%@\" selector \"%@\" argument %d should be type %s", + NSStringFromClass([(id)obj class]), + NSStringFromSelector((SEL)sel), (argCount - 2), expectedArgType); + NSCAssert(0, @"callback selector argument type mistake"); + } + } + argCount++; + } + + // Check that the proper number of arguments are present in the selector + if (argCount != [sig numberOfArguments]) { + NSLog(@"\"%@\" selector \"%@\" should have %d arguments", + NSStringFromClass([(id)obj class]), + NSStringFromSelector((SEL)sel), (argCount - 2)); + NSCAssert(0, @"callback selector arguments incorrect"); + } + } + } + + va_end(argList); +#endif +} + +NSString *GTMFetcherCleanedUserAgentString(NSString *str) { + // Reference http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html + // and http://www-archive.mozilla.org/build/user-agent-strings.html + + if (str == nil) return @""; + + NSMutableString *result = [NSMutableString stringWithString:str]; + + // Replace spaces and commas with underscores + [result replaceOccurrencesOfString:@" " + withString:@"_" + options:0 + range:NSMakeRange(0, result.length)]; + [result replaceOccurrencesOfString:@"," + withString:@"_" + options:0 + range:NSMakeRange(0, result.length)]; + + // Delete http token separators and remaining whitespace + static NSCharacterSet *charsToDelete = nil; + if (charsToDelete == nil) { + // Make a set of unwanted characters + NSString *const kSeparators = @"()<>@;:\\\"/[]?={}"; + + NSMutableCharacterSet *mutableChars = + [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy]; + [mutableChars addCharactersInString:kSeparators]; + charsToDelete = [mutableChars copy]; // hang on to an immutable copy + } + + while (1) { + NSRange separatorRange = [result rangeOfCharacterFromSet:charsToDelete]; + if (separatorRange.location == NSNotFound) break; + + [result deleteCharactersInRange:separatorRange]; + }; + + return result; +} + +NSString *GTMFetcherSystemVersionString(void) { + static NSString *sSavedSystemString; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ +#if TARGET_OS_MAC && !TARGET_OS_IPHONE + // Mac build + NSProcessInfo *procInfo = [NSProcessInfo processInfo]; +#if !defined(MAC_OS_X_VERSION_10_10) + BOOL hasOperatingSystemVersion = NO; +#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10 + BOOL hasOperatingSystemVersion = + [procInfo respondsToSelector:@selector(operatingSystemVersion)]; +#else + BOOL hasOperatingSystemVersion = YES; +#endif + NSString *versString; + if (hasOperatingSystemVersion) { +#if defined(MAC_OS_X_VERSION_10_10) + // A reference to NSOperatingSystemVersion requires the 10.10 SDK. + NSOperatingSystemVersion version = procInfo.operatingSystemVersion; + versString = [NSString stringWithFormat:@"%zd.%zd.%zd", + version.majorVersion, version.minorVersion, version.patchVersion]; +#else +#pragma unused(procInfo) +#endif + } else { + // With Gestalt inexplicably deprecated in 10.8, we're reduced to reading + // the system plist file. + NSString *const kPath = @"/System/Library/CoreServices/SystemVersion.plist"; + NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:kPath]; + versString = [plist objectForKey:@"ProductVersion"]; + if (versString.length == 0) { + versString = @"10.?.?"; + } + } + + sSavedSystemString = [[NSString alloc] initWithFormat:@"MacOSX/%@", versString]; +#elif TARGET_OS_IPHONE + // Compiling against the iPhone SDK + // Avoid the slowness of calling currentDevice repeatedly on the iPhone + UIDevice* currentDevice = [UIDevice currentDevice]; + + NSString *rawModel = [currentDevice model]; + NSString *model = GTMFetcherCleanedUserAgentString(rawModel); + + NSString *systemVersion = [currentDevice systemVersion]; + +#if TARGET_IPHONE_SIMULATOR + NSString *hardwareModel = @"sim"; +#else + NSString *hardwareModel; + struct utsname unameRecord; + if (uname(&unameRecord) == 0) { + NSString *machineName = [NSString stringWithCString:unameRecord.machine + encoding:NSUTF8StringEncoding]; + hardwareModel = GTMFetcherCleanedUserAgentString(machineName); + } else { + hardwareModel = @"unk"; + } +#endif + + sSavedSystemString = [[NSString alloc] initWithFormat:@"%@/%@ hw/%@", + model, systemVersion, hardwareModel]; + // Example: iPod_Touch/2.2 hw/iPod1_1 +#elif defined(_SYS_UTSNAME_H) + // Foundation-only build + struct utsname unameRecord; + uname(&unameRecord); + + sSavedSystemString = [NSString stringWithFormat:@"%s/%s", + unameRecord.sysname, unameRecord.release]; // "Darwin/8.11.1" +#endif + }); + return sSavedSystemString; +} + +NSString *GTMFetcherStandardUserAgentString(NSBundle * GTM_NULLABLE_TYPE bundle) { + NSString *result = [NSString stringWithFormat:@"%@ %@", + GTMFetcherApplicationIdentifier(bundle), + GTMFetcherSystemVersionString()]; + return result; +} + +NSString *GTMFetcherApplicationIdentifier(NSBundle * GTM_NULLABLE_TYPE bundle) { + @synchronized([GTMSessionFetcher class]) { + static NSMutableDictionary *sAppIDMap = nil; + + // If there's a bundle ID, use that; otherwise, use the process name + if (bundle == nil) { + bundle = [NSBundle mainBundle]; + } + NSString *bundleID = [bundle bundleIdentifier]; + if (bundleID == nil) { + bundleID = @""; + } + + NSString *identifier = [sAppIDMap objectForKey:bundleID]; + if (identifier) return identifier; + + // Apps may add a string to the info.plist to uniquely identify different builds. + identifier = [bundle objectForInfoDictionaryKey:@"GTMUserAgentID"]; + if (identifier.length == 0) { + if (bundleID.length > 0) { + identifier = bundleID; + } else { + // Fall back on the procname, prefixed by "proc" to flag that it's + // autogenerated and perhaps unreliable + NSString *procName = [[NSProcessInfo processInfo] processName]; + identifier = [NSString stringWithFormat:@"proc_%@", procName]; + } + } + + // Clean up whitespace and special characters + identifier = GTMFetcherCleanedUserAgentString(identifier); + + // If there's a version number, append that + NSString *version = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + if (version.length == 0) { + version = [bundle objectForInfoDictionaryKey:@"CFBundleVersion"]; + } + + // Clean up whitespace and special characters + version = GTMFetcherCleanedUserAgentString(version); + + // Glue the two together (cleanup done above or else cleanup would strip the + // slash) + if (version.length > 0) { + identifier = [identifier stringByAppendingFormat:@"/%@", version]; + } + + if (sAppIDMap == nil) { + sAppIDMap = [[NSMutableDictionary alloc] init]; + } + [sAppIDMap setObject:identifier forKey:bundleID]; + return identifier; + } +} + +#if DEBUG +@implementation GTMSessionSyncMonitorInternal { + NSValue *_objectKey; // The synchronize target object. + const char *_functionName; // The function containing the monitored sync block. +} + +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName { + self = [super init]; + if (self) { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + _objectKey = [NSValue valueWithNonretainedObject:object]; + _functionName = functionName; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + if (counters == nil) { + counters = [NSMutableDictionary dictionary]; + threadDict[(id)threadKey] = counters; + } + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSUInteger numberOfSyncingFunctions = functionNamesCounter.count; + + if (!allowRecursive) { + BOOL isTopLevelSyncScope = (numberOfSyncingFunctions == 0); + NSArray *stack = [NSThread callStackSymbols]; + GTMSESSION_ASSERT_DEBUG(isTopLevelSyncScope, + @"*** Recursive sync on %@ at %s; previous sync at %@\n%@", + [object class], functionName, functionNamesCounter.allObjects, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + } + + if (!functionNamesCounter) { + functionNamesCounter = [NSCountedSet set]; + counters[_objectKey] = functionNamesCounter; + } + [functionNamesCounter addObject:@(functionName)]; + } + return self; +} + +- (void)dealloc { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSString *functionNameStr = @(_functionName); + NSUInteger numberOfSyncsByThisFunction = [functionNamesCounter countForObject:functionNameStr]; + NSArray *stack = [NSThread callStackSymbols]; + GTMSESSION_ASSERT_DEBUG(numberOfSyncsByThisFunction > 0, @"Sync not found on %@ at %s\n%@", + [_objectKey.nonretainedObjectValue class], _functionName, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + [functionNamesCounter removeObject:functionNameStr]; + if (functionNamesCounter.count == 0) { + [counters removeObjectForKey:_objectKey]; + } +} + ++ (NSArray *)functionsHoldingSynchronizationOnObject:(id)object { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + NSValue *localObjectKey = [NSValue valueWithNonretainedObject:object]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[localObjectKey]; + return functionNamesCounter.count > 0 ? functionNamesCounter.allObjects : nil; +} +@end +#endif // DEBUG +GTM_ASSUME_NONNULL_END diff --git a/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h new file mode 100644 index 0000000..bc0a65c --- /dev/null +++ b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h @@ -0,0 +1,107 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GTMSessionFetcher.h" + +// GTM HTTP Logging +// +// All traffic using GTMSessionFetcher can be easily logged. Call +// +// [GTMSessionFetcher setLoggingEnabled:YES]; +// +// to begin generating log files. +// +// Log files are put into a folder on the desktop called "GTMHTTPDebugLogs" +// unless another directory is specified with +setLoggingDirectory. +// +// In the iPhone simulator, the default logs location is the user's home +// directory in ~/Library/Application Support. On the iPhone device, the +// default logs location is the application's documents directory on the device. +// +// Tip: use the Finder's "Sort By Date" to find the most recent logs. +// +// Each run of an application gets a separate set of log files. An html +// file is generated to simplify browsing the run's http transactions. +// The html file includes javascript links for inline viewing of uploaded +// and downloaded data. +// +// A symlink is created in the logs folder to simplify finding the html file +// for the latest run of the application; the symlink is called +// +// AppName_http_log_newest.html +// +// For better viewing of XML logs, use Camino or Firefox rather than Safari. +// +// Each fetcher may be given a comment to be inserted as a label in the logs, +// such as +// [fetcher setCommentWithFormat:@"retrieve item %@", itemName]; +// +// Projects may define STRIP_GTM_FETCH_LOGGING to remove logging code. + +#if !STRIP_GTM_FETCH_LOGGING + +@interface GTMSessionFetcher (GTMSessionFetcherLogging) + +// Note: the default logs directory is ~/Desktop/GTMHTTPDebugLogs; it will be +// created as needed. If a custom directory is set, the directory should +// already exist. ++ (void)setLoggingDirectory:(NSString *)path; ++ (NSString *)loggingDirectory; + +// client apps can turn logging on and off ++ (void)setLoggingEnabled:(BOOL)isLoggingEnabled; ++ (BOOL)isLoggingEnabled; + +// client apps can turn off logging to a file if they want to only check +// the fetcher's log property ++ (void)setLoggingToFileEnabled:(BOOL)isLoggingToFileEnabled; ++ (BOOL)isLoggingToFileEnabled; + +// client apps can optionally specify process name and date string used in +// log file names ++ (void)setLoggingProcessName:(NSString *)processName; ++ (NSString *)loggingProcessName; + ++ (void)setLoggingDateStamp:(NSString *)dateStamp; ++ (NSString *)loggingDateStamp; + +// client apps can specify the directory for the log for this specific run, +// typically to match the directory used by another fetcher class, like: +// +// [GTMSessionFetcher setLogDirectoryForCurrentRun:[GTMHTTPFetcher logDirectoryForCurrentRun]]; +// +// Setting this overrides the logging directory, process name, and date stamp when writing +// the log file. ++ (void)setLogDirectoryForCurrentRun:(NSString *)logDirectoryForCurrentRun; ++ (NSString *)logDirectoryForCurrentRun; + +// Prunes old log directories that have not been modified since the provided date. +// This will not delete the current run's log directory. ++ (void)deleteLogDirectoriesOlderThanDate:(NSDate *)date; + +// internal; called by fetcher +- (void)logFetchWithError:(NSError *)error; +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream; +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider; + +// internal; accessors useful for viewing logs ++ (NSString *)processNameLogPrefix; ++ (NSString *)symlinkNameSuffix; ++ (NSString *)htmlFileName; + +@end + +#endif // !STRIP_GTM_FETCH_LOGGING diff --git a/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m new file mode 100644 index 0000000..19a91eb --- /dev/null +++ b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m @@ -0,0 +1,976 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#include +#include + +#import "GTMSessionFetcherLogging.h" + +#ifndef STRIP_GTM_FETCH_LOGGING + #error GTMSessionFetcher headers should have defaulted this if it wasn't already defined. +#endif + +#if !STRIP_GTM_FETCH_LOGGING + +// Sensitive credential strings are replaced in logs with _snip_ +// +// Apps that must see the contents of sensitive tokens can set this to 1 +#ifndef SKIP_GTM_FETCH_LOGGING_SNIPPING +#define SKIP_GTM_FETCH_LOGGING_SNIPPING 0 +#endif + +// If GTMReadMonitorInputStream is available, it can be used for +// capturing uploaded streams of data +// +// We locally declare methods of GTMReadMonitorInputStream so we +// do not need to import the header, as some projects may not have it available +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMReadMonitorInputStream : NSInputStream + ++ (instancetype)inputStreamWithStream:(NSInputStream *)input; + +@property (assign) id readDelegate; +@property (assign) SEL readSelector; + +@end +#else +@class GTMReadMonitorInputStream; +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionFetcher (GTMHTTPFetcherLoggingUtilities) + ++ (NSString *)headersStringForDictionary:(NSDictionary *)dict; ++ (NSString *)snipSubstringOfString:(NSString *)originalStr + betweenStartString:(NSString *)startStr + endString:(NSString *)endStr; +- (void)inputStream:(GTMReadMonitorInputStream *)stream + readIntoBuffer:(void *)buffer + length:(int64_t)length; + +@end + +@implementation GTMSessionFetcher (GTMSessionFetcherLogging) + +// fetchers come and fetchers go, but statics are forever +static BOOL gIsLoggingEnabled = NO; +static BOOL gIsLoggingToFile = YES; +static NSString *gLoggingDirectoryPath = nil; +static NSString *gLogDirectoryForCurrentRun = nil; +static NSString *gLoggingDateStamp = nil; +static NSString *gLoggingProcessName = nil; + ++ (void)setLoggingDirectory:(NSString *)path { + gLoggingDirectoryPath = [path copy]; +} + ++ (NSString *)loggingDirectory { + if (!gLoggingDirectoryPath) { + NSArray *paths = nil; +#if TARGET_IPHONE_SIMULATOR + // default to a directory called GTMHTTPDebugLogs into a sandbox-safe + // directory that a developer can find easily, the application home + paths = @[ NSHomeDirectory() ]; +#elif TARGET_OS_IPHONE + // Neither ~/Desktop nor ~/Home is writable on an actual iPhone device. + // Put it in ~/Documents. + paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); +#else + // default to a directory called GTMHTTPDebugLogs in the desktop folder + paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES); +#endif + + NSString *desktopPath = paths.firstObject; + if (desktopPath) { + NSString *const kGTMLogFolderName = @"GTMHTTPDebugLogs"; + NSString *logsFolderPath = [desktopPath stringByAppendingPathComponent:kGTMLogFolderName]; + + NSFileManager *fileMgr = [NSFileManager defaultManager]; + BOOL isDir; + BOOL doesFolderExist = [fileMgr fileExistsAtPath:logsFolderPath isDirectory:&isDir]; + if (!doesFolderExist) { + // make the directory + doesFolderExist = [fileMgr createDirectoryAtPath:logsFolderPath + withIntermediateDirectories:YES + attributes:nil + error:NULL]; + } + if (doesFolderExist) { + // it's there; store it in the global + gLoggingDirectoryPath = [logsFolderPath copy]; + } + } + } + return gLoggingDirectoryPath; +} + ++ (void)setLogDirectoryForCurrentRun:(NSString *)logDirectoryForCurrentRun { + // Set the path for this run's logs. + gLogDirectoryForCurrentRun = [logDirectoryForCurrentRun copy]; +} + ++ (NSString *)logDirectoryForCurrentRun { + // make a directory for this run's logs, like SyncProto_logs_10-16_01-56-58PM + if (gLogDirectoryForCurrentRun) return gLogDirectoryForCurrentRun; + + NSString *parentDir = [self loggingDirectory]; + NSString *logNamePrefix = [self processNameLogPrefix]; + NSString *dateStamp = [self loggingDateStamp]; + NSString *dirName = [NSString stringWithFormat:@"%@%@", logNamePrefix, dateStamp]; + NSString *logDirectory = [parentDir stringByAppendingPathComponent:dirName]; + + if (gIsLoggingToFile) { + NSFileManager *fileMgr = [NSFileManager defaultManager]; + // Be sure that the first time this app runs, it's not writing to a preexisting folder + static BOOL gShouldReuseFolder = NO; + if (!gShouldReuseFolder) { + gShouldReuseFolder = YES; + NSString *origLogDir = logDirectory; + for (int ctr = 2; ctr < 20; ++ctr) { + if (![fileMgr fileExistsAtPath:logDirectory]) break; + + // append a digit + logDirectory = [origLogDir stringByAppendingFormat:@"_%d", ctr]; + } + } + if (![fileMgr createDirectoryAtPath:logDirectory + withIntermediateDirectories:YES + attributes:nil + error:NULL]) return nil; + } + gLogDirectoryForCurrentRun = logDirectory; + + return gLogDirectoryForCurrentRun; +} + ++ (void)setLoggingEnabled:(BOOL)isLoggingEnabled { + gIsLoggingEnabled = isLoggingEnabled; +} + ++ (BOOL)isLoggingEnabled { + return gIsLoggingEnabled; +} + ++ (void)setLoggingToFileEnabled:(BOOL)isLoggingToFileEnabled { + gIsLoggingToFile = isLoggingToFileEnabled; +} + ++ (BOOL)isLoggingToFileEnabled { + return gIsLoggingToFile; +} + ++ (void)setLoggingProcessName:(NSString *)processName { + gLoggingProcessName = [processName copy]; +} + ++ (NSString *)loggingProcessName { + // get the process name (once per run) replacing spaces with underscores + if (!gLoggingProcessName) { + NSString *procName = [[NSProcessInfo processInfo] processName]; + gLoggingProcessName = [procName stringByReplacingOccurrencesOfString:@" " withString:@"_"]; + } + return gLoggingProcessName; +} + ++ (void)setLoggingDateStamp:(NSString *)dateStamp { + gLoggingDateStamp = [dateStamp copy]; +} + ++ (NSString *)loggingDateStamp { + // We'll pick one date stamp per run, so a run that starts at a later second + // will get a unique results html file + if (!gLoggingDateStamp) { + // produce a string like 08-21_01-41-23PM + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + [formatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [formatter setDateFormat:@"M-dd_hh-mm-ssa"]; + + gLoggingDateStamp = [formatter stringFromDate:[NSDate date]]; + } + return gLoggingDateStamp; +} + ++ (NSString *)processNameLogPrefix { + static NSString *gPrefix = nil; + if (!gPrefix) { + NSString *processName = [self loggingProcessName]; + gPrefix = [[NSString alloc] initWithFormat:@"%@_log_", processName]; + } + return gPrefix; +} + ++ (NSString *)symlinkNameSuffix { + return @"_log_newest.html"; +} + ++ (NSString *)htmlFileName { + return @"aperçu_http_log.html"; +} + ++ (void)deleteLogDirectoriesOlderThanDate:(NSDate *)cutoffDate { + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSURL *parentDir = [NSURL fileURLWithPath:[[self class] loggingDirectory]]; + NSURL *logDirectoryForCurrentRun = + [NSURL fileURLWithPath:[[self class] logDirectoryForCurrentRun]]; + NSError *error; + NSArray *contents = [fileMgr contentsOfDirectoryAtURL:parentDir + includingPropertiesForKeys:@[ NSURLContentModificationDateKey ] + options:0 + error:&error]; + for (NSURL *itemURL in contents) { + if ([itemURL isEqual:logDirectoryForCurrentRun]) continue; + + NSDate *modDate; + if ([itemURL getResourceValue:&modDate + forKey:NSURLContentModificationDateKey + error:&error]) { + if ([modDate compare:cutoffDate] == NSOrderedAscending) { + if (![fileMgr removeItemAtURL:itemURL error:&error]) { + NSLog(@"deleteLogDirectoriesOlderThanDate failed to delete %@: %@", + itemURL.path, error); + } + } + } else { + NSLog(@"deleteLogDirectoriesOlderThanDate failed to get mod date of %@: %@", + itemURL.path, error); + } + } +} + +// formattedStringFromData returns a prettyprinted string for XML or JSON input, +// and a plain string for other input data +- (NSString *)formattedStringFromData:(NSData *)inputData + contentType:(NSString *)contentType + JSON:(NSDictionary **)outJSON { + if (!inputData) return nil; + + // if the content type is JSON and we have the parsing class available, use that + if ([contentType hasPrefix:@"application/json"] && inputData.length > 5) { + // convert from JSON string to NSObjects and back to a formatted string + NSMutableDictionary *obj = [NSJSONSerialization JSONObjectWithData:inputData + options:NSJSONReadingMutableContainers + error:NULL]; + if (obj) { + if (outJSON) *outJSON = obj; + if ([obj isKindOfClass:[NSMutableDictionary class]]) { + // for security and privacy, omit OAuth 2 response access and refresh tokens + if ([obj valueForKey:@"refresh_token"] != nil) { + [obj setObject:@"_snip_" forKey:@"refresh_token"]; + } + if ([obj valueForKey:@"access_token"] != nil) { + [obj setObject:@"_snip_" forKey:@"access_token"]; + } + } + NSData *data = [NSJSONSerialization dataWithJSONObject:obj + options:NSJSONWritingPrettyPrinted + error:NULL]; + if (data) { + NSString *jsonStr = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + return jsonStr; + } + } + } + +#if !TARGET_OS_IPHONE && !GTM_SKIP_LOG_XMLFORMAT + // verify that this data starts with the bytes indicating XML + + NSString *const kXMLLintPath = @"/usr/bin/xmllint"; + static BOOL gHasCheckedAvailability = NO; + static BOOL gIsXMLLintAvailable = NO; + + if (!gHasCheckedAvailability) { + gIsXMLLintAvailable = [[NSFileManager defaultManager] fileExistsAtPath:kXMLLintPath]; + gHasCheckedAvailability = YES; + } + if (gIsXMLLintAvailable + && inputData.length > 5 + && strncmp(inputData.bytes, " 0) { + // success + inputData = formattedData; + } + } +#else + // we can't call external tasks on the iPhone; leave the XML unformatted +#endif + + NSString *dataStr = [[NSString alloc] initWithData:inputData + encoding:NSUTF8StringEncoding]; + return dataStr; +} + +// stringFromStreamData creates a string given the supplied data +// +// If NSString can create a UTF-8 string from the data, then that is returned. +// +// Otherwise, this routine tries to find a MIME boundary at the beginning of the data block, and +// uses that to break up the data into parts. Each part will be used to try to make a UTF-8 string. +// For parts that fail, a replacement string showing the part header and <> is supplied +// in place of the binary data. + +- (NSString *)stringFromStreamData:(NSData *)data + contentType:(NSString *)contentType { + + if (!data) return nil; + + // optimistically, see if the whole data block is UTF-8 + NSString *streamDataStr = [self formattedStringFromData:data + contentType:contentType + JSON:NULL]; + if (streamDataStr) return streamDataStr; + + // Munge a buffer by replacing non-ASCII bytes with underscores, and turn that munged buffer an + // NSString. That gives us a string we can use with NSScanner. + NSMutableData *mutableData = [NSMutableData dataWithData:data]; + unsigned char *bytes = (unsigned char *)mutableData.mutableBytes; + + for (unsigned int idx = 0; idx < mutableData.length; ++idx) { + if (bytes[idx] > 0x7F || bytes[idx] == 0) { + bytes[idx] = '_'; + } + } + + NSString *mungedStr = [[NSString alloc] initWithData:mutableData + encoding:NSUTF8StringEncoding]; + if (mungedStr) { + + // scan for the boundary string + NSString *boundary = nil; + NSScanner *scanner = [NSScanner scannerWithString:mungedStr]; + + if ([scanner scanUpToString:@"\r\n" intoString:&boundary] + && [boundary hasPrefix:@"--"]) { + + // we found a boundary string; use it to divide the string into parts + NSArray *mungedParts = [mungedStr componentsSeparatedByString:boundary]; + + // look at each munged part in the original string, and try to convert those into UTF-8 + NSMutableArray *origParts = [NSMutableArray array]; + NSUInteger offset = 0; + for (NSString *mungedPart in mungedParts) { + NSUInteger partSize = mungedPart.length; + NSData *origPartData = [data subdataWithRange:NSMakeRange(offset, partSize)]; + NSString *origPartStr = [[NSString alloc] initWithData:origPartData + encoding:NSUTF8StringEncoding]; + if (origPartStr) { + // we could make this original part into UTF-8; use the string + [origParts addObject:origPartStr]; + } else { + // this part can't be made into UTF-8; scan the header, if we can + NSString *header = nil; + NSScanner *headerScanner = [NSScanner scannerWithString:mungedPart]; + if (![headerScanner scanUpToString:@"\r\n\r\n" intoString:&header]) { + // we couldn't find a header + header = @""; + } + // make a part string with the header and <> + NSString *binStr = [NSString stringWithFormat:@"\r%@\r<<%lu bytes>>\r", + header, (long)(partSize - header.length)]; + [origParts addObject:binStr]; + } + offset += partSize + boundary.length; + } + // rejoin the original parts + streamDataStr = [origParts componentsJoinedByString:boundary]; + } + } + if (!streamDataStr) { + // give up; just make a string showing the uploaded bytes + streamDataStr = [NSString stringWithFormat:@"<<%u bytes>>", (unsigned int)data.length]; + } + return streamDataStr; +} + +// logFetchWithError is called following a successful or failed fetch attempt +// +// This method does all the work for appending to and creating log files + +- (void)logFetchWithError:(NSError *)error { + if (![[self class] isLoggingEnabled]) return; + NSString *logDirectory = [[self class] logDirectoryForCurrentRun]; + if (!logDirectory) return; + NSString *processName = [[self class] loggingProcessName]; + + // TODO: add Javascript to display response data formatted in hex + + // each response's NSData goes into its own xml or txt file, though all responses for this run of + // the app share a main html file. This counter tracks all fetch responses for this app run. + // + // we'll use a local variable since this routine may be reentered while waiting for XML formatting + // to be completed by an external task + static int gResponseCounter = 0; + int responseCounter = ++gResponseCounter; + + NSURLResponse *response = [self response]; + NSDictionary *responseHeaders = [self responseHeaders]; + NSString *responseDataStr = nil; + NSDictionary *responseJSON = nil; + + // if there's response data, decide what kind of file to put it in based on the first bytes of the + // file or on the mime type supplied by the server + NSString *responseMIMEType = [response MIMEType]; + BOOL isResponseImage = NO; + + // file name for an image data file + NSString *responseDataFileName = nil; + + int64_t responseDataLength = self.downloadedLength; + if (responseDataLength > 0) { + NSData *downloadedData = self.downloadedData; + if (downloadedData == nil + && responseDataLength > 0 + && responseDataLength < 20000 + && self.destinationFileURL) { + // There's a download file that's not too big, so get the data to display from the downloaded + // file. + NSURL *destinationURL = self.destinationFileURL; + downloadedData = [NSData dataWithContentsOfURL:destinationURL]; + } + NSString *responseType = [responseHeaders valueForKey:@"Content-Type"]; + responseDataStr = [self formattedStringFromData:downloadedData + contentType:responseType + JSON:&responseJSON]; + NSString *responseDataExtn = nil; + NSData *dataToWrite = nil; + if (responseDataStr) { + // we were able to make a UTF-8 string from the response data + if ([responseMIMEType isEqual:@"application/atom+xml"] + || [responseMIMEType hasSuffix:@"/xml"]) { + responseDataExtn = @"xml"; + dataToWrite = [responseDataStr dataUsingEncoding:NSUTF8StringEncoding]; + } + } else if ([responseMIMEType isEqual:@"image/jpeg"]) { + responseDataExtn = @"jpg"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else if ([responseMIMEType isEqual:@"image/gif"]) { + responseDataExtn = @"gif"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else if ([responseMIMEType isEqual:@"image/png"]) { + responseDataExtn = @"png"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else { + // add more non-text types here + } + // if we have an extension, save the raw data in a file with that extension + if (responseDataExtn && dataToWrite) { + // generate a response file base name like + NSString *responseBaseName = [NSString stringWithFormat:@"fetch_%d_response", responseCounter]; + responseDataFileName = [responseBaseName stringByAppendingPathExtension:responseDataExtn]; + NSString *responseDataFilePath = [logDirectory stringByAppendingPathComponent:responseDataFileName]; + + NSError *downloadedError = nil; + if (gIsLoggingToFile && ![dataToWrite writeToFile:responseDataFilePath + options:0 + error:&downloadedError]) { + NSLog(@"%@ logging write error:%@ (%@)", [self class], downloadedError, responseDataFileName); + } + } + } + // we'll have one main html file per run of the app + NSString *htmlName = [[self class] htmlFileName]; + NSString *htmlPath =[logDirectory stringByAppendingPathComponent:htmlName]; + + // if the html file exists (from logging previous fetches) we don't need + // to re-write the header or the scripts + NSFileManager *fileMgr = [NSFileManager defaultManager]; + BOOL didFileExist = [fileMgr fileExistsAtPath:htmlPath]; + + NSMutableString* outputHTML = [NSMutableString string]; + + // we need a header to say we'll have UTF-8 text + if (!didFileExist) { + [outputHTML appendFormat:@"%@ HTTP fetch log %@", + processName, [[self class] loggingDateStamp]]; + } + // now write the visible html elements + NSString *copyableFileName = [NSString stringWithFormat:@"fetch_%d.txt", responseCounter]; + + NSDate *now = [NSDate date]; + // write the date & time, the comment, and the link to the plain-text (copyable) log + [outputHTML appendFormat:@"%@      ", now]; + + NSString *comment = [self comment]; + if (comment.length > 0) { + [outputHTML appendFormat:@"%@      ", comment]; + } + [outputHTML appendFormat:@"request/response log
", copyableFileName]; + NSTimeInterval elapsed = -self.initialBeginFetchDate.timeIntervalSinceNow; + [outputHTML appendFormat:@"elapsed: %5.3fsec
", elapsed]; + + // write the request URL + NSURLRequest *request = self.request; + NSString *requestMethod = request.HTTPMethod; + NSURL *requestURL = request.URL; + + // Save the request URL for next time in case this redirects. + NSString *redirectedFromURLString = [self.redirectedFromURL absoluteString]; + self.redirectedFromURL = [requestURL copy]; + if (redirectedFromURLString) { + [outputHTML appendFormat:@"redirected from %@
", + redirectedFromURLString]; + } + [outputHTML appendFormat:@"request: %@ %@
\n", requestMethod, requestURL]; + + // write the request headers + NSDictionary *requestHeaders = request.allHTTPHeaderFields; + NSUInteger numberOfRequestHeaders = requestHeaders.count; + if (numberOfRequestHeaders > 0) { + // Indicate if the request is authorized; warn if the request is authorized but non-SSL + NSString *auth = [requestHeaders objectForKey:@"Authorization"]; + NSString *headerDetails = @""; + if (auth) { + BOOL isInsecure = [[requestURL scheme] isEqual:@"http"]; + if (isInsecure) { + // 26A0 = ⚠ + headerDetails = + @"   authorized, non-SSL "; + } else { + headerDetails = @"   authorized"; + } + } + NSString *cookiesHdr = [requestHeaders objectForKey:@"Cookie"]; + if (cookiesHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   cookies"]; + } + NSString *matchHdr = [requestHeaders objectForKey:@"If-Match"]; + if (matchHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   if-match"]; + } + matchHdr = [requestHeaders objectForKey:@"If-None-Match"]; + if (matchHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   if-none-match"]; + } + [outputHTML appendFormat:@"   headers: %d %@
", + (int)numberOfRequestHeaders, headerDetails]; + } else { + [outputHTML appendFormat:@"   headers: none
"]; + } + // write the request post data + NSData *bodyData = nil; + NSData *loggedStreamData = self.loggedStreamData; + if (loggedStreamData) { + bodyData = loggedStreamData; + } else { + bodyData = self.bodyData; + if (bodyData == nil) { + bodyData = self.request.HTTPBody; + } + } + uint64_t bodyDataLength = bodyData.length; + + if (bodyData.length == 0) { + // If the data is in a body upload file URL, read that in if it's not huge. + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSNumber *fileSizeNum = nil; + NSError *fileSizeError = nil; + if ([bodyFileURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:&fileSizeError]) { + bodyDataLength = [fileSizeNum unsignedLongLongValue]; + if (bodyDataLength > 0 && bodyDataLength < 50000) { + bodyData = [NSData dataWithContentsOfURL:bodyFileURL + options:NSDataReadingUncached + error:&fileSizeError]; + } + } + } + } + NSString *bodyDataStr = nil; + NSString *postType = [requestHeaders valueForKey:@"Content-Type"]; + + if (bodyDataLength > 0) { + [outputHTML appendFormat:@"   data: %llu bytes, %@
\n", + bodyDataLength, postType ? postType : @"(no type)"]; + NSString *logRequestBody = self.logRequestBody; + if (logRequestBody) { + bodyDataStr = [logRequestBody copy]; + self.logRequestBody = nil; + } else { + bodyDataStr = [self stringFromStreamData:bodyData + contentType:postType]; + if (bodyDataStr) { + // remove OAuth 2 client secret and refresh token + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"client_secret=" + endString:@"&"]; + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"refresh_token=" + endString:@"&"]; + // remove ClientLogin password + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"&Passwd=" + endString:@"&"]; + } + } + } else { + // no post data + } + // write the response status, MIME type, URL + NSInteger status = [self statusCode]; + if (response) { + NSString *statusString = @""; + if (status != 0) { + if (status == 200 || status == 201) { + statusString = [NSString stringWithFormat:@"%ld", (long)status]; + + // report any JSON-RPC error + if ([responseJSON isKindOfClass:[NSDictionary class]]) { + NSDictionary *jsonError = [responseJSON objectForKey:@"error"]; + if ([jsonError isKindOfClass:[NSDictionary class]]) { + NSString *jsonCode = [[jsonError valueForKey:@"code"] description]; + NSString *jsonMessage = [jsonError valueForKey:@"message"]; + if (jsonCode || jsonMessage) { + // 2691 = ⚑ + NSString *const jsonErrFmt = + @"   JSON error: %@ %@  ⚑"; + statusString = [statusString stringByAppendingFormat:jsonErrFmt, + jsonCode ? jsonCode : @"", + jsonMessage ? jsonMessage : @""]; + } + } + } + } else { + // purple for anything other than 200 or 201 + NSString *flag = status >= 400 ? @" ⚑" : @""; // 2691 = ⚑ + NSString *explanation = [NSHTTPURLResponse localizedStringForStatusCode:status]; + NSString *const statusFormat = @"%ld %@ %@"; + statusString = [NSString stringWithFormat:statusFormat, (long)status, explanation, flag]; + } + } + // show the response URL only if it's different from the request URL + NSString *responseURLStr = @""; + NSURL *responseURL = response.URL; + + if (responseURL && ![responseURL isEqual:request.URL]) { + NSString *const responseURLFormat = + @"response URL: %@
\n"; + responseURLStr = [NSString stringWithFormat:responseURLFormat, [responseURL absoluteString]]; + } + [outputHTML appendFormat:@"response:  status %@
\n%@", + statusString, responseURLStr]; + // Write the response headers + NSUInteger numberOfResponseHeaders = responseHeaders.count; + if (numberOfResponseHeaders > 0) { + // Indicate if the server is setting cookies + NSString *cookiesSet = [responseHeaders valueForKey:@"Set-Cookie"]; + NSString *cookiesStr = + cookiesSet ? @"  sets cookies" : @""; + // Indicate if the server is redirecting + NSString *location = [responseHeaders valueForKey:@"Location"]; + BOOL isRedirect = status >= 300 && status <= 399 && location != nil; + NSString *redirectsStr = + isRedirect ? @"  redirects" : @""; + [outputHTML appendFormat:@"   headers: %d %@ %@
\n", + (int)numberOfResponseHeaders, cookiesStr, redirectsStr]; + } else { + [outputHTML appendString:@"   headers: none
\n"]; + } + } + // error + if (error) { + [outputHTML appendFormat:@"Error: %@
\n", error.description]; + } + // Write the response data + if (responseDataFileName) { + if (isResponseImage) { + // Make a small inline image that links to the full image file + [outputHTML appendFormat:@"   data: %lld bytes, %@
", + responseDataLength, responseMIMEType]; + NSString *const fmt = + @"image\n"; + [outputHTML appendFormat:fmt, responseDataFileName, responseDataFileName]; + } else { + // The response data was XML; link to the xml file + NSString *const fmt = + @"   data: %lld bytes, %@   %@\n"; + [outputHTML appendFormat:fmt, responseDataLength, responseMIMEType, + responseDataFileName, [responseDataFileName pathExtension]]; + } + } else { + // The response data was not an image; just show the length and MIME type + [outputHTML appendFormat:@"   data: %lld bytes, %@\n", + responseDataLength, responseMIMEType ? responseMIMEType : @"(no response type)"]; + } + // Make a single string of the request and response, suitable for copying + // to the clipboard and pasting into a bug report + NSMutableString *copyable = [NSMutableString string]; + if (comment) { + [copyable appendFormat:@"%@\n\n", comment]; + } + [copyable appendFormat:@"%@ elapsed: %5.3fsec\n", now, elapsed]; + if (redirectedFromURLString) { + [copyable appendFormat:@"Redirected from %@\n", redirectedFromURLString]; + } + [copyable appendFormat:@"Request: %@ %@\n", requestMethod, requestURL]; + if (requestHeaders.count > 0) { + [copyable appendFormat:@"Request headers:\n%@\n", + [[self class] headersStringForDictionary:requestHeaders]]; + } + if (bodyDataLength > 0) { + [copyable appendFormat:@"Request body: (%llu bytes)\n", bodyDataLength]; + if (bodyDataStr) { + [copyable appendFormat:@"%@\n", bodyDataStr]; + } + [copyable appendString:@"\n"]; + } + if (response) { + [copyable appendFormat:@"Response: status %d\n", (int) status]; + [copyable appendFormat:@"Response headers:\n%@\n", + [[self class] headersStringForDictionary:responseHeaders]]; + [copyable appendFormat:@"Response body: (%lld bytes)\n", responseDataLength]; + if (responseDataLength > 0) { + NSString *logResponseBody = self.logResponseBody; + if (logResponseBody) { + // The user has provided the response body text. + responseDataStr = [logResponseBody copy]; + self.logResponseBody = nil; + } + if (responseDataStr != nil) { + [copyable appendFormat:@"%@\n", responseDataStr]; + } else { + // Even though it's redundant, we'll put in text to indicate that all the bytes are binary. + if (self.destinationFileURL) { + [copyable appendFormat:@"<<%lld bytes>> to file %@\n", + responseDataLength, self.destinationFileURL.path]; + } else { + [copyable appendFormat:@"<<%lld bytes>>\n", responseDataLength]; + } + } + } + } + if (error) { + [copyable appendFormat:@"Error: %@\n", error]; + } + // Save to log property before adding the separator + self.log = copyable; + + [copyable appendString:@"-----------------------------------------------------------\n"]; + + // Write the copyable version to another file (linked to at the top of the html file, above) + // + // Ideally, something to just copy this to the clipboard like + // Copy here." + // would work everywhere, but it only works in Safari as of 8/2010 + if (gIsLoggingToFile) { + NSString *parentDir = [[self class] loggingDirectory]; + NSString *copyablePath = [logDirectory stringByAppendingPathComponent:copyableFileName]; + NSError *copyableError = nil; + if (![copyable writeToFile:copyablePath + atomically:NO + encoding:NSUTF8StringEncoding + error:©ableError]) { + // Error writing to file + NSLog(@"%@ logging write error:%@ (%@)", [self class], copyableError, copyablePath); + } + [outputHTML appendString:@"

"]; + + // Append the HTML to the main output file + const char* htmlBytes = outputHTML.UTF8String; + NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:htmlPath + append:YES]; + [stream open]; + [stream write:(const uint8_t *) htmlBytes maxLength:strlen(htmlBytes)]; + [stream close]; + + // Make a symlink to the latest html + NSString *const symlinkNameSuffix = [[self class] symlinkNameSuffix]; + NSString *symlinkName = [processName stringByAppendingString:symlinkNameSuffix]; + NSString *symlinkPath = [parentDir stringByAppendingPathComponent:symlinkName]; + + [fileMgr removeItemAtPath:symlinkPath error:NULL]; + [fileMgr createSymbolicLinkAtPath:symlinkPath + withDestinationPath:htmlPath + error:NULL]; +#if TARGET_OS_IPHONE + static BOOL gReportedLoggingPath = NO; + if (!gReportedLoggingPath) { + gReportedLoggingPath = YES; + NSLog(@"GTMSessionFetcher logging to \"%@\"", parentDir); + } +#endif + } +} + +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream { + if (!inputStream) return nil; + if (![GTMSessionFetcher isLoggingEnabled]) return inputStream; + + [self clearLoggedStreamData]; // Clear any previous data. + Class monitorClass = NSClassFromString(@"GTMReadMonitorInputStream"); + if (!monitorClass) { + NSString const *str = @"<>"; + NSData *stringData = [str dataUsingEncoding:NSUTF8StringEncoding]; + [self appendLoggedStreamData:stringData]; + return inputStream; + } + inputStream = [monitorClass inputStreamWithStream:inputStream]; + + GTMReadMonitorInputStream *readMonitorInputStream = (GTMReadMonitorInputStream *)inputStream; + [readMonitorInputStream setReadDelegate:self]; + SEL readSel = @selector(inputStream:readIntoBuffer:length:); + [readMonitorInputStream setReadSelector:readSel]; + + return inputStream; +} + +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider { + if (!streamProvider) return nil; + if (![GTMSessionFetcher isLoggingEnabled]) return streamProvider; + + [self clearLoggedStreamData]; // Clear any previous data. + Class monitorClass = NSClassFromString(@"GTMReadMonitorInputStream"); + if (!monitorClass) { + NSString const *str = @"<>"; + NSData *stringData = [str dataUsingEncoding:NSUTF8StringEncoding]; + [self appendLoggedStreamData:stringData]; + return streamProvider; + } + GTMSessionFetcherBodyStreamProvider loggedStreamProvider = + ^(GTMSessionFetcherBodyStreamProviderResponse response) { + streamProvider(^(NSInputStream *bodyStream) { + bodyStream = [self loggedInputStreamForInputStream:bodyStream]; + response(bodyStream); + }); + }; + return loggedStreamProvider; +} + +@end + +@implementation GTMSessionFetcher (GTMSessionFetcherLoggingUtilities) + +- (void)inputStream:(GTMReadMonitorInputStream *)stream + readIntoBuffer:(void *)buffer + length:(int64_t)length { + // append the captured data + NSData *data = [NSData dataWithBytesNoCopy:buffer + length:(NSUInteger)length + freeWhenDone:NO]; + [self appendLoggedStreamData:data]; +} + +#pragma mark Fomatting Utilities + ++ (NSString *)snipSubstringOfString:(NSString *)originalStr + betweenStartString:(NSString *)startStr + endString:(NSString *)endStr { +#if SKIP_GTM_FETCH_LOGGING_SNIPPING + return originalStr; +#else + if (!originalStr) return nil; + + // Find the start string, and replace everything between it + // and the end string (or the end of the original string) with "_snip_" + NSRange startRange = [originalStr rangeOfString:startStr]; + if (startRange.location == NSNotFound) return originalStr; + + // We found the start string + NSUInteger originalLength = originalStr.length; + NSUInteger startOfTarget = NSMaxRange(startRange); + NSRange targetAndRest = NSMakeRange(startOfTarget, originalLength - startOfTarget); + NSRange endRange = [originalStr rangeOfString:endStr + options:0 + range:targetAndRest]; + NSRange replaceRange; + if (endRange.location == NSNotFound) { + // Found no end marker so replace to end of string + replaceRange = targetAndRest; + } else { + // Replace up to the endStr + replaceRange = NSMakeRange(startOfTarget, endRange.location - startOfTarget); + } + NSString *result = [originalStr stringByReplacingCharactersInRange:replaceRange + withString:@"_snip_"]; + return result; +#endif // SKIP_GTM_FETCH_LOGGING_SNIPPING +} + ++ (NSString *)headersStringForDictionary:(NSDictionary *)dict { + // Format the dictionary in http header style, like + // Accept: application/json + // Cache-Control: no-cache + // Content-Type: application/json; charset=utf-8 + // + // Pad the key names, but not beyond 16 chars, since long custom header + // keys just create too much whitespace + NSArray *keys = [dict.allKeys sortedArrayUsingSelector:@selector(compare:)]; + + NSMutableString *str = [NSMutableString string]; + for (NSString *key in keys) { + NSString *value = [dict valueForKey:key]; + if ([key isEqual:@"Authorization"]) { + // Remove OAuth 1 token + value = [[self class] snipSubstringOfString:value + betweenStartString:@"oauth_token=\"" + endString:@"\""]; + + // Remove OAuth 2 bearer token (draft 16, and older form) + value = [[self class] snipSubstringOfString:value + betweenStartString:@"Bearer " + endString:@"\n"]; + value = [[self class] snipSubstringOfString:value + betweenStartString:@"OAuth " + endString:@"\n"]; + + // Remove Google ClientLogin + value = [[self class] snipSubstringOfString:value + betweenStartString:@"GoogleLogin auth=" + endString:@"\n"]; + } + [str appendFormat:@" %@: %@\n", key, value]; + } + return str; +} + +@end + +#endif // !STRIP_GTM_FETCH_LOGGING diff --git a/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h new file mode 100644 index 0000000..a696ac7 --- /dev/null +++ b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h @@ -0,0 +1,190 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// For best performance and convenient usage, fetchers should be generated by a common +// GTMSessionFetcherService instance, like +// +// _fetcherService = [[GTMSessionFetcherService alloc] init]; +// GTMSessionFetcher* myFirstFetcher = [_fetcherService fetcherWithRequest:request1]; +// GTMSessionFetcher* mySecondFetcher = [_fetcherService fetcherWithRequest:request2]; + +#import "GTMSessionFetcher.h" + +GTM_ASSUME_NONNULL_BEGIN + +// Notifications. + +// This notification indicates a reusable session has become invalid. It is intended mainly for the +// service's unit tests. +// +// The notification object is the fetcher service. +// The invalid session is provided via the userInfo kGTMSessionFetcherServiceSessionKey key. +extern NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification; +extern NSString *const kGTMSessionFetcherServiceSessionKey; + +@interface GTMSessionFetcherService : NSObject + +// Queues of delayed and running fetchers. Each dictionary contains arrays +// of GTMSessionFetcher *fetchers, keyed by NSString *host +@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSArray *) *delayedFetchersByHost; +@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSArray *) *runningFetchersByHost; + +// A max value of 0 means no fetchers should be delayed. +// The default limit is 10 simultaneous fetchers targeting each host. +// This does not apply to fetchers whose useBackgroundSession property is YES. Since services are +// not resurrected on an app relaunch, delayed fetchers would effectively be abandoned. +@property(atomic, assign) NSUInteger maxRunningFetchersPerHost; + +// Properties to be applied to each fetcher; see GTMSessionFetcher.h for descriptions +@property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration; +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock; +@property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage; +@property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue; +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock; +@property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential; +@property(atomic, strong) NSURLCredential *proxyCredential; +@property(atomic, copy, GTM_NULLABLE) GTM_NSArrayOf(NSString *) *allowedInsecureSchemes; +@property(atomic, assign) BOOL allowLocalhostRequest; +@property(atomic, assign) BOOL allowInvalidServerCertificates; +@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled; +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherRetryBlock retryBlock; +@property(atomic, assign) NSTimeInterval maxRetryInterval; +@property(atomic, assign) NSTimeInterval minRetryInterval; +@property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties; + +#if GTM_BACKGROUND_TASK_FETCHING +@property(atomic, assign) BOOL skipBackgroundTask; +#endif + +// A default useragent of GTMFetcherStandardUserAgentString(nil) will be given to each fetcher +// created by this service unless the request already has a user-agent header set. +// This default will be added starting with builds with the SDKs for OS X 10.11 and iOS 9. +// +// To use the configuration's default user agent, set this property to nil. +@property(atomic, copy, GTM_NULLABLE) NSString *userAgent; + +// The authorizer to attach to the created fetchers. If a specific fetcher should +// not authorize its requests, the fetcher's authorizer property may be set to nil +// before the fetch begins. +@property(atomic, strong, GTM_NULLABLE) id authorizer; + +// Delegate queue used by the session when calling back to the fetcher. The default +// is the main queue. Changing this does not affect the queue used to call back to the +// application; that is specified by the callbackQueue property above. +@property(atomic, strong, GTM_NULL_RESETTABLE) NSOperationQueue *sessionDelegateQueue; + +// When enabled, indicates the same session should be used by subsequent fetchers. +// +// This is enabled by default. +@property(atomic, assign) BOOL reuseSession; + +// Sets the delay until an unused session is invalidated. +// The default interval is 60 seconds. +// +// If the interval is set to 0, then any reused session is not invalidated except by +// explicitly invoking -resetSession. Be aware that setting the interval to 0 thus +// causes the session's delegate to be retained until the session is explicitly reset. +@property(atomic, assign) NSTimeInterval unusedSessionTimeout; + +// If shouldReuseSession is enabled, this will force creation of a new session when future +// fetchers begin. +- (void)resetSession; + +// Create a fetcher +// +// These methods will return a fetcher. If successfully created, the connection +// will hold a strong reference to it for the life of the connection as well. +// So the caller doesn't have to hold onto the fetcher explicitly unless they +// want to be able to monitor or cancel it. +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request; +- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL; +- (GTMSessionFetcher *)fetcherWithURLString:(NSString *)requestURLString; + +// Common method for fetcher creation. +// +// -fetcherWithRequest:fetcherClass: may be overridden to customize creation of +// fetchers. This is the ONLY method in the GTMSessionFetcher library intended to +// be overridden. +- (id)fetcherWithRequest:(NSURLRequest *)request + fetcherClass:(Class)fetcherClass; + +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher; + +- (NSUInteger)numberOfFetchers; // running + delayed fetchers +- (NSUInteger)numberOfRunningFetchers; +- (NSUInteger)numberOfDelayedFetchers; + +// Return a list of all running or delayed fetchers. This includes fetchers created +// by the service which have been started and have not yet stopped. +// +// Returns an array of fetcher objects, or nil if none. +- (GTM_NULLABLE GTM_NSArrayOf(GTMSessionFetcher *) *)issuedFetchers; + +// Search for running or delayed fetchers with the specified URL. +// +// Returns an array of fetcher objects found, or nil if none found. +- (GTM_NULLABLE GTM_NSArrayOf(GTMSessionFetcher *) *)issuedFetchersWithRequestURL:(NSURL *)requestURL; + +- (void)stopAllFetchers; + +// Methods for use by the fetcher class only. +- (GTM_NULLABLE NSURLSession *)session; +- (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation; +- (GTM_NULLABLE id)sessionDelegate; +- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate; + +// The testBlock can inspect its fetcher parameter's request property to +// determine which fetcher is being faked. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock; + +@end + +@interface GTMSessionFetcherService (TestingSupport) + +// Convenience method to create a fetcher service for testing. +// +// Fetchers generated by this mock fetcher service will not perform any +// network operation, but will invoke callbacks and provide the supplied data +// or error to the completion handler. +// +// You can make more customized mocks by setting the test block property of the service +// or fetcher; the test block can inspect the fetcher's request or other properties. +// +// See the description of the testBlock property below. ++ (instancetype)mockFetcherServiceWithFakedData:(GTM_NULLABLE NSData *)fakedDataOrNil + fakedError:(GTM_NULLABLE NSError *)fakedErrorOrNil; + +// Spin the run loop and discard events (or, if not on the main thread, just sleep the thread) +// until all running and delayed fetchers have completed. +// +// This is only for use in testing or in tools without a user interface. +// +// Synchronous fetches should never be done by shipping apps; they are +// sufficient reason for rejection from the app store. +// +// Returns NO if timed out. +- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds; + +@end + +@interface GTMSessionFetcherService (BackwardsCompatibilityOnly) + +// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves. +// This method is just for compatibility with the old fetcher. +@property(atomic, assign) NSInteger cookieStorageMethod; + +@end + +GTM_ASSUME_NONNULL_END diff --git a/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m new file mode 100644 index 0000000..fc6e6d9 --- /dev/null +++ b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m @@ -0,0 +1,1352 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcherService.h" + +NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification + = @"kGTMSessionFetcherServiceSessionBecameInvalidNotification"; +NSString *const kGTMSessionFetcherServiceSessionKey + = @"kGTMSessionFetcherServiceSessionKey"; + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (ServiceMethods) +- (BOOL)beginFetchMayDelay:(BOOL)mayDelay + mayAuthorize:(BOOL)mayAuthorize; +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionFetcherService () + +@property(atomic, strong, readwrite) NSDictionary *delayedFetchersByHost; +@property(atomic, strong, readwrite) NSDictionary *runningFetchersByHost; + +@end + +// Since NSURLSession doesn't support a separate delegate per task (!), instances of this +// class serve as a session delegate trampoline. +// +// This class maps a session's tasks to fetchers, and resends delegate messages to the task's +// fetcher. +@interface GTMSessionFetcherSessionDelegateDispatcher : NSObject + +// The session for the tasks in this dispatcher's task-to-fetcher map. +@property(atomic) NSURLSession *session; + +// The timer interval for invalidating a session that has no active tasks. +@property(atomic) NSTimeInterval discardInterval; + +// The current discard timer. +@property(atomic, readonly) NSTimer *discardTimer; + + +- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService + sessionDiscardInterval:(NSTimeInterval)discardInterval; + +- (void)setFetcher:(GTMSessionFetcher *)fetcher + forTask:(NSURLSessionTask *)task; +- (void)removeFetcher:(GTMSessionFetcher *)fetcher; + +// Before using a session, tells the delegate dispatcher to stop the discard timer. +- (void)startSessionUsage; + +// When abandoning a delegate dispatcher, we want to avoid the session retaining +// the delegate after tasks complete. +- (void)abandon; + +@end + + +@implementation GTMSessionFetcherService { + NSMutableDictionary *_delayedFetchersByHost; + NSMutableDictionary *_runningFetchersByHost; + NSUInteger _maxRunningFetchersPerHost; + + // When this ivar is nil, the service will not reuse sessions. + GTMSessionFetcherSessionDelegateDispatcher *_delegateDispatcher; + + // Fetchers will wait on this if another fetcher is creating the shared NSURLSession. + dispatch_semaphore_t _sessionCreationSemaphore; + + dispatch_queue_t _callbackQueue; + NSOperationQueue *_delegateQueue; + NSHTTPCookieStorage *_cookieStorage; + NSString *_userAgent; + NSTimeInterval _timeout; + + NSURLCredential *_credential; // Username & password. + NSURLCredential *_proxyCredential; // Credential supplied to proxy servers. + + NSInteger _cookieStorageMethod; + + id _authorizer; + + // For waitForCompletionOfAllFetchersWithTimeout: we need to wait on stopped fetchers since + // they've not yet finished invoking their queued callbacks. This array is nil except when + // waiting on fetchers. + NSMutableArray *_stoppedFetchersToWaitFor; + + // For fetchers that enqueued their callbacks before stopAllFetchers was called on the service, + // set a barrier so the callbacks know to bail out. + NSDate *_stoppedAllFetchersDate; +} + +@synthesize maxRunningFetchersPerHost = _maxRunningFetchersPerHost, + configuration = _configuration, + configurationBlock = _configurationBlock, + cookieStorage = _cookieStorage, + userAgent = _userAgent, + challengeBlock = _challengeBlock, + credential = _credential, + proxyCredential = _proxyCredential, + allowedInsecureSchemes = _allowedInsecureSchemes, + allowLocalhostRequest = _allowLocalhostRequest, + allowInvalidServerCertificates = _allowInvalidServerCertificates, + retryEnabled = _retryEnabled, + retryBlock = _retryBlock, + maxRetryInterval = _maxRetryInterval, + minRetryInterval = _minRetryInterval, + properties = _properties, + unusedSessionTimeout = _unusedSessionTimeout, + testBlock = _testBlock; + +#if GTM_BACKGROUND_TASK_FETCHING +@synthesize skipBackgroundTask = _skipBackgroundTask; +#endif + +- (instancetype)init { + self = [super init]; + if (self) { + _delayedFetchersByHost = [[NSMutableDictionary alloc] init]; + _runningFetchersByHost = [[NSMutableDictionary alloc] init]; + _maxRunningFetchersPerHost = 10; + _cookieStorageMethod = -1; + _unusedSessionTimeout = 60.0; + _delegateDispatcher = + [[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + _callbackQueue = dispatch_get_main_queue(); + + _delegateQueue = [[NSOperationQueue alloc] init]; + _delegateQueue.maxConcurrentOperationCount = 1; + _delegateQueue.name = @"com.google.GTMSessionFetcher.NSURLSessionDelegateQueue"; + + _sessionCreationSemaphore = dispatch_semaphore_create(1); + + // Starting with the SDKs for OS X 10.11/iOS 9, the service has a default useragent. + // Apps can remove this and get the default system "CFNetwork" useragent by setting the + // fetcher service's userAgent property to nil. +#if (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0) + _userAgent = GTMFetcherStandardUserAgentString(nil); +#endif + } + return self; +} + +- (void)dealloc { + [self detachAuthorizer]; + [_delegateDispatcher abandon]; +} + +#pragma mark Generate a new fetcher + +// Clients may override this method. Clients should not override any other library methods. +- (id)fetcherWithRequest:(NSURLRequest *)request + fetcherClass:(Class)fetcherClass { + GTMSessionFetcher *fetcher = [[fetcherClass alloc] initWithRequest:request + configuration:self.configuration]; + fetcher.callbackQueue = self.callbackQueue; + fetcher.sessionDelegateQueue = self.sessionDelegateQueue; + fetcher.challengeBlock = self.challengeBlock; + fetcher.credential = self.credential; + fetcher.proxyCredential = self.proxyCredential; + fetcher.authorizer = self.authorizer; + fetcher.cookieStorage = self.cookieStorage; + fetcher.allowedInsecureSchemes = self.allowedInsecureSchemes; + fetcher.allowLocalhostRequest = self.allowLocalhostRequest; + fetcher.allowInvalidServerCertificates = self.allowInvalidServerCertificates; + fetcher.configurationBlock = self.configurationBlock; + fetcher.retryEnabled = self.retryEnabled; + fetcher.retryBlock = self.retryBlock; + fetcher.maxRetryInterval = self.maxRetryInterval; + fetcher.minRetryInterval = self.minRetryInterval; + fetcher.properties = self.properties; + fetcher.service = self; + if (self.cookieStorageMethod >= 0) { + [fetcher setCookieStorageMethod:self.cookieStorageMethod]; + } + +#if GTM_BACKGROUND_TASK_FETCHING + fetcher.skipBackgroundTask = self.skipBackgroundTask; +#endif + + NSString *userAgent = self.userAgent; + if (userAgent.length > 0 + && [request valueForHTTPHeaderField:@"User-Agent"] == nil) { + [fetcher setRequestValue:userAgent + forHTTPHeaderField:@"User-Agent"]; + } + fetcher.testBlock = self.testBlock; + + return fetcher; +} + +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request { + return [self fetcherWithRequest:request + fetcherClass:[GTMSessionFetcher class]]; +} + +- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL { + return [self fetcherWithRequest:[NSURLRequest requestWithURL:requestURL]]; +} + +- (GTMSessionFetcher *)fetcherWithURLString:(NSString *)requestURLString { + NSURL *url = [NSURL URLWithString:requestURLString]; + return [self fetcherWithURL:url]; +} + +// Returns a session for the fetcher's host, or nil. +- (NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLSession *session = _delegateDispatcher.session; + return session; + } +} + +// Returns a session for the fetcher's host, or nil. For shared sessions, this +// waits on a semaphore, blocking other fetchers while the caller creates the +// session if needed. +- (NSURLSession *)sessionForFetcherCreation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + if (!_delegateDispatcher) { + // This fetcher is creating a non-shared session, so skip the semaphore usage. + return nil; + } + } + + // Wait if another fetcher is currently creating a session; avoid waiting + // inside the @synchronized block, as that can deadlock. + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Before getting the NSURLSession for task creation, it is + // important to invalidate and nil out the session discard timer; otherwise + // the session can be invalidated between when it is returned to the + // fetcher, and when the fetcher attempts to create its NSURLSessionTask. + [_delegateDispatcher startSessionUsage]; + + NSURLSession *session = _delegateDispatcher.session; + if (session) { + // The calling fetcher will receive a preexisting session, so + // we can allow other fetchers to create a session. + dispatch_semaphore_signal(_sessionCreationSemaphore); + } else { + // No existing session was obtained, so the calling fetcher will create the session; + // it *must* invoke fetcherDidCreateSession: to signal the dispatcher's semaphore after + // the session has been created (or fails to be created) to avoid a hang. + } + return session; + } +} + +- (id)sessionDelegate { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateDispatcher; + } +} + +#pragma mark Queue Management + +- (void)addRunningFetcher:(GTMSessionFetcher *)fetcher + forHost:(NSString *)host { + // Add to the array of running fetchers for this host, creating the array if needed. + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + if (runningForHost == nil) { + runningForHost = [NSMutableArray arrayWithObject:fetcher]; + [_runningFetchersByHost setObject:runningForHost forKey:host]; + } else { + [runningForHost addObject:fetcher]; + } +} + +- (void)addDelayedFetcher:(GTMSessionFetcher *)fetcher + forHost:(NSString *)host { + // Add to the array of delayed fetchers for this host, creating the array if needed. + NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + if (delayedForHost == nil) { + delayedForHost = [NSMutableArray arrayWithObject:fetcher]; + [_delayedFetchersByHost setObject:delayedForHost forKey:host]; + } else { + [delayedForHost addObject:fetcher]; + } +} + +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSString *host = fetcher.request.URL.host; + if (host == nil) { + return NO; + } + NSArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + NSUInteger idx = [delayedForHost indexOfObjectIdenticalTo:fetcher]; + BOOL isDelayed = (delayedForHost != nil) && (idx != NSNotFound); + return isDelayed; + } +} + +- (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher { + // Entry point from the fetcher + NSURL *requestURL = fetcher.request.URL; + NSString *host = requestURL.host; + + // Addresses "file:///path" case where localhost is the implicit host. + if (host.length == 0 && [requestURL isFileURL]) { + host = @"localhost"; + } + + if (host.length == 0) { + // Data URIs legitimately have no host, reject other hostless URLs. + GTMSESSION_ASSERT_DEBUG([[requestURL scheme] isEqual:@"data"], @"%@ lacks host", fetcher); + return YES; + } + + BOOL shouldBeginResult; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + if (runningForHost != nil + && [runningForHost indexOfObjectIdenticalTo:fetcher] != NSNotFound) { + GTMSESSION_ASSERT_DEBUG(NO, @"%@ was already running", fetcher); + return YES; + } + + BOOL shouldRunNow = (fetcher.usingBackgroundSession + || _maxRunningFetchersPerHost == 0 + || _maxRunningFetchersPerHost > + [[self class] numberOfNonBackgroundSessionFetchers:runningForHost]); + if (shouldRunNow) { + [self addRunningFetcher:fetcher forHost:host]; + shouldBeginResult = YES; + } else { + [self addDelayedFetcher:fetcher forHost:host]; + shouldBeginResult = NO; + } + } // @synchronized(self) + + // We'll save the host that serves as the key for this fetcher's array + // to avoid any chance of the underlying request changing, stranding + // the fetcher in the wrong array + fetcher.serviceHost = host; + + return shouldBeginResult; +} + +- (void)startFetcher:(GTMSessionFetcher *)fetcher { + [fetcher beginFetchMayDelay:NO + mayAuthorize:YES]; +} + +// Internal utility. Returns a fetcher's delegate if it's a dispatcher, or nil if the fetcher +// is its own delegate and has no dispatcher. +- (GTMSessionFetcherSessionDelegateDispatcher *)delegateDispatcherForFetcher:(GTMSessionFetcher *)fetcher { + GTMSessionCheckNotSynchronized(self); + + NSURLSession *fetcherSession = fetcher.session; + if (fetcherSession) { + id fetcherDelegate = fetcherSession.delegate; + BOOL hasDispatcher = (fetcherDelegate != nil && fetcherDelegate != fetcher); + if (hasDispatcher) { + GTMSESSION_ASSERT_DEBUG([fetcherDelegate isKindOfClass:[GTMSessionFetcherSessionDelegateDispatcher class]], + @"Fetcher delegate class: %@", [fetcherDelegate class]); + return (GTMSessionFetcherSessionDelegateDispatcher *)fetcherDelegate; + } + } + return nil; +} + +- (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher { + if (fetcher.canShareSession) { + NSURLSession *fetcherSession = fetcher.session; + GTMSESSION_ASSERT_DEBUG(fetcherSession != nil, @"Fetcher missing its session: %@", fetcher); + + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + if (delegateDispatcher) { + GTMSESSION_ASSERT_DEBUG(delegateDispatcher.session == nil, + @"Fetcher made an extra session: %@", fetcher); + + // Save this fetcher's session. + delegateDispatcher.session = fetcherSession; + + // Allow other fetchers to request this session now. + dispatch_semaphore_signal(_sessionCreationSemaphore); + } + } +} + +- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher { + // If this fetcher has a separate delegate with a shared session, then + // this fetcher should be added to the delegate's map of tasks to fetchers. + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + if (delegateDispatcher) { + GTMSESSION_ASSERT_DEBUG(fetcher.canShareSession, + @"Inappropriate shared session: %@", fetcher); + + // There should already be a session, from this or a previous fetcher. + // + // Sanity check that the fetcher's session is the delegate's shared session. + NSURLSession *sharedSession = delegateDispatcher.session; + NSURLSession *fetcherSession = fetcher.session; + GTMSESSION_ASSERT_DEBUG(sharedSession != nil, @"Missing delegate session: %@", fetcher); + GTMSESSION_ASSERT_DEBUG(fetcherSession == sharedSession, + @"Inconsistent session: %@ %@ (shared: %@)", + fetcher, fetcherSession, sharedSession); + + if (sharedSession != nil && fetcherSession == sharedSession) { + NSURLSessionTask *task = fetcher.sessionTask; + GTMSESSION_ASSERT_DEBUG(task != nil, @"Missing session task: %@", fetcher); + + if (task) { + [delegateDispatcher setFetcher:fetcher + forTask:task]; + } + } + } +} + +- (void)stopFetcher:(GTMSessionFetcher *)fetcher { + [fetcher stopFetching]; +} + +- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher { + // Entry point from the fetcher + NSString *host = fetcher.serviceHost; + if (!host) { + // fetcher has been stopped previously + return; + } + + // This removeFetcher: invocation is a fallback; typically, fetchers are removed from the task + // map when the task completes. + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + [delegateDispatcher removeFetcher:fetcher]; + + NSMutableArray *fetchersToStart; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // If a test is waiting for all fetchers to stop, it needs to wait for this one + // to invoke its callbacks on the callback queue. + [_stoppedFetchersToWaitFor addObject:fetcher]; + + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + [runningForHost removeObject:fetcher]; + + NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + [delayedForHost removeObject:fetcher]; + + while (delayedForHost.count > 0 + && [[self class] numberOfNonBackgroundSessionFetchers:runningForHost] + < _maxRunningFetchersPerHost) { + // Start another delayed fetcher running, scanning for the minimum + // priority value, defaulting to FIFO for equal priorities + GTMSessionFetcher *nextFetcher = nil; + for (GTMSessionFetcher *delayedFetcher in delayedForHost) { + if (nextFetcher == nil + || delayedFetcher.servicePriority < nextFetcher.servicePriority) { + nextFetcher = delayedFetcher; + } + } + + if (nextFetcher) { + [self addRunningFetcher:nextFetcher forHost:host]; + runningForHost = [_runningFetchersByHost objectForKey:host]; + + [delayedForHost removeObjectIdenticalTo:nextFetcher]; + + if (!fetchersToStart) { + fetchersToStart = [NSMutableArray array]; + } + [fetchersToStart addObject:nextFetcher]; + } + } + + if (runningForHost.count == 0) { + // None left; remove the empty array + [_runningFetchersByHost removeObjectForKey:host]; + } + + if (delayedForHost.count == 0) { + [_delayedFetchersByHost removeObjectForKey:host]; + } + } // @synchronized(self) + + // Start fetchers outside of the synchronized block to avoid a deadlock. + for (GTMSessionFetcher *nextFetcher in fetchersToStart) { + [self startFetcher:nextFetcher]; + } + + // The fetcher is no longer in the running or the delayed array, + // so remove its host and thread properties + fetcher.serviceHost = nil; +} + +- (NSUInteger)numberOfFetchers { + NSUInteger running = [self numberOfRunningFetchers]; + NSUInteger delayed = [self numberOfDelayedFetchers]; + return running + delayed; +} + +- (NSUInteger)numberOfRunningFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger sum = 0; + for (NSString *host in _runningFetchersByHost) { + NSArray *fetchers = [_runningFetchersByHost objectForKey:host]; + sum += fetchers.count; + } + return sum; + } +} + +- (NSUInteger)numberOfDelayedFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger sum = 0; + for (NSString *host in _delayedFetchersByHost) { + NSArray *fetchers = [_delayedFetchersByHost objectForKey:host]; + sum += fetchers.count; + } + return sum; + } +} + +- (NSArray *)issuedFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSMutableArray *allFetchers = [NSMutableArray array]; + void (^accumulateFetchers)(id, id, BOOL *) = ^(NSString *host, + NSArray *fetchersForHost, + BOOL *stop) { + [allFetchers addObjectsFromArray:fetchersForHost]; + }; + [_runningFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers]; + [_delayedFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers]; + + GTMSESSION_ASSERT_DEBUG(allFetchers.count == [NSSet setWithArray:allFetchers].count, + @"Fetcher appears multiple times\n running: %@\n delayed: %@", + _runningFetchersByHost, _delayedFetchersByHost); + + return allFetchers.count > 0 ? allFetchers : nil; + } +} + +- (NSArray *)issuedFetchersWithRequestURL:(NSURL *)requestURL { + NSString *host = requestURL.host; + if (host.length == 0) return nil; + + NSURL *targetURL = [requestURL absoluteURL]; + + NSArray *allFetchers = [self issuedFetchers]; + NSIndexSet *indexes = [allFetchers indexesOfObjectsPassingTest:^BOOL(GTMSessionFetcher *fetcher, + NSUInteger idx, + BOOL *stop) { + NSURL *fetcherURL = [fetcher.request.URL absoluteURL]; + return [fetcherURL isEqual:targetURL]; + }]; + + NSArray *result = nil; + if (indexes.count > 0) { + result = [allFetchers objectsAtIndexes:indexes]; + } + return result; +} + +- (void)stopAllFetchers { + NSArray *delayedFetchersByHost; + NSArray *runningFetchersByHost; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Set the time barrier so fetchers know not to call back even if + // the stop calls below occur after the fetchers naturally + // stopped and so were removed from _runningFetchersByHost, + // but while the callbacks were already enqueued before stopAllFetchers + // was invoked. + _stoppedAllFetchersDate = [[NSDate alloc] init]; + + // Remove fetchers from the delayed list to avoid fetcherDidStop: from + // starting more fetchers running as a side effect of stopping one + delayedFetchersByHost = _delayedFetchersByHost.allValues; + [_delayedFetchersByHost removeAllObjects]; + + runningFetchersByHost = _runningFetchersByHost.allValues; + [_runningFetchersByHost removeAllObjects]; + } + + for (NSArray *delayedForHost in delayedFetchersByHost) { + for (GTMSessionFetcher *fetcher in delayedForHost) { + [self stopFetcher:fetcher]; + } + } + + for (NSArray *runningForHost in runningFetchersByHost) { + for (GTMSessionFetcher *fetcher in runningForHost) { + [self stopFetcher:fetcher]; + } + } +} + +- (NSDate *)stoppedAllFetchersDate { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _stoppedAllFetchersDate; + } +} + +#pragma mark Accessors + +- (BOOL)reuseSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateDispatcher != nil; + } +} + +- (void)setReuseSession:(BOOL)shouldReuse { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL wasReusing = (_delegateDispatcher != nil); + if (shouldReuse != wasReusing) { + [self abandonDispatcher]; + if (shouldReuse) { + _delegateDispatcher = + [[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + } else { + _delegateDispatcher = nil; + } + } + } +} + +- (void)resetSession { + GTMSessionCheckNotSynchronized(self); + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + [self resetSessionInternal]; + } + + dispatch_semaphore_signal(_sessionCreationSemaphore); +} + +- (void)resetSessionInternal { + GTMSessionCheckSynchronized(self); + + // The old dispatchers may be retained as delegates of any ongoing sessions by those sessions. + if (_delegateDispatcher) { + [self abandonDispatcher]; + _delegateDispatcher = + [[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + } +} + +- (void)resetSessionForDispatcherDiscardTimer:(NSTimer *)timer { + GTMSessionCheckNotSynchronized(self); + + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_delegateDispatcher.discardTimer == timer) { + // If the delegate dispatcher's current discardTimer is the same object as the timer + // that fired, no fetcher has recently attempted to start using the session by calling + // startSessionUsage, which invalidates and nils out the timer. + [self resetSessionInternal]; + } else { + // A fetcher has invalidated the timer between its triggering and now, potentially + // meaning a fetcher has requested access to the NSURLSession, and may be in the process + // of starting a new task. The dispatcher should not be abandoned, as this can lead + // to a race condition between calling -finishTasksAndInvalidate on the NSURLSession + // and the fetcher attempting to create a new task. + } + } + + dispatch_semaphore_signal(_sessionCreationSemaphore); +} + +- (NSTimeInterval)unusedSessionTimeout { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _unusedSessionTimeout; + } +} + +- (void)setUnusedSessionTimeout:(NSTimeInterval)timeout { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _unusedSessionTimeout = timeout; + _delegateDispatcher.discardInterval = timeout; + } +} + +// This method should be called inside of @synchronized(self) +- (void)abandonDispatcher { + GTMSessionCheckSynchronized(self); + [_delegateDispatcher abandon]; +} + +- (NSDictionary *)runningFetchersByHost { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_runningFetchersByHost copy]; + } +} + +- (void)setRunningFetchersByHost:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _runningFetchersByHost = [dict mutableCopy]; + } +} + +- (NSDictionary *)delayedFetchersByHost { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_delayedFetchersByHost copy]; + } +} + +- (void)setDelayedFetchersByHost:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delayedFetchersByHost = [dict mutableCopy]; + } +} + +- (id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _authorizer; + } +} + +- (void)setAuthorizer:(id)obj { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (obj != _authorizer) { + [self detachAuthorizer]; + } + + _authorizer = obj; + } + + // Use the fetcher service for the authorization fetches if the auth + // object supports fetcher services + if ([obj respondsToSelector:@selector(setFetcherService:)]) { +#if GTM_USE_SESSION_FETCHER + [obj setFetcherService:self]; +#else + [obj setFetcherService:(id)self]; +#endif + } +} + +// This should be called inside a @synchronized(self) block except during dealloc. +- (void)detachAuthorizer { + // This method is called by the fetcher service's dealloc and setAuthorizer: + // methods; do not override. + // + // The fetcher service retains the authorizer, and the authorizer has a + // weak pointer to the fetcher service (a non-zeroing pointer for + // compatibility with iOS 4 and Mac OS X 10.5/10.6.) + // + // When this fetcher service no longer uses the authorizer, we want to remove + // the authorizer's dependence on the fetcher service. Authorizers can still + // function without a fetcher service. + if ([_authorizer respondsToSelector:@selector(fetcherService)]) { + id authFetcherService = [_authorizer fetcherService]; + if (authFetcherService == self) { + [_authorizer setFetcherService:nil]; + } + } +} + +- (dispatch_queue_t GTM_NONNULL_TYPE)callbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _callbackQueue; + } // @synchronized(self) +} + +- (void)setCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _callbackQueue = queue ?: dispatch_get_main_queue(); + } // @synchronized(self) +} + +- (NSOperationQueue * GTM_NONNULL_TYPE)sessionDelegateQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateQueue; + } // @synchronized(self) +} + +- (void)setSessionDelegateQueue:(NSOperationQueue * GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateQueue = queue ?: [NSOperationQueue mainQueue]; + } // @synchronized(self) +} + +- (NSOperationQueue *)delegateQueue { + // Provided for compatibility with the old fetcher service. The gtm-oauth2 code respects + // any custom delegate queue for calling the app. + return nil; +} + ++ (NSUInteger)numberOfNonBackgroundSessionFetchers:(NSArray *)fetchers { + NSUInteger sum = 0; + for (GTMSessionFetcher *fetcher in fetchers) { + if (!fetcher.usingBackgroundSession) { + ++sum; + } + } + return sum; +} + +@end + +@implementation GTMSessionFetcherService (TestingSupport) + ++ (instancetype)mockFetcherServiceWithFakedData:(NSData *)fakedDataOrNil + fakedError:(NSError *)fakedErrorOrNil { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + NSURL *url = [NSURL URLWithString:@"http://example.invalid"]; + NSHTTPURLResponse *fakedResponse = + [[NSHTTPURLResponse alloc] initWithURL:url + statusCode:(fakedErrorOrNil ? 500 : 200) + HTTPVersion:@"HTTP/1.1" + headerFields:nil]; + GTMSessionFetcherService *service = [[self alloc] init]; + service.allowedInsecureSchemes = @[ @"http" ]; + service.testBlock = ^(GTMSessionFetcher *fetcherToTest, + GTMSessionFetcherTestResponse testResponse) { + testResponse(fakedResponse, fakedDataOrNil, fakedErrorOrNil); + }; + return service; +#else + GTMSESSION_ASSERT_DEBUG(0, @"Test blocks disabled"); + return nil; +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK +} + +#pragma mark Synchronous Wait for Unit Testing + +- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds { + NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + _stoppedFetchersToWaitFor = [NSMutableArray array]; + + BOOL shouldSpinRunLoop = [NSThread isMainThread]; + const NSTimeInterval kSpinInterval = 0.001; + BOOL didTimeOut = NO; + while (([self numberOfFetchers] > 0 || _stoppedFetchersToWaitFor.count > 0)) { + didTimeOut = [giveUpDate timeIntervalSinceNow] < 0; + if (didTimeOut) break; + + GTMSessionFetcher *stoppedFetcher = _stoppedFetchersToWaitFor.firstObject; + if (stoppedFetcher) { + [_stoppedFetchersToWaitFor removeObject:stoppedFetcher]; + [stoppedFetcher waitForCompletionWithTimeout:10.0 * kSpinInterval]; + } + + if (shouldSpinRunLoop) { + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:kSpinInterval]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + [NSThread sleepForTimeInterval:kSpinInterval]; + } + } + _stoppedFetchersToWaitFor = nil; + + return !didTimeOut; +} + +@end + +@implementation GTMSessionFetcherService (BackwardsCompatibilityOnly) + +- (NSInteger)cookieStorageMethod { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _cookieStorageMethod; + } +} + +- (void)setCookieStorageMethod:(NSInteger)cookieStorageMethod { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _cookieStorageMethod = cookieStorageMethod; + } +} + +@end + +@implementation GTMSessionFetcherSessionDelegateDispatcher { + __weak GTMSessionFetcherService *_parentService; + NSURLSession *_session; + + // The task map maps NSURLSessionTasks to GTMSessionFetchers + NSMutableDictionary *_taskToFetcherMap; + // The discard timer will invalidate sessions after the session's last task completes. + NSTimer *_discardTimer; + NSTimeInterval _discardInterval; +} + +@synthesize discardInterval = _discardInterval, + session = _session; + +- (instancetype)init { + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService + sessionDiscardInterval:(NSTimeInterval)discardInterval { + self = [super init]; + if (self) { + _discardInterval = discardInterval; + _parentService = parentService; + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@ %p %@ %@", + [self class], self, + _session ?: @"", + _taskToFetcherMap.count > 0 ? _taskToFetcherMap : @""]; +} + +- (NSTimer *)discardTimer { + GTMSessionCheckNotSynchronized(self); + @synchronized(self) { + return _discardTimer; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)startDiscardTimer { + GTMSessionCheckSynchronized(self); + [_discardTimer invalidate]; + _discardTimer = nil; + if (_discardInterval > 0) { + _discardTimer = [NSTimer timerWithTimeInterval:_discardInterval + target:self + selector:@selector(discardTimerFired:) + userInfo:nil + repeats:NO]; + [_discardTimer setTolerance:(_discardInterval / 10)]; + [[NSRunLoop mainRunLoop] addTimer:_discardTimer forMode:NSRunLoopCommonModes]; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)destroyDiscardTimer { + GTMSessionCheckSynchronized(self); + [_discardTimer invalidate]; + _discardTimer = nil; +} + +- (void)discardTimerFired:(NSTimer *)timer { + GTMSessionFetcherService *service; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger numberOfTasks = _taskToFetcherMap.count; + if (numberOfTasks == 0) { + service = _parentService; + } + } + + // Inform the service that the discard timer has fired, and should check whether the + // service can abandon us. -resetSession cannot be called directly, as there is a + // race condition that must be guarded against with the NSURLSession being returned + // from sessionForFetcherCreation outside other locks. The service can take steps + // to prevent resetting the session if that has occurred. + // + // The service must be called from outside the @synchronized block. + [service resetSessionForDispatcherDiscardTimer:timer]; +} + +- (void)abandon { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self destroySessionAndTimer]; + } +} + +- (void)startSessionUsage { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self destroyDiscardTimer]; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)destroySessionAndTimer { + GTMSessionCheckSynchronized(self); + [self destroyDiscardTimer]; + + // Break any retain cycle from the session holding the delegate. + [_session finishTasksAndInvalidate]; + + // Immediately clear the session so no new task may be issued with it. + // + // The _taskToFetcherMap needs to stay valid until the outstanding tasks finish. + _session = nil; +} + +- (void)setFetcher:(GTMSessionFetcher *)fetcher forTask:(NSURLSessionTask *)task { + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"missing fetcher"); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_taskToFetcherMap == nil) { + _taskToFetcherMap = [[NSMutableDictionary alloc] init]; + } + + if (fetcher) { + [_taskToFetcherMap setObject:fetcher forKey:task]; + [self destroyDiscardTimer]; + } + } +} + +- (void)removeFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Typically, a fetcher should be removed when its task invokes + // URLSession:task:didCompleteWithError:. + // + // When fetching with a testBlock, though, the task completed delegate + // method may not be invoked, requiring cleanup here. + NSArray *tasks = [_taskToFetcherMap allKeysForObject:fetcher]; + GTMSESSION_ASSERT_DEBUG(tasks.count <= 1, @"fetcher task not unmapped: %@", tasks); + [_taskToFetcherMap removeObjectsForKeys:tasks]; + + if (_taskToFetcherMap.count == 0) { + [self startDiscardTimer]; + } + } +} + +// This helper method provides synchronized access to the task map for the delegate +// methods below. +- (id)fetcherForTask:(NSURLSessionTask *)task { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_taskToFetcherMap objectForKey:task]; + } +} + +- (void)removeTaskFromMap:(NSURLSessionTask *)task { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_taskToFetcherMap removeObjectForKey:task]; + } +} + +- (void)setSession:(NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = session; + } +} + +- (NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _session; + } +} + +- (NSTimeInterval)discardInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _discardInterval; + } +} + +- (void)setDiscardInterval:(NSTimeInterval)interval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _discardInterval = interval; + } +} + +// NSURLSessionDelegate protocol methods. + +// - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session; +// +// TODO(seh): How do we route this to an appropriate fetcher? + + +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", + [self class], self, session, error); + NSDictionary *localTaskToFetcherMap; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = nil; + + localTaskToFetcherMap = [_taskToFetcherMap copy]; + } + + // Any "suspended" tasks may not have received callbacks from NSURLSession when the session + // completes; we'll call them now. + [localTaskToFetcherMap enumerateKeysAndObjectsUsingBlock:^(NSURLSessionTask *task, + GTMSessionFetcher *fetcher, + BOOL *stop) { + if (fetcher.session == session) { + // Our delegate method URLSession:task:didCompleteWithError: will rely on + // _taskToFetcherMap so that should still contain this fetcher. + NSError *canceledError = [NSError errorWithDomain:NSURLErrorDomain + code:NSURLErrorCancelled + userInfo:nil]; + [self URLSession:session task:task didCompleteWithError:canceledError]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"Unexpected session in fetcher: %@ has %@ (expected %@)", + fetcher, fetcher.session, session); + } + }]; + + // Our tests rely on this notification to know the session discard timer fired. + NSDictionary *userInfo = @{ kGTMSessionFetcherServiceSessionKey : session }; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherServiceSessionBecameInvalidNotification + object:_parentService + userInfo:userInfo]; +} + + +#pragma mark - NSURLSessionTaskDelegate + +// NSURLSessionTaskDelegate protocol methods. +// +// We won't test here if the fetcher responds to these since we only want this +// class to implement the same delegate methods the fetcher does (so NSURLSession's +// tests for respondsToSelector: will have the same result whether the session +// delegate is the fetcher or this dispatcher.) + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task +willPerformHTTPRedirection:response + newRequest:request + completionHandler:completionHandler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))handler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + didReceiveChallenge:challenge + completionHandler:handler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + needNewBodyStream:(void (^)(NSInputStream *bodyStream))handler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + needNewBodyStream:handler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + didSendBodyData:bytesSent + totalBytesSent:totalBytesSent +totalBytesExpectedToSend:totalBytesExpectedToSend]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error { + id fetcher = [self fetcherForTask:task]; + + // This is the usual way tasks are removed from the task map. + [self removeTaskFromMap:task]; + + [fetcher URLSession:session + task:task + didCompleteWithError:error]; +} + +// NSURLSessionDataDelegate protocol methods. + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition))handler { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + didReceiveResponse:response + completionHandler:handler]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { + id fetcher = [self fetcherForTask:dataTask]; + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"Missing fetcher for %@", dataTask); + [self removeTaskFromMap:dataTask]; + if (fetcher) { + GTMSESSION_ASSERT_DEBUG([fetcher isKindOfClass:[GTMSessionFetcher class]], + @"Expecting GTMSessionFetcher"); + [self setFetcher:(GTMSessionFetcher *)fetcher forTask:downloadTask]; + } + + [fetcher URLSession:session + dataTask:dataTask +didBecomeDownloadTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + didReceiveData:data]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *))handler { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + willCacheResponse:proposedResponse + completionHandler:handler]; +} + +// NSURLSessionDownloadDelegate protocol methods. + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask +didFinishDownloadingToURL:(NSURL *)location { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask +didFinishDownloadingToURL:location]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalWritten +totalBytesExpectedToWrite:(int64_t)totalExpected { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask + didWriteData:bytesWritten + totalBytesWritten:totalWritten +totalBytesExpectedToWrite:totalExpected]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset +expectedTotalBytes:(int64_t)expectedTotalBytes { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask + didResumeAtOffset:fileOffset + expectedTotalBytes:expectedTotalBytes]; +} + +@end diff --git a/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h new file mode 100644 index 0000000..51372f2 --- /dev/null +++ b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h @@ -0,0 +1,128 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// GTMSessionUploadFetcher implements Google's resumable upload protocol. + +// +// This subclass of GTMSessionFetcher simulates the series of fetches +// needed for chunked upload as a single fetch operation. +// +// Protocol document: TBD +// +// To the client, the only fetcher that exists is this class; the subsidiary +// fetchers needed for uploading chunks are not visible (though the most recent +// chunk fetcher may be accessed via the -activeFetcher or -chunkFetcher methods, and +// -responseHeaders and -statusCode reflect results from the most recent chunk +// fetcher.) +// +// Chunk fetchers are discarded as soon as they have completed. +// + +// Note: Unlike the fetcher superclass, the methods of GTMSessionUploadFetcher should +// only be used from the main thread until further work is done to make this subclass +// thread-safe. + +#import "GTMSessionFetcher.h" +#import "GTMSessionFetcherService.h" + +GTM_ASSUME_NONNULL_BEGIN + +// Unless an application knows it needs a smaller chunk size, it should use the standard +// chunk size, which sends the entire file as a single chunk to minimize upload overhead. +extern int64_t const kGTMSessionUploadFetcherStandardChunkSize; + +// When uploading requires data buffer allocations (such as uploading from an NSData or +// an NSFileHandle) this is the maximum buffer size that will be created by the fetcher. +extern int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize; + +// Notification that the upload location URL was provided by the server. +extern NSString *const kGTMSessionFetcherUploadLocationObtainedNotification; + +// Block to provide data during uploads. +// +// Response data may be allocated with dataWithBytesNoCopy:length:freeWhenDone: for efficiency, +// and released after the response block returns. +// +// Pass nil as the data (and optionally an NSError) for a failure. +typedef void (^GTMSessionUploadFetcherDataProviderResponse)(NSData * GTM_NULLABLE_TYPE data, + NSError * GTM_NULLABLE_TYPE error); +typedef void (^GTMSessionUploadFetcherDataProvider)(int64_t offset, int64_t length, + GTMSessionUploadFetcherDataProviderResponse response); + +@interface GTMSessionUploadFetcher : GTMSessionFetcher + +// Create an upload fetcher specifying either the request or the resume location URL, +// then set an upload data source using one of these: +// +// setUploadFileURL: +// setUploadDataLength:provider: +// setUploadFileHandle: +// setUploadData: + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil; + ++ (instancetype)uploadFetcherWithLocation:(NSURL * GTM_NULLABLE_TYPE)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil; + +- (void)setUploadDataLength:(int64_t)fullLength + provider:(GTM_NULLABLE GTMSessionUploadFetcherDataProvider)block; + ++ (NSArray *)uploadFetchersForBackgroundSessions; ++ (GTM_NULLABLE instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier; + +- (void)pauseFetching; +- (void)resumeFetching; +- (BOOL)isPaused; + +@property(atomic, strong, GTM_NULLABLE) NSURL *uploadLocationURL; +@property(atomic, strong, GTM_NULLABLE) NSData *uploadData; +@property(atomic, strong, GTM_NULLABLE) NSURL *uploadFileURL; +@property(atomic, strong, GTM_NULLABLE) NSFileHandle *uploadFileHandle; +@property(atomic, copy, readonly, GTM_NULLABLE) GTMSessionUploadFetcherDataProvider uploadDataProvider; +@property(atomic, copy) NSString *uploadMIMEType; +@property(atomic, assign) int64_t chunkSize; +@property(atomic, readonly, assign) int64_t currentOffset; + +// The fetcher for the current data chunk, if any +@property(atomic, strong, GTM_NULLABLE) GTMSessionFetcher *chunkFetcher; + +// The active fetcher is the current chunk fetcher, or the upload fetcher itself +// if no chunk fetcher has yet been created. +@property(atomic, readonly) GTMSessionFetcher *activeFetcher; + +// The last request made by an active fetcher. Useful for testing. +@property(atomic, readonly, GTM_NULLABLE) NSURLRequest *lastChunkRequest; + +// The status code from the most recently-completed fetch. +@property(atomic, assign) NSInteger statusCode; + +// Exposed for testing only. +@property(atomic, readonly, GTM_NULLABLE) dispatch_queue_t delegateCallbackQueue; +@property(atomic, readonly, GTM_NULLABLE) GTMSessionFetcherCompletionHandler delegateCompletionHandler; + +@end + +@interface GTMSessionFetcher (GTMSessionUploadFetcherMethods) + +@property(readonly, GTM_NULLABLE) GTMSessionUploadFetcher *parentUploadFetcher; + +@end + +GTM_ASSUME_NONNULL_END diff --git a/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m new file mode 100644 index 0000000..3c71fd9 --- /dev/null +++ b/Code Burner/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m @@ -0,0 +1,1798 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionUploadFetcher.h" + +static NSString *const kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey = @"_upChunk"; +static NSString *const kGTMSessionIdentifierUploadFileURLMetadataKey = @"_upFileURL"; +static NSString *const kGTMSessionIdentifierUploadFileLengthMetadataKey = @"_upFileLen"; +static NSString *const kGTMSessionIdentifierUploadLocationURLMetadataKey = @"_upLocURL"; +static NSString *const kGTMSessionIdentifierUploadMIMETypeMetadataKey = @"_uploadMIME"; +static NSString *const kGTMSessionIdentifierUploadChunkSizeMetadataKey = @"_upChSize"; +static NSString *const kGTMSessionIdentifierUploadCurrentOffsetMetadataKey = @"_upOffset"; + +static NSString *const kGTMSessionHeaderXGoogUploadChunkGranularity = @"X-Goog-Upload-Chunk-Granularity"; +static NSString *const kGTMSessionHeaderXGoogUploadCommand = @"X-Goog-Upload-Command"; +static NSString *const kGTMSessionHeaderXGoogUploadContentLength = @"X-Goog-Upload-Content-Length"; +static NSString *const kGTMSessionHeaderXGoogUploadContentType = @"X-Goog-Upload-Content-Type"; +static NSString *const kGTMSessionHeaderXGoogUploadOffset = @"X-Goog-Upload-Offset"; +static NSString *const kGTMSessionHeaderXGoogUploadProtocol = @"X-Goog-Upload-Protocol"; +static NSString *const kGTMSessionHeaderXGoogUploadSizeReceived = @"X-Goog-Upload-Size-Received"; +static NSString *const kGTMSessionHeaderXGoogUploadStatus = @"X-Goog-Upload-Status"; +static NSString *const kGTMSessionHeaderXGoogUploadURL = @"X-Goog-Upload-URL"; + +// Property of chunk fetchers identifying the parent upload fetcher. Non-retained NSValue. +static NSString *const kGTMSessionUploadFetcherChunkParentKey = @"_uploadFetcherChunkParent"; + +int64_t const kGTMSessionUploadFetcherStandardChunkSize = (int64_t)LLONG_MAX; + +#if TARGET_OS_IPHONE +int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = 10 * 1024 * 1024; // 10 MB for iOS +#else +int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = 100 * 1024 * 1024; // 100 MB for OS X +#endif + +typedef NS_ENUM(NSUInteger, GTMSessionUploadFetcherStatus) { + kStatusUnknown, + kStatusActive, + kStatusFinal, + kStatusCancelled, +}; + +NSString *const kGTMSessionFetcherUploadLocationObtainedNotification = + @"kGTMSessionFetcherUploadLocationObtainedNotification"; + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (ProtectedMethods) + +// Access to non-public method on the parent fetcher class. +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks; +- (void)createSessionIdentifierWithMetadata:(NSDictionary *)metadata; +- (GTMSessionFetcherCompletionHandler)completionHandlerWithTarget:(id)target + didFinishSelector:(SEL)finishedSelector; +- (void)invokeOnCallbackQueue:(dispatch_queue_t)callbackQueue + afterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block; +- (NSTimer *)retryTimer; + +@property(readwrite, strong) NSData *downloadedData; +- (void)releaseCallbacks; + +- (NSInteger)statusCodeUnsynchronized; + +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionUploadFetcher () + +// Changing readonly to readwrite. +@property(atomic, strong, readwrite) NSURLRequest *lastChunkRequest; +@property(atomic, readwrite, assign) int64_t currentOffset; + +// Internal properties. +@property(strong, atomic, GTM_NULLABLE) GTMSessionFetcher *fetcherInFlight; // Synchronized on self. + +@property(assign, atomic, getter=isSubdataGenerating) BOOL subdataGenerating; +@property(assign, atomic) BOOL shouldInitiateOffsetQuery; +@property(assign, atomic) int64_t uploadGranularity; + +@end + +@implementation GTMSessionUploadFetcher { + GTMSessionFetcher *_chunkFetcher; + + // We'll call through to the delegate's completion handler. + GTMSessionFetcherCompletionHandler _delegateCompletionHandler; + dispatch_queue_t _delegateCallbackQueue; + + // The initial fetch's body length and bytes actually sent are + // needed for calculating progress during subsequent chunk uploads + int64_t _initialBodyLength; + int64_t _initialBodySent; + + // The upload server address for the chunks of this upload session. + NSURL *_uploadLocationURL; + + // _uploadData, _uploadDataProvider, or _uploadFileHandle may be set, but only one. + NSData *_uploadData; + NSFileHandle *_uploadFileHandle; + GTMSessionUploadFetcherDataProvider _uploadDataProvider; + NSURL *_uploadFileURL; + int64_t _uploadFileLength; + NSString *_uploadMIMEType; + int64_t _chunkSize; + int64_t _uploadGranularity; + BOOL _isPaused; + BOOL _isRestartedUpload; + BOOL _shouldInitiateOffsetQuery; + + // Tied to useBackgroundSession property, since this property is applicable to chunk fetchers. + BOOL _useBackgroundSessionOnChunkFetchers; + + // We keep the latest offset into the upload data just for progress reporting. + int64_t _currentOffset; + + NSDictionary *_recentChunkReponseHeaders; + NSInteger _recentChunkStatusCode; + + // For waiting, we need to know the fetcher in flight, if any, and if subdata generation + // is in progress. + GTMSessionFetcher *_fetcherInFlight; + BOOL _isSubdataGenerating; +} + ++ (void)load { + [self uploadFetchersForBackgroundSessions]; +} + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTMSessionFetcherService *)fetcherService { + GTMSessionUploadFetcher *fetcher = [self uploadFetcherWithRequest:request + fetcherService:fetcherService]; + [fetcher setLocationURL:nil + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize]; + return fetcher; +} + ++ (instancetype)uploadFetcherWithLocation:(NSURL * GTM_NULLABLE_TYPE)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTMSessionFetcherService *)fetcherService { + GTMSessionUploadFetcher *fetcher = [self uploadFetcherWithRequest:nil + fetcherService:fetcherService]; + [fetcher setLocationURL:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize]; + return fetcher; +} + ++ (instancetype)uploadFetcherForSessionIdentifierMetadata:(NSDictionary *)metadata { + GTMSESSION_ASSERT_DEBUG( + [metadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] boolValue], + @"Session identifier metadata is not for an upload fetcher: %@", metadata); + + NSNumber *uploadFileLengthNum = metadata[kGTMSessionIdentifierUploadFileLengthMetadataKey]; + GTMSESSION_ASSERT_DEBUG(uploadFileLengthNum != nil, + @"Session metadata missing an UploadFileSize"); + if (uploadFileLengthNum == nil) return nil; + + int64_t uploadFileLength = [uploadFileLengthNum longLongValue]; + GTMSESSION_ASSERT_DEBUG(uploadFileLength >= 0, @"Session metadata UploadFileSize is unknown"); + + NSString *uploadFileURLString = metadata[kGTMSessionIdentifierUploadFileURLMetadataKey]; + GTMSESSION_ASSERT_DEBUG(uploadFileURLString, @"Session metadata missing an UploadFileURL"); + if (uploadFileURLString == nil) return nil; + + NSURL *uploadFileURL = [NSURL URLWithString:uploadFileURLString]; + // There used to be a call here to NSURL checkResourceIsReachableAndReturnError: to check for the + // existence of the file (also tried NSFileManager fileExistsAtPath:). We've determined + // empirically that the check can fail at startup even when the upload file does in fact exist. + // For now, we'll go ahead and restore the background upload fetcher. If the file doesn't exist, + // it will fail later. + + NSString *uploadLocationURLString = metadata[kGTMSessionIdentifierUploadLocationURLMetadataKey]; + NSURL *uploadLocationURL = + uploadLocationURLString ? [NSURL URLWithString:uploadLocationURLString] : nil; + + NSString *uploadMIMEType = + metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey]; + int64_t uploadChunkSize = + [metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] longLongValue]; + if (uploadChunkSize <= 0) { + uploadChunkSize = kGTMSessionUploadFetcherStandardChunkSize; + } + int64_t currentOffset = + [metadata[kGTMSessionIdentifierUploadCurrentOffsetMetadataKey] longLongValue]; + GTMSESSION_ASSERT_DEBUG(currentOffset <= uploadFileLength, + @"CurrentOffset (%lld) exceeds UploadFileSize (%lld)", + currentOffset, uploadFileLength); + if (currentOffset > uploadFileLength) return nil; + + GTMSessionUploadFetcher *uploadFetcher = [self uploadFetcherWithLocation:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:uploadChunkSize + fetcherService:nil]; + // Set the upload file length before setting the upload file URL tries to determine the length. + [uploadFetcher setUploadFileLength:uploadFileLength]; + + uploadFetcher.uploadFileURL = uploadFileURL; + uploadFetcher.sessionUserInfo = metadata; + uploadFetcher.useBackgroundSession = YES; + uploadFetcher.currentOffset = currentOffset; + uploadFetcher.allowedInsecureSchemes = @[ @"http" ]; // Allowed on restored upload fetcher. + return uploadFetcher; +} + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + fetcherService:(GTMSessionFetcherService *)fetcherService { + // Internal utility method for instantiating fetchers + GTMSessionUploadFetcher *fetcher; + if ([fetcherService isKindOfClass:[GTMSessionFetcherService class]]) { + fetcher = [fetcherService fetcherWithRequest:request + fetcherClass:self]; + } else { + fetcher = [self fetcherWithRequest:request]; + } + fetcher.useBackgroundSession = YES; + return fetcher; +} + ++ (NSPointerArray *)uploadFetcherPointerArrayForBackgroundSessions { + static NSPointerArray *gUploadFetcherPointerArrayForBackgroundSessions = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gUploadFetcherPointerArrayForBackgroundSessions = [NSPointerArray weakObjectsPointerArray]; + }); + return gUploadFetcherPointerArrayForBackgroundSessions; +} + ++ (instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + NSArray *uploadFetchersForBackgroundSessions = [self uploadFetchersForBackgroundSessions]; + for (GTMSessionUploadFetcher *uploadFetcher in uploadFetchersForBackgroundSessions) { + if ([uploadFetcher.chunkFetcher.sessionIdentifier isEqual:sessionIdentifier]) { + return uploadFetcher; + } + } + return nil; +} + ++ (NSArray *)uploadFetchersForBackgroundSessions { + // Collect the background session upload fetchers that are still in memory. + NSPointerArray *uploadFetcherPointerArray = [self uploadFetcherPointerArrayForBackgroundSessions]; + [uploadFetcherPointerArray compact]; + NSMutableSet *restoredSessionIdentifiers = [[NSMutableSet alloc] init]; + NSMutableArray *uploadFetchers = [[NSMutableArray alloc] init]; + for (GTMSessionUploadFetcher *uploadFetcher in uploadFetcherPointerArray) { + NSString *sessionIdentifier = uploadFetcher.chunkFetcher.sessionIdentifier; + if (sessionIdentifier) { + [restoredSessionIdentifiers addObject:sessionIdentifier]; + [uploadFetchers addObject:uploadFetcher]; + } + } + + // The system may have other ongoing background upload sessions. Restore upload fetchers for those + // too. + NSArray *fetchers = [GTMSessionFetcher fetchersForBackgroundSessions]; + for (GTMSessionFetcher *fetcher in fetchers) { + NSString *sessionIdentifier = fetcher.sessionIdentifier; + if (!sessionIdentifier || [restoredSessionIdentifiers containsObject:sessionIdentifier]) { + continue; + } + NSDictionary *sessionIdentifierMetadata = [fetcher sessionIdentifierMetadata]; + if (sessionIdentifierMetadata == nil) { + continue; + } + if (![sessionIdentifierMetadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] boolValue]) { + continue; + } + GTMSessionUploadFetcher *uploadFetcher = + [self uploadFetcherForSessionIdentifierMetadata:sessionIdentifierMetadata]; + if (uploadFetcher == nil) { + // Something went wrong with this upload fetcher, so kill the restored chunk fetcher. + [fetcher stopFetching]; + continue; + } + [uploadFetchers addObject:uploadFetcher]; + uploadFetcher->_chunkFetcher = fetcher; + uploadFetcher->_fetcherInFlight = fetcher; + [uploadFetcher attachSendProgressBlockToChunkFetcher:fetcher]; + fetcher.completionHandler = + [fetcher completionHandlerWithTarget:uploadFetcher + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; + + GTMSESSION_LOG_DEBUG(@"%@ restoring upload fetcher %@ for chunk fetcher %@", + [self class], uploadFetcher, fetcher); + } + return uploadFetchers; +} + +- (void)setUploadData:(NSData *)data { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadData != data) { + _uploadData = data; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSData *)uploadData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadData; + } +} + +- (void)setUploadFileHandle:(NSFileHandle *)fh { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileHandle != fh) { + _uploadFileHandle = fh; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSFileHandle *)uploadFileHandle { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadFileHandle; + } +} + +- (void)setUploadFileURL:(NSURL *)uploadURL { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileURL != uploadURL) { + _uploadFileURL = uploadURL; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSURL *)uploadFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadFileURL; + } +} + +- (void)setUploadFileLength:(int64_t)fullLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadFileLength = fullLength; + } +} + +- (void)setUploadDataLength:(int64_t)fullLength + provider:(GTMSessionUploadFetcherDataProvider)block { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadDataProvider = [block copy]; + _uploadFileLength = fullLength; + } + [self setupRequestHeaders]; +} + +- (GTMSessionUploadFetcherDataProvider)uploadDataProvider { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadDataProvider; + } +} + + +- (void)setUploadMIMEType:(NSString *)uploadMIMEType { + GTMSESSION_ASSERT_DEBUG(0, @"TODO: disallow setUploadMIMEType by making declaration readonly"); + // (and uploadMIMEType, chunksize, currentOffset) + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadMIMEType = uploadMIMEType; + } +} + +- (NSString *)uploadMIMEType { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadMIMEType; + } +} + +- (void)setChunkSize:(int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _chunkSize = chunkSize; + } +} + +- (int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _chunkSize; + } +} + +- (void)setupRequestHeaders { + GTMSessionCheckNotSynchronized(self); + +#if DEBUG + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + int hasData = (_uploadData != nil) ? 1 : 0; + int hasFileHandle = (_uploadFileHandle != nil) ? 1 : 0; + int hasFileURL = (_uploadFileURL != nil) ? 1 : 0; + int hasUploadDataProvider = (_uploadDataProvider != nil) ? 1 : 0; + int numberOfSources = hasData + hasFileHandle + hasFileURL + hasUploadDataProvider; + #pragma unused(numberOfSources) + GTMSESSION_ASSERT_DEBUG(numberOfSources == 1, + @"Need just one upload source (%d)", numberOfSources); + } // @synchronized(self) +#endif + + // Add our custom headers to the initial request indicating the data + // type and total size to be delivered later in the chunk requests. + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + + GTMSESSION_ASSERT_DEBUG((mutableRequest == nil) != (_uploadLocationURL == nil), + @"Request and location are mutually exclusive"); + if (!mutableRequest) return; + + NSNumber *lengthNum = @([self fullUploadLength]); + [mutableRequest setValue:@"resumable" + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadProtocol]; + [mutableRequest setValue:@"start" + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + [mutableRequest setValue:_uploadMIMEType + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentType]; + [mutableRequest setValue:lengthNum.stringValue + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentLength]; + + NSString *method = mutableRequest.HTTPMethod; + if (method == nil || [method caseInsensitiveCompare:@"GET"] == NSOrderedSame) { + [mutableRequest setHTTPMethod:@"POST"]; + } + + // Ensure the user agent header identifies this to the upload server as a + // GTMSessionUploadFetcher client. The /1 can be incremented in the unlikely circumstance + // we need to make a bug fix in the client that the server can recognize. + NSString *const kUserAgentStub = @"(GTMSUF/1)"; + NSString *userAgent = [mutableRequest valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent == nil + || [userAgent rangeOfString:kUserAgentStub].location == NSNotFound) { + if (userAgent.length == 0) { + userAgent = GTMFetcherStandardUserAgentString(nil); + } + userAgent = [userAgent stringByAppendingFormat:@" %@", kUserAgentStub]; + [mutableRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + [self setRequest:mutableRequest]; +} + +- (void)setLocationURL:(NSURL * GTM_NULLABLE_TYPE)location + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(chunkSize > 0, @"chunk size is zero"); + + // When resuming an upload, set the known upload target URL. + _uploadLocationURL = location; + + _uploadMIMEType = uploadMIMEType; + _chunkSize = chunkSize; + + // Indicate that we've not yet determined the file handle's length + _uploadFileLength = -1; + + // Indicate that we've not yet determined the upload fetcher status + _recentChunkStatusCode = -1; + + // If this is restarting an upload begun by another fetcher, + // the location is specified but the request is nil + _isRestartedUpload = (location != nil); + } // @synchronized(self) +} + +- (int64_t)fullUploadLength { + int64_t result; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadData) { + result = (int64_t)_uploadData.length; + } else { + if (_uploadFileLength == -1) { + if (_uploadFileHandle) { + // First time through, seek to end to determine file length + _uploadFileLength = (int64_t)[_uploadFileHandle seekToEndOfFile]; + } else if (_uploadDataProvider) { + // _uploadFileLength is set when the _uploadDataProvider is set. + GTMSESSION_ASSERT_DEBUG(_uploadFileLength >= 0, @"No uploadDataProvider length set"); + } else { + NSNumber *filesizeNum; + NSError *valueError; + if ([_uploadFileURL getResourceValue:&filesizeNum + forKey:NSURLFileSizeKey + error:&valueError]) { + _uploadFileLength = filesizeNum.longLongValue; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Cannot get file size: %@\n %@", + valueError, _uploadFileURL.path); + _uploadFileLength = 0; + } + } + } + result = _uploadFileLength; + } + } // @synchronized(self) + return result; +} + +// Make a subdata of the upload data. +- (void)generateChunkSubdataWithOffset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + GTMSessionUploadFetcherDataProvider uploadDataProvider = self.uploadDataProvider; + if (uploadDataProvider) { + uploadDataProvider(offset, length, response); + return; + } + + NSData *uploadData = self.uploadData; + if (uploadData) { + // NSData provided. + NSData *resultData; + if (offset == 0 && length == (int64_t)uploadData.length) { + resultData = uploadData; + } else { + int64_t dataLength = (int64_t)uploadData.length; + // Ensure our range is valid. b/18007814 + if (offset + length > dataLength) { + NSString *errorMessage = [NSString stringWithFormat: + @"Range invalid for upload data. offset: %lld\tlength: %lld\tdataLength: %lld", + offset, length, dataLength]; + GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage); + response(nil, [self uploadChunkUnavailableErrorWithDescription:errorMessage]); + return; + } + NSRange range = NSMakeRange((NSUInteger)offset, (NSUInteger)length); + resultData = [uploadData subdataWithRange:range]; + } + response(resultData, nil); + return; + } + NSURL *uploadFileURL = self.uploadFileURL; + if (uploadFileURL) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self generateChunkSubdataFromFileURL:uploadFileURL + offset:offset + length:length + response:response]; + }); + return; + } + GTMSESSION_ASSERT_DEBUG(_uploadFileHandle, @"Unexpectedly missing upload data package"); + NSFileHandle *uploadFileHandle = self.uploadFileHandle; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self generateChunkSubdataFromFileHandle:uploadFileHandle + offset:offset + length:length + response:response]; + }); +} + +- (void)generateChunkSubdataFromFileHandle:(NSFileHandle *)fileHandle + offset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + NSData *resultData; + NSError *error; + @try { + [fileHandle seekToFileOffset:(unsigned long long)offset]; + resultData = [fileHandle readDataOfLength:(NSUInteger)length]; + } + @catch (NSException *exception) { + GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileHandle failed to read, %@", exception); + error = [self uploadChunkUnavailableErrorWithDescription:exception.description]; + } + // The response always re-dispatches to the main thread, so we skip doing that here. + response(resultData, error); +} + +- (void)generateChunkSubdataFromFileURL:(NSURL *)fileURL + offset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + GTMSessionCheckNotSynchronized(self); + + NSData *resultData; + NSError *error; + int64_t fullUploadLength = [self fullUploadLength]; + NSData *mappedData = + [NSData dataWithContentsOfURL:fileURL + options:NSDataReadingMappedAlways + NSDataReadingUncached + error:&error]; + if (!mappedData) { + // We could not create an NSData by memory-mapping the file. +#if TARGET_IPHONE_SIMULATOR + // NSTemporaryDirectory() can differ in the simulator between app restarts, + // yet the contents for the new path remains unchanged, so try the latest temp path. + if ([error.domain isEqual:NSCocoaErrorDomain] && (error.code == NSFileReadNoSuchFileError)) { + NSString *filename = [fileURL lastPathComponent]; + NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + NSURL *newFileURL = [NSURL fileURLWithPath:filePath]; + if (![newFileURL isEqual:fileURL]) { + [self generateChunkSubdataFromFileURL:newFileURL + offset:offset + length:length + response:response]; + return; + } + } +#endif + + // If the file is just too large to create an NSData for, or if for some other reason we can't + // map it, create an NSFileHandle instead to read a subset into an NSData. +#if DEBUG + NSNumber *fileSizeNum; + BOOL hasFileSize = [fileURL getResourceValue:&fileSizeNum forKey:NSURLFileSizeKey error:NULL]; + GTMSESSION_LOG_DEBUG(@"Note: uploadFileURL is falling back to creating upload chunks by reading" + @" an NSFileHandle since uploadFileURL failed to map the upload file," + @" file size %@, %@", + hasFileSize ? fileSizeNum : @"unknown", error); +#endif + + NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:fileURL + error:&error]; + if (fileHandle != nil) { + [self generateChunkSubdataFromFileHandle:fileHandle + offset:offset + length:length + response:response]; + return; + } + GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileURL failed to read, %@", error); + // Fall through with the error. + } else { + // Successfully created an NSData by memory-mapping the file. + if (offset > 0 || length < fullUploadLength) { + NSRange range = NSMakeRange((NSUInteger)offset, (NSUInteger)length); + resultData = [mappedData subdataWithRange:range]; + } else { + resultData = mappedData; + } + } + // The response always re-dispatches to the main thread, so we skip re-dispatching here. + response(resultData, error); +} + +- (NSError *)uploadChunkUnavailableErrorWithDescription:(NSString *)description { + // The description in the userInfo is intended as a clue to programmers, not + // for client code to examine or rely on. + NSDictionary *userInfo = @{ @"description" : description }; + return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorUploadChunkUnavailable + userInfo:userInfo]; +} + +- (NSError *)prematureFailureErrorWithUserInfo:(NSDictionary *)userInfo { + // An error for if we get an unexpected status from the upload server or + // otherwise cannot continue. This is an issue beyond the upload protocol; + // there's no way the client can do anything useful except give up. + NSError *error = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:501 // Not implemented + userInfo:userInfo]; + return error; +} + ++ (GTMSessionUploadFetcherStatus)uploadStatusFromResponseHeaders:(NSDictionary *)responseHeaders { + NSString *statusString = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus]; + if ([statusString isEqual:@"active"]) { + return kStatusActive; + } + if ([statusString isEqual:@"final"]) { + return kStatusFinal; + } + if ([statusString isEqual:@"cancelled"]) { + return kStatusCancelled; + } + return kStatusUnknown; +} + +#pragma mark Method overrides affecting the initial fetch only + +- (void)setCompletionHandler:(GTMSessionFetcherCompletionHandler)handler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCompletionHandler = handler; + } +} + +- (void)setDelegateCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCallbackQueue = queue; + } +} + +- (dispatch_queue_t GTM_NULLABLE_TYPE)delegateCallbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateCallbackQueue; + } +} + +- (BOOL)isRestartedUpload { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isRestartedUpload; + } +} + +- (GTMSessionFetcher * GTM_NULLABLE_TYPE)chunkFetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _chunkFetcher; + } +} + +- (void)setChunkFetcher:(GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _chunkFetcher = fetcher; + } +} + +- (void)setFetcherInFlight:(GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _fetcherInFlight = fetcher; + } +} + +- (GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcherInFlight { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _fetcherInFlight; + } +} + +- (void)beginFetchWithCompletionHandler:(GTMSessionFetcherCompletionHandler)handler { + GTMSessionCheckNotSynchronized(self); + + [self setInitialBodyLength:[self bodyLength]]; + + // We'll hold onto the superclass's callback queue so we can invoke the handler + // even after the superclass has released the queue and its callback handler, as + // happens during auth failure. + [self setDelegateCallbackQueue:self.callbackQueue]; + self.completionHandler = handler; + + if ([self isRestartedUpload]) { + // When restarting an upload, we know the destination location for chunk fetches, + // but we need to query to find the initial offset. + if (![self isPaused]) { + [self sendQueryForUploadOffsetWithFetcherProperties:self.properties]; + } + return; + } + // We don't want to call into the client's completion block immediately + // after the finish of the initial connection (the delegate is called only + // when uploading finishes), so we substitute our own completion block to be + // called when the initial connection finishes + GTMSESSION_ASSERT_DEBUG(self.fetcherInFlight == nil, @"unexpected fetcher in flight: %@", + self.fetcherInFlight); + + self.fetcherInFlight = self; + [super beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + self.fetcherInFlight = nil; + // callback + + BOOL hasTestBlock = (self.testBlock != nil); + if (![self isRestartedUpload] && !hasTestBlock) { + if (error == nil) { + [self beginChunkFetches]; + } else { + if ([self retryTimer] == nil) { + [self invokeFinalCallbackWithData:nil + error:error + shouldInvalidateLocation:YES]; + } + } + } else { + // If there was no initial request, then this fetch is resuming some + // other uploadFetcher's initial request, and the superclass's connection + // is never used, so at this point we call the user's actual completion + // block. + if (!hasTestBlock) { + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + } else { + // There was a test block, so we won't do chunk fetches, but we simulate obtaining + // the data to be uploaded from the upload data provider block or the file handle, + // and then call back. + [self generateChunkSubdataWithOffset:0 + length:[self fullUploadLength] + response:^(NSData *generateData, NSError *generateError) { + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + }]; + } + } + }]; +} + +- (void)beginChunkFetches { + GTMSessionCheckNotSynchronized(self); + +#if DEBUG + // The initial response of the resumable upload protocol should have an + // empty body + // + // This assert typically happens because the upload create/edit link URL was + // not supplied with the request, and the server is thus expecting a non- + // resumable request/response. + if (self.downloadedData.length > 0) { + NSData *downloadedData = self.downloadedData; + NSString *str = [[NSString alloc] initWithData:downloadedData + encoding:NSUTF8StringEncoding]; + #pragma unused(str) + GTMSESSION_ASSERT_DEBUG(NO, @"unexpected response data (uploading to the wrong URL?)\n%@", str); + } +#endif + + // We need to get the upload URL from the location header to continue. + NSDictionary *responseHeaders = [self responseHeaders]; + + [self retrieveUploadChunkGranularityFromResponseHeaders:responseHeaders]; + + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown, + @"beginChunkFetches has unexpected upload status for headers %@", responseHeaders); + + BOOL isPrematureStop = (uploadStatus == kStatusFinal) || (uploadStatus == kStatusCancelled); + + NSString *uploadLocationURLStr = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadURL]; + BOOL hasUploadLocation = (uploadLocationURLStr.length > 0); + + if (isPrematureStop || !hasUploadLocation) { + GTMSESSION_ASSERT_DEBUG(NO, @"Premature failure: upload-status:\"%@\" location:%@", + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], uploadLocationURLStr); + // We cannot continue since we do not know the location to use + // as our upload destination. + NSDictionary *userInfo = nil; + NSData *downloadedData = self.downloadedData; + if (downloadedData.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : downloadedData }; + } + NSError *failureError = [self prematureFailureErrorWithUserInfo:userInfo]; + [self invokeFinalCallbackWithData:nil + error:failureError + shouldInvalidateLocation:YES]; + return; + } + + self.uploadLocationURL = [NSURL URLWithString:uploadLocationURLStr]; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherUploadLocationObtainedNotification + object:self]; + + // we've now sent all of the initial post body data, so we need to include + // its size in future progress indicator callbacks + [self setInitialBodySent:[self initialBodyLength]]; + + // just in case the user paused us during the initial fetch... + if (![self isPaused]) { + [self uploadNextChunkWithOffset:0]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + // Overrides the superclass. + [self invokeDelegateWithDidSendBytes:bytesSent + totalBytesSent:totalBytesSent + totalBytesExpectedToSend:totalBytesExpectedToSend + [self fullUploadLength]]; +} + +- (BOOL)shouldReleaseCallbacksUponCompletion { + // Overrides the superclass. + + // We don't want the superclass to release the delegate and callback + // blocks once the initial fetch has finished + // + // This is invoked for only successful completion of the connection; + // an error always will invoke and release the callbacks + return NO; +} + +- (void)invokeFinalCallbackWithData:(NSData *)data + error:(NSError *)error + shouldInvalidateLocation:(BOOL)shouldInvalidateLocation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (shouldInvalidateLocation) { + _uploadLocationURL = nil; + } + + dispatch_queue_t queue = _delegateCallbackQueue; + GTMSessionFetcherCompletionHandler handler = _delegateCompletionHandler; + if (queue && handler) { + [self invokeOnCallbackQueue:queue + afterUserStopped:NO + block:^{ + handler(data, error); + }]; + } + } // @synchronized(self) + + [self releaseUploadAndBaseCallbacks]; +} + +- (void)releaseUploadAndBaseCallbacks { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCallbackQueue = nil; + _delegateCompletionHandler = nil; + _uploadDataProvider = nil; + } + + // Release the base class's callbacks, too, if needed. + [self releaseCallbacks]; +} + +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks { + GTMSessionCheckNotSynchronized(self); + + // Clear _fetcherInFlight when stopped. Moved from stopFetching, since that's a public method, + // where this method does the work. Fixes issue clearing value when retryBlock included. + GTMSessionFetcher *fetcherInFlight = self.fetcherInFlight; + if (fetcherInFlight == self) { + self.fetcherInFlight = nil; + } + + [super stopFetchReleasingCallbacks:shouldReleaseCallbacks]; + + if (shouldReleaseCallbacks) { + [self releaseUploadAndBaseCallbacks]; + } +} + +#pragma mark Chunk fetching methods + +- (void)uploadNextChunkWithOffset:(int64_t)offset { + // use the properties in each chunk fetcher + NSDictionary *props = [self properties]; + + [self uploadNextChunkWithOffset:offset + fetcherProperties:props]; +} + +- (void)sendQueryForUploadOffsetWithFetcherProperties:(NSDictionary *)props { + GTMSessionFetcher *queryFetcher = [self uploadFetcherWithProperties:props + isQueryFetch:YES]; + queryFetcher.bodyData = [NSData data]; + + NSString *originalComment = self.comment; + [queryFetcher setCommentWithFormat:@"%@ (query offset)", + originalComment ? originalComment : @"upload"]; + + [queryFetcher setRequestValue:@"query" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + + self.fetcherInFlight = queryFetcher; + [queryFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(queryFetcher:finishedWithData:error:)]; +} + +- (void)queryFetcher:(GTMSessionFetcher *)queryFetcher + finishedWithData:(NSData *)data + error:(NSError *)error { + self.fetcherInFlight = nil; + + NSDictionary *responseHeaders = [queryFetcher responseHeaders]; + NSString *sizeReceivedHeader; + + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown || error != nil, + @"query fetcher completion has unexpected upload status for headers %@", responseHeaders); + + if (error == nil) { + sizeReceivedHeader = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadSizeReceived]; + + if (uploadStatus == kStatusCancelled || + (uploadStatus == kStatusActive && sizeReceivedHeader == nil)) { + NSDictionary *userInfo = nil; + if (data.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : data }; + } + error = [self prematureFailureErrorWithUserInfo:userInfo]; + } + } + + if (error == nil) { + int64_t offset = [sizeReceivedHeader longLongValue]; + int64_t fullUploadLength = [self fullUploadLength]; + if (offset >= fullUploadLength || uploadStatus == kStatusFinal) { + // Handle we're done + [self chunkFetcher:queryFetcher finishedWithData:data error:nil]; + } else { + [self retrieveUploadChunkGranularityFromResponseHeaders:responseHeaders]; + [self uploadNextChunkWithOffset:offset]; + } + } else { + // Handle query error + [self chunkFetcher:queryFetcher finishedWithData:data error:error]; + } +} + +- (void)sendCancelUploadWithFetcherProperties:(NSDictionary *)props { + GTMSessionFetcher *cancelFetcher = [self uploadFetcherWithProperties:props + isQueryFetch:YES]; + cancelFetcher.bodyData = [NSData data]; + + NSString *originalComment = self.comment; + [cancelFetcher setCommentWithFormat:@"%@ (cancel)", + originalComment ? originalComment : @"upload"]; + + [cancelFetcher setRequestValue:@"cancel" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + + self.fetcherInFlight = cancelFetcher; + [cancelFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + self.fetcherInFlight = nil; + if (error) { + GTMSESSION_LOG_DEBUG(@"cancelFetcher %@", error); + } + }]; +} + +- (void)uploadNextChunkWithOffset:(int64_t)offset + fetcherProperties:(NSDictionary *)props { + GTMSessionCheckNotSynchronized(self); + + // Example chunk headers: + // X-Goog-Upload-Command: upload, finalize + // X-Goog-Upload-Offset: 0 + // Content-Length: 2000000 + // Content-Type: image/jpeg + // + // {bytes 0-1999999} + + // The chunk upload URL requires no authentication header. + GTMSessionFetcher *chunkFetcher = [self uploadFetcherWithProperties:props + isQueryFetch:NO]; + [self attachSendProgressBlockToChunkFetcher:chunkFetcher]; + + BOOL isUploadingFileURL = (self.uploadFileURL != nil); + + // Upload another chunk, meeting server-required granularity. + int64_t chunkSize = self.chunkSize; + + int64_t fullUploadLength = [self fullUploadLength]; + + BOOL isUploadingFullFile = (offset == 0 && chunkSize >= fullUploadLength); + if (!isUploadingFileURL || !isUploadingFullFile) { + // We're not uploading the entire file and given the file URL. Since we'll be + // allocating a subdata block for a chunk, we need to bound it to something that + // won't blow the process's memory. + if (chunkSize > kGTMSessionUploadFetcherMaximumDemandBufferSize) { + chunkSize = kGTMSessionUploadFetcherMaximumDemandBufferSize; + } + } + + int64_t granularity = self.uploadGranularity; + if (granularity > 0) { + if (chunkSize < granularity) { + chunkSize = granularity; + } else { + chunkSize = chunkSize - (chunkSize % granularity); + } + } + + GTMSESSION_ASSERT_DEBUG(offset < fullUploadLength || fullUploadLength == 0, + @"offset %lld exceeds data length %lld", offset, fullUploadLength); + + if (granularity > 0) { + offset = offset - (offset % granularity); + } + + // If the chunk size is bigger than the remaining data, or else + // it's close enough in size to the remaining data that we'd rather + // avoid having a whole extra http fetch for the leftover bit, then make + // this chunk size exactly match the remaining data size + NSString *command; + int64_t thisChunkSize = chunkSize; + + BOOL isChunkTooBig = (thisChunkSize >= (fullUploadLength - offset)); + BOOL isChunkAlmostBigEnough = (fullUploadLength - offset - 2500 < thisChunkSize); + BOOL isFinalChunk = isChunkTooBig || isChunkAlmostBigEnough; + if (isFinalChunk) { + thisChunkSize = fullUploadLength - offset; + if (thisChunkSize > 0) { + command = @"upload, finalize"; + } else { + command = @"finalize"; + } + } else { + command = @"upload"; + } + NSString *lengthStr = @(thisChunkSize).stringValue; + NSString *offsetStr = @(offset).stringValue; + + [chunkFetcher setRequestValue:command forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + [chunkFetcher setRequestValue:lengthStr forHTTPHeaderField:@"Content-Length"]; + [chunkFetcher setRequestValue:offsetStr forHTTPHeaderField:kGTMSessionHeaderXGoogUploadOffset]; + + // Append the range of bytes in this chunk to the fetcher comment. + NSString *baseComment = self.comment; + [chunkFetcher setCommentWithFormat:@"%@ (%lld-%lld)", + baseComment ? baseComment : @"upload", offset, MAX(0, offset + thisChunkSize - 1)]; + + // The chunk size may have changed, so determine again if we're uploading the full file. + isUploadingFullFile = (offset == 0 && thisChunkSize >= fullUploadLength); + if (isUploadingFullFile && isUploadingFileURL) { + // The data is the full upload file URL. + chunkFetcher.bodyFileURL = self.uploadFileURL; + [self beginChunkFetcher:chunkFetcher + offset:offset]; + } else { + // Make an NSData for the subset for this upload chunk. + self.subdataGenerating = YES; + [self generateChunkSubdataWithOffset:offset + length:thisChunkSize + response:^(NSData *chunkData, NSError *chunkError) { + // The subdata methods may leave us on a background thread. + dispatch_async(dispatch_get_main_queue(), ^{ + self.subdataGenerating = NO; + if (chunkData == nil) { + NSError *responseError = chunkError; + if (!responseError) { + responseError = [self uploadChunkUnavailableErrorWithDescription:@"chunkData is nil"]; + } + [self invokeFinalCallbackWithData:nil + error:responseError + shouldInvalidateLocation:YES]; + return; + } + + BOOL didWriteFile = NO; + if (isUploadingFileURL) { + // Make a temporary file with the data subset. + NSString *tempName = + [NSString stringWithFormat:@"GTMUpload_temp_%@", [[NSUUID UUID] UUIDString]]; + NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:tempName]; + NSError *writeError; + didWriteFile = [chunkData writeToFile:tempPath + options:NSDataWritingAtomic + error:&writeError]; + if (didWriteFile) { + chunkFetcher.bodyFileURL = [NSURL fileURLWithPath:tempPath]; + } else { + GTMSESSION_LOG_DEBUG(@"writeToFile failed: %@\n%@", writeError, tempPath); + } + } + if (!didWriteFile) { + chunkFetcher.bodyData = [chunkData copy]; + } + [self beginChunkFetcher:chunkFetcher + offset:offset]; + }); + }]; + } +} + +- (void)beginChunkFetcher:(GTMSessionFetcher *)chunkFetcher + offset:(int64_t)offset { + + // Track the current offset for progress reporting + self.currentOffset = offset; + + // Hang on to the fetcher in case we need to cancel it. We set these before beginning the + // chunk fetch so the observers notified of chunk fetches can inspect the upload fetcher to + // match to the chunk. + self.chunkFetcher = chunkFetcher; + self.fetcherInFlight = chunkFetcher; + + // Update the last chunk request, including any request headers. + self.lastChunkRequest = chunkFetcher.request; + + [chunkFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; +} + +- (void)attachSendProgressBlockToChunkFetcher:(GTMSessionFetcher *)chunkFetcher { + chunkFetcher.sendProgressBlock = ^(int64_t bytesSent, int64_t totalBytesSent, + int64_t totalBytesExpectedToSend) { + // The total bytes expected include the initial body and the full chunked + // data, independent of how big this fetcher's chunk is. + int64_t initialBodySent = [self bodyLength]; // TODO(grobbins) use [self initialBodySent] + int64_t totalSent = initialBodySent + self.currentOffset + totalBytesSent; + int64_t totalExpected = initialBodySent + [self fullUploadLength]; + + [self invokeDelegateWithDidSendBytes:bytesSent + totalBytesSent:totalSent + totalBytesExpectedToSend:totalExpected]; + }; +} + +- (NSDictionary *)uploadSessionIdentifierMetadata { + NSMutableDictionary *metadata = [NSMutableDictionary dictionary]; + metadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] = @YES; + GTMSESSION_ASSERT_DEBUG(self.uploadFileURL, + @"Invalid upload fetcher to create session identifier for metadata"); + metadata[kGTMSessionIdentifierUploadFileURLMetadataKey] = [self.uploadFileURL absoluteString]; + metadata[kGTMSessionIdentifierUploadFileLengthMetadataKey] = @([self fullUploadLength]); + + if (self.uploadLocationURL) { + metadata[kGTMSessionIdentifierUploadLocationURLMetadataKey] = + [self.uploadLocationURL absoluteString]; + } + if (self.uploadMIMEType) { + metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey] = self.uploadMIMEType; + } + metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] = @(self.chunkSize); + metadata[kGTMSessionIdentifierUploadCurrentOffsetMetadataKey] = @(self.currentOffset); + return metadata; +} + +- (GTMSessionFetcher *)uploadFetcherWithProperties:(NSDictionary *)properties + isQueryFetch:(BOOL)isQueryFetch { + GTMSessionCheckNotSynchronized(self); + + // Common code to make a request for a query command or for a chunk upload. + NSURL *uploadLocationURL = self.uploadLocationURL; + NSMutableURLRequest *chunkRequest = [NSMutableURLRequest requestWithURL:uploadLocationURL]; + [chunkRequest setHTTPMethod:@"PUT"]; + + // copy the user-agent from the original connection + NSURLRequest *origRequest = self.request; + NSString *userAgent = [origRequest valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent.length > 0) { + [chunkRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + // To avoid timeouts when debugging, copy the timeout of the initial fetcher. + NSTimeInterval origTimeout = [origRequest timeoutInterval]; + [chunkRequest setTimeoutInterval:origTimeout]; + + // + // Make a new chunk fetcher. + // + GTMSessionFetcher *chunkFetcher = [GTMSessionFetcher fetcherWithRequest:chunkRequest]; + chunkFetcher.callbackQueue = self.callbackQueue; + chunkFetcher.sessionUserInfo = self.sessionUserInfo; + chunkFetcher.configurationBlock = self.configurationBlock; + chunkFetcher.allowedInsecureSchemes = self.allowedInsecureSchemes; + chunkFetcher.allowLocalhostRequest = self.allowLocalhostRequest; + chunkFetcher.allowInvalidServerCertificates = self.allowInvalidServerCertificates; + chunkFetcher.useUploadTask = !isQueryFetch; + + if (self.uploadFileURL && !isQueryFetch && self.useBackgroundSession) { + [chunkFetcher createSessionIdentifierWithMetadata:[self uploadSessionIdentifierMetadata]]; + } + + // Give the chunk fetcher the same properties as the previous chunk fetcher + chunkFetcher.properties = [properties mutableCopy]; + [chunkFetcher setProperty:[NSValue valueWithNonretainedObject:self] + forKey:kGTMSessionUploadFetcherChunkParentKey]; + + // copy other fetcher settings to the new fetcher + chunkFetcher.retryEnabled = self.retryEnabled; + chunkFetcher.maxRetryInterval = self.maxRetryInterval; + + if ([self isRetryEnabled]) { + // We interpose our own retry method both so we can change the request to ask the server to + // tell us where to resume the chunk. + chunkFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *chunkError, + GTMSessionFetcherRetryResponse response){ + void (^finish)(BOOL) = ^(BOOL shouldRetry){ + // We'll retry by sending an offset query. + if (shouldRetry) { + self.shouldInitiateOffsetQuery = YES; + + // We don't know what our actual offset is anymore, but the server will tell us. + self.currentOffset = 0; + } + // We don't actually want to retry this specific fetcher. + response(NO); + }; + + GTMSessionFetcherRetryBlock retryBlock = self.retryBlock; + if (retryBlock) { + // Ask the client, then call the finish block above. + retryBlock(suggestedWillRetry, chunkError, finish); + } else { + finish(suggestedWillRetry); + } + }; + } + + return chunkFetcher; +} + +- (void)chunkFetcher:(GTMSessionFetcher *)chunkFetcher + finishedWithData:(NSData *)data + error:(NSError *)error { + BOOL hasDestroyedOldChunkFetcher = NO; + self.fetcherInFlight = nil; + + NSDictionary *responseHeaders = [chunkFetcher responseHeaders]; + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown + || error != nil + || self.wasCreatedFromBackgroundSession, + @"chunk fetcher completion has kStatusUnknown upload status for headers %@ fetcher %@", + responseHeaders, self); + BOOL isUploadStatusStopped = (uploadStatus == kStatusFinal || uploadStatus == kStatusCancelled); + + int64_t previousContentLength = + [[chunkFetcher.request valueForHTTPHeaderField:@"Content-Length"] longLongValue]; + // The Content-Length header may not be present if the chunk fetcher was recreated from + // a background session. + BOOL hasKnownChunkSize = (previousContentLength > 0); + BOOL needsQuery = (!hasKnownChunkSize && !isUploadStatusStopped); + + if (error || needsQuery) { + NSInteger status = error.code; + + // Status 4xx indicates a bad offset in the Google upload protocol. However, do not retry status + // 404 per spec, nor if the upload size appears to have been zero (since the server will just + // keep asking us to retry.) + if (self.shouldInitiateOffsetQuery || + needsQuery || + ([error.domain isEqual:kGTMSessionFetcherStatusDomain] && + status >= 400 && status <= 499 && + status != 404 && + uploadStatus == kStatusActive && + previousContentLength > 0)) { + self.shouldInitiateOffsetQuery = NO; + [self destroyChunkFetcher]; + hasDestroyedOldChunkFetcher = YES; + [self sendQueryForUploadOffsetWithFetcherProperties:chunkFetcher.properties]; + } else { + // Some unexpected status has occurred; handle it as we would a regular + // object fetcher failure. + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:NO]; + } + } else { + // The chunk has uploaded successfully. + int64_t newOffset = self.currentOffset + previousContentLength; +#if DEBUG + // Verify that if we think all of the uploading data has been sent, the server responded with + // the "final" upload status. + BOOL hasUploadAllData = (newOffset == [self fullUploadLength]); + BOOL isFinalStatus = (uploadStatus == kStatusFinal); + #pragma unused(hasUploadAllData,isFinalStatus) + GTMSESSION_ASSERT_DEBUG(hasUploadAllData == isFinalStatus || !hasKnownChunkSize, + @"uploadStatus:%@ newOffset:%zd (%lld + %zd) fullUploadLength:%lld" + @" chunkFetcher:%@ requestHeaders:%@ responseHeaders:%@", + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], + newOffset, self.currentOffset, previousContentLength, + [self fullUploadLength], + chunkFetcher, chunkFetcher.request.allHTTPHeaderFields, + responseHeaders); +#endif + if (isUploadStatusStopped) { + // This was the last chunk. + if (error == nil && uploadStatus == kStatusCancelled) { + // Report cancelled status as an error. + NSDictionary *userInfo = nil; + if (data.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : data }; + } + data = nil; + error = [self prematureFailureErrorWithUserInfo:userInfo]; + } else { + // The upload is in final status. + // + // Take the chunk fetcher's data as the superclass data. + self.downloadedData = data; + self.statusCode = chunkFetcher.statusCode; + } + + // we're done + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + } else { + // Start the next chunk. + self.currentOffset = newOffset; + + // We want to destroy this chunk fetcher before creating the next one, but + // we want to pass on its properties + NSDictionary *props = [chunkFetcher properties]; + + // We no longer need to be able to cancel this chunkFetcher. Destroy it + // before we create a new chunk fetcher. + [self destroyChunkFetcher]; + hasDestroyedOldChunkFetcher = YES; + + [self uploadNextChunkWithOffset:newOffset + fetcherProperties:props]; + } + } + if (!hasDestroyedOldChunkFetcher) { + [self destroyChunkFetcher]; + } +} + +- (void)destroyChunkFetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_fetcherInFlight == _chunkFetcher) { + _fetcherInFlight = nil; + } + + [_chunkFetcher stopFetching]; + + NSURL *chunkFileURL = _chunkFetcher.bodyFileURL; + BOOL wasTemporaryUploadFile = ![chunkFileURL isEqual:_uploadFileURL]; + if (wasTemporaryUploadFile) { + NSError *error; + [[NSFileManager defaultManager] removeItemAtURL:chunkFileURL + error:&error]; + if (error) { + GTMSESSION_LOG_DEBUG(@"removingItemAtURL failed: %@\n%@", error, chunkFileURL); + } + } + + _recentChunkReponseHeaders = _chunkFetcher.responseHeaders; + + // To avoid retain cycles, remove all properties except the parent identifier. + _chunkFetcher.properties = + @{ kGTMSessionUploadFetcherChunkParentKey : [NSValue valueWithNonretainedObject:self] }; + + _chunkFetcher.retryBlock = nil; + _chunkFetcher.sendProgressBlock = nil; + _chunkFetcher = nil; + } // @synchronized(self) +} + +// This method calculates the proper values to pass to the client's send progress block. +// +// The actual total bytes sent include the initial body sent, plus the +// offset into the batched data prior to the current chunk fetcher + +- (void)invokeDelegateWithDidSendBytes:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpected { + GTMSessionCheckNotSynchronized(self); + + // Ensure the chunk fetcher survives the callback in case the user pauses the upload process. + __block GTMSessionFetcher *holdFetcher = self.chunkFetcher; + + [self invokeOnCallbackQueue:self.delegateCallbackQueue + afterUserStopped:NO + block:^{ + GTMSessionFetcherSendProgressBlock sendProgressBlock = self.sendProgressBlock; + if (sendProgressBlock) { + sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpected); + } + holdFetcher = nil; + }]; +} + +- (void)retrieveUploadChunkGranularityFromResponseHeaders:(NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + + // Standard granularity for Google uploads is 256K. + NSString *chunkGranularityHeader = + [responseHeaders objectForKey:@"X-Goog-Upload-Chunk-Granularity"]; + self.uploadGranularity = chunkGranularityHeader.longLongValue; +} + +#pragma mark - + +- (BOOL)isPaused { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isPaused; + } // @synchronized(self) +} + +- (void)pauseFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _isPaused = YES; + } // @synchronized(self) + + // Pausing just means stopping the current chunk from uploading; + // when we resume, we will send a query request to the server to + // figure out what bytes to resume sending. + // + // We won't try to cancel the initial data upload, but rather will check + // for being paused in beginChunkFetches. + [self destroyChunkFetcher]; +} + +- (void)resumeFetching { + BOOL wasPaused; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + wasPaused = _isPaused; + _isPaused = NO; + } // @synchronized(self) + + if (wasPaused) { + [self sendQueryForUploadOffsetWithFetcherProperties:self.properties]; + } +} + +- (void)stopFetching { + // Overrides the superclass + [self destroyChunkFetcher]; + + // If we think the server is waiting for more data, then tell it there won't be more. + if (self.uploadLocationURL) { + [self sendCancelUploadWithFetcherProperties:[self properties]]; + self.uploadLocationURL = nil; + } + + [super stopFetching]; +} + +#pragma mark - + +// Public properties. +@synthesize currentOffset = _currentOffset, + delegateCompletionHandler = _delegateCompletionHandler, + chunkFetcher = _chunkFetcher, + lastChunkRequest = _lastChunkRequest, + subdataGenerating = _subdataGenerating, + shouldInitiateOffsetQuery = _shouldInitiateOffsetQuery, + uploadGranularity = _uploadGranularity; + +// Internal properties. +@dynamic fetcherInFlight; +@dynamic activeFetcher; +@dynamic statusCode; +@dynamic delegateCallbackQueue; + ++ (void)removePointer:(void *)pointer fromPointerArray:(NSPointerArray *)pointerArray { + for (NSUInteger index = 0; index < pointerArray.count; ++index) { + void *pointerAtIndex = [pointerArray pointerAtIndex:index]; + if (pointerAtIndex == pointer) { + [pointerArray removePointerAtIndex:index]; + return; + } + } +} + +- (BOOL)useBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _useBackgroundSessionOnChunkFetchers; + } // @synchronized(self +} + +- (void)setUseBackgroundSession:(BOOL)useBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_useBackgroundSessionOnChunkFetchers != useBackgroundSession) { + _useBackgroundSessionOnChunkFetchers = useBackgroundSession; + NSPointerArray *uploadFetcherPointerArrayForBackgroundSessions = + [[self class] uploadFetcherPointerArrayForBackgroundSessions]; + if (_useBackgroundSessionOnChunkFetchers) { + [uploadFetcherPointerArrayForBackgroundSessions addPointer:(__bridge void *)self]; + } else { + [[self class] removePointer:(__bridge void *)self + fromPointerArray:uploadFetcherPointerArrayForBackgroundSessions]; + } + } + } // @synchronized(self +} + +- (BOOL)canFetchWithBackgroundSession { + // The initial upload fetcher is always a foreground session; the + // useBackgroundSession property will apply only to chunk fetchers, + // not to queries. + return NO; +} + +- (NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + // Overrides the superclass + + // If asked for the fetcher's response, use the most recent chunk fetcher's response, + // since the original request's response lacks useful information like the actual + // Content-Type. + NSDictionary *dict = self.chunkFetcher.responseHeaders; + if (dict) { + return dict; + } + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_recentChunkReponseHeaders) { + return _recentChunkReponseHeaders; + } + } // @synchronized(self + + // No chunk fetcher yet completed, so return whatever we have from the initial fetch. + return [super responseHeaders]; +} + +- (NSInteger)statusCodeUnsynchronized { + GTMSessionCheckSynchronized(self); + + if (_recentChunkStatusCode != -1) { + // Overrides the superclass to indicate status appropriate to the initial + // or latest chunk fetch + return _recentChunkStatusCode; + } else { + return [super statusCodeUnsynchronized]; + } +} + + +- (void)setStatusCode:(NSInteger)val { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _recentChunkStatusCode = val; + } +} + +- (int64_t)initialBodyLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _initialBodyLength; + } +} + +- (void)setInitialBodyLength:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _initialBodyLength = length; + } +} + +- (int64_t)initialBodySent { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _initialBodySent; + } +} + +- (void)setInitialBodySent:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _initialBodySent = length; + } +} + +- (NSURL *)uploadLocationURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadLocationURL; + } +} + +- (void)setUploadLocationURL:(NSURL *)locationURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadLocationURL = locationURL; + } +} + +- (GTMSessionFetcher *)activeFetcher { + GTMSessionFetcher *result = self.fetcherInFlight; + if (result) return result; + + return self; +} + +- (BOOL)isFetching { + // If there is an active chunk fetcher, then the upload fetcher is considered + // to still be fetching. + if (self.fetcherInFlight != nil) return YES; + + return [super isFetching]; +} + +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds { + NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + + while (self.fetcherInFlight || self.subdataGenerating) { + if ([timeoutDate timeIntervalSinceNow] < 0) return NO; + + if (self.subdataGenerating) { + // Allow time for subdata generation. + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:0.001]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + // Wait for any chunk or query fetchers that still have pending callbacks or + // notifications. + BOOL timedOut; + + if (self.fetcherInFlight == self) { + timedOut = ![super waitForCompletionWithTimeout:timeoutInSeconds]; + } else { + timedOut = ![self.fetcherInFlight waitForCompletionWithTimeout:timeoutInSeconds]; + } + if (timedOut) return NO; + } + } + return YES; +} + +@end + +@implementation GTMSessionFetcher (GTMSessionUploadFetcherMethods) + +- (GTMSessionUploadFetcher *)parentUploadFetcher { + NSValue *property = [self propertyForKey:kGTMSessionUploadFetcherChunkParentKey]; + if (!property) return nil; + + GTMSessionUploadFetcher *uploadFetcher = property.nonretainedObjectValue; + + GTMSESSION_ASSERT_DEBUG([uploadFetcher isKindOfClass:[GTMSessionUploadFetcher class]], + @"Unexpected parent upload fetcher class: %@", [uploadFetcher class]); + return uploadFetcher; +} + +@end diff --git a/Code Burner/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugSelectorValidation.h b/Code Burner/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugSelectorValidation.h new file mode 100644 index 0000000..2396524 --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugSelectorValidation.h @@ -0,0 +1,100 @@ +// +// GTMDebugSelectorValidation.h +// +// This file should only be included within an implimation file. In any +// function that takes an object and selector to invoke, you should call: +// +// GTMAssertSelectorNilOrImplementedWithArguments(obj, sel, @encode(arg1type), ..., NULL) +// or +// GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(obj, sel, @encode(returnType), @encode(arg1type), ..., NULL) +// +// This will then validate that the selector is defined and using the right +// type(s), this can help catch errors much earlier then waiting for the +// selector to actually fire (and in the case of error selectors, might never +// really be tested until in the field). +// +// Copyright 2007-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#if DEBUG + +#import +#import "GTMDefines.h" + +static void GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(id obj, SEL sel, const char *retType, ...) { + + // verify that the object's selector is implemented with the proper + // number and type of arguments + va_list argList; + va_start(argList, retType); + + if (obj && sel) { + // check that the selector is implemented + _GTMDevAssert([obj respondsToSelector:sel], + @"\"%@\" selector \"%@\" is unimplemented or misnamed", + NSStringFromClass([obj class]), + NSStringFromSelector(sel)); + + const char *expectedArgType; + NSUInteger argCount = 2; // skip self and _cmd + NSMethodSignature *sig = [obj methodSignatureForSelector:sel]; + + // check that each expected argument is present and of the correct type + while ((expectedArgType = va_arg(argList, const char*)) != 0) { + + if ([sig numberOfArguments] > argCount) { + const char *foundArgType = [sig getArgumentTypeAtIndex:argCount]; + + _GTMDevAssert(0 == strncmp(foundArgType, expectedArgType, strlen(expectedArgType)), + @"\"%@\" selector \"%@\" argument %u should be type %s", + NSStringFromClass([obj class]), + NSStringFromSelector(sel), + (uint32_t)(argCount - 2), + expectedArgType); + } + argCount++; + } + + // check that the proper number of arguments are present in the selector + _GTMDevAssert(argCount == [sig numberOfArguments], + @"\"%@\" selector \"%@\" should have %u arguments", + NSStringFromClass([obj class]), + NSStringFromSelector(sel), + (uint32_t)(argCount - 2)); + + // if asked, validate the return type + if (retType && (strcmp("gtm_skip_return_test", retType) != 0)) { + const char *foundRetType = [sig methodReturnType]; + _GTMDevAssert(0 == strncmp(foundRetType, retType, strlen(retType)), + @"\"%@\" selector \"%@\" return type should be type %s", + NSStringFromClass([obj class]), + NSStringFromSelector(sel), + retType); + } + } + + va_end(argList); +} + +#define GTMAssertSelectorNilOrImplementedWithArguments(obj, sel, ...) \ + GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments((obj), (sel), "gtm_skip_return_test", __VA_ARGS__) + +#else // DEBUG + +// make it go away if not debug +#define GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(obj, sel, retType, ...) do { } while (0) +#define GTMAssertSelectorNilOrImplementedWithArguments(obj, sel, ...) do { } while (0) + +#endif // DEBUG diff --git a/Code Burner/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugThreadValidation.h b/Code Burner/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugThreadValidation.h new file mode 100644 index 0000000..3f50f17 --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugThreadValidation.h @@ -0,0 +1,44 @@ +// +// GTMDebugThreadValidation.h +// +// Copyright 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMDefines.h" +#import + +// GTMCheckCurrentQueue, GTMIsCurrentQueue +// +// GTMCheckCurrentQueue takes a target queue and uses _GTMDevAssert to +// report if that is not the currently executing queue. +// +// GTMIsCurrentQueue takes a target queue and returns true if the target queue +// is the currently executing dispatch queue. This can be passed to another +// assertion call in debug builds; it should never be used in release code. +// +// The dispatch queue must have a label. +#define GTMCheckCurrentQueue(targetQueue) \ + _GTMDevAssert(GTMIsCurrentQueue(targetQueue), \ + @"Current queue is %s (expected %s)", \ + _GTMQueueName(DISPATCH_CURRENT_QUEUE_LABEL), \ + _GTMQueueName(targetQueue)) + +#define GTMIsCurrentQueue(targetQueue) \ + (strcmp(_GTMQueueName(DISPATCH_CURRENT_QUEUE_LABEL), \ + _GTMQueueName(targetQueue)) == 0) + +#define _GTMQueueName(queue) \ + (strlen(dispatch_queue_get_label(queue)) > 0 ? \ + dispatch_queue_get_label(queue) : "unnamed") diff --git a/Code Burner/Pods/GoogleToolboxForMac/DebugUtils/GTMMethodCheck.h b/Code Burner/Pods/GoogleToolboxForMac/DebugUtils/GTMMethodCheck.h new file mode 100644 index 0000000..9fad81d --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/DebugUtils/GTMMethodCheck.h @@ -0,0 +1,69 @@ +// +// GTMMethodCheck.h +// +// Copyright 2006-2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import +#import +#import + +/// A macro for enforcing debug time checks to make sure all required methods are linked in +// +// When using categories, it can be very easy to forget to include the +// implementation of a category. +// Let's say you had a class foo that depended on method bar of class baz, and +// method bar was implemented as a member of a category. +// You could add the following code: +// +// GTM_METHOD_CHECK(baz, bar) +// +// and the code would check to make sure baz was implemented just before main +// was called. This works for both dynamic libraries, and executables. +// +// +// This is not compiled into release builds. + +#ifdef DEBUG + +// This is the "magic". +// A) we need a multi layer define here so that the preprocessor expands +// __LINE__ the way we want it. We need __LINE__ so that each of our +// GTM_METHOD_CHECKs generates a unique function name. +#define GTM_METHOD_CHECK(class, method) GTM_METHOD_CHECK_INNER(class, method, __LINE__) +#define GTM_METHOD_CHECK_INNER(class, method, line) \ + GTM_METHOD_CHECK_INNER_INNER(class, method, line) + +// B) define a function that is called at startup to check that |class| has an +// implementation for |method| (either a class method or an instance method). +#define GTM_METHOD_CHECK_INNER_INNER(class, method, line) \ +__attribute__ ((constructor, visibility("hidden"))) \ + static void xxGTMMethodCheckMethod ## class ## line () { \ + @autoreleasepool { \ + if (![class instancesRespondToSelector:@selector(method)] \ + && ![class respondsToSelector:@selector(method)]) { \ + fprintf(stderr, "%s:%d: error: We need method '%s' to be linked in for class '%s'\n", \ + __FILE__, line, #method, #class); \ + exit(EX_SOFTWARE); \ + } \ + } \ +} + +#else // DEBUG + +// Do nothing in release. +#define GTM_METHOD_CHECK(class, method) + +#endif // DEBUG diff --git a/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.h b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.h new file mode 100644 index 0000000..dceadc4 --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.h @@ -0,0 +1,199 @@ +// +// GTMNSData+zlib.h +// +// Copyright 2007-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import +#import "GTMDefines.h" + +/// Helpers for dealing w/ zlib inflate/deflate calls. +@interface NSData (GTMZLibAdditions) + +// NOTE: For 64bit, none of these apis handle input sizes >32bits, they will +// return nil when given such data. To handle data of that size you really +// should be streaming it rather then doing it all in memory. + +#pragma mark Gzip Compression + +/// Return an autoreleased NSData w/ the result of gzipping the bytes. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length; ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of gzipping the payload of |data|. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByGzippingData:(NSData *)data __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of gzipping the bytes using |level| compression level. +// +// |level| can be 1-9, any other values will be clipped to that range. ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of gzipping the payload of |data| using |level| compression level. ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error; + +#pragma mark Zlib "Stream" Compression + +// NOTE: deflate is *NOT* gzip. deflate is a "zlib" stream. pick which one +// you really want to create. (the inflate api will handle either) + +/// Return an autoreleased NSData w/ the result of deflating the bytes. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of deflating the payload of |data|. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of deflating the bytes using |level| compression level. +// +// |level| can be 1-9, any other values will be clipped to that range. ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of deflating the payload of |data| using |level| compression level. ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error; + +#pragma mark Uncompress of Gzip or Zlib + +/// Return an autoreleased NSData w/ the result of decompressing the bytes. +// +// The bytes to decompress can be zlib or gzip payloads. ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of decompressing the payload of |data|. +// +// The data to decompress can be zlib or gzip payloads. ++ (NSData *)gtm_dataByInflatingData:(NSData *)data __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByInflatingData:(NSData *)data + error:(NSError **)error; + +#pragma mark "Raw" Compression Support + +// NOTE: raw deflate is *NOT* gzip or deflate. it does not include a header +// of any form and should only be used within streams here an external crc/etc. +// is done to validate the data. The RawInflate apis can be used on data +// processed like this. + +/// Return an autoreleased NSData w/ the result of *raw* deflating the bytes. +// +// Uses the default compression level. +// *No* header is added to the resulting data. ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of *raw* deflating the payload of |data|. +// +// Uses the default compression level. +// *No* header is added to the resulting data. ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of *raw* deflating the bytes using |level| compression level. +// +// |level| can be 1-9, any other values will be clipped to that range. +// *No* header is added to the resulting data. ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of *raw* deflating the payload of |data| using |level| compression level. +// *No* header is added to the resulting data. ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of *raw* decompressing the bytes. +// +// The data to decompress, it should *not* have any header (zlib nor gzip). ++ (NSData *)gtm_dataByRawInflatingBytes:(const void *)bytes + length:(NSUInteger)length __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawInflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of *raw* decompressing the payload of |data|. +// +// The data to decompress, it should *not* have any header (zlib nor gzip). ++ (NSData *)gtm_dataByRawInflatingData:(NSData *)data __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawInflatingData:(NSData *)data + error:(NSError **)error; + +@end + +FOUNDATION_EXPORT NSString *const GTMNSDataZlibErrorDomain; +FOUNDATION_EXPORT NSString *const GTMNSDataZlibErrorKey; // NSNumber +FOUNDATION_EXPORT NSString *const GTMNSDataZlibRemainingBytesKey; // NSNumber + +typedef NS_ENUM(NSInteger, GTMNSDataZlibError) { + GTMNSDataZlibErrorGreaterThan32BitsToCompress = 1024, + // An internal zlib error. + // GTMNSDataZlibErrorKey will contain the error value. + // NSLocalizedDescriptionKey may contain an error string from zlib. + // Look in zlib.h for list of errors. + GTMNSDataZlibErrorInternal, + // There was left over data in the buffer that was not used. + // GTMNSDataZlibRemainingBytesKey will contain number of remaining bytes. + GTMNSDataZlibErrorDataRemaining +}; diff --git a/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.m b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.m new file mode 100644 index 0000000..bf74b2d --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.m @@ -0,0 +1,531 @@ +// +// GTMNSData+zlib.m +// +// Copyright 2007-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMNSData+zlib.h" +#import +#import "GTMDefines.h" + +#define kChunkSize 1024 + +NSString *const GTMNSDataZlibErrorDomain = @"com.google.GTMNSDataZlibErrorDomain"; +NSString *const GTMNSDataZlibErrorKey = @"GTMNSDataZlibErrorKey"; +NSString *const GTMNSDataZlibRemainingBytesKey = @"GTMNSDataZlibRemainingBytesKey"; + +typedef enum { + CompressionModeZlib, + CompressionModeGzip, + CompressionModeRaw, +} CompressionMode; + +@interface NSData (GTMZlibAdditionsPrivate) ++ (NSData *)gtm_dataByCompressingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + mode:(CompressionMode)mode + error:(NSError **)error; ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length + isRawData:(BOOL)isRawData + error:(NSError **)error; +@end + +@implementation NSData (GTMZlibAdditionsPrivate) + ++ (NSData *)gtm_dataByCompressingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + mode:(CompressionMode)mode + error:(NSError **)error { + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + if (error) { + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorGreaterThan32BitsToCompress + userInfo:nil]; + } + return nil; + } +#endif + + if (level == Z_DEFAULT_COMPRESSION) { + // the default value is actually outside the range, so we have to let it + // through specifically. + } else if (level < Z_BEST_SPEED) { + level = Z_BEST_SPEED; + } else if (level > Z_BEST_COMPRESSION) { + level = Z_BEST_COMPRESSION; + } + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + int memLevel = 8; // the default + int windowBits = 15; // the default + switch (mode) { + case CompressionModeZlib: + // nothing to do + break; + + case CompressionModeGzip: + windowBits += 16; // enable gzip header instead of zlib header + break; + + case CompressionModeRaw: + windowBits *= -1; // Negative to mean no header. + break; + } + int retCode; + if ((retCode = deflateInit2(&strm, level, Z_DEFLATED, windowBits, + memLevel, Z_DEFAULT_STRATEGY)) != Z_OK) { + // COV_NF_START - no real way to force this in a unittest (we guard all args) + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GTMNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + // COV_NF_END + } + + // hint the size at 1/4 the input size + NSMutableData *result = [NSMutableData dataWithCapacity:(length/4)]; + unsigned char output[kChunkSize]; + + // setup the input + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char*)bytes; + + // loop to collect the data + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = deflate(&strm, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + // COV_NF_START - no real way to force this in a unittest + // (in inflate, we can feed bogus/truncated data to test, but an error + // here would be some internal issue w/in zlib, and there isn't any real + // way to test it) + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GTMNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorInternal + userInfo:userInfo]; + } + deflateEnd(&strm); + return nil; + // COV_NF_END + } + // collect what we got + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // if the loop exits, we used all input and the stream ended + _GTMDevAssert(strm.avail_in == 0, + @"thought we finished deflate w/o using all input, %u bytes left", + strm.avail_in); + _GTMDevAssert(retCode == Z_STREAM_END, + @"thought we finished deflate w/o getting a result of stream end, code %d", + retCode); + + // clean up + deflateEnd(&strm); + + return result; +} // gtm_dataByCompressingBytes:length:compressionLevel:useGzip: + ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length + isRawData:(BOOL)isRawData + error:(NSError **)error { + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + return nil; + } +#endif + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + // setup the input + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char*)bytes; + + int windowBits = 15; // 15 to enable any window size + if (isRawData) { + windowBits *= -1; // make it negative to signal no header. + } else { + windowBits += 32; // and +32 to enable zlib or gzip header detection. + } + + int retCode; + if ((retCode = inflateInit2(&strm, windowBits)) != Z_OK) { + // COV_NF_START - no real way to force this in a unittest (we guard all args) + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GTMNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + // COV_NF_END + } + + // hint the size at 4x the input size + NSMutableData *result = [NSMutableData dataWithCapacity:(length*4)]; + unsigned char output[kChunkSize]; + + // loop to collect the data + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = inflate(&strm, Z_NO_FLUSH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + if (error) { + NSMutableDictionary *userInfo = + [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GTMNSDataZlibErrorKey]; + if (strm.msg) { + NSString *message = [NSString stringWithUTF8String:strm.msg]; + if (message) { + [userInfo setObject:message forKey:NSLocalizedDescriptionKey]; + } + } + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorInternal + userInfo:userInfo]; + } + inflateEnd(&strm); + return nil; + } + // collect what we got + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // make sure there wasn't more data tacked onto the end of a valid compressed + // stream. + if (strm.avail_in != 0) { + if (error) { + NSDictionary *userInfo = + [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:strm.avail_in] + forKey:GTMNSDataZlibRemainingBytesKey]; + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorDataRemaining + userInfo:userInfo]; + } + result = nil; + } + // the only way out of the loop was by hitting the end of the stream + _GTMDevAssert(retCode == Z_STREAM_END, + @"thought we finished inflate w/o getting a result of stream end, code %d", + retCode); + + // clean up + inflateEnd(&strm); + + return result; +} // gtm_dataByInflatingBytes:length:windowBits: + +@end + + +@implementation NSData (GTMZLibAdditions) + ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByGzippingBytes:bytes length:length error:NULL]; +} // gtm_dataByGzippingBytes:length: + ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error { + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeGzip + error:error]; +} // gtm_dataByGzippingBytes:length:error: + ++ (NSData *)gtm_dataByGzippingData:(NSData *)data { + return [self gtm_dataByGzippingData:data error:NULL]; +} // gtm_dataByGzippingData: + ++ (NSData *)gtm_dataByGzippingData:(NSData *)data error:(NSError **)error { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeGzip + error:error]; +} // gtm_dataByGzippingData:error: + ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level { + return [self gtm_dataByGzippingBytes:bytes + length:length + compressionLevel:level + error:NULL]; +} // gtm_dataByGzippingBytes:length:level: + ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error{ + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:level + mode:CompressionModeGzip + error:error]; +} // gtm_dataByGzippingBytes:length:level:error + ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + compressionLevel:(int)level { + return [self gtm_dataByGzippingData:data + compressionLevel:level + error:NULL]; +} // gtm_dataByGzippingData:level: + ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error{ + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:level + mode:CompressionModeGzip + error:error]; +} // gtm_dataByGzippingData:level:error + +#pragma mark - + ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByDeflatingBytes:bytes + length:length + error:NULL]; +} // gtm_dataByDeflatingBytes:length: + ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error{ + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeZlib + error:error]; +} // gtm_dataByDeflatingBytes:length:error + ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data { + return [self gtm_dataByDeflatingData:data error:NULL]; +} // gtm_dataByDeflatingData: + ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data error:(NSError **)error { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeZlib + error:error]; +} // gtm_dataByDeflatingData: + ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level { + return [self gtm_dataByDeflatingBytes:bytes + length:length + compressionLevel:level + error:NULL]; +} // gtm_dataByDeflatingBytes:length:level: + ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error { + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:level + mode:CompressionModeZlib + error:error]; +} // gtm_dataByDeflatingBytes:length:level:error: + ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + compressionLevel:(int)level { + return [self gtm_dataByDeflatingData:data + compressionLevel:level + error:NULL]; +} // gtm_dataByDeflatingData:level: + ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:level + mode:CompressionModeZlib + error:error]; +} // gtm_dataByDeflatingData:level:error: + +#pragma mark - + ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByInflatingBytes:bytes + length:length + error:NULL]; +} // gtm_dataByInflatingBytes:length: + ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error { + return [self gtm_dataByInflatingBytes:bytes + length:length + isRawData:NO + error:error]; +} // gtm_dataByInflatingBytes:length:error: + ++ (NSData *)gtm_dataByInflatingData:(NSData *)data { + return [self gtm_dataByInflatingData:data error:NULL]; +} // gtm_dataByInflatingData: + ++ (NSData *)gtm_dataByInflatingData:(NSData *)data + error:(NSError **)error { + return [self gtm_dataByInflatingBytes:[data bytes] + length:[data length] + isRawData:NO + error:error]; +} // gtm_dataByInflatingData: + +#pragma mark - + ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:NULL]; +} // gtm_dataByRawDeflatingBytes:length: + ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error { + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeRaw + error:error]; +} // gtm_dataByRawDeflatingBytes:length:error: + ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data { + return [self gtm_dataByRawDeflatingData:data error:NULL]; +} // gtm_dataByRawDeflatingData: + ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data error:(NSError **)error { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeRaw + error:error]; +} // gtm_dataByRawDeflatingData:error: + ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level { + return [self gtm_dataByRawDeflatingBytes:bytes + length:length + compressionLevel:level + error:NULL]; +} // gtm_dataByRawDeflatingBytes:length:compressionLevel: + ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error{ + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:level + mode:CompressionModeRaw + error:error]; +} // gtm_dataByRawDeflatingBytes:length:compressionLevel:error: + ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data + compressionLevel:(int)level { + return [self gtm_dataByRawDeflatingData:data + compressionLevel:level + error:NULL]; +} // gtm_dataByRawDeflatingData:compressionLevel: + ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:level + mode:CompressionModeRaw + error:error]; +} // gtm_dataByRawDeflatingData:compressionLevel:error: + ++ (NSData *)gtm_dataByRawInflatingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByInflatingBytes:bytes + length:length + error:NULL]; +} // gtm_dataByRawInflatingBytes:length: + ++ (NSData *)gtm_dataByRawInflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error{ + return [self gtm_dataByInflatingBytes:bytes + length:length + isRawData:YES + error:error]; +} // gtm_dataByRawInflatingBytes:length:error: + ++ (NSData *)gtm_dataByRawInflatingData:(NSData *)data { + return [self gtm_dataByRawInflatingData:data + error:NULL]; +} // gtm_dataByRawInflatingData: + ++ (NSData *)gtm_dataByRawInflatingData:(NSData *)data + error:(NSError **)error { + return [self gtm_dataByInflatingBytes:[data bytes] + length:[data length] + isRawData:YES + error:error]; +} // gtm_dataByRawInflatingData:error: + +@end diff --git a/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.h b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.h new file mode 100644 index 0000000..b2f0564 --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.h @@ -0,0 +1,40 @@ +// +// GTMNSDictionary+URLArguments.h +// +// Copyright 2006-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import + +/// Utility for building a URL or POST argument string. +@interface NSDictionary (GTMNSDictionaryURLArgumentsAdditions) + +/// Returns a dictionary of the decoded key-value pairs in a http arguments +/// string of the form key1=value1&key2=value2&...&keyN=valueN. +/// Keys and values will be unescaped automatically. +/// Only the first value for a repeated key is returned. +/// +/// NOTE: Apps targeting iOS 8 or OS X 10.10 and later should use +/// NSURLComponents and NSURLQueryItem to create URLs with +/// query arguments instead of using these category methods. ++ (NSDictionary *)gtm_dictionaryWithHttpArgumentsString:(NSString *)argString; + +/// Gets a string representation of the dictionary in the form +/// key1=value1&key2=value2&...&keyN=valueN, suitable for use as either +/// URL arguments (after a '?') or POST body. Keys and values will be escaped +/// automatically, so should be unescaped in the dictionary. +- (NSString *)gtm_httpArgumentsString; + +@end diff --git a/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.m b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.m new file mode 100644 index 0000000..e9fa766 --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.m @@ -0,0 +1,77 @@ +// +// GTMNSDictionary+URLArguments.m +// +// Copyright 2006-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMNSDictionary+URLArguments.h" +#import "GTMNSString+URLArguments.h" +#import "GTMMethodCheck.h" +#import "GTMDefines.h" + + +// Export a nonsense symbol to suppress a libtool warning when this is linked alone in a static lib. +__attribute__((visibility("default"))) + char GTMNSDictionaryURLArgumentsExportToSuppressLibToolWarning = 0; + + +@implementation NSDictionary (GTMNSDictionaryURLArgumentsAdditions) + +GTM_METHOD_CHECK(NSString, gtm_stringByEscapingForURLArgument); +GTM_METHOD_CHECK(NSString, gtm_stringByUnescapingFromURLArgument); + ++ (NSDictionary *)gtm_dictionaryWithHttpArgumentsString:(NSString *)argString { + NSMutableDictionary* ret = [NSMutableDictionary dictionary]; + NSArray* components = [argString componentsSeparatedByString:@"&"]; + NSString* component; + // Use reverse order so that the first occurrence of a key replaces + // those subsequent. + for (component in [components reverseObjectEnumerator]) { + if ([component length] == 0) + continue; + NSRange pos = [component rangeOfString:@"="]; + NSString *key; + NSString *val; + if (pos.location == NSNotFound) { + key = [component gtm_stringByUnescapingFromURLArgument]; + val = @""; + } else { + key = [[component substringToIndex:pos.location] + gtm_stringByUnescapingFromURLArgument]; + val = [[component substringFromIndex:pos.location + pos.length] + gtm_stringByUnescapingFromURLArgument]; + } + // gtm_stringByUnescapingFromURLArgument returns nil on invalid UTF8 + // and NSMutableDictionary raises an exception when passed nil values. + if (!key) key = @""; + if (!val) val = @""; + [ret setObject:val forKey:key]; + } + return ret; +} + +- (NSString *)gtm_httpArgumentsString { + NSMutableArray* arguments = [NSMutableArray arrayWithCapacity:[self count]]; + NSString* key; + for (key in self) { + [arguments addObject:[NSString stringWithFormat:@"%@=%@", + [key gtm_stringByEscapingForURLArgument], + [[[self objectForKey:key] description] gtm_stringByEscapingForURLArgument]]]; + } + + return [arguments componentsJoinedByString:@"&"]; +} + +@end diff --git a/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.h b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.h new file mode 100644 index 0000000..b3a3e3e --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.h @@ -0,0 +1,45 @@ +// +// GTMNSString+URLArguments.h +// +// Copyright 2006-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import + +/// Utilities for encoding and decoding URL arguments. +@interface NSString (GTMNSStringURLArgumentsAdditions) + +/// Returns a string that is escaped properly to be a URL argument. +/// +/// This differs from stringByAddingPercentEscapesUsingEncoding: in that it +/// will escape all the reserved characters (per RFC 3986 +/// ) which +/// stringByAddingPercentEscapesUsingEncoding would leave. +/// +/// This will also escape '%', so this should not be used on a string that has +/// already been escaped unless double-escaping is the desired result. +/// +/// NOTE: Apps targeting iOS 8 or OS X 10.10 and later should use +/// NSURLComponents and NSURLQueryItem to create properly-escaped +/// URLs instead of using these category methods. +- (NSString*)gtm_stringByEscapingForURLArgument; + +/// Returns the unescaped version of a URL argument +/// +/// This has the same behavior as stringByReplacingPercentEscapesUsingEncoding:, +/// except that it will also convert '+' to space. +- (NSString*)gtm_stringByUnescapingFromURLArgument; + +@end diff --git a/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.m b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.m new file mode 100644 index 0000000..e785c5e --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.m @@ -0,0 +1,48 @@ +// +// GTMNSString+URLArguments.m +// +// Copyright 2006-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMNSString+URLArguments.h" + +@implementation NSString (GTMNSStringURLArgumentsAdditions) + +- (NSString *)gtm_stringByEscapingForURLArgument { + // Encode all the reserved characters, per RFC 3986 + // () + CFStringRef escaped = + CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)self, + NULL, + (CFStringRef)@"!*'();:@&=+$,/?%#[]", + kCFStringEncodingUTF8); +#if defined(__has_feature) && __has_feature(objc_arc) + return CFBridgingRelease(escaped); +#else + return [(NSString *)escaped autorelease]; +#endif +} + +- (NSString *)gtm_stringByUnescapingFromURLArgument { + NSMutableString *resultString = [NSMutableString stringWithString:self]; + [resultString replaceOccurrencesOfString:@"+" + withString:@" " + options:NSLiteralSearch + range:NSMakeRange(0, [resultString length])]; + return [resultString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; +} + +@end diff --git a/Code Burner/Pods/GoogleToolboxForMac/GTMDefines.h b/Code Burner/Pods/GoogleToolboxForMac/GTMDefines.h new file mode 100644 index 0000000..7baa7b2 --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/GTMDefines.h @@ -0,0 +1,401 @@ +// +// GTMDefines.h +// +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +// ============================================================================ + +#include +#include + +#ifdef __OBJC__ +#include +#endif // __OBJC__ + +#if TARGET_OS_IPHONE +#include +#endif // TARGET_OS_IPHONE + +// ---------------------------------------------------------------------------- +// CPP symbols that can be overridden in a prefix to control how the toolbox +// is compiled. +// ---------------------------------------------------------------------------- + + +// By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and +// GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens +// when a validation fails. If you implement your own validators, you may want +// to control their internals using the same macros for consistency. +#ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT + #define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0 +#endif + +// Ensure __has_feature and __has_extension are safe to use. +// See http://clang-analyzer.llvm.org/annotations.html +#ifndef __has_feature // Optional. + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef __has_extension + #define __has_extension __has_feature // Compatibility with pre-3.0 compilers. +#endif + +// Give ourselves a consistent way to do inlines. Apple's macros even use +// a few different actual definitions, so we're based off of the foundation +// one. +#if !defined(GTM_INLINE) + #if (defined (__GNUC__) && (__GNUC__ == 4)) || defined (__clang__) + #define GTM_INLINE static __inline__ __attribute__((always_inline)) + #else + #define GTM_INLINE static __inline__ + #endif +#endif + +// Give ourselves a consistent way of doing externs that links up nicely +// when mixing objc and objc++ +#if !defined (GTM_EXTERN) + #if defined __cplusplus + #define GTM_EXTERN extern "C" + #define GTM_EXTERN_C_BEGIN extern "C" { + #define GTM_EXTERN_C_END } + #else + #define GTM_EXTERN extern + #define GTM_EXTERN_C_BEGIN + #define GTM_EXTERN_C_END + #endif +#endif + +// Give ourselves a consistent way of exporting things if we have visibility +// set to hidden. +#if !defined (GTM_EXPORT) + #define GTM_EXPORT __attribute__((visibility("default"))) +#endif + +// Give ourselves a consistent way of declaring something as unused. This +// doesn't use __unused because that is only supported in gcc 4.2 and greater. +#if !defined (GTM_UNUSED) +#define GTM_UNUSED(x) ((void)(x)) +#endif + +// _GTMDevLog & _GTMDevAssert +// +// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for +// developer level errors. This implementation simply macros to NSLog/NSAssert. +// It is not intended to be a general logging/reporting system. +// +// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert +// for a little more background on the usage of these macros. +// +// _GTMDevLog log some error/problem in debug builds +// _GTMDevAssert assert if condition isn't met w/in a method/function +// in all builds. +// +// To replace this system, just provide different macro definitions in your +// prefix header. Remember, any implementation you provide *must* be thread +// safe since this could be called by anything in what ever situtation it has +// been placed in. +// + +// We only define the simple macros if nothing else has defined this. +#ifndef _GTMDevLog + +#ifdef DEBUG + #define _GTMDevLog(...) NSLog(__VA_ARGS__) +#else + #define _GTMDevLog(...) do { } while (0) +#endif + +#endif // _GTMDevLog + +#ifndef _GTMDevAssert +// we directly invoke the NSAssert handler so we can pass on the varargs +// (NSAssert doesn't have a macro we can use that takes varargs) +#if !defined(NS_BLOCK_ASSERTIONS) + #define _GTMDevAssert(condition, ...) \ + do { \ + if (!(condition)) { \ + [[NSAssertionHandler currentHandler] \ + handleFailureInFunction:(NSString *) \ + [NSString stringWithUTF8String:__PRETTY_FUNCTION__] \ + file:(NSString *)[NSString stringWithUTF8String:__FILE__] \ + lineNumber:__LINE__ \ + description:__VA_ARGS__]; \ + } \ + } while(0) +#else // !defined(NS_BLOCK_ASSERTIONS) + #define _GTMDevAssert(condition, ...) do { } while (0) +#endif // !defined(NS_BLOCK_ASSERTIONS) + +#endif // _GTMDevAssert + +// _GTMCompileAssert +// +// Note: Software for current compilers should just use _Static_assert directly +// instead of this macro. +// +// _GTMCompileAssert is an assert that is meant to fire at compile time if you +// want to check things at compile instead of runtime. For example if you +// want to check that a wchar is 4 bytes instead of 2 you would use +// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X) +// Note that the second "arg" is not in quotes, and must be a valid processor +// symbol in it's own right (no spaces, punctuation etc). + +// Wrapping this in an #ifndef allows external groups to define their own +// compile time assert scheme. +#ifndef _GTMCompileAssert + #if __has_feature(c_static_assert) || __has_extension(c_static_assert) + #define _GTMCompileAssert(test, msg) _Static_assert((test), #msg) + #else + // Pre-Xcode 7 support. + // + // We got this technique from here: + // http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html + #define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg + #define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg) + #define _GTMCompileAssert(test, msg) \ + typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ] + #endif // __has_feature(c_static_assert) || __has_extension(c_static_assert) +#endif // _GTMCompileAssert + +// ---------------------------------------------------------------------------- +// CPP symbols defined based on the project settings so the GTM code has +// simple things to test against w/o scattering the knowledge of project +// setting through all the code. +// ---------------------------------------------------------------------------- + +// Provide a single constant CPP symbol that all of GTM uses for ifdefing +// iPhone code. +#if TARGET_OS_IPHONE // iPhone SDK + // For iPhone specific stuff + #define GTM_IPHONE_SDK 1 + #if TARGET_IPHONE_SIMULATOR + #define GTM_IPHONE_DEVICE 0 + #define GTM_IPHONE_SIMULATOR 1 + #else + #define GTM_IPHONE_DEVICE 1 + #define GTM_IPHONE_SIMULATOR 0 + #endif // TARGET_IPHONE_SIMULATOR + // By default, GTM has provided it's own unittesting support, define this + // to use the support provided by Xcode, especially for the Xcode4 support + // for unittesting. + // This is going to be deprecated as Apple is deprecating SenTest. + #ifndef GTM_IPHONE_USE_SENTEST + #define GTM_IPHONE_USE_SENTEST 0 + #endif + // Define this to use XCTest instead of OCUnit/SenTest. + #ifndef GTM_USING_XCTEST + #define GTM_USING_XCTEST 0 + #endif + #if GTM_IPHONE_USE_SENTEST && GTM_USING_XCTEST + #error Can't define both GTM_IPHONE_USE_SENTEST and GTM_USING_XCTEST + #endif + #define GTM_MACOS_SDK 0 +#else + // For MacOS specific stuff + #define GTM_MACOS_SDK 1 + #define GTM_IPHONE_SDK 0 + #define GTM_IPHONE_SIMULATOR 0 + #define GTM_IPHONE_DEVICE 0 + #define GTM_IPHONE_USE_SENTEST 0 + #ifndef GTM_USING_XCTEST + #define GTM_USING_XCTEST 0 + #endif +#endif + +// Some of our own availability macros +#if GTM_MACOS_SDK +#define GTM_AVAILABLE_ONLY_ON_IPHONE UNAVAILABLE_ATTRIBUTE +#define GTM_AVAILABLE_ONLY_ON_MACOS +#else +#define GTM_AVAILABLE_ONLY_ON_IPHONE +#define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE +#endif + +// GC was dropped by Apple, define the old constant incase anyone still keys +// off of it. +#ifndef GTM_SUPPORT_GC + #define GTM_SUPPORT_GC 0 +#endif + +// Some support for advanced clang static analysis functionality +#ifndef NS_RETURNS_RETAINED + #if __has_feature(attribute_ns_returns_retained) + #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) + #else + #define NS_RETURNS_RETAINED + #endif +#endif + +#ifndef NS_RETURNS_NOT_RETAINED + #if __has_feature(attribute_ns_returns_not_retained) + #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) + #else + #define NS_RETURNS_NOT_RETAINED + #endif +#endif + +#ifndef CF_RETURNS_RETAINED + #if __has_feature(attribute_cf_returns_retained) + #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) + #else + #define CF_RETURNS_RETAINED + #endif +#endif + +#ifndef CF_RETURNS_NOT_RETAINED + #if __has_feature(attribute_cf_returns_not_retained) + #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) + #else + #define CF_RETURNS_NOT_RETAINED + #endif +#endif + +#ifndef NS_CONSUMED + #if __has_feature(attribute_ns_consumed) + #define NS_CONSUMED __attribute__((ns_consumed)) + #else + #define NS_CONSUMED + #endif +#endif + +#ifndef CF_CONSUMED + #if __has_feature(attribute_cf_consumed) + #define CF_CONSUMED __attribute__((cf_consumed)) + #else + #define CF_CONSUMED + #endif +#endif + +#ifndef NS_CONSUMES_SELF + #if __has_feature(attribute_ns_consumes_self) + #define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) + #else + #define NS_CONSUMES_SELF + #endif +#endif + +#ifndef GTM_NONNULL + #if defined(__has_attribute) + #if __has_attribute(nonnull) + #define GTM_NONNULL(x) __attribute__((nonnull x)) + #else + #define GTM_NONNULL(x) + #endif + #else + #define GTM_NONNULL(x) + #endif +#endif + +// Invalidates the initializer from which it's called. +#ifndef GTMInvalidateInitializer + #if __has_feature(objc_arc) + #define GTMInvalidateInitializer() \ + do { \ + [self class]; /* Avoid warning of dead store to |self|. */ \ + _GTMDevAssert(NO, @"Invalid initializer."); \ + return nil; \ + } while (0) + #else + #define GTMInvalidateInitializer() \ + do { \ + [self release]; \ + _GTMDevAssert(NO, @"Invalid initializer."); \ + return nil; \ + } while (0) + #endif +#endif + +#ifndef GTMCFAutorelease + // GTMCFAutorelease returns an id. In contrast, Apple's CFAutorelease returns + // a CFTypeRef. + #if __has_feature(objc_arc) + #define GTMCFAutorelease(x) CFBridgingRelease(x) + #else + #define GTMCFAutorelease(x) ([(id)x autorelease]) + #endif +#endif + +#ifdef __OBJC__ + + +// Macro to allow you to create NSStrings out of other macros. +// #define FOO foo +// NSString *fooString = GTM_NSSTRINGIFY(FOO); +#if !defined (GTM_NSSTRINGIFY) + #define GTM_NSSTRINGIFY_INNER(x) @#x + #define GTM_NSSTRINGIFY(x) GTM_NSSTRINGIFY_INNER(x) +#endif + +// Macro to allow fast enumeration when building for 10.5 or later, and +// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration +// does keys, so pick the right thing, nothing is done on the FastEnumeration +// side to be sure you're getting what you wanted. +#ifndef GTM_FOREACH_OBJECT + #if TARGET_OS_IPHONE || !(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) + #define GTM_FOREACH_ENUMEREE(element, enumeration) \ + for (element in enumeration) + #define GTM_FOREACH_OBJECT(element, collection) \ + for (element in collection) + #define GTM_FOREACH_KEY(element, collection) \ + for (element in collection) + #else + #define GTM_FOREACH_ENUMEREE(element, enumeration) \ + for (NSEnumerator *_ ## element ## _enum = enumeration; \ + (element = [_ ## element ## _enum nextObject]) != nil; ) + #define GTM_FOREACH_OBJECT(element, collection) \ + GTM_FOREACH_ENUMEREE(element, [collection objectEnumerator]) + #define GTM_FOREACH_KEY(element, collection) \ + GTM_FOREACH_ENUMEREE(element, [collection keyEnumerator]) + #endif +#endif + +// ============================================================================ + +// GTM_SEL_STRING is for specifying selector (usually property) names to KVC +// or KVO methods. +// In debug it will generate warnings for undeclared selectors if +// -Wunknown-selector is turned on. +// In release it will have no runtime overhead. +#ifndef GTM_SEL_STRING + #ifdef DEBUG + #define GTM_SEL_STRING(selName) NSStringFromSelector(@selector(selName)) + #else + #define GTM_SEL_STRING(selName) @#selName + #endif // DEBUG +#endif // GTM_SEL_STRING + +#ifndef GTM_WEAK +#if __has_feature(objc_arc_weak) + // With ARC enabled, __weak means a reference that isn't implicitly + // retained. __weak objects are accessed through runtime functions, so + // they are zeroed out, but this requires OS X 10.7+. + // At clang r251041+, ARC-style zeroing weak references even work in + // non-ARC mode. + #define GTM_WEAK __weak + #elif __has_feature(objc_arc) + // ARC, but targeting 10.6 or older, where zeroing weak references don't + // exist. + #define GTM_WEAK __unsafe_unretained + #else + // With manual reference counting, __weak used to be silently ignored. + // clang r251041 gives it the ARC semantics instead. This means they + // now require a deployment target of 10.7, while some clients of GTM + // still target 10.6. In these cases, expand to __unsafe_unretained instead + #define GTM_WEAK + #endif +#endif + +#endif // __OBJC__ diff --git a/Code Burner/Pods/GoogleToolboxForMac/LICENSE b/Code Burner/Pods/GoogleToolboxForMac/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Code Burner/Pods/GoogleToolboxForMac/README.md b/Code Burner/Pods/GoogleToolboxForMac/README.md new file mode 100644 index 0000000..710560a --- /dev/null +++ b/Code Burner/Pods/GoogleToolboxForMac/README.md @@ -0,0 +1,15 @@ +# GTM: Google Toolbox for Mac # + +**Project site**
+**Discussion group** + +# Google Toolbox for Mac # + +A collection of source from different Google projects that may be of use to +developers working other iOS or OS X projects. + +If you find a problem/bug or want a new feature to be included in the Google +Toolbox for Mac, please join the +[discussion group](http://groups.google.com/group/google-toolbox-for-mac) +or submit an +[issue](https://github.com/google/google-toolbox-for-mac/issues). diff --git a/Code Burner/Pods/Headers/Private/Firebase/Firebase.h b/Code Burner/Pods/Headers/Private/Firebase/Firebase.h new file mode 120000 index 0000000..6d62033 --- /dev/null +++ b/Code Burner/Pods/Headers/Private/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/Core/Sources/Firebase.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/FirebaseInstanceID/FIRInstanceID.h b/Code Burner/Pods/Headers/Private/FirebaseInstanceID/FIRInstanceID.h new file mode 120000 index 0000000..0aaa73c --- /dev/null +++ b/Code Burner/Pods/Headers/Private/FirebaseInstanceID/FIRInstanceID.h @@ -0,0 +1 @@ +../../../FirebaseInstanceID/Sources/FIRInstanceID.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcher.h b/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcher.h new file mode 120000 index 0000000..7ed730f --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcher.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcher.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherLogging.h b/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherLogging.h new file mode 120000 index 0000000..ada41e3 --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherLogging.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcherLogging.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherService.h b/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherService.h new file mode 120000 index 0000000..1ef9cbb --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherService.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcherService.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionUploadFetcher.h b/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionUploadFetcher.h new file mode 120000 index 0000000..cef7a0d --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GTMSessionFetcher/GTMSessionUploadFetcher.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionUploadFetcher.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugSelectorValidation.h b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugSelectorValidation.h new file mode 120000 index 0000000..521da72 --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugSelectorValidation.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/DebugUtils/GTMDebugSelectorValidation.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugThreadValidation.h b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugThreadValidation.h new file mode 120000 index 0000000..de29ea1 --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugThreadValidation.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/DebugUtils/GTMDebugThreadValidation.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMDefines.h b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMDefines.h new file mode 120000 index 0000000..5503110 --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMDefines.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/GTMDefines.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMMethodCheck.h b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMMethodCheck.h new file mode 120000 index 0000000..56dfa7e --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMMethodCheck.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/DebugUtils/GTMMethodCheck.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMNSData+zlib.h b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMNSData+zlib.h new file mode 120000 index 0000000..9e72419 --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMNSData+zlib.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/Foundation/GTMNSData+zlib.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMNSDictionary+URLArguments.h b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMNSDictionary+URLArguments.h new file mode 120000 index 0000000..b2ff829 --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMNSDictionary+URLArguments.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMNSString+URLArguments.h b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMNSString+URLArguments.h new file mode 120000 index 0000000..3b9b1a2 --- /dev/null +++ b/Code Burner/Pods/Headers/Private/GoogleToolboxForMac/GTMNSString+URLArguments.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics+AppDelegate.h b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics+AppDelegate.h new file mode 120000 index 0000000..5ea8208 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics+AppDelegate.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics.h b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics.h new file mode 120000 index 0000000..92d9b85 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalyticsConfiguration.h b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalyticsConfiguration.h new file mode 120000 index 0000000..1e35aa2 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalyticsConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/frameworks/FirebaseAnalytics.framework/Headers/FIRAnalyticsConfiguration.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRApp.h b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRApp.h new file mode 120000 index 0000000..a4ca439 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRApp.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/frameworks/FirebaseAnalytics.framework/Headers/FIRApp.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRConfiguration.h b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRConfiguration.h new file mode 120000 index 0000000..4c29bba --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/frameworks/FirebaseAnalytics.framework/Headers/FIRConfiguration.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIREventNames.h b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIREventNames.h new file mode 120000 index 0000000..75aea08 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIREventNames.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/frameworks/FirebaseAnalytics.framework/Headers/FIREventNames.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIROptions.h b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIROptions.h new file mode 120000 index 0000000..eb7d9f5 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIROptions.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/frameworks/FirebaseAnalytics.framework/Headers/FIROptions.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRParameterNames.h b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRParameterNames.h new file mode 120000 index 0000000..c5f352c --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRParameterNames.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/frameworks/FirebaseAnalytics.framework/Headers/FIRParameterNames.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRUserPropertyNames.h b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRUserPropertyNames.h new file mode 120000 index 0000000..6e26060 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRUserPropertyNames.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FirebaseAnalytics.h b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FirebaseAnalytics.h new file mode 120000 index 0000000..0859122 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FirebaseAnalytics.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/frameworks/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuth.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuth.h new file mode 120000 index 0000000..8196f5a --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuth.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FIRAuth.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthCredential.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthCredential.h new file mode 120000 index 0000000..2ef5ac8 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthCredential.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FIRAuthCredential.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthErrors.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthErrors.h new file mode 120000 index 0000000..dd17a23 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthErrors.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FIRAuthErrors.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIREmailPasswordAuthProvider.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIREmailPasswordAuthProvider.h new file mode 120000 index 0000000..8fc925f --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIREmailPasswordAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FIREmailPasswordAuthProvider.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRFacebookAuthProvider.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRFacebookAuthProvider.h new file mode 120000 index 0000000..8eba155 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRFacebookAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FIRFacebookAuthProvider.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGitHubAuthProvider.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGitHubAuthProvider.h new file mode 120000 index 0000000..6e94066 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGitHubAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FIRGitHubAuthProvider.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGoogleAuthProvider.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGoogleAuthProvider.h new file mode 120000 index 0000000..966579f --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGoogleAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FIRGoogleAuthProvider.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRTwitterAuthProvider.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRTwitterAuthProvider.h new file mode 120000 index 0000000..b4325f3 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRTwitterAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FIRTwitterAuthProvider.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUser.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUser.h new file mode 120000 index 0000000..f6b013b --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUser.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FIRUser.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUserInfo.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUserInfo.h new file mode 120000 index 0000000..368d346 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUserInfo.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FIRUserInfo.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuth.h b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuth.h new file mode 120000 index 0000000..488c240 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuth.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/frameworks/FirebaseAuth.framework/Headers/FirebaseAuth.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRAnalyticsConfiguration.h b/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRAnalyticsConfiguration.h new file mode 120000 index 0000000..52778f0 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRAnalyticsConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/frameworks/FirebaseCore.framework/Headers/FIRAnalyticsConfiguration.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRApp.h b/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRApp.h new file mode 120000 index 0000000..a0b1657 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRApp.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/frameworks/FirebaseCore.framework/Headers/FIRApp.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRConfiguration.h b/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRConfiguration.h new file mode 120000 index 0000000..fd1cfbf --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/frameworks/FirebaseCore.framework/Headers/FIRConfiguration.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIROptions.h b/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIROptions.h new file mode 120000 index 0000000..39759eb --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIROptions.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/frameworks/FirebaseCore.framework/Headers/FIROptions.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FirebaseCore.h b/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FirebaseCore.h new file mode 120000 index 0000000..8f62016 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseCore/FirebaseCore/FirebaseCore.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/frameworks/FirebaseCore.framework/Headers/FirebaseCore.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataEventType.h b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataEventType.h new file mode 120000 index 0000000..ba0eb10 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataEventType.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataEventType.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataSnapshot.h b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataSnapshot.h new file mode 120000 index 0000000..635d198 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataSnapshot.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataSnapshot.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabase.h b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabase.h new file mode 120000 index 0000000..72f9038 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabase.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabase.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseQuery.h b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseQuery.h new file mode 120000 index 0000000..9ad7555 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseQuery.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseQuery.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseReference.h b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseReference.h new file mode 120000 index 0000000..b935ca6 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseReference.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseReference.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRMutableData.h b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRMutableData.h new file mode 120000 index 0000000..4efb3f2 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRMutableData.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRMutableData.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRServerValue.h b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRServerValue.h new file mode 120000 index 0000000..8632fa0 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRServerValue.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRServerValue.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRTransactionResult.h b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRTransactionResult.h new file mode 120000 index 0000000..c56d5c8 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRTransactionResult.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRTransactionResult.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FirebaseDatabase.h b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FirebaseDatabase.h new file mode 120000 index 0000000..4eefb9c --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FirebaseDatabase.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FirebaseDatabase.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseInstanceID/FIRInstanceID.h b/Code Burner/Pods/Headers/Public/FirebaseInstanceID/FIRInstanceID.h new file mode 120000 index 0000000..0aaa73c --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseInstanceID/FIRInstanceID.h @@ -0,0 +1 @@ +../../../FirebaseInstanceID/Sources/FIRInstanceID.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FIRInstanceID.h b/Code Burner/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FIRInstanceID.h new file mode 120000 index 0000000..61992a3 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FIRInstanceID.h @@ -0,0 +1 @@ +../../../../FirebaseInstanceID/Frameworks/frameworks/FirebaseInstanceID.framework/Headers/FIRInstanceID.h \ No newline at end of file diff --git a/Code Burner/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FirebaseInstanceID.h b/Code Burner/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FirebaseInstanceID.h new file mode 120000 index 0000000..9c6ce35 --- /dev/null +++ b/Code Burner/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FirebaseInstanceID.h @@ -0,0 +1 @@ +../../../../FirebaseInstanceID/Frameworks/frameworks/FirebaseInstanceID.framework/Headers/FirebaseInstanceID.h \ No newline at end of file diff --git a/Code Burner/Pods/Pods.xcodeproj/project.pbxproj b/Code Burner/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..35e144d --- /dev/null +++ b/Code Burner/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,882 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0E6F2758E5743B053E54C51B0D236AF0 /* GTMSessionUploadFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 51D29E10113F59F8B03D62B62AC507C9 /* GTMSessionUploadFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1235AC549ED1B1EF40635602DCF8B4D5 /* GTMSessionFetcherLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 43D4176DA600C72D135D59B357970934 /* GTMSessionFetcherLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 226B1BFF4E3FC473A1C88F2CFD77C9AF /* GTMDebugThreadValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = AF9AF0A6BF948AD226A8865B09C54090 /* GTMDebugThreadValidation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2583A3E4525E67AC3D64936F3952D567 /* Pods-Task Burner-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D81D90A049FA6F1EC648D7C77F549B /* Pods-Task Burner-dummy.m */; }; + 26BE741AD59EF185570AC9C853F44FAD /* GTMNSData+zlib.h in Headers */ = {isa = PBXBuildFile; fileRef = F53D6A595711D2D2F72DF8A1C69F4B76 /* GTMNSData+zlib.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3328D6AA0A6DD5371B63ECAD18718F3F /* GoogleToolboxForMac-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = ACE77093C121EA932E8AC513F0E9F7CF /* GoogleToolboxForMac-dummy.m */; }; + 476D901118FCE3506AF5ECEFC743403B /* GTMDebugSelectorValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = 198915C0CA44B0356C9834B46191A039 /* GTMDebugSelectorValidation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 522C0FE7197A2D7D3D925ADA58429D05 /* GTMSessionUploadFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = F4566B7D99D538A8B56C58885B5C7AF9 /* GTMSessionUploadFetcher.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 5353CD4CF7B378621E34EA62C699E40F /* GTMNSDictionary+URLArguments.m in Sources */ = {isa = PBXBuildFile; fileRef = 76CE7EF4EC993A5A43620E9D17CA2672 /* GTMNSDictionary+URLArguments.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0 -w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 5E255A5B5203BE00C7B9E4D2E0D3BDC7 /* GTMMethodCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = ECD0F1EFC7009C67FE0D11DB12122952 /* GTMMethodCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 66C6BF3F708DA86153C829B78B3DA77A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B4690263E3C2DD3C24DEAC554FFBD486 /* Foundation.framework */; }; + 6C262944569C29D04DFA3C5F21494AAB /* GTMNSDictionary+URLArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = 79096A79B53D03AD3665115E0DA95A45 /* GTMNSDictionary+URLArguments.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 74B88A8B5B43AE22CE208F1AF9315336 /* GTMSessionFetcher-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DD91002BCF9915312AD20281FD51435 /* GTMSessionFetcher-dummy.m */; }; + 9B3794E275C6348A291A1E0A52CAF113 /* GTMSessionFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 65C61B699F2853C1A38C4E2D8F98EF63 /* GTMSessionFetcher.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 9BB31E94CF2D3BEB22EEC2E0D2147C64 /* GTMSessionFetcherService.m in Sources */ = {isa = PBXBuildFile; fileRef = AA060057AF151DB56F7677AF4F95B457 /* GTMSessionFetcherService.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + A46AF96BFE3E00583C3C2AB6C1322D7B /* GTMDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EB8DA35765DD5E8F31B2FBF56495D2A /* GTMDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ACBF3E2E9A6B3E9FD859BF001F20D694 /* GTMNSString+URLArguments.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F7865566B8E2ED0B4F7BE5D7CBC7122 /* GTMNSString+URLArguments.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc -w -Xanalyzer -analyzer-disable-all-checks"; }; }; + B4B084A9C602985BE7858EA801AD4382 /* GTMSessionFetcherService.h in Headers */ = {isa = PBXBuildFile; fileRef = A65BC05DA1122277E055FA1A3EE4AFAF /* GTMSessionFetcherService.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CDA0F61C3BD605E63D0500A1A0574969 /* GTMSessionFetcherLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 97D84A1EA42F010E0CAB6B5D20A6DC9C /* GTMSessionFetcherLogging.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + E071ED04676790AFF262727DB6BC5DE1 /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 450D20C8A4B2C00E0E699329C336A410 /* GTMNSData+zlib.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0 -w -Xanalyzer -analyzer-disable-all-checks"; }; }; + E723E1309A6A0D437B3AB3C392BF1F93 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B4690263E3C2DD3C24DEAC554FFBD486 /* Foundation.framework */; }; + E84DEF53F8F01BAF747EB387654EC0AC /* GTMNSString+URLArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = 271F3453FC8A4680AD9B2B2756C3DC8E /* GTMNSString+URLArguments.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E982A741CDD1A8CC804FC7F20E5C006F /* GTMSessionFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 453FA2537F543AD7C2DD6562A32E8B26 /* GTMSessionFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F3E77AA87F046EA6488343E942699FC2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B4690263E3C2DD3C24DEAC554FFBD486 /* Foundation.framework */; }; + FDA904E57877210782AFC6E37383A93C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CAFD15069DBFFAF7E7CD48183E2D230C /* Security.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 402CF8AFD3F030BFD607E1A1FF3CDDA0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 58E7450DB13C5ECCE92D3C0DF7CF0903; + remoteInfo = GoogleToolboxForMac; + }; + 46A250E2AE529E111F158A88D1FA619B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = DE868725B18AE240E550C5515AE66BC4; + remoteInfo = GTMSessionFetcher; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 01D4834F06DB740C2829D5D6876C60E7 /* libGoogleToolboxForMac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libGoogleToolboxForMac.a; path = libGoogleToolboxForMac.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 0AF57663DC977510D58585C2C7095993 /* FIRInstanceID.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstanceID.h; path = Sources/FIRInstanceID.h; sourceTree = ""; }; + 1681F0B4DDE056E943C58F99F7F8D96E /* GoogleToolboxForMac-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GoogleToolboxForMac-prefix.pch"; sourceTree = ""; }; + 198915C0CA44B0356C9834B46191A039 /* GTMDebugSelectorValidation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMDebugSelectorValidation.h; path = DebugUtils/GTMDebugSelectorValidation.h; sourceTree = ""; }; + 1E12D9E778B2314B4E96D753DE05B80B /* FirebaseAnalytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseAnalytics.framework; path = Frameworks/frameworks/FirebaseAnalytics.framework; sourceTree = ""; }; + 1F7865566B8E2ED0B4F7BE5D7CBC7122 /* GTMNSString+URLArguments.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GTMNSString+URLArguments.m"; path = "Foundation/GTMNSString+URLArguments.m"; sourceTree = ""; }; + 271F3453FC8A4680AD9B2B2756C3DC8E /* GTMNSString+URLArguments.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GTMNSString+URLArguments.h"; path = "Foundation/GTMNSString+URLArguments.h"; sourceTree = ""; }; + 3302A115413B703F3744584FED312A14 /* Pods-Task Burner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Task Burner.release.xcconfig"; sourceTree = ""; }; + 396FAFC8A93A407C7062DA87A02001A5 /* FirebaseInstanceID.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseInstanceID.framework; path = Frameworks/frameworks/FirebaseInstanceID.framework; sourceTree = ""; }; + 3A9F1E2FEAB05086AE95B22A86CB9DFC /* Firebase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Firebase.h; path = Core/Sources/Firebase.h; sourceTree = ""; }; + 3C7420535ACBD3D143B95490196FF34F /* Pods-Task Burner-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Task Burner-acknowledgements.markdown"; sourceTree = ""; }; + 3EB8DA35765DD5E8F31B2FBF56495D2A /* GTMDefines.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = GTMDefines.h; sourceTree = ""; }; + 43D4176DA600C72D135D59B357970934 /* GTMSessionFetcherLogging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherLogging.h; path = Source/GTMSessionFetcherLogging.h; sourceTree = ""; }; + 450D20C8A4B2C00E0E699329C336A410 /* GTMNSData+zlib.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GTMNSData+zlib.m"; path = "Foundation/GTMNSData+zlib.m"; sourceTree = ""; }; + 453FA2537F543AD7C2DD6562A32E8B26 /* GTMSessionFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcher.h; path = Source/GTMSessionFetcher.h; sourceTree = ""; }; + 4DD91002BCF9915312AD20281FD51435 /* GTMSessionFetcher-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GTMSessionFetcher-dummy.m"; sourceTree = ""; }; + 51D29E10113F59F8B03D62B62AC507C9 /* GTMSessionUploadFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionUploadFetcher.h; path = Source/GTMSessionUploadFetcher.h; sourceTree = ""; }; + 5696FC1316CB903A341D34EB9AFB06B4 /* GTMSessionFetcher-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GTMSessionFetcher-prefix.pch"; sourceTree = ""; }; + 632CA29AC91DB6DF4F279FCBC9EC20D3 /* FirebaseCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseCore.framework; path = Frameworks/frameworks/FirebaseCore.framework; sourceTree = ""; }; + 65C61B699F2853C1A38C4E2D8F98EF63 /* GTMSessionFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcher.m; path = Source/GTMSessionFetcher.m; sourceTree = ""; }; + 6B344812936B5768866A3C61F687744F /* GTMSessionFetcher.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GTMSessionFetcher.xcconfig; sourceTree = ""; }; + 7358C9A3231ACC54052C7EF3484C7768 /* GoogleInterchangeUtilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GoogleInterchangeUtilities.framework; path = Frameworks/frameworks/GoogleInterchangeUtilities.framework; sourceTree = ""; }; + 76C5068038AD5399FF8EB3D8A3E6D0F8 /* libPods-Task Burner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libPods-Task Burner.a"; path = "libPods-Task Burner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 76CE7EF4EC993A5A43620E9D17CA2672 /* GTMNSDictionary+URLArguments.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GTMNSDictionary+URLArguments.m"; path = "Foundation/GTMNSDictionary+URLArguments.m"; sourceTree = ""; }; + 79096A79B53D03AD3665115E0DA95A45 /* GTMNSDictionary+URLArguments.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GTMNSDictionary+URLArguments.h"; path = "Foundation/GTMNSDictionary+URLArguments.h"; sourceTree = ""; }; + 84D81D90A049FA6F1EC648D7C77F549B /* Pods-Task Burner-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Task Burner-dummy.m"; sourceTree = ""; }; + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 97D84A1EA42F010E0CAB6B5D20A6DC9C /* GTMSessionFetcherLogging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherLogging.m; path = Source/GTMSessionFetcherLogging.m; sourceTree = ""; }; + 9E8ACF90A25AEB15F1010B7B6E9EC3F8 /* libGTMSessionFetcher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libGTMSessionFetcher.a; path = libGTMSessionFetcher.a; sourceTree = BUILT_PRODUCTS_DIR; }; + A65BC05DA1122277E055FA1A3EE4AFAF /* GTMSessionFetcherService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherService.h; path = Source/GTMSessionFetcherService.h; sourceTree = ""; }; + AA060057AF151DB56F7677AF4F95B457 /* GTMSessionFetcherService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherService.m; path = Source/GTMSessionFetcherService.m; sourceTree = ""; }; + ACE77093C121EA932E8AC513F0E9F7CF /* GoogleToolboxForMac-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GoogleToolboxForMac-dummy.m"; sourceTree = ""; }; + AF9AF0A6BF948AD226A8865B09C54090 /* GTMDebugThreadValidation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMDebugThreadValidation.h; path = DebugUtils/GTMDebugThreadValidation.h; sourceTree = ""; }; + B0BCEB2BE215955E08FBABAC2F342963 /* GoogleToolboxForMac.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleToolboxForMac.xcconfig; sourceTree = ""; }; + B4690263E3C2DD3C24DEAC554FFBD486 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + BDEFD270EB956D87018E680BD7111D50 /* FirebaseAuth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseAuth.framework; path = Frameworks/frameworks/FirebaseAuth.framework; sourceTree = ""; }; + C76746CE34097BBFFE14EDA4648E655E /* FirebaseDatabase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseDatabase.framework; path = Frameworks/FirebaseDatabase.framework; sourceTree = ""; }; + C971B9EA7E7B9214492546F7D4052C0F /* Pods-Task Burner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Task Burner.debug.xcconfig"; sourceTree = ""; }; + CAFD15069DBFFAF7E7CD48183E2D230C /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + DAF48B844D73C0CDD7693B471096C430 /* Pods-Task Burner-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Task Burner-resources.sh"; sourceTree = ""; }; + DC59A955ADA37DD0F6FDDF181FAF3E77 /* GoogleSymbolUtilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GoogleSymbolUtilities.framework; path = Frameworks/frameworks/GoogleSymbolUtilities.framework; sourceTree = ""; }; + E10345C14514E28C3AD064233A3A4D9F /* Pods-Task Burner-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Task Burner-frameworks.sh"; sourceTree = ""; }; + ECD0F1EFC7009C67FE0D11DB12122952 /* GTMMethodCheck.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMMethodCheck.h; path = DebugUtils/GTMMethodCheck.h; sourceTree = ""; }; + F4566B7D99D538A8B56C58885B5C7AF9 /* GTMSessionUploadFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionUploadFetcher.m; path = Source/GTMSessionUploadFetcher.m; sourceTree = ""; }; + F53D6A595711D2D2F72DF8A1C69F4B76 /* GTMNSData+zlib.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GTMNSData+zlib.h"; path = "Foundation/GTMNSData+zlib.h"; sourceTree = ""; }; + FF727D42E333859869F3AB7B03C5A46C /* Pods-Task Burner-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Task Burner-acknowledgements.plist"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 39DAA8001E09064D451C0B69AE13E8EF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E723E1309A6A0D437B3AB3C392BF1F93 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D2BE8CE5663DF1EA1CF1CC5269C6067 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 66C6BF3F708DA86153C829B78B3DA77A /* Foundation.framework in Frameworks */, + FDA904E57877210782AFC6E37383A93C /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E468DEE3816A9E9ED082166AC0F3EAAB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F3E77AA87F046EA6488343E942699FC2 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0FEE339796C999F898C7C3F9AD4291A3 /* GoogleSymbolUtilities */ = { + isa = PBXGroup; + children = ( + EE95B9FE529E517EC9845CBD7B603700 /* Frameworks */, + ); + name = GoogleSymbolUtilities; + path = GoogleSymbolUtilities; + sourceTree = ""; + }; + 19D2B8153A76EF4EA5D4C72988567FC5 /* NSString+URLArguments */ = { + isa = PBXGroup; + children = ( + 271F3453FC8A4680AD9B2B2756C3DC8E /* GTMNSString+URLArguments.h */, + 1F7865566B8E2ED0B4F7BE5D7CBC7122 /* GTMNSString+URLArguments.m */, + ); + name = "NSString+URLArguments"; + sourceTree = ""; + }; + 1ED5EA34C05D3C08A1CBF967F58EB3F3 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 396FAFC8A93A407C7062DA87A02001A5 /* FirebaseInstanceID.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 1F82E856F6366BC55E8AA15B58F769A2 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 7358C9A3231ACC54052C7EF3484C7768 /* GoogleInterchangeUtilities.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 215C9F496CE94E15A70809F1F5273BF1 /* Core */ = { + isa = PBXGroup; + children = ( + 453FA2537F543AD7C2DD6562A32E8B26 /* GTMSessionFetcher.h */, + 65C61B699F2853C1A38C4E2D8F98EF63 /* GTMSessionFetcher.m */, + 43D4176DA600C72D135D59B357970934 /* GTMSessionFetcherLogging.h */, + 97D84A1EA42F010E0CAB6B5D20A6DC9C /* GTMSessionFetcherLogging.m */, + A65BC05DA1122277E055FA1A3EE4AFAF /* GTMSessionFetcherService.h */, + AA060057AF151DB56F7677AF4F95B457 /* GTMSessionFetcherService.m */, + 51D29E10113F59F8B03D62B62AC507C9 /* GTMSessionUploadFetcher.h */, + F4566B7D99D538A8B56C58885B5C7AF9 /* GTMSessionUploadFetcher.m */, + ); + name = Core; + sourceTree = ""; + }; + 2E339049816F198EB76DEA4264EF8374 /* iOS */ = { + isa = PBXGroup; + children = ( + B4690263E3C2DD3C24DEAC554FFBD486 /* Foundation.framework */, + CAFD15069DBFFAF7E7CD48183E2D230C /* Security.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 34BA21F2493AC2BEE7166F17FFF446B4 /* GoogleInterchangeUtilities */ = { + isa = PBXGroup; + children = ( + 1F82E856F6366BC55E8AA15B58F769A2 /* Frameworks */, + ); + name = GoogleInterchangeUtilities; + path = GoogleInterchangeUtilities; + sourceTree = ""; + }; + 3943FEDA5C06ECF21C1E4FD03971709E /* FirebaseDatabase */ = { + isa = PBXGroup; + children = ( + ABA129E5F40A1914956201088AE08DA3 /* Frameworks */, + ); + name = FirebaseDatabase; + path = FirebaseDatabase; + sourceTree = ""; + }; + 3B867DE8F1D99A2FBD94E56BBFE03622 /* Support Files */ = { + isa = PBXGroup; + children = ( + 6B344812936B5768866A3C61F687744F /* GTMSessionFetcher.xcconfig */, + 4DD91002BCF9915312AD20281FD51435 /* GTMSessionFetcher-dummy.m */, + 5696FC1316CB903A341D34EB9AFB06B4 /* GTMSessionFetcher-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/GTMSessionFetcher"; + sourceTree = ""; + }; + 3ECD1C145F16F5A5BEAB2F46E2B9381D /* Pods-Task Burner */ = { + isa = PBXGroup; + children = ( + 3C7420535ACBD3D143B95490196FF34F /* Pods-Task Burner-acknowledgements.markdown */, + FF727D42E333859869F3AB7B03C5A46C /* Pods-Task Burner-acknowledgements.plist */, + 84D81D90A049FA6F1EC648D7C77F549B /* Pods-Task Burner-dummy.m */, + E10345C14514E28C3AD064233A3A4D9F /* Pods-Task Burner-frameworks.sh */, + DAF48B844D73C0CDD7693B471096C430 /* Pods-Task Burner-resources.sh */, + C971B9EA7E7B9214492546F7D4052C0F /* Pods-Task Burner.debug.xcconfig */, + 3302A115413B703F3744584FED312A14 /* Pods-Task Burner.release.xcconfig */, + ); + name = "Pods-Task Burner"; + path = "Target Support Files/Pods-Task Burner"; + sourceTree = ""; + }; + 433CD3331B6C3787F473C941B61FC68F /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2E339049816F198EB76DEA4264EF8374 /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + 560773E1DFF7905574F357ED3595A850 /* Defines */ = { + isa = PBXGroup; + children = ( + 3EB8DA35765DD5E8F31B2FBF56495D2A /* GTMDefines.h */, + ); + name = Defines; + sourceTree = ""; + }; + 5D5116B919B72D5A776CCCA5A55D56D1 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1E12D9E778B2314B4E96D753DE05B80B /* FirebaseAnalytics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 641AECE8A3441FE880D9579EBE42D127 /* NSData+zlib */ = { + isa = PBXGroup; + children = ( + F53D6A595711D2D2F72DF8A1C69F4B76 /* GTMNSData+zlib.h */, + 450D20C8A4B2C00E0E699329C336A410 /* GTMNSData+zlib.m */, + ); + name = "NSData+zlib"; + sourceTree = ""; + }; + 67C13782D164C33418A3DC007345EEAF /* FirebaseAuth */ = { + isa = PBXGroup; + children = ( + E411536E94FE8F4BA5EA00002396504C /* Frameworks */, + ); + name = FirebaseAuth; + path = FirebaseAuth; + sourceTree = ""; + }; + 6F4E97D49905C5A87BF4EDE313450678 /* FirebaseCore */ = { + isa = PBXGroup; + children = ( + DE3230BFB229154DF7E393CE076D0793 /* Frameworks */, + ); + name = FirebaseCore; + path = FirebaseCore; + sourceTree = ""; + }; + 7C68E5C9EED5495C7D12FDB7C93E2165 /* Pods */ = { + isa = PBXGroup; + children = ( + CD39BC08FBFAAEE49168C0CF3BF12D23 /* Firebase */, + B7D51504E8AC0BAE4AB9C10D917D45D0 /* FirebaseAnalytics */, + 67C13782D164C33418A3DC007345EEAF /* FirebaseAuth */, + 6F4E97D49905C5A87BF4EDE313450678 /* FirebaseCore */, + 3943FEDA5C06ECF21C1E4FD03971709E /* FirebaseDatabase */, + A631107F6BF85505BD6AF2EA4161EDBA /* FirebaseInstanceID */, + 34BA21F2493AC2BEE7166F17FFF446B4 /* GoogleInterchangeUtilities */, + 0FEE339796C999F898C7C3F9AD4291A3 /* GoogleSymbolUtilities */, + DDCD13879941F5F7855540BCAB02B535 /* GoogleToolboxForMac */, + EB3B4C9F23A040955FC08C2735B4A166 /* GTMSessionFetcher */, + ); + name = Pods; + sourceTree = ""; + }; + 7DB346D0F39D3F0E887471402A8071AB = { + isa = PBXGroup; + children = ( + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */, + 433CD3331B6C3787F473C941B61FC68F /* Frameworks */, + 7C68E5C9EED5495C7D12FDB7C93E2165 /* Pods */, + 899757495517A251C8F12BFC05F2F662 /* Products */, + BF0DBC5867069C8A0F9DA76ACA815FE1 /* Targets Support Files */, + ); + sourceTree = ""; + }; + 899757495517A251C8F12BFC05F2F662 /* Products */ = { + isa = PBXGroup; + children = ( + 01D4834F06DB740C2829D5D6876C60E7 /* libGoogleToolboxForMac.a */, + 9E8ACF90A25AEB15F1010B7B6E9EC3F8 /* libGTMSessionFetcher.a */, + 76C5068038AD5399FF8EB3D8A3E6D0F8 /* libPods-Task Burner.a */, + ); + name = Products; + sourceTree = ""; + }; + A631107F6BF85505BD6AF2EA4161EDBA /* FirebaseInstanceID */ = { + isa = PBXGroup; + children = ( + 0AF57663DC977510D58585C2C7095993 /* FIRInstanceID.h */, + 1ED5EA34C05D3C08A1CBF967F58EB3F3 /* Frameworks */, + ); + name = FirebaseInstanceID; + path = FirebaseInstanceID; + sourceTree = ""; + }; + ABA129E5F40A1914956201088AE08DA3 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C76746CE34097BBFFE14EDA4648E655E /* FirebaseDatabase.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + AD6ADF88ECAB4A3B956393CC65657758 /* Support Files */ = { + isa = PBXGroup; + children = ( + B0BCEB2BE215955E08FBABAC2F342963 /* GoogleToolboxForMac.xcconfig */, + ACE77093C121EA932E8AC513F0E9F7CF /* GoogleToolboxForMac-dummy.m */, + 1681F0B4DDE056E943C58F99F7F8D96E /* GoogleToolboxForMac-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/GoogleToolboxForMac"; + sourceTree = ""; + }; + B7D51504E8AC0BAE4AB9C10D917D45D0 /* FirebaseAnalytics */ = { + isa = PBXGroup; + children = ( + 5D5116B919B72D5A776CCCA5A55D56D1 /* Frameworks */, + ); + name = FirebaseAnalytics; + path = FirebaseAnalytics; + sourceTree = ""; + }; + BF0DBC5867069C8A0F9DA76ACA815FE1 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 3ECD1C145F16F5A5BEAB2F46E2B9381D /* Pods-Task Burner */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + CD39BC08FBFAAEE49168C0CF3BF12D23 /* Firebase */ = { + isa = PBXGroup; + children = ( + FAA4848E856FF791438A9A3C0E295A17 /* Core */, + ); + name = Firebase; + path = Firebase; + sourceTree = ""; + }; + DDCD13879941F5F7855540BCAB02B535 /* GoogleToolboxForMac */ = { + isa = PBXGroup; + children = ( + E8613E68AD5AEDA48D6572140F4C2E64 /* DebugUtils */, + 560773E1DFF7905574F357ED3595A850 /* Defines */, + 641AECE8A3441FE880D9579EBE42D127 /* NSData+zlib */, + F01B5FDE5AF7D014989E670E22354AB0 /* NSDictionary+URLArguments */, + 19D2B8153A76EF4EA5D4C72988567FC5 /* NSString+URLArguments */, + AD6ADF88ECAB4A3B956393CC65657758 /* Support Files */, + ); + name = GoogleToolboxForMac; + path = GoogleToolboxForMac; + sourceTree = ""; + }; + DE3230BFB229154DF7E393CE076D0793 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 632CA29AC91DB6DF4F279FCBC9EC20D3 /* FirebaseCore.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + E411536E94FE8F4BA5EA00002396504C /* Frameworks */ = { + isa = PBXGroup; + children = ( + BDEFD270EB956D87018E680BD7111D50 /* FirebaseAuth.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + E8613E68AD5AEDA48D6572140F4C2E64 /* DebugUtils */ = { + isa = PBXGroup; + children = ( + 198915C0CA44B0356C9834B46191A039 /* GTMDebugSelectorValidation.h */, + AF9AF0A6BF948AD226A8865B09C54090 /* GTMDebugThreadValidation.h */, + ECD0F1EFC7009C67FE0D11DB12122952 /* GTMMethodCheck.h */, + ); + name = DebugUtils; + sourceTree = ""; + }; + EB3B4C9F23A040955FC08C2735B4A166 /* GTMSessionFetcher */ = { + isa = PBXGroup; + children = ( + 215C9F496CE94E15A70809F1F5273BF1 /* Core */, + 3B867DE8F1D99A2FBD94E56BBFE03622 /* Support Files */, + ); + name = GTMSessionFetcher; + path = GTMSessionFetcher; + sourceTree = ""; + }; + EE95B9FE529E517EC9845CBD7B603700 /* Frameworks */ = { + isa = PBXGroup; + children = ( + DC59A955ADA37DD0F6FDDF181FAF3E77 /* GoogleSymbolUtilities.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + F01B5FDE5AF7D014989E670E22354AB0 /* NSDictionary+URLArguments */ = { + isa = PBXGroup; + children = ( + 79096A79B53D03AD3665115E0DA95A45 /* GTMNSDictionary+URLArguments.h */, + 76CE7EF4EC993A5A43620E9D17CA2672 /* GTMNSDictionary+URLArguments.m */, + ); + name = "NSDictionary+URLArguments"; + sourceTree = ""; + }; + FAA4848E856FF791438A9A3C0E295A17 /* Core */ = { + isa = PBXGroup; + children = ( + 3A9F1E2FEAB05086AE95B22A86CB9DFC /* Firebase.h */, + ); + name = Core; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 0CBA5A14986DAE7D6A473749221AA81F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 476D901118FCE3506AF5ECEFC743403B /* GTMDebugSelectorValidation.h in Headers */, + 226B1BFF4E3FC473A1C88F2CFD77C9AF /* GTMDebugThreadValidation.h in Headers */, + A46AF96BFE3E00583C3C2AB6C1322D7B /* GTMDefines.h in Headers */, + 5E255A5B5203BE00C7B9E4D2E0D3BDC7 /* GTMMethodCheck.h in Headers */, + 26BE741AD59EF185570AC9C853F44FAD /* GTMNSData+zlib.h in Headers */, + 6C262944569C29D04DFA3C5F21494AAB /* GTMNSDictionary+URLArguments.h in Headers */, + E84DEF53F8F01BAF747EB387654EC0AC /* GTMNSString+URLArguments.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A922FE66E6DEA4BD3090DCEB4580F34E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E982A741CDD1A8CC804FC7F20E5C006F /* GTMSessionFetcher.h in Headers */, + 1235AC549ED1B1EF40635602DCF8B4D5 /* GTMSessionFetcherLogging.h in Headers */, + B4B084A9C602985BE7858EA801AD4382 /* GTMSessionFetcherService.h in Headers */, + 0E6F2758E5743B053E54C51B0D236AF0 /* GTMSessionUploadFetcher.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 1E5280EF7C55EA14FF78108514A368E3 /* Pods-Task Burner */ = { + isa = PBXNativeTarget; + buildConfigurationList = A59ACE6F9676B20B2B8BEB84FFEFEE31 /* Build configuration list for PBXNativeTarget "Pods-Task Burner" */; + buildPhases = ( + F420568B3452EA879A95D5FCBB393332 /* Sources */, + 39DAA8001E09064D451C0B69AE13E8EF /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 9D56C6408784B28A8DFE97E0EBA85906 /* PBXTargetDependency */, + D16A576588AF6A610139B6AB9B910A5A /* PBXTargetDependency */, + ); + name = "Pods-Task Burner"; + productName = "Pods-Task Burner"; + productReference = 76C5068038AD5399FF8EB3D8A3E6D0F8 /* libPods-Task Burner.a */; + productType = "com.apple.product-type.library.static"; + }; + 58E7450DB13C5ECCE92D3C0DF7CF0903 /* GoogleToolboxForMac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 26AE791F404F3732C3335D0EFE25E20A /* Build configuration list for PBXNativeTarget "GoogleToolboxForMac" */; + buildPhases = ( + F86A0216D6948A1D34655DBC29C561FC /* Sources */, + E468DEE3816A9E9ED082166AC0F3EAAB /* Frameworks */, + 0CBA5A14986DAE7D6A473749221AA81F /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GoogleToolboxForMac; + productName = GoogleToolboxForMac; + productReference = 01D4834F06DB740C2829D5D6876C60E7 /* libGoogleToolboxForMac.a */; + productType = "com.apple.product-type.library.static"; + }; + DE868725B18AE240E550C5515AE66BC4 /* GTMSessionFetcher */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4693C211CA1C7318A8B388F1C2D24725 /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */; + buildPhases = ( + 474FE5FB84FE06E59DA34EFCEB7B07B2 /* Sources */, + 8D2BE8CE5663DF1EA1CF1CC5269C6067 /* Frameworks */, + A922FE66E6DEA4BD3090DCEB4580F34E /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GTMSessionFetcher; + productName = GTMSessionFetcher; + productReference = 9E8ACF90A25AEB15F1010B7B6E9EC3F8 /* libGTMSessionFetcher.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0730; + LastUpgradeCheck = 0700; + }; + buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 7DB346D0F39D3F0E887471402A8071AB; + productRefGroup = 899757495517A251C8F12BFC05F2F662 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 58E7450DB13C5ECCE92D3C0DF7CF0903 /* GoogleToolboxForMac */, + DE868725B18AE240E550C5515AE66BC4 /* GTMSessionFetcher */, + 1E5280EF7C55EA14FF78108514A368E3 /* Pods-Task Burner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 474FE5FB84FE06E59DA34EFCEB7B07B2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74B88A8B5B43AE22CE208F1AF9315336 /* GTMSessionFetcher-dummy.m in Sources */, + 9B3794E275C6348A291A1E0A52CAF113 /* GTMSessionFetcher.m in Sources */, + CDA0F61C3BD605E63D0500A1A0574969 /* GTMSessionFetcherLogging.m in Sources */, + 9BB31E94CF2D3BEB22EEC2E0D2147C64 /* GTMSessionFetcherService.m in Sources */, + 522C0FE7197A2D7D3D925ADA58429D05 /* GTMSessionUploadFetcher.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F420568B3452EA879A95D5FCBB393332 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2583A3E4525E67AC3D64936F3952D567 /* Pods-Task Burner-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F86A0216D6948A1D34655DBC29C561FC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3328D6AA0A6DD5371B63ECAD18718F3F /* GoogleToolboxForMac-dummy.m in Sources */, + E071ED04676790AFF262727DB6BC5DE1 /* GTMNSData+zlib.m in Sources */, + 5353CD4CF7B378621E34EA62C699E40F /* GTMNSDictionary+URLArguments.m in Sources */, + ACBF3E2E9A6B3E9FD859BF001F20D694 /* GTMNSString+URLArguments.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 9D56C6408784B28A8DFE97E0EBA85906 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GTMSessionFetcher; + target = DE868725B18AE240E550C5515AE66BC4 /* GTMSessionFetcher */; + targetProxy = 46A250E2AE529E111F158A88D1FA619B /* PBXContainerItemProxy */; + }; + D16A576588AF6A610139B6AB9B910A5A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleToolboxForMac; + target = 58E7450DB13C5ECCE92D3C0DF7CF0903 /* GoogleToolboxForMac */; + targetProxy = 402CF8AFD3F030BFD607E1A1FF3CDDA0 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 059338D4D9216B410FCAE27130A15DED /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C971B9EA7E7B9214492546F7D4052C0F /* Pods-Task Burner.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MACH_O_TYPE = staticlib; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 12914D756594D15C6F2CA12FE5F89F1B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_REQUIRED = NO; + COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + ONLY_ACTIVE_ARCH = YES; + PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 280F1391035F25CB3FC30138CEEE39B4 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3302A115413B703F3744584FED312A14 /* Pods-Task Burner.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MACH_O_TYPE = staticlib; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 2F5F5B61233D182FE923F37462D6E73B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B0BCEB2BE215955E08FBABAC2F342963 /* GoogleToolboxForMac.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 3E15E1221F5F51D737D557DF33F26CE7 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B0BCEB2BE215955E08FBABAC2F342963 /* GoogleToolboxForMac.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 6089EF5AAE5528CF09E8655B284A438E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6B344812936B5768866A3C61F687744F /* GTMSessionFetcher.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 85750C6A2D9EFD780B5CD014850783CA /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6B344812936B5768866A3C61F687744F /* GTMSessionFetcher.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + E72E7977875C2D251FC62736BBDDC389 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_REQUIRED = NO; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 26AE791F404F3732C3335D0EFE25E20A /* Build configuration list for PBXNativeTarget "GoogleToolboxForMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3E15E1221F5F51D737D557DF33F26CE7 /* Debug */, + 2F5F5B61233D182FE923F37462D6E73B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 12914D756594D15C6F2CA12FE5F89F1B /* Debug */, + E72E7977875C2D251FC62736BBDDC389 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4693C211CA1C7318A8B388F1C2D24725 /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 85750C6A2D9EFD780B5CD014850783CA /* Debug */, + 6089EF5AAE5528CF09E8655B284A438E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A59ACE6F9676B20B2B8BEB84FFEFEE31 /* Build configuration list for PBXNativeTarget "Pods-Task Burner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 059338D4D9216B410FCAE27130A15DED /* Debug */, + 280F1391035F25CB3FC30138CEEE39B4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; +} diff --git a/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme new file mode 100644 index 0000000..1faa246 --- /dev/null +++ b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme new file mode 100644 index 0000000..ff1438d --- /dev/null +++ b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Burner.xcscheme b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Burner.xcscheme new file mode 100644 index 0000000..93c596a --- /dev/null +++ b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Burner.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..82973a5 --- /dev/null +++ b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,42 @@ + + + + + SchemeUserState + + GTMSessionFetcher.xcscheme + + orderHint + 2 + + GoogleToolboxForMac.xcscheme + + orderHint + 1 + + Pods-Task Burner.xcscheme + + orderHint + 3 + + + SuppressBuildableAutocreation + + 1E5280EF7C55EA14FF78108514A368E3 + + primary + + + 58E7450DB13C5ECCE92D3C0DF7CF0903 + + primary + + + DE868725B18AE240E550C5515AE66BC4 + + primary + + + + + diff --git a/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme new file mode 100644 index 0000000..8aa99fc --- /dev/null +++ b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme new file mode 100644 index 0000000..43f1ae2 --- /dev/null +++ b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/Pods-Task Burner.xcscheme b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/Pods-Task Burner.xcscheme new file mode 100644 index 0000000..a6086f3 --- /dev/null +++ b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/Pods-Task Burner.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/xcschememanagement.plist b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..6025899 --- /dev/null +++ b/Code Burner/Pods/Pods.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,42 @@ + + + + + SchemeUserState + + GTMSessionFetcher.xcscheme + + isShown + + + GoogleToolboxForMac.xcscheme + + isShown + + + Pods-Task Burner.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + 1E5280EF7C55EA14FF78108514A368E3 + + primary + + + 58E7450DB13C5ECCE92D3C0DF7CF0903 + + primary + + + DE868725B18AE240E550C5515AE66BC4 + + primary + + + + + diff --git a/Code Burner/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m b/Code Burner/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m new file mode 100644 index 0000000..13d68b3 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GTMSessionFetcher : NSObject +@end +@implementation PodsDummy_GTMSessionFetcher +@end diff --git a/Code Burner/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch b/Code Burner/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import +#endif + diff --git a/Code Burner/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig b/Code Burner/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig new file mode 100644 index 0000000..ec28739 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig @@ -0,0 +1,9 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleInterchangeUtilities" "${PODS_ROOT}/Headers/Public/GoogleSymbolUtilities" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = -framework "Security" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES diff --git a/Code Burner/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-dummy.m b/Code Burner/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-dummy.m new file mode 100644 index 0000000..9e35ec0 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GoogleToolboxForMac : NSObject +@end +@implementation PodsDummy_GoogleToolboxForMac +@end diff --git a/Code Burner/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch b/Code Burner/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import +#endif + diff --git a/Code Burner/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.xcconfig b/Code Burner/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.xcconfig new file mode 100644 index 0000000..3899b59 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.xcconfig @@ -0,0 +1,9 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/GoogleToolboxForMac" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleInterchangeUtilities" "${PODS_ROOT}/Headers/Public/GoogleSymbolUtilities" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = -l"z" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES diff --git a/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-acknowledgements.markdown b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-acknowledgements.markdown new file mode 100644 index 0000000..a6a3554 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-acknowledgements.markdown @@ -0,0 +1,447 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## Firebase + +Copyright 2016 Google + +## FirebaseAnalytics + +Copyright 2016 Google + +## FirebaseAuth + +Copyright 2016 Google + +## FirebaseCore + +Copyright 2016 Google + +## FirebaseDatabase + +Copyright 2016 Google + +## FirebaseInstanceID + +Copyright 2016 Google + +## GTMSessionFetcher + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## GoogleInterchangeUtilities + +Copyright 2016 Google + +## GoogleSymbolUtilities + +Copyright 2016 Google + +## GoogleToolboxForMac + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Generated by CocoaPods - https://cocoapods.org diff --git a/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-acknowledgements.plist b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-acknowledgements.plist new file mode 100644 index 0000000..5659be3 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-acknowledgements.plist @@ -0,0 +1,533 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Copyright 2016 Google + License + Copyright + Title + Firebase + Type + PSGroupSpecifier + + + FooterText + Copyright 2016 Google + License + Copyright + Title + FirebaseAnalytics + Type + PSGroupSpecifier + + + FooterText + Copyright 2016 Google + License + Copyright + Title + FirebaseAuth + Type + PSGroupSpecifier + + + FooterText + Copyright 2016 Google + License + Copyright + Title + FirebaseCore + Type + PSGroupSpecifier + + + FooterText + Copyright 2016 Google + License + Copyright + Title + FirebaseDatabase + Type + PSGroupSpecifier + + + FooterText + Copyright 2016 Google + License + Copyright + Title + FirebaseInstanceID + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + GTMSessionFetcher + Type + PSGroupSpecifier + + + FooterText + Copyright 2016 Google + License + Copyright + Title + GoogleInterchangeUtilities + Type + PSGroupSpecifier + + + FooterText + Copyright 2016 Google + License + Copyright + Title + GoogleSymbolUtilities + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + GoogleToolboxForMac + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-dummy.m b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-dummy.m new file mode 100644 index 0000000..c18edc1 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_Task_Burner : NSObject +@end +@implementation PodsDummy_Pods_Task_Burner +@end diff --git a/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-frameworks.sh b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-frameworks.sh new file mode 100755 index 0000000..893c16a --- /dev/null +++ b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-frameworks.sh @@ -0,0 +1,84 @@ +#!/bin/sh +set -e + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +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 dont' throw errors + echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync -av --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}" + 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 && exit ${PIPESTATUS[0]}) + 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 +} + +# 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_identitiy + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\"" + /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1" + fi +} + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + # Get architectures for current file + archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" + stripped="" + for arch in $archs; do + if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" || exit 1 + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi +} + diff --git a/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-resources.sh b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-resources.sh new file mode 100755 index 0000000..25e9d37 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-resources.sh @@ -0,0 +1,96 @@ +#!/bin/sh +set -e + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +case "${TARGETED_DEVICE_FAMILY}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; +esac + +install_resource() +{ + if [[ "$1" = /* ]] ; then + RESOURCE_PATH="$1" + else + RESOURCE_PATH="${PODS_ROOT}/$1" + fi + if [[ ! -e "$RESOURCE_PATH" ]] ; then + cat << EOM +error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. +EOM + exit 1 + fi + case $RESOURCE_PATH in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.framework) + echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" + xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + *) + echo "$RESOURCE_PATH" + echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" + ;; + esac +} + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] +then + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "${PODS_ROOT}*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi diff --git a/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner.debug.xcconfig b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner.debug.xcconfig new file mode 100644 index 0000000..4c376a3 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner.debug.xcconfig @@ -0,0 +1,10 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/FirebaseAnalytics/Frameworks/frameworks" "${PODS_ROOT}/FirebaseAuth/Frameworks/frameworks" "${PODS_ROOT}/FirebaseCore/Frameworks/frameworks" "${PODS_ROOT}/FirebaseDatabase/Frameworks" "${PODS_ROOT}/FirebaseInstanceID/Frameworks/frameworks" "${PODS_ROOT}/GoogleInterchangeUtilities/Frameworks/frameworks" "${PODS_ROOT}/GoogleSymbolUtilities/Frameworks/frameworks" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) ${PODS_ROOT}/Firebase/Core/Sources $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleInterchangeUtilities" "${PODS_ROOT}/Headers/Public/GoogleSymbolUtilities" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher" "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Firebase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAuth" -isystem "${PODS_ROOT}/Headers/Public/FirebaseCore" -isystem "${PODS_ROOT}/Headers/Public/FirebaseDatabase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" -isystem "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" -isystem "${PODS_ROOT}/Headers/Public/GoogleInterchangeUtilities" -isystem "${PODS_ROOT}/Headers/Public/GoogleSymbolUtilities" -isystem "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = $(inherited) -ObjC -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"c++" -l"icucore" -l"sqlite3" -l"z" -framework "AddressBook" -framework "CFNetwork" -framework "FirebaseAnalytics" -framework "FirebaseAuth" -framework "FirebaseCore" -framework "FirebaseDatabase" -framework "FirebaseInstanceID" -framework "GoogleInterchangeUtilities" -framework "GoogleSymbolUtilities" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT}/Pods diff --git a/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner.release.xcconfig b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner.release.xcconfig new file mode 100644 index 0000000..4c376a3 --- /dev/null +++ b/Code Burner/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner.release.xcconfig @@ -0,0 +1,10 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/FirebaseAnalytics/Frameworks/frameworks" "${PODS_ROOT}/FirebaseAuth/Frameworks/frameworks" "${PODS_ROOT}/FirebaseCore/Frameworks/frameworks" "${PODS_ROOT}/FirebaseDatabase/Frameworks" "${PODS_ROOT}/FirebaseInstanceID/Frameworks/frameworks" "${PODS_ROOT}/GoogleInterchangeUtilities/Frameworks/frameworks" "${PODS_ROOT}/GoogleSymbolUtilities/Frameworks/frameworks" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) ${PODS_ROOT}/Firebase/Core/Sources $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleInterchangeUtilities" "${PODS_ROOT}/Headers/Public/GoogleSymbolUtilities" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher" "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Firebase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAuth" -isystem "${PODS_ROOT}/Headers/Public/FirebaseCore" -isystem "${PODS_ROOT}/Headers/Public/FirebaseDatabase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" -isystem "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" -isystem "${PODS_ROOT}/Headers/Public/GoogleInterchangeUtilities" -isystem "${PODS_ROOT}/Headers/Public/GoogleSymbolUtilities" -isystem "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = $(inherited) -ObjC -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"c++" -l"icucore" -l"sqlite3" -l"z" -framework "AddressBook" -framework "CFNetwork" -framework "FirebaseAnalytics" -framework "FirebaseAuth" -framework "FirebaseCore" -framework "FirebaseDatabase" -framework "FirebaseInstanceID" -framework "GoogleInterchangeUtilities" -framework "GoogleSymbolUtilities" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT}/Pods diff --git a/Code Burner/Task Burner.xcodeproj/project.pbxproj b/Code Burner/Task Burner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ce49bf3 --- /dev/null +++ b/Code Burner/Task Burner.xcodeproj/project.pbxproj @@ -0,0 +1,431 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 45CA5D42B8CBE71912BD2C9A /* libPods-Task Burner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B72FA14CE29787D43139CEF1 /* libPods-Task Burner.a */; }; + B82D98C81DB6A79100FDFCCD /* TasksTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82D98C71DB6A79100FDFCCD /* TasksTableViewCell.swift */; }; + B82D98CA1DB6B2C800FDFCCD /* TaskViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82D98C91DB6B2C800FDFCCD /* TaskViewController.swift */; }; + B82D98CC1DB6E29E00FDFCCD /* AlertController-Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82D98CB1DB6E29E00FDFCCD /* AlertController-Extension.swift */; }; + B84AC7BC1DB52D1300FA230A /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B84AC7BB1DB52D1300FA230A /* GoogleService-Info.plist */; }; + B8C2F8DE1DB5232A00207796 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8C2F8DD1DB5232A00207796 /* AppDelegate.swift */; }; + B8C2F8E01DB5232A00207796 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8C2F8DF1DB5232A00207796 /* MainViewController.swift */; }; + B8C2F8E31DB5232A00207796 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B8C2F8E11DB5232A00207796 /* Main.storyboard */; }; + B8C2F8E51DB5232B00207796 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B8C2F8E41DB5232B00207796 /* Assets.xcassets */; }; + B8C2F8E81DB5232B00207796 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B8C2F8E61DB5232B00207796 /* LaunchScreen.storyboard */; }; + B8E067311DB62088007419FC /* TasksTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8E067301DB62088007419FC /* TasksTableViewController.swift */; }; + B8E067331DB62CAE007419FC /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8E067321DB62CAE007419FC /* Task.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 207C24F525BD260A052EACE5 /* Pods-Task Burner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Task Burner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner.release.xcconfig"; sourceTree = ""; }; + B72FA14CE29787D43139CEF1 /* libPods-Task Burner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Task Burner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + B82D98C71DB6A79100FDFCCD /* TasksTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TasksTableViewCell.swift; sourceTree = ""; }; + B82D98C91DB6B2C800FDFCCD /* TaskViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TaskViewController.swift; sourceTree = ""; }; + B82D98CB1DB6E29E00FDFCCD /* AlertController-Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AlertController-Extension.swift"; sourceTree = ""; }; + B82D98CD1DB72A8200FDFCCD /* Task Burner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Task Burner-Bridging-Header.h"; sourceTree = ""; }; + B84AC7BB1DB52D1300FA230A /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + B84AC7BD1DB52D3C00FA230A /* Task Burner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Task Burner.entitlements"; sourceTree = ""; }; + B8C2F8DA1DB5232A00207796 /* Task Burner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Task Burner.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + B8C2F8DD1DB5232A00207796 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + B8C2F8DF1DB5232A00207796 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; + B8C2F8E21DB5232A00207796 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + B8C2F8E41DB5232B00207796 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B8C2F8E71DB5232B00207796 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + B8C2F8E91DB5232B00207796 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B8E067301DB62088007419FC /* TasksTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TasksTableViewController.swift; sourceTree = ""; }; + B8E067321DB62CAE007419FC /* Task.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Task.swift; sourceTree = ""; }; + DF26735651F8B15D975F56B5 /* Pods-Task Burner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Task Burner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B8C2F8D71DB5232A00207796 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 45CA5D42B8CBE71912BD2C9A /* libPods-Task Burner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B5022416AD8DF4145B8B5A4C /* Pods */ = { + isa = PBXGroup; + children = ( + DF26735651F8B15D975F56B5 /* Pods-Task Burner.debug.xcconfig */, + 207C24F525BD260A052EACE5 /* Pods-Task Burner.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + B8C2F8D11DB5232A00207796 = { + isa = PBXGroup; + children = ( + B8C2F8DC1DB5232A00207796 /* Task Burner */, + B8C2F8DB1DB5232A00207796 /* Products */, + B5022416AD8DF4145B8B5A4C /* Pods */, + E7291096473FC2BC761E220C /* Frameworks */, + ); + sourceTree = ""; + }; + B8C2F8DB1DB5232A00207796 /* Products */ = { + isa = PBXGroup; + children = ( + B8C2F8DA1DB5232A00207796 /* Task Burner.app */, + ); + name = Products; + sourceTree = ""; + }; + B8C2F8DC1DB5232A00207796 /* Task Burner */ = { + isa = PBXGroup; + children = ( + B84AC7BD1DB52D3C00FA230A /* Task Burner.entitlements */, + B8C2F8DD1DB5232A00207796 /* AppDelegate.swift */, + B82D98CB1DB6E29E00FDFCCD /* AlertController-Extension.swift */, + B8C2F8DF1DB5232A00207796 /* MainViewController.swift */, + B8E067321DB62CAE007419FC /* Task.swift */, + B8E067301DB62088007419FC /* TasksTableViewController.swift */, + B82D98C71DB6A79100FDFCCD /* TasksTableViewCell.swift */, + B82D98C91DB6B2C800FDFCCD /* TaskViewController.swift */, + B8C2F8E11DB5232A00207796 /* Main.storyboard */, + B8C2F8E41DB5232B00207796 /* Assets.xcassets */, + B8C2F8E61DB5232B00207796 /* LaunchScreen.storyboard */, + B84AC7BB1DB52D1300FA230A /* GoogleService-Info.plist */, + B8C2F8E91DB5232B00207796 /* Info.plist */, + B82D98CD1DB72A8200FDFCCD /* Task Burner-Bridging-Header.h */, + ); + path = "Task Burner"; + sourceTree = ""; + }; + E7291096473FC2BC761E220C /* Frameworks */ = { + isa = PBXGroup; + children = ( + B72FA14CE29787D43139CEF1 /* libPods-Task Burner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B8C2F8D91DB5232A00207796 /* Task Burner */ = { + isa = PBXNativeTarget; + buildConfigurationList = B8C2F8EC1DB5232B00207796 /* Build configuration list for PBXNativeTarget "Task Burner" */; + buildPhases = ( + E6D3BDC72DBC94F932597F78 /* [CP] Check Pods Manifest.lock */, + B8C2F8D61DB5232A00207796 /* Sources */, + B8C2F8D71DB5232A00207796 /* Frameworks */, + B8C2F8D81DB5232A00207796 /* Resources */, + 0FFB6AD8644EA1930C3358D1 /* [CP] Embed Pods Frameworks */, + 7BAC257DE23402FE29997F00 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Task Burner"; + productName = "Task Burner"; + productReference = B8C2F8DA1DB5232A00207796 /* Task Burner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B8C2F8D21DB5232A00207796 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0810; + LastUpgradeCheck = 0810; + ORGANIZATIONNAME = "Andrei Nagy"; + TargetAttributes = { + B8C2F8D91DB5232A00207796 = { + CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 0800; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Keychain = { + enabled = 1; + }; + }; + }; + }; + }; + buildConfigurationList = B8C2F8D51DB5232A00207796 /* Build configuration list for PBXProject "Task Burner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B8C2F8D11DB5232A00207796; + productRefGroup = B8C2F8DB1DB5232A00207796 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B8C2F8D91DB5232A00207796 /* Task Burner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B8C2F8D81DB5232A00207796 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B84AC7BC1DB52D1300FA230A /* GoogleService-Info.plist in Resources */, + B8C2F8E81DB5232B00207796 /* LaunchScreen.storyboard in Resources */, + B8C2F8E51DB5232B00207796 /* Assets.xcassets in Resources */, + B8C2F8E31DB5232A00207796 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0FFB6AD8644EA1930C3358D1 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 7BAC257DE23402FE29997F00 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Task Burner/Pods-Task Burner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + E6D3BDC72DBC94F932597F78 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B8C2F8D61DB5232A00207796 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B8E067331DB62CAE007419FC /* Task.swift in Sources */, + B82D98C81DB6A79100FDFCCD /* TasksTableViewCell.swift in Sources */, + B8E067311DB62088007419FC /* TasksTableViewController.swift in Sources */, + B8C2F8E01DB5232A00207796 /* MainViewController.swift in Sources */, + B8C2F8DE1DB5232A00207796 /* AppDelegate.swift in Sources */, + B82D98CC1DB6E29E00FDFCCD /* AlertController-Extension.swift in Sources */, + B82D98CA1DB6B2C800FDFCCD /* TaskViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + B8C2F8E11DB5232A00207796 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B8C2F8E21DB5232A00207796 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + B8C2F8E61DB5232B00207796 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B8C2F8E71DB5232B00207796 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + B8C2F8EA1DB5232B00207796 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "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 = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + B8C2F8EB1DB5232B00207796 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + 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; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B8C2F8ED1DB5232B00207796 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DF26735651F8B15D975F56B5 /* Pods-Task Burner.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = "Task Burner/Task Burner.entitlements"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = ""; + INFOPLIST_FILE = "Task Burner/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.weheartswift.taskburner; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Task Burner/Task Burner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + B8C2F8EE1DB5232B00207796 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 207C24F525BD260A052EACE5 /* Pods-Task Burner.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = "Task Burner/Task Burner.entitlements"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = ""; + INFOPLIST_FILE = "Task Burner/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.weheartswift.taskburner; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Task Burner/Task Burner-Bridging-Header.h"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B8C2F8D51DB5232A00207796 /* Build configuration list for PBXProject "Task Burner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B8C2F8EA1DB5232B00207796 /* Debug */, + B8C2F8EB1DB5232B00207796 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B8C2F8EC1DB5232B00207796 /* Build configuration list for PBXNativeTarget "Task Burner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B8C2F8ED1DB5232B00207796 /* Debug */, + B8C2F8EE1DB5232B00207796 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B8C2F8D21DB5232A00207796 /* Project object */; +} diff --git a/Code Burner/Task Burner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Code Burner/Task Burner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..75ea9ad --- /dev/null +++ b/Code Burner/Task Burner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Code Burner/Task Burner.xcodeproj/project.xcworkspace/xcuserdata/nand.xcuserdatad/UserInterfaceState.xcuserstate b/Code Burner/Task Burner.xcodeproj/project.xcworkspace/xcuserdata/nand.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..5a748ba Binary files /dev/null and b/Code Burner/Task Burner.xcodeproj/project.xcworkspace/xcuserdata/nand.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Code Burner/Task Burner.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Task Burner.xcscheme b/Code Burner/Task Burner.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Task Burner.xcscheme new file mode 100644 index 0000000..b5a5200 --- /dev/null +++ b/Code Burner/Task Burner.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Task Burner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Task Burner.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist b/Code Burner/Task Burner.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..cf3da8d --- /dev/null +++ b/Code Burner/Task Burner.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + Task Burner.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + B8C2F8D91DB5232A00207796 + + primary + + + + + diff --git a/Code Burner/Task Burner.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/Task Burner.xcscheme b/Code Burner/Task Burner.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/Task Burner.xcscheme new file mode 100644 index 0000000..074a7bc --- /dev/null +++ b/Code Burner/Task Burner.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/Task Burner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Task Burner.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/xcschememanagement.plist b/Code Burner/Task Burner.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..cf3da8d --- /dev/null +++ b/Code Burner/Task Burner.xcodeproj/xcuserdata/andrei.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + Task Burner.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + B8C2F8D91DB5232A00207796 + + primary + + + + + diff --git a/Code Burner/Task Burner.xcodeproj/xcuserdata/nand.xcuserdatad/xcschemes/Task Burner.xcscheme b/Code Burner/Task Burner.xcodeproj/xcuserdata/nand.xcuserdatad/xcschemes/Task Burner.xcscheme new file mode 100644 index 0000000..074a7bc --- /dev/null +++ b/Code Burner/Task Burner.xcodeproj/xcuserdata/nand.xcuserdatad/xcschemes/Task Burner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Task Burner.xcodeproj/xcuserdata/nand.xcuserdatad/xcschemes/xcschememanagement.plist b/Code Burner/Task Burner.xcodeproj/xcuserdata/nand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..cf3da8d --- /dev/null +++ b/Code Burner/Task Burner.xcodeproj/xcuserdata/nand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + Task Burner.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + B8C2F8D91DB5232A00207796 + + primary + + + + + diff --git a/Code Burner/Task Burner.xcworkspace/contents.xcworkspacedata b/Code Burner/Task Burner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..4ac1a8a --- /dev/null +++ b/Code Burner/Task Burner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Code Burner/Task Burner.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate b/Code Burner/Task Burner.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..84db1d4 Binary files /dev/null and b/Code Burner/Task Burner.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Code Burner/Task Burner.xcworkspace/xcuserdata/andrei.xcuserdatad/UserInterfaceState.xcuserstate b/Code Burner/Task Burner.xcworkspace/xcuserdata/andrei.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..2a934a9 Binary files /dev/null and b/Code Burner/Task Burner.xcworkspace/xcuserdata/andrei.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Code Burner/Task Burner.xcworkspace/xcuserdata/nand.xcuserdatad/UserInterfaceState.xcuserstate b/Code Burner/Task Burner.xcworkspace/xcuserdata/nand.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..9c4a357 Binary files /dev/null and b/Code Burner/Task Burner.xcworkspace/xcuserdata/nand.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Code Burner/Task Burner.xcworkspace/xcuserdata/nand.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Code Burner/Task Burner.xcworkspace/xcuserdata/nand.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..404a35d --- /dev/null +++ b/Code Burner/Task Burner.xcworkspace/xcuserdata/nand.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Task Burner/AlertController-Extension.swift b/Code Burner/Task Burner/AlertController-Extension.swift new file mode 100644 index 0000000..5ffe394 --- /dev/null +++ b/Code Burner/Task Burner/AlertController-Extension.swift @@ -0,0 +1,24 @@ +// +// AlertController-Extension.swift +// Task Burner +// +// Created by Andrei Nagy on 10/19/16. +// Copyright © 2016 weheartswift.com. All rights reserved. +// + +import Foundation +import UIKit + +extension UIAlertController { + + static func withError(error: NSError) -> UIAlertController { + let alert = UIAlertController(title: "Error", + message: error.localizedDescription, + preferredStyle: .alert) + + let cancelAction = UIAlertAction(title: "Ok", + style: .default) + alert.addAction(cancelAction) + return alert + } +} diff --git a/Code Burner/Task Burner/AppDelegate.swift b/Code Burner/Task Burner/AppDelegate.swift new file mode 100644 index 0000000..f9d2c93 --- /dev/null +++ b/Code Burner/Task Burner/AppDelegate.swift @@ -0,0 +1,48 @@ +// +// AppDelegate.swift +// Task Burner +// +// Created by Andrei Nagy on 10/17/16. +// Copyright © 2016 weheartswift.com. All rights reserved. +// + +import UIKit +import Firebase + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + + FIRApp.configure() + FIRDatabase.database().persistenceEnabled = true + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Contents.json b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..2d7e7f3 --- /dev/null +++ b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,151 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-App-57x57@1x.png", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "iphone", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..d39c904 Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..265e477 Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..a2a3405 Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..49dedb3 Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..55f1ac1 Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..75dbcdb Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..4a31fec Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..afa783e Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..5e356e6 Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..2a4994e Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..7868d9c Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..db032c2 Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png new file mode 100644 index 0000000..2503b71 Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png differ diff --git a/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..5e0ee07 Binary files /dev/null and b/Code Burner/Task Burner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/Code Burner/Task Burner/Base.lproj/LaunchScreen.storyboard b/Code Burner/Task Burner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/Code Burner/Task Burner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Task Burner/Base.lproj/Main.storyboard b/Code Burner/Task Burner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..c53abd9 --- /dev/null +++ b/Code Burner/Task Burner/Base.lproj/Main.storyboard @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Code Burner/Task Burner/GoogleService-Info.plist b/Code Burner/Task Burner/GoogleService-Info.plist new file mode 100644 index 0000000..90dd632 --- /dev/null +++ b/Code Burner/Task Burner/GoogleService-Info.plist @@ -0,0 +1,40 @@ + + + + + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 + CLIENT_ID + 728646273657-g26tag9152qbp2e50aussp72dmeoce3d.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.728646273657-g26tag9152qbp2e50aussp72dmeoce3d + API_KEY + AIzaSyA7BDboQqWqCC8cFFAs0mQB6ww8BTVq9-M + GCM_SENDER_ID + 728646273657 + PLIST_VERSION + 1 + BUNDLE_ID + com.weheartswift.taskburner + PROJECT_ID + task-burner-b9eed + STORAGE_BUCKET + task-burner-b9eed.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:728646273657:ios:4aa1cabbaec64d03 + DATABASE_URL + https://task-burner-b9eed.firebaseio.com + + \ No newline at end of file diff --git a/Code Burner/Task Burner/Info.plist b/Code Burner/Task Burner/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/Code Burner/Task Burner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Code Burner/Task Burner/MainViewController.swift b/Code Burner/Task Burner/MainViewController.swift new file mode 100644 index 0000000..7abd140 --- /dev/null +++ b/Code Burner/Task Burner/MainViewController.swift @@ -0,0 +1,100 @@ +// +// ViewController.swift +// Task Burner +// +// Created by Andrei Nagy on 10/17/16. +// Copyright © 2016 weheartswift.com. All rights reserved. +// + +import UIKit +import Firebase + +let kUserLoggedInSegueIdentifier = "userLoggedIn" + +class MainViewController: UIViewController { + + /* @IBOutlets create references so strings can be read from + the UITextFields + */ + @IBOutlet weak var emailField: UITextField! + @IBOutlet weak var passwordField: UITextField! + + /* Have a reference to the last signed in user to compare + changes + */ + weak var currentUser: FIRUser? + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + if let auth = FIRAuth.auth() { + + /* Add a state change listener to firebase + to get a notification if the user signed in. + */ + auth.addStateDidChangeListener({ (auth, user) in + if user != nil && user != self.currentUser { + self.currentUser = user + self.performSegue(withIdentifier: kUserLoggedInSegueIdentifier, + sender: self) + } + }) + } + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + if let auth = FIRAuth.auth() { + /* Following the balance principle in iOS, + Stop listening to user state changes while not on screen. + */ + auth.removeStateDidChangeListener(self) + } + } + + @IBAction func login() { + if let email = self.emailField.text, + let password = self.passwordField.text, + let auth = FIRAuth.auth() { + + /* If both email and password fields are not empty, + call firebase signin + */ + auth.signIn(withEmail: email, + password: password) + } + } + + @IBAction func register() { + if let email = self.emailField.text, + let password = self.passwordField.text, + let auth = FIRAuth.auth() { + /* Note: creating a user automatically signs in. + */ + auth.createUser(withEmail: email, + password: password) { user, error in + if error != nil { + self.present(UIAlertController.withError(error: error as! NSError), + animated: true, + completion: nil) + } + } + } + } + + @IBAction func signOut(segue: UIStoryboardSegue) { + /* When Sign out is pressed, and the task list controller closes, + call Firebase sign out. + */ + if let auth = FIRAuth.auth() { + do { + try auth.signOut() + } catch { + self.present(UIAlertController.withError(error: error as NSError), + animated: true, + completion: nil) + } + } + } +} + diff --git a/Code Burner/Task Burner/Task Burner-Bridging-Header.h b/Code Burner/Task Burner/Task Burner-Bridging-Header.h new file mode 100644 index 0000000..200daac --- /dev/null +++ b/Code Burner/Task Burner/Task Burner-Bridging-Header.h @@ -0,0 +1,5 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import diff --git a/Code Burner/Task Burner/Task Burner.entitlements b/Code Burner/Task Burner/Task Burner.entitlements new file mode 100644 index 0000000..62040ca --- /dev/null +++ b/Code Burner/Task Burner/Task Burner.entitlements @@ -0,0 +1,10 @@ + + + + + keychain-access-groups + + $(AppIdentifierPrefix)com.weheartswift.taskburner + + + diff --git a/Code Burner/Task Burner/Task.swift b/Code Burner/Task Burner/Task.swift new file mode 100644 index 0000000..721706c --- /dev/null +++ b/Code Burner/Task Burner/Task.swift @@ -0,0 +1,55 @@ +// +// Task.swift +// Task Burner +// +// Created by Andrei Nagy on 10/18/16. +// Copyright © 2016 weheartswift.com. All rights reserved. +// + +import Foundation +import Firebase + +/* Have keys as constants to prevent spelling errors + * and avoid confusion. eg. "title" can be found in + * ViewControllers too, so places can exist where the + * particular string is used for something else. + */ +let kTaskTitleKey = "title" +let kTaskCompletedKey = "completed" +let kTaskUserKey = "user" + +struct Task { + let title: String + let user: String + let firebaseReference: FIRDatabaseReference? + var completed: Bool + + /* Constructor for instantiating a new object in code. + */ + init(title: String, user: String, completed: Bool, id: String = "") { + self.title = title + self.user = user + self.completed = completed + self.firebaseReference = nil + } + + /* Constructor for instantiating an object received from Firebase. + */ + init(snapshot: FIRDataSnapshot) { + let snapshotValue = snapshot.value as! [String: Any] + self.title = snapshotValue[kTaskTitleKey] as! String + self.user = snapshotValue[kTaskUserKey] as! String + self.completed = snapshotValue[kTaskCompletedKey] as! Bool + self.firebaseReference = snapshot.ref + } + + /* Member to help updating values of an existing object. + */ + func toDictionary() -> Any { + return [ + kTaskTitleKey: self.title, + kTaskUserKey: self.user, + kTaskCompletedKey: self.completed + ] + } +} diff --git a/Code Burner/Task Burner/TaskViewController.swift b/Code Burner/Task Burner/TaskViewController.swift new file mode 100644 index 0000000..d2e6ea5 --- /dev/null +++ b/Code Burner/Task Burner/TaskViewController.swift @@ -0,0 +1,30 @@ +// +// CreateTaskViewController.swift +// Task Burner +// +// Created by Andrei Nagy on 10/18/16. +// Copyright © 2016 weheartswift.com. All rights reserved. +// + +import UIKit + +class TaskViewController: UIViewController { + + var taskTitle: String? + var taskCompleted: Bool? + + @IBOutlet weak var titleField: UITextField! + @IBOutlet weak var completedSwitch: UISwitch! + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + self.titleField.text = self.taskTitle ?? "" + self.completedSwitch.setOn(taskCompleted ?? false, animated:false) + } + + func updateValues() { + self.taskTitle = self.titleField.text + self.taskCompleted = self.completedSwitch.isOn + } +} diff --git a/Code Burner/Task Burner/TasksTableViewCell.swift b/Code Burner/Task Burner/TasksTableViewCell.swift new file mode 100644 index 0000000..94c87d9 --- /dev/null +++ b/Code Burner/Task Burner/TasksTableViewCell.swift @@ -0,0 +1,15 @@ +// +// TasksTableViewCell.swift +// Task Burner +// +// Created by Andrei Nagy on 10/18/16. +// Copyright © 2016 weheartswift.com. All rights reserved. +// + +import UIKit + +class TasksTableViewCell: UITableViewCell { + + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var completedSwitch: UISwitch! +} diff --git a/Code Burner/Task Burner/TasksTableViewController.swift b/Code Burner/Task Burner/TasksTableViewController.swift new file mode 100644 index 0000000..bdba36d --- /dev/null +++ b/Code Burner/Task Burner/TasksTableViewController.swift @@ -0,0 +1,134 @@ +// +// TasksTableViewController.swift +// Task Burner +// +// Created by Andrei Nagy on 10/18/16. +// Copyright © 2016 weheartswift.com. All rights reserved. +// + +import UIKit +import Firebase + +let kTasksListPath = "tasks-list" +let kTaskViewControllerSegueIdentifier = "TaskViewController" + +class TasksTableViewController: UITableViewController { + + let tasksReference = FIRDatabase.database().reference(withPath: kTasksListPath) + var tasks = [Task]() + var selectedTask: Task? = nil + weak var currentUser = FIRAuth.auth()?.currentUser + + override func viewDidLoad() { + super.viewDidLoad() + + /* Query tasks from firebase when this view controller is instantiated + */ + self.tasksReference.queryOrdered(byChild: kTaskCompletedKey).observe(.value, with: { snapshot in + + /* The callback block will be executed each and every time the value changes. + */ + var items: [Task] = [] + + for item in snapshot.children { + let task = Task(snapshot: item as! FIRDataSnapshot) + items.append(task) + } + + self.tasks = items + self.tableView.reloadData() + }) + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == kTaskViewControllerSegueIdentifier { + /* Pass along the selected task to the particular task view controller. + */ + if let taskViewController = segue.destination as? TaskViewController { + taskViewController.taskTitle = self.selectedTask?.title + taskViewController.taskCompleted = self.selectedTask?.completed + } + } + } + + @IBAction func prepareForUnwind(segue: UIStoryboardSegue) { + if let taskViewController = segue.source as? TaskViewController { + taskViewController.updateValues() + + if let task = self.selectedTask { + /* This particular task was an existing one + it should be updated in Firebase. + */ + if let title = taskViewController.taskTitle, + let completed = taskViewController.taskCompleted, + let email = self.currentUser?.email { + + let taskFirebasePath = task.firebaseReference + taskFirebasePath?.updateChildValues([ + kTaskTitleKey: title, + kTaskUserKey: email, + kTaskCompletedKey: completed + ]) + } + } else { + /* This task is new, + it should be created in Firebase + */ + if let title = taskViewController.taskTitle, + let completed = taskViewController.taskCompleted, + let email = self.currentUser?.email { + + let task = Task(title: title, user: email, completed: completed) + let taskFirebasePath = self.tasksReference.ref.child(title.lowercased()) + taskFirebasePath.setValue(task.toDictionary()) + } + } + } + self.selectedTask = nil + } + + @IBAction func addTask() { + self.performSegue(withIdentifier: kTaskViewControllerSegueIdentifier, sender: self) + } + + // MARK: - Table view data source + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return self.tasks.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell", for: indexPath) + + if let c = cell as? TasksTableViewCell { + let task = self.tasks[indexPath.row] + c.titleLabel.text = task.title + c.completedSwitch.setOn(task.completed, animated: true) + } + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let task = self.tasks[indexPath.row] + + /* Keep a reference to the task that is currently edited. + */ + self.selectedTask = task + self.performSegue(withIdentifier: kTaskViewControllerSegueIdentifier, sender: self) + } + + override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + return true + } + + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + let task = self.tasks[indexPath.row] + /* Delete this task. + No tableview updates should be done here because a callback notification + will be provided. + */ + task.firebaseReference?.removeValue() + } + } +} diff --git a/Old Old Task Master/Podfile b/Old Old Task Master/Podfile new file mode 100644 index 0000000..5b1eb15 --- /dev/null +++ b/Old Old Task Master/Podfile @@ -0,0 +1,8 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '10.3' + +target 'Task Master' do + pod 'Firebase/Core' + pod 'Firebase/Database' + pod 'Firebase/Auth' + end diff --git a/Old Old Task Master/Podfile.lock b/Old Old Task Master/Podfile.lock new file mode 100644 index 0000000..88a8631 --- /dev/null +++ b/Old Old Task Master/Podfile.lock @@ -0,0 +1,54 @@ +PODS: + - Firebase/Auth (3.16.0): + - Firebase/Core + - FirebaseAuth (= 3.1.1) + - Firebase/Core (3.16.0): + - FirebaseAnalytics (= 3.8.0) + - FirebaseCore (= 3.6.0) + - Firebase/Database (3.16.0): + - Firebase/Core + - FirebaseDatabase (= 3.1.2) + - FirebaseAnalytics (3.8.0): + - FirebaseCore (~> 3.6) + - FirebaseInstanceID (~> 1.0) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseAuth (3.1.1): + - FirebaseAnalytics (~> 3.7) + - GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1) + - GTMSessionFetcher/Core (~> 1.1) + - FirebaseCore (3.6.0): + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseDatabase (3.1.2): + - FirebaseAnalytics (~> 3.7) + - FirebaseInstanceID (1.0.10): + - FirebaseCore (~> 3.6) + - GoogleToolboxForMac/DebugUtils (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/Defines (2.1.1) + - GoogleToolboxForMac/NSData+zlib (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSDictionary+URLArguments (2.1.1): + - GoogleToolboxForMac/DebugUtils (= 2.1.1) + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (2.1.1) + - GTMSessionFetcher/Core (1.1.9) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Core + - Firebase/Database + +SPEC CHECKSUMS: + Firebase: 21bf4a89d3f01bfbe11adc3a5d934a4a3d3a5fd6 + FirebaseAnalytics: 920e46455f27b0a52a80907a6d9b73ee4bd1c635 + FirebaseAuth: cc8a1824170adbd351edb7f994490a3fb5c18be6 + FirebaseCore: 9691ee2ade70c098d7cf92440f4303f16d83ca75 + FirebaseDatabase: 05c96d7b43a7368dc91c07791adb49683e1738d1 + FirebaseInstanceID: b9eedd6846fb5e1f0f7279e1deaa7a7e4cf8392e + GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0 + GTMSessionFetcher: 5c046c76a1f859bc9c187e918f18e4fc7bb57b5e + +PODFILE CHECKSUM: 5dada07b8ffcd867f75f4115acd0e8c161a70c90 + +COCOAPODS: 1.2.1 diff --git a/Old Old Task Master/Pods/Firebase/Core/Sources/Firebase.h b/Old Old Task Master/Pods/Firebase/Core/Sources/Firebase.h new file mode 100755 index 0000000..90798a6 --- /dev/null +++ b/Old Old Task Master/Pods/Firebase/Core/Sources/Firebase.h @@ -0,0 +1,52 @@ +#import +#import + +#if !defined(__has_include) + #error "Firebase.h won't import anything if your compiler doesn't support __has_include. Please \ + import the headers individually." +#else + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + +#endif // defined(__has_include) diff --git a/Old Old Task Master/Pods/Firebase/Core/Sources/module.modulemap b/Old Old Task Master/Pods/Firebase/Core/Sources/module.modulemap new file mode 100755 index 0000000..3685b54 --- /dev/null +++ b/Old Old Task Master/Pods/Firebase/Core/Sources/module.modulemap @@ -0,0 +1,4 @@ +module Firebase { + export * + header "Firebase.h" +} \ No newline at end of file diff --git a/Old Old Task Master/Pods/Firebase/README.md b/Old Old Task Master/Pods/Firebase/README.md new file mode 100755 index 0000000..bfc5419 --- /dev/null +++ b/Old Old Task Master/Pods/Firebase/README.md @@ -0,0 +1,76 @@ +# Firebase APIs for iOS + +Simplify your iOS development, grow your user base, and monetize more +effectively with Firebase services. + +Much more information can be found at [https://firebase.google.com](https://firebase.google.com). + +## Install a Firebase SDK using CocoaPods + +Firebase distributes several iOS specific APIs and SDKs via CocoaPods. +You can install the CocoaPods tool on OS X by running the following command from +the terminal. Detailed information is available in the [Getting Started +guide](https://guides.cocoapods.org/using/getting-started.html#getting-started). + +``` +$ sudo gem install cocoapods +``` + +## Try out an SDK + +You can try any of the SDKs with `pod try`. Run the following command and select +the SDK you are interested in when prompted: + +``` +$ pod try Firebase +``` + +Note that some SDKs may require credentials. More information is available in +the SDK-specific documentation at [https://firebase.google.com/docs/](https://firebase.google.com/docs/). + +## Add a Firebase SDK to your iOS app + +CocoaPods is used to install and manage dependencies in existing Xcode projects. + +1. Create an Xcode project, and save it to your local machine. +2. Create a file named `Podfile` in your project directory. This file defines + your project's dependencies, and is commonly referred to as a Podspec. +3. Open `Podfile`, and add your dependencies. A simple Podspec is shown here: + + ``` + platform :ios, '7.0' + pod 'Firebase' + ``` + +4. Save the file. +5. Open a terminal and `cd` to the directory containing the Podfile. + + ``` + $ cd /project/ + ``` + +6. Run the `pod install` command. This will install the SDKs specified in the + Podspec, along with any dependencies they may have. + + ``` + $ pod install + ``` + +7. Open your app's `.xcworkspace` file to launch Xcode. + Use this file for all development on your app. +8. You can also install other Firebase SDKs by adding the subspecs in the + Podfile. + + ``` + pod 'Firebase/AdMob' + pod 'Firebase/Analytics' + pod 'Firebase/AppIndexing' + pod 'Firebase/Auth' + pod 'Firebase/Crash' + pod 'Firebase/Database' + pod 'Firebase/DynamicLinks' + pod 'Firebase/Invites' + pod 'Firebase/Messaging' + pod 'Firebase/RemoteConfig' + pod 'Firebase/Storage' + ``` diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100755 index 0000000..35dc4be Binary files /dev/null and b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100755 index 0000000..e3ff4c1 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,57 @@ +#import + +#import "FIRAnalytics.h" + +/** + * Provides App Delegate handlers to be used in your App Delegate. + * + * To save time integrating Firebase Analytics in an application, Firebase Analytics does not + * require delegation implementation from the AppDelegate. Instead this is automatically done by + * Firebase Analytics. Should you choose instead to delegate manually, you can turn off the App + * Delegate Proxy by adding FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting + * it to NO, and adding the methods in this category to corresponding delegation handlers. + * + * To handle Universal Links, you must return YES in + * [UIApplicationDelegate application:didFinishLaunchingWithOptions:]. + */ +@interface FIRAnalytics (AppDelegate) + +/** + * Handles events related to a URL session that are waiting to be processed. + * + * For optimal use of Firebase Analytics, call this method from the + * [UIApplicationDelegate application:handleEventsForBackgroundURLSession:completionHandler] + * method of the app delegate in your app. + * + * @param identifier The identifier of the URL session requiring attention. + * @param completionHandler The completion handler to call when you finish processing the events. + * Calling this completion handler lets the system know that your app's user interface is + * updated and a new snapshot can be taken. + */ ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(void (^)(void))completionHandler; + +/** + * Handles the event when the app is launched by a URL. + * + * Call this method from [UIApplicationDelegate application:openURL:options:] (on iOS 9.0 and + * above), or [UIApplicationDelegate application:openURL:sourceApplication:annotation:] (on iOS 8.x + * and below) in your app. + * + * @param url The URL resource to open. This resource can be a network resource or a file. + */ ++ (void)handleOpenURL:(NSURL *)url; + +/** + * Handles the event when the app receives data associated with user activity that includes a + * Universal Link (on iOS 9.0 and above). + * + * Call this method from [UIApplication continueUserActivity:restorationHandler:] in your app + * delegate (on iOS 9.0 and above). + * + * @param userActivity The activity object containing the data associated with the task the user + * was performing. + */ ++ (void)handleUserActivity:(id)userActivity; + +@end diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100755 index 0000000..f5023f5 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,102 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///

    +///
  • app_clear_data
  • +///
  • app_remove
  • +///
  • app_update
  • +///
  • error
  • +///
  • first_open
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_" prefix +/// is reserved and should not be used. Note that event names are case-sensitive and that +/// logging two events whose names differ only in case will result in two distinct events. +/// @param parameters The dictionary of event parameters. Passing nil indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only NSString +/// and NSNumber (signed 64-bit integer and 64-bit floating-point number) parameter types are +/// supported. NSString parameter values can be up to 100 characters long. The "firebase_" +/// prefix is reserved and should not be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters; + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to nil removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_" prefix is +/// reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name; + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 36 characters long. Setting userID to nil removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets the current screen name, which specifies the current visual context in your app. This helps +/// identify the areas in your app where users spend their time and how they interact with your app. +/// +/// Note that screen reporting is enabled automatically and records the class name of the current +/// UIViewController for you without requiring you to call this method. If you implement +/// viewDidAppear in your UIViewController but do not call [super viewDidAppear:], that screen class +/// will not be automatically tracked. The class name can optionally be overridden by calling this +/// method in the viewDidAppear callback of your UIViewController and specifying the +/// screenClassOverride parameter. +/// +/// If your app does not use a distinct UIViewController for each screen, you should call this +/// method and specify a distinct screenName each time a new screen is presented to the user. +/// +/// The screen name and screen class remain in effect until the current UIViewController changes or +/// a new call to setScreenName:screenClass: is made. +/// +/// @param screenName The name of the current screen. Should contain 1 to 100 characters. Set to nil +/// to clear the current screen name. +/// @param screenClassOverride The name of the screen class. Should contain 1 to 100 characters. By +/// default this is the class name of the current UIViewController. Set to nil to revert to the +/// default class name. ++ (void)setScreenName:(nullable NSString *)screenName + screenClass:(nullable NSString *)screenClassOverride; + +/// The unique ID for this instance of the application. ++ (NSString *)appInstanceID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalyticsConfiguration.h b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalyticsConfiguration.h new file mode 100755 index 0000000..dc227a4 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalyticsConfiguration.h @@ -0,0 +1 @@ +#import diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRApp.h b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRApp.h new file mode 100755 index 0000000..de24da1 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRApp.h @@ -0,0 +1 @@ +#import diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRConfiguration.h b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRConfiguration.h new file mode 100755 index 0000000..be2ff7b --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRConfiguration.h @@ -0,0 +1 @@ +#import diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100755 index 0000000..3b40eec --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,336 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_" +/// prefix is reserved and should not be used. + +/// Add Payment Info event. This event signifies that a user has submitted their payment information +/// to your app. +static NSString *const kFIREventAddPaymentInfo = @"add_payment_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item was added to a cart for +/// purchase. Add this event to a funnel with kFIREventEcommercePurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c kFIRParameterValue parameter, you must +/// also supply the @c kFIRParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c kFIRParameterQuantity (signed 64-bit integer as NSNumber)
  • +///
  • @c kFIRParameterItemID (NSString)
  • +///
  • @c kFIRParameterItemName (NSString)
  • +///
  • @c kFIRParameterItemCategory (NSString)
  • +///
  • @c kFIRParameterItemLocationID (NSString) (optional)
  • +///
  • @c kFIRParameterPrice (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterOrigin (NSString) (optional)
  • +///
  • @c kFIRParameterDestination (NSString) (optional)
  • +///
  • @c kFIRParameterStartDate (NSString) (optional)
  • +///
  • @c kFIRParameterEndDate (NSString) (optional)
  • +///
+static NSString *const kFIREventAddToCart = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. +/// Use this event to identify popular gift items in your app. Note: If you supply the +/// @c kFIRParameterValue parameter, you must also supply the @c kFIRParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c kFIRParameterQuantity (signed 64-bit integer as NSNumber)
  • +///
  • @c kFIRParameterItemID (NSString)
  • +///
  • @c kFIRParameterItemName (NSString)
  • +///
  • @c kFIRParameterItemCategory (NSString)
  • +///
  • @c kFIRParameterItemLocationID (NSString) (optional)
  • +///
  • @c kFIRParameterPrice (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist = @"add_to_wishlist"; + +/// App Open event. By logging this event when an App is moved to the foreground, developers can +/// understand how often users leave and return during the course of a Session. Although Sessions +/// are automatically reported, this event can provide further clarification around the continuous +/// engagement of app-users. +static NSString *const kFIREventAppOpen = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your kFIREventEcommercePurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c kFIRParameterValue +/// parameter, you must also supply the @c kFIRParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterTransactionID (NSString) (optional)
  • +///
  • @c kFIRParameterStartDate (NSString) (optional)
  • +///
  • @c kFIRParameterEndDate (NSString) (optional)
  • +///
  • @c kFIRParameterNumberOfNights (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfRooms (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfPassengers (signed 64-bit integer as NSNumber) (optional) +/// for travel bookings
  • +///
  • @c kFIRParameterOrigin (NSString) (optional)
  • +///
  • @c kFIRParameterDestination (NSString) (optional)
  • +///
  • @c kFIRParameterTravelClass (NSString) (optional) for travel bookings
  • +///
+static NSString *const kFIREventBeginCheckout = @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters kFIRParameterSource, +/// kFIRParameterMedium or kFIRParameterCampaign. Params: +/// +///
    +///
  • @c kFIRParameterSource (NSString)
  • +///
  • @c kFIRParameterMedium (NSString)
  • +///
  • @c kFIRParameterCampaign (NSString)
  • +///
  • @c kFIRParameterTerm (NSString) (optional)
  • +///
  • @c kFIRParameterContent (NSString) (optional)
  • +///
  • @c kFIRParameterAdNetworkClickID (NSString) (optional)
  • +///
  • @c kFIRParameterCP1 (NSString) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails = @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c kFIREventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c kFIRParameterVirtualCurrencyName (NSString)
  • +///
  • @c kFIRParameterValue (signed 64-bit integer or double as NSNumber)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency = @"earn_virtual_currency"; + +/// E-Commerce Purchase event. This event signifies that an item was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c kFIRParameterValue parameter, you must also +/// supply the @c kFIRParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterTransactionID (NSString) (optional)
  • +///
  • @c kFIRParameterTax (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterShipping (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterCoupon (NSString) (optional)
  • +///
  • @c kFIRParameterLocation (NSString) (optional)
  • +///
  • @c kFIRParameterStartDate (NSString) (optional)
  • +///
  • @c kFIRParameterEndDate (NSString) (optional)
  • +///
  • @c kFIRParameterNumberOfNights (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfRooms (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfPassengers (signed 64-bit integer as NSNumber) (optional) +/// for travel bookings
  • +///
  • @c kFIRParameterOrigin (NSString) (optional)
  • +///
  • @c kFIRParameterDestination (NSString) (optional)
  • +///
  • @c kFIRParameterTravelClass (NSString) (optional) for travel bookings
  • +///
+static NSString *const kFIREventEcommercePurchase = @"ecommerce_purchase"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c kFIRParameterValue parameter, you must also supply the @c kFIRParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
+static NSString *const kFIREventGenerateLead = @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c kFIRParameterGroupID (NSString)
  • +///
+static NSString *const kFIREventJoinGroup = @"join_group"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c kFIRParameterLevel (signed 64-bit integer as NSNumber)
  • +///
  • @c kFIRParameterCharacter (NSString) (optional)
  • +///
+static NSString *const kFIREventLevelUp = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c kFIRParameterScore (signed 64-bit integer as NSNumber)
  • +///
  • @c kFIRParameterLevel (signed 64-bit integer as NSNumber) (optional)
  • +///
  • @c kFIRParameterCharacter (NSString) (optional)
  • +///
+static NSString *const kFIREventPostScore = @"post_score"; + +/// Present Offer event. This event signifies that the app has presented a purchase offer to a user. +/// Add this event to a funnel with the kFIREventAddToCart and kFIREventEcommercePurchase to gauge +/// your conversion process. Note: If you supply the @c kFIRParameterValue parameter, you must +/// also supply the @c kFIRParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c kFIRParameterQuantity (signed 64-bit integer as NSNumber)
  • +///
  • @c kFIRParameterItemID (NSString)
  • +///
  • @c kFIRParameterItemName (NSString)
  • +///
  • @c kFIRParameterItemCategory (NSString)
  • +///
  • @c kFIRParameterItemLocationID (NSString) (optional)
  • +///
  • @c kFIRParameterPrice (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
+static NSString *const kFIREventPresentOffer = @"present_offer"; + +/// E-Commerce Purchase Refund event. This event signifies that an item purchase was refunded. +/// Note: If you supply the @c kFIRParameterValue parameter, you must also supply the +/// @c kFIRParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterTransactionID (NSString) (optional)
  • +///
+static NSString *const kFIREventPurchaseRefund = @"purchase_refund"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c kFIRParameterSearchTerm (NSString)
  • +///
  • @c kFIRParameterStartDate (NSString) (optional)
  • +///
  • @c kFIRParameterEndDate (NSString) (optional)
  • +///
  • @c kFIRParameterNumberOfNights (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfRooms (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfPassengers (signed 64-bit integer as NSNumber) (optional) +/// for travel bookings
  • +///
  • @c kFIRParameterOrigin (NSString) (optional)
  • +///
  • @c kFIRParameterDestination (NSString) (optional)
  • +///
  • @c kFIRParameterTravelClass (NSString) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c kFIRParameterContentType (NSString)
  • +///
  • @c kFIRParameterItemID (NSString)
  • +///
+static NSString *const kFIREventSelectContent = @"select_content"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c kFIRParameterContentType (NSString)
  • +///
  • @c kFIRParameterItemID (NSString)
  • +///
+static NSString *const kFIREventShare = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c kFIRParameterSignUpMethod (NSString)
  • +///
+static NSString *const kFIREventSignUp = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c kFIRParameterItemName (NSString)
  • +///
  • @c kFIRParameterVirtualCurrencyName (NSString)
  • +///
  • @c kFIRParameterValue (signed 64-bit integer or double as NSNumber)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with kFIREventTutorialComplete to understand how many users complete this +/// process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin = @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with kFIREventTutorialBegin to gauge the completion rate of your +/// on-boarding process. +static NSString *const kFIREventTutorialComplete = @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c kFIRParameterAchievementID (NSString)
  • +///
+static NSString *const kFIREventUnlockAchievement = @"unlock_achievement"; + +/// View Item event. This event signifies that some content was shown to the user. This content may +/// be a product, a webpage or just a simple image or text. Use the appropriate parameters to +/// contextualize the event. Use this event to discover the most popular items viewed in your app. +/// Note: If you supply the @c kFIRParameterValue parameter, you must also supply the +/// @c kFIRParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c kFIRParameterItemID (NSString)
  • +///
  • @c kFIRParameterItemName (NSString)
  • +///
  • @c kFIRParameterItemCategory (NSString)
  • +///
  • @c kFIRParameterItemLocationID (NSString) (optional)
  • +///
  • @c kFIRParameterPrice (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterQuantity (signed 64-bit integer as NSNumber) (optional)
  • +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterStartDate (NSString) (optional)
  • +///
  • @c kFIRParameterEndDate (NSString) (optional)
  • +///
  • @c kFIRParameterFlightNumber (NSString) (optional) for travel bookings
  • +///
  • @c kFIRParameterNumberOfPassengers (signed 64-bit integer as NSNumber) (optional) +/// for travel bookings
  • +///
  • @c kFIRParameterNumberOfNights (signed 64-bit integer as NSNumber) (optional) for +/// travel bookings
  • +///
  • @c kFIRParameterNumberOfRooms (signed 64-bit integer as NSNumber) (optional) for +/// travel bookings
  • +///
  • @c kFIRParameterOrigin (NSString) (optional)
  • +///
  • @c kFIRParameterDestination (NSString) (optional)
  • +///
  • @c kFIRParameterSearchTerm (NSString) (optional) for travel bookings
  • +///
  • @c kFIRParameterTravelClass (NSString) (optional) for travel bookings
  • +///
+static NSString *const kFIREventViewItem = @"view_item"; + +/// View Item List event. Log this event when the user has been presented with a list of items of a +/// certain category. Params: +/// +///
    +///
  • @c kFIRParameterItemCategory (NSString)
  • +///
+static NSString *const kFIREventViewItemList = @"view_item_list"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c kFIRParameterSearchTerm (NSString)
  • +///
+static NSString *const kFIREventViewSearchResults = @"view_search_results"; diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIROptions.h b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIROptions.h new file mode 100755 index 0000000..126824b --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIROptions.h @@ -0,0 +1 @@ +#import diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100755 index 0000000..a43e347 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,369 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long. The "firebase_" prefix is reserved and should not be used. + +/// Game achievement ID (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterAchievementID : @"10_matches_won",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterAchievementID = @"achievement_id"; + +/// Ad Network Click ID (NSString). Used for network-specific click IDs which vary in format. +///
+///     NSDictionary *params = @{
+///       kFIRParameterAdNetworkClickID : @"1234567",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterAdNetworkClickID = @"aclid"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterCampaign : @"winter_promotion",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterCampaign = @"campaign"; + +/// Character used in game (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterCharacter : @"beat_boss",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterCharacter = @"character"; + +/// Campaign content (NSString). +static NSString *const kFIRParameterContent = @"content"; + +/// Type of content selected (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterContentType : @"news article",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterContentType = @"content_type"; + +/// Coupon code for a purchasable item (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterCoupon : @"zz123",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterCoupon = @"coupon"; + +/// Campaign custom parameter (NSString). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     NSDictionary *params = @{
+///       kFIRParameterCP1 : @"custom_data",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterCP1 = @"cp1"; + +/// Purchase currency in 3-letter +/// ISO_4217 format (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterCurrency : @"USD",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterCurrency = @"currency"; + +/// Flight or Travel destination (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterDestination : @"Mountain View, CA",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterDestination = @"destination"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterEndDate : @"2015-09-14",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterEndDate = @"end_date"; + +/// Flight number for travel events (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterFlightNumber : @"ZZ800",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterFlightNumber = @"flight_number"; + +/// Group/clan/guild ID (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterGroupID : @"g1",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterGroupID = @"group_id"; + +/// Item category (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterItemCategory : @"t-shirts",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterItemCategory = @"item_category"; + +/// Item ID (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterItemID : @"p7654",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterItemID = @"item_id"; + +/// The Google Place ID (NSString) that +/// corresponds to the associated item. Alternatively, you can supply your own custom Location ID. +///
+///     NSDictionary *params = @{
+///       kFIRParameterItemLocationID : @"ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterItemLocationID = @"item_location_id"; + +/// Item name (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterItemName : @"abc",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterItemName = @"item_name"; + +/// Level in game (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterLevel : @(42),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterLevel = @"level"; + +/// Location (NSString). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     NSDictionary *params = @{
+///       kFIRParameterLocation : @"ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterLocation = @"location"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterMedium : @"email",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterMedium = @"medium"; + +/// Number of nights staying at hotel (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterNumberOfNights : @(3),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterNumberOfNights = @"number_of_nights"; + +/// Number of passengers traveling (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterNumberOfPassengers : @(11),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterNumberOfPassengers = @"number_of_passengers"; + +/// Number of rooms for travel events (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterNumberOfRooms : @(2),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterNumberOfRooms = @"number_of_rooms"; + +/// Flight or Travel origin (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterOrigin : @"Mountain View, CA",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterOrigin = @"origin"; + +/// Purchase price (double as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterPrice : @(1.0),
+///       kFIRParameterCurrency : @"USD",  // e.g. $1.00 USD
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterPrice = @"price"; + +/// Purchase quantity (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterQuantity : @(1),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterQuantity = @"quantity"; + +/// Score in game (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterScore : @(4200),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterScore = @"score"; + +/// The search string/keywords used (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterSearchTerm : @"periodic table",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterSearchTerm = @"search_term"; + +/// Shipping cost (double as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterShipping : @(9.50),
+///       kFIRParameterCurrency : @"USD",  // e.g. $9.50 USD
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterShipping = @"shipping"; + +/// Sign up method (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterSignUpMethod : @"google",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterSignUpMethod = @"sign_up_method"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterSource : @"InMobi",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterSource = @"source"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterStartDate : @"2015-09-14",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterStartDate = @"start_date"; + +/// Tax amount (double as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterTax : @(1.0),
+///       kFIRParameterCurrency : @"USD",  // e.g. $1.00 USD
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterTax = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterTerm : @"game",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterTerm = @"term"; + +/// A single ID for a ecommerce group transaction (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterTransactionID : @"ab7236dd9823",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterTransactionID = @"transaction_id"; + +/// Travel class (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterTravelClass : @"business",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterTravelClass = @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as signed +/// 64-bit integer or double as NSNumber. Notes: Values for pre-defined currency-related events +/// (such as @c kFIREventAddToCart) should be supplied using double as NSNumber and must be +/// accompanied by a @c kFIRParameterCurrency parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. +///
+///     NSDictionary *params = @{
+///       kFIRParameterValue : @(3.99),
+///       kFIRParameterCurrency : @"USD",  // e.g. $3.99 USD
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterValue = @"value"; + +/// Name of virtual currency type (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterVirtualCurrencyName : @"virtual_currency_name",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName = @"virtual_currency_name"; diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100755 index 0000000..54cf1c2 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,13 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_" prefix is reserved and should not be used. + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod = @"sign_up_method"; diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100755 index 0000000..3142c97 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,9 @@ +#import "FIRAnalyticsConfiguration.h" +#import "FIRApp.h" +#import "FIRConfiguration.h" +#import "FIROptions.h" +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Modules/module.modulemap b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100755 index 0000000..6394d59 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,8 @@ +framework module FirebaseAnalytics { + umbrella header "FirebaseAnalytics.h" + export * + module * { export *} + link "sqlite3" + link "z" + link framework "UIKit" +} \ No newline at end of file diff --git a/Old Old Task Master/Pods/FirebaseAuth/CHANGELOG.md b/Old Old Task Master/Pods/FirebaseAuth/CHANGELOG.md new file mode 100755 index 0000000..a42f7d1 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/CHANGELOG.md @@ -0,0 +1,38 @@ +# 2017-02-06 -- v3.1.1 +- Allows handling of additional errors when sending OOB action emails. The + server can respond with the following new error messages: + INVALID_MESSAGE_PAYLOAD,INVALID_SENDER and INVALID_RECIPIENT_EMAIL. +- Removes incorrect reference to FIRAuthErrorCodeCredentialTooOld in FIRUser.h. +- Provides additional error information from server if available. + +# 2016-12-13 -- v3.1.0 +- Adds FIRAuth methods that enable the app to follow up with user actions + delivered by email, such as verifying email address or reset password. +- No longer applies the keychain workaround introduced in v3.0.5 on iOS 10.2 + simulator or above since the issue has been fixed. +- Fixes nullability compilation warnings when used in Swift. +- Better reports missing password error. + +# 2016-10-24 -- v3.0.6 +- Switches to depend on open sourced GoogleToolboxForMac and GTMSessionFetcher. +- Improves logging of keychain error when initializing. + +# 2016-09-14 -- v3.0.5 +- Works around a keychain issue in iOS 10 simulator. +- Reports the correct error for invalid email when signing in with email and + password. + +# 2016-07-18 -- v3.0.4 +- Fixes a race condition bug that could crash the app with an exception from + NSURLSession on iOS 9. + +# 2016-06-20 -- v3.0.3 +- Adds documentation for all possible errors returned by each method. +- Improves error handling and messages for a variety of error conditions. +- Whether or not an user is considered anonymous is now consistent with other + platforms. +- A saved signed in user is now siloed between different Firebase projects + within the same app. + +# 2016-05-18 -- v3.0.2 +- Initial public release. diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/FirebaseAuth b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/FirebaseAuth new file mode 100755 index 0000000..18675e6 Binary files /dev/null and b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/FirebaseAuth differ diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuth.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuth.h new file mode 100755 index 0000000..1f2be01 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuth.h @@ -0,0 +1,488 @@ +/** @file FIRAuth.h + @brief Firebase Auth SDK + @copyright Copyright 2015 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +#import "FIRAuthErrors.h" + +@class FIRApp; +@class FIRAuth; +@class FIRAuthCredential; +@class FIRUser; +@protocol FIRAuthStateListener; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthStateDidChangeListenerHandle + @brief The type of handle returned by @c FIRAuth.addAuthStateDidChangeListener:. + */ +typedef id FIRAuthStateDidChangeListenerHandle; + +/** @typedef FIRAuthStateDidChangeListenerBlock + @brief The type of block which can be registered as a listener for auth state did change events. + + @param auth The FIRAuth object on which state changes occurred. + @param user Optionally; the current signed in user, if any. + */ +typedef void(^FIRAuthStateDidChangeListenerBlock)(FIRAuth *auth, FIRUser *_Nullable user); + +/** + @brief The name of the @c NSNotificationCenter notification which is posted when the auth state + changes (for example, a new token has been produced, a user signs in or signs out). The + object parameter of the notification is the sender @c FIRAuth instance. + */ +extern NSString *const FIRAuthStateDidChangeNotification; + +/** @typedef FIRAuthResultCallback + @brief The type of block invoked when sign-in related events complete. + + @param user Optionally; the signed in user, if any. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRAuthResultCallback)(FIRUser *_Nullable user, NSError *_Nullable error); + +/** @typedef FIRProviderQueryCallback + @brief The type of block invoked when a list of identity providers for a given email address is + requested. + + @param providers Optionally; a list of provider identifiers, if any. + @see FIRGoogleAuthProviderID etc. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRProviderQueryCallback)(NSArray *_Nullable providers, + NSError *_Nullable error); + +/** @typedef FIRSendPasswordResetCallback + @brief The type of block invoked when sending a password reset email. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRSendPasswordResetCallback)(NSError *_Nullable error); + +/** @typedef FIRConfirmPasswordResetCallback + @brief The type of block invoked when performing a password reset. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRConfirmPasswordResetCallback)(NSError *_Nullable error); + +/** @typedef FIRVerifyPasswordResetCodeCallback + @brief The type of block invoked when verifying that an out of band code should be used to + perform password reset. + + @param email Optionally; the email address of the user for which the out of band code applies. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRVerifyPasswordResetCodeCallback)(NSString *_Nullable email, + NSError *_Nullable error); + +/** @typedef FIRApplyActionCodeCallback + @brief The type of block invoked when applying an action code. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRApplyActionCodeCallback)(NSError *_Nullable error); + +/** + @brief Keys used to retrieve operation data from a @c FIRActionCodeInfo object by the @c + dataForKey method. + */ +typedef NS_ENUM(NSInteger, FIRActionDataKey) { + /** + * The email address to which the code was sent. + * For FIRActionCodeOperationRecoverEmail, the new email address for the account. + */ + FIRActionCodeEmailKey = 0, + + /** For FIRActionCodeOperationRecoverEmail, the current email address for the account. */ + FIRActionCodeFromEmailKey = 1 +}; + +/** @class FIRActionCodeInfo + @brief Manages information regarding action codes. + */ +@interface FIRActionCodeInfo : NSObject + +/** + @brief Operations which can be performed with action codes. + */ +typedef NS_ENUM(NSInteger, FIRActionCodeOperation) { + /** Action code for unknown operation. */ + FIRActionCodeOperationUnknown = 0, + + /** Action code for password reset operation. */ + FIRActionCodeOperationPasswordReset = 1, + + /** Action code for verify email operation. */ + FIRActionCodeOperationVerifyEmail = 2 +}; + +/** + @brief The operation being performed. + */ +@property(nonatomic, readonly) FIRActionCodeOperation operation; + +/** @fn dataForKey: + @brief The operation being performed. + + @param key The FIRActionDataKey value used to retrieve the operation data. + + @return The operation data pertaining to the provided action code key. + */ +- (NSString *)dataForKey:(FIRActionDataKey)key; + +/** @fn init + @brief please use initWithOperation: instead. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +/** @typedef FIRCheckActionCodeCallBack + @brief The type of block invoked when performing a check action code operation. + + @param info Metadata corresponding to the action code. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRCheckActionCodeCallBack)(FIRActionCodeInfo *_Nullable info, + NSError *_Nullable error); + +/** @class FIRAuth + @brief Manages authentication for Firebase apps. + @remarks This class is thread-safe. + */ +@interface FIRAuth : NSObject + +/** @fn auth + @brief Gets the auth object for the default Firebase app. + @remarks Thread safe. + */ ++ (nullable FIRAuth *)auth NS_SWIFT_NAME(auth()); + +/** @fn authWithApp: + @brief Gets the auth object for a @c FIRApp. + + @param app The FIRApp for which to retrieve the associated FIRAuth instance. + @return The FIRAuth instance associated with the given FIRApp. + */ ++ (nullable FIRAuth *)authWithApp:(FIRApp *)app; + +/** @property app + @brief Gets the @c FIRApp object that this auth object is connected to. + */ +@property(nonatomic, weak, readonly, nullable) FIRApp *app; + +/** @property currentUser + @brief Synchronously gets the cached current user, or null if there is none. + */ +@property(nonatomic, strong, readonly, nullable) FIRUser *currentUser; + +/** @fn init + @brief Please access auth instances using @c FIRAuth.auth and @c FIRAuth.authForApp:. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn fetchProvidersForEmail:completion: + @brief Fetches the list of IdPs that can be used for signing in with the provided email address. + Useful for an "identifier-first" sign-in flow. + + @param email The email address for which to obtain a list of identity providers. + @param completion Optionally; a block which is invoked when the list of providers for the + specified email address is ready or an error was encountered. Invoked asynchronously on the + main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed.
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)fetchProvidersForEmail:(NSString *)email + completion:(nullable FIRProviderQueryCallback)completion; + +/** @fn signInWithEmail:password:completion: + @brief Signs in using an email address and password. + + @param email The user's email address. + @param password The user's password. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + +
    +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that email and password + accounts are not enabled. Enable them in the Auth section of the + Firebase console. +
  • +
  • @c FIRAuthErrorCodeUserDisabled - Indicates the user's account is disabled. +
  • +
  • @c FIRAuthErrorCodeWrongPassword - Indicates the user attempted + sign in with an incorrect password. +
  • +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)signInWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn signInWithCredential:completion: + @brief Asynchronously signs in to Firebase with the given 3rd-party credentials (e.g. a Facebook + login Access Token, a Google ID Token/Access Token pair, etc.) + + @param credential The credential supplied by the IdP. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidCredential - Indicates the supplied credential is invalid. + This could happen if it has expired or it is malformed. +
  • +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that accounts + with the identity provider represented by the credential are not enabled. + Enable them in the Auth section of the Firebase console. +
  • +
  • @c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email asserted by the credential + (e.g. the email in a Facebook access token) is already in use by an existing account, + that cannot be authenticated with this sign-in method. Call fetchProvidersForEmail for + this user’s email and then prompt them to sign in with any of the sign-in providers + returned. This error will only be thrown if the "One account per email address" + setting is enabled in the Firebase console, under Auth settings. Please note that the + error code raised in this specific situation may not be the same on + Web and Android. +
  • +
  • @c FIRAuthErrorCodeUserDisabled - Indicates the user's account is disabled. +
  • +
  • @c FIRAuthErrorCodeWrongPassword - Indicates the user attempted sign in with an + incorrect password, if credential is of the type EmailPasswordAuthCredential. +
  • +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)signInWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn signInAnonymouslyWithCompletion: + @brief Asynchronously creates and becomes an anonymous user. + @param completion Optionally; a block which is invoked when the sign in finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks If there is already an anonymous user signed in, that user will be returned instead. + If there is any other existing user signed in, that user will be signed out. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that anonymous accounts are + not enabled. Enable them in the Auth section of the Firebase console. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)signInAnonymouslyWithCompletion:(nullable FIRAuthResultCallback)completion; + +/** @fn signInWithCustomToken:completion: + @brief Asynchronously signs in to Firebase with the given Auth token. + + @param token A self-signed custom auth token. + @param completion Optionally; a block which is invoked when the sign in finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidCustomToken - Indicates a validation error with + the custom token. +
  • +
  • @c FIRAuthErrorCodeCustomTokenMismatch - Indicates the service account and the API key + belong to different projects. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)signInWithCustomToken:(NSString *)token + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn createUserWithEmail:password:completion: + @brief Creates and, on success, signs in a user with the given email address and password. + + @param email The user's email address. + @param password The user's desired password. + @param completion Optionally; a block which is invoked when the sign up flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed. +
  • +
  • @c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email used to attempt sign up + already exists. Call fetchProvidersForEmail to check which sign-in mechanisms the user + used, and prompt the user to sign in with one of those. +
  • +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that email and password accounts + are not enabled. Enable them in the Auth section of the Firebase console. +
  • +
  • @c FIRAuthErrorCodeWeakPassword - Indicates an attempt to set a password that is + considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo + dictionary object will contain more detailed explanation that can be shown to the user. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)createUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn confirmPasswordResetWithCode:newPassword:completion: + @brief Resets the password given a code sent to the user outside of the app and a new password + for the user. + + @param newPassword The new password. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeWeakPassword - Indicates an attempt to set a password that is + considered too weak. +
  • +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates the administrator disabled sign + in with the specified identity provider. +
  • +
  • @c FIRAuthErrorCodeExpiredActionCode - Indicates the OOB code is expired. +
  • +
  • @c FIRAuthErrorCodeInvalidActionCode - Indicates the OOB code is invalid. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)confirmPasswordResetWithCode:(NSString *)code + newPassword:(NSString *)newPassword + completion:(FIRConfirmPasswordResetCallback)completion; + +/** @fn checkActionCode:completion: + @brief Checks the validity of an out of band code. + + @param code The out of band code to check validity. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)checkActionCode:(NSString *)code completion:(FIRCheckActionCodeCallBack)completion; + +/** @fn verifyPasswordResetCode:completion: + @brief Checks the validity of a verify password reset code. + + @param code The password reset code to be verified. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)verifyPasswordResetCode:(NSString *)code + completion:(FIRVerifyPasswordResetCodeCallback)completion; + +/** @fn applyActionCode:completion: + @brief Applies out of band code. + + @param code The out of band code to be applied. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks This method will not work for out of band codes which require an additional parameter, + such as password reset code. + */ +- (void)applyActionCode:(NSString *)code + completion:(FIRApplyActionCodeCallback)completion; + +/** @fn sendPasswordResetWithEmail:completion: + @brief Initiates a password reset for the given email address. + + @param email The email address of the user. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidRecipientEmail - Indicates an invalid recipient email was + sent in the request. +
  • +
  • @c FIRAuthErrorCodeInvalidSender - Indicates an invalid sender email is set in + the console for this action. +
  • +
  • @c FIRAuthErrorCodeInvalidMessagePayload - Indicates an invalid email template for + sending update email. +
  • +
+ */ +- (void)sendPasswordResetWithEmail:(NSString *)email + completion:(nullable FIRSendPasswordResetCallback)completion; + +/** @fn signOut: + @brief Signs out the current user. + + @param error Optionally; if an error occurs, upon return contains an NSError object that + describes the problem; is nil otherwise. + @return @YES when the sign out request was successful. @NO otherwise. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeKeychainError - Indicates an error occurred when accessing the + keychain. The @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo + dictionary will contain more information about the error encountered. +
  • +
+ + */ +- (BOOL)signOut:(NSError *_Nullable *_Nullable)error; + +/** @fn addAuthStateDidChangeListener: + @brief Registers a block as an "auth state did change" listener. To be invoked when: + + + The block is registered as a listener, + + The current user changes, or, + + The current user's access token changes. + + @param listener The block to be invoked. The block is always invoked asynchronously on the main + thread, even for it's initial invocation after having been added as a listener. + + @remarks The block is invoked immediately after adding it according to it's standard invocation + semantics, asynchronously on the main thread. Users should pay special attention to + making sure the block does not inadvertently retain objects which should not be retained by + the long-lived block. The block itself will be retained by @c FIRAuth until it is + unregistered or until the @c FIRAuth instance is otherwise deallocated. + + @return A handle useful for manually unregistering the block as a listener. + */ +- (FIRAuthStateDidChangeListenerHandle)addAuthStateDidChangeListener: + (FIRAuthStateDidChangeListenerBlock)listener; + +/** @fn removeAuthStateDidChangeListener: + @brief Unregisters a block as an "auth state did change" listener. + + @param listenerHandle The handle for the listener. + */ +- (void)removeAuthStateDidChangeListener:(FIRAuthStateDidChangeListenerHandle)listenerHandle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthCredential.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthCredential.h new file mode 100755 index 0000000..f960143 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthCredential.h @@ -0,0 +1,31 @@ +/** @file FIRAuthCredential.h + @brief Firebase Auth SDK + @copyright Copyright 2015 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthCredential + @brief Represents a credential. + */ +@interface FIRAuthCredential : NSObject + +/** @property provider + @brief Gets the name of the identity provider for the credential. + */ +@property(nonatomic, copy, readonly) NSString *provider; + +/** @fn init + @brief This is an abstract base class. Concrete instances should be created via factory + methods available in the various authentication provider libraries (like the Facebook + provider or the Google provider libraries.) + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthErrors.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthErrors.h new file mode 100755 index 0000000..3940347 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthErrors.h @@ -0,0 +1,176 @@ +/** @file FIRAuthErrors.h + @brief Firebase Auth SDK + @copyright Copyright 2015 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +/** @class FIRAuthErrors + @remarks Error Codes common to all API Methods: +
    +
  • @c FIRAuthErrorCodeNetworkError
  • +
  • @c FIRAuthErrorCodeUserNotFound
  • +
  • @c FIRAuthErrorCodeUserTokenExpired
  • +
  • @c FIRAuthErrorCodeTooManyRequests
  • +
  • @c FIRAuthErrorCodeInvalidAPIKey
  • +
  • @c FIRAuthErrorCodeAppNotAuthorized
  • +
  • @c FIRAuthErrorCodeKeychainError
  • +
  • @c FIRAuthErrorCodeInternalError
  • +
+ @remarks Common error codes for @c FIRUser operations: +
    +
  • @c FIRAuthErrorCodeInvalidUserToken
  • +
  • @c FIRAuthErrorCodeUserDisabled
  • +
+ */ +@interface FIRAuthErrors + +/** + @brief The Firebase Auth error domain. + */ +extern NSString *const FIRAuthErrorDomain; + +/** + @brief The name of the key for the "error_name" string in the NSError userinfo dictionary. + */ +extern NSString *const FIRAuthErrorNameKey; + +/** + @brief Error codes used by Firebase Auth. + */ +typedef NS_ENUM(NSInteger, FIRAuthErrorCode) { + /** Indicates a validation error with the custom token. + */ + FIRAuthErrorCodeInvalidCustomToken = 17000, + + /** Indicates the service account and the API key belong to different projects. + */ + FIRAuthErrorCodeCustomTokenMismatch = 17002, + + /** Indicates the IDP token or requestUri is invalid. + */ + FIRAuthErrorCodeInvalidCredential = 17004, + + /** Indicates the user's account is disabled on the server. + */ + FIRAuthErrorCodeUserDisabled = 17005, + + /** Indicates the administrator disabled sign in with the specified identity provider. + */ + FIRAuthErrorCodeOperationNotAllowed = 17006, + + /** Indicates the email used to attempt a sign up is already in use. + */ + FIRAuthErrorCodeEmailAlreadyInUse = 17007, + + /** Indicates the email is invalid. + */ + FIRAuthErrorCodeInvalidEmail = 17008, + + /** Indicates the user attempted sign in with a wrong password. + */ + FIRAuthErrorCodeWrongPassword = 17009, + + /** Indicates that too many requests were made to a server method. + */ + FIRAuthErrorCodeTooManyRequests = 17010, + + /** Indicates the user account was not found. + */ + FIRAuthErrorCodeUserNotFound = 17011, + + /** Indicates account linking is required. + */ + FIRAuthErrorCodeAccountExistsWithDifferentCredential = 17012, + + /** Same enum as @c FIRAuthErrorCodeAccountExistsWithDifferentCredential , + but with incorrect spelling. Only exists for backwards compatiblity. + */ + FIRAuthErrrorCodeAccountExistsWithDifferentCredential = 17012, + + /** Indicates the user has attemped to change email or password more than 5 minutes after + signing in. + */ + FIRAuthErrorCodeRequiresRecentLogin = 17014, + + /** Indicates an attempt to link a provider to which the account is already linked. + */ + FIRAuthErrorCodeProviderAlreadyLinked = 17015, + + /** Indicates an attempt to unlink a provider that is not linked. + */ + FIRAuthErrorCodeNoSuchProvider = 17016, + + /** Indicates user's saved auth credential is invalid, the user needs to sign in again. + */ + FIRAuthErrorCodeInvalidUserToken = 17017, + + /** Indicates a network error occurred (such as a timeout, interrupted connection, or + unreachable host). These types of errors are often recoverable with a retry. The @c + NSUnderlyingError field in the @c NSError.userInfo dictionary will contain the error + encountered. + */ + FIRAuthErrorCodeNetworkError = 17020, + + /** Indicates the saved token has expired, for example, the user may have changed account + password on another device. The user needs to sign in again on the device that made this + request. + */ + FIRAuthErrorCodeUserTokenExpired = 17021, + + /** Indicates an invalid API key was supplied in the request. + */ + FIRAuthErrorCodeInvalidAPIKey = 17023, + + /** Indicates that an attempt was made to reauthenticate with a user which is not the current + user. + */ + FIRAuthErrorCodeUserMismatch = 17024, + + /** Indicates an attempt to link with a credential that has already been linked with a + different Firebase account + */ + FIRAuthErrorCodeCredentialAlreadyInUse = 17025, + + /** Indicates an attempt to set a password that is considered too weak. + */ + FIRAuthErrorCodeWeakPassword = 17026, + + /** Indicates the App is not authorized to use Firebase Authentication with the + provided API Key. + */ + FIRAuthErrorCodeAppNotAuthorized = 17028, + + /** Indicates the OOB code is expired. + */ + FIRAuthErrorCodeExpiredActionCode = 17029, + + /** Indicates the OOB code is invalid. + */ + FIRAuthErrorCodeInvalidActionCode = 17030, + + /** Indicates that there are invalid parameters in the payload during a "send password reset + * email" attempt. + */ + FIRAuthErrorCodeInvalidMessagePayload = 17031, + + /** Indicates that the sender email is invalid during a "send password reset email" attempt. + */ + FIRAuthErrorCodeInvalidSender = 17032, + + /** Indicates that the recipient email is invalid. + */ + FIRAuthErrorCodeInvalidRecipientEmail = 17033, + + /** Indicates an error occurred while attempting to access the keychain. + */ + FIRAuthErrorCodeKeychainError = 17995, + + /** Indicates an internal error occurred. + */ + FIRAuthErrorCodeInternalError = 17999, +}; + +@end diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIREmailPasswordAuthProvider.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIREmailPasswordAuthProvider.h new file mode 100755 index 0000000..a18d5b4 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIREmailPasswordAuthProvider.h @@ -0,0 +1,40 @@ +/** @file FIREmailPasswordAuthProvider.h + @brief Firebase Auth SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the email & password identity provider. + */ +extern NSString *const FIREmailPasswordAuthProviderID; + +/** @class FIREmailPasswordAuthProvider + @brief A concrete implementation of @c FIRAuthProvider for Email & Password Sign In. + */ +@interface FIREmailPasswordAuthProvider : NSObject + +/** @fn credentialWithEmail:password: + @brief Creates an @c FIRAuthCredential for an email & password sign in. + + @param email The user's email address. + @param password The user's password. + @return A FIRAuthCredential containing the email & password credential. + */ ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRFacebookAuthProvider.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRFacebookAuthProvider.h new file mode 100755 index 0000000..ce968d2 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRFacebookAuthProvider.h @@ -0,0 +1,39 @@ +/** @file FIRFacebookAuthProvider.h + @brief Firebase Auth SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Facebook identity provider. + */ +extern NSString *const FIRFacebookAuthProviderID; + +/** @class FIRFacebookAuthProvider + @brief Utility class for constructing Facebook credentials. + */ +@interface FIRFacebookAuthProvider : NSObject + +/** @fn credentialWithAccessToken: + @brief Creates an @c FIRAuthCredential for a Facebook sign in. + + @param accessToken The Access Token from Facebook. + @return A FIRAuthCredential containing the Facebook credentials. + */ ++ (FIRAuthCredential *)credentialWithAccessToken:(NSString *)accessToken; + +/** @fn init + @brief This class should not be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGitHubAuthProvider.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGitHubAuthProvider.h new file mode 100755 index 0000000..fcc1491 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGitHubAuthProvider.h @@ -0,0 +1,39 @@ +/** @file FIRGitHubAuthProvider.h + @brief Firebase Auth SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the GitHub identity provider. + */ +extern NSString *const FIRGitHubAuthProviderID; + +/** @class FIRGitHubAuthProvider + @brief Utility class for constructing GitHub credentials. + */ +@interface FIRGitHubAuthProvider : NSObject + +/** @fn credentialWithToken: + @brief Creates an @c FIRAuthCredential for a GitHub sign in. + + @param token The GitHub OAuth access token. + @return A FIRAuthCredential containing the GitHub credential. + */ ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGoogleAuthProvider.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGoogleAuthProvider.h new file mode 100755 index 0000000..cdd574b --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGoogleAuthProvider.h @@ -0,0 +1,41 @@ +/** @file FIRGoogleAuthProvider.h + @brief Firebase Auth SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Google identity provider. + */ +extern NSString *const FIRGoogleAuthProviderID; + +/** @class FIRGoogleAuthProvider + @brief Utility class for constructing Google Sign In credentials. + */ +@interface FIRGoogleAuthProvider : NSObject + +/** @fn credentialWithIDToken:accessToken: + @brief Creates an @c FIRAuthCredential for a Google sign in. + + @param IDToken The ID Token from Google. + @param accessToken The Access Token from Google. + @return A FIRAuthCredential containing the Google credentials. + */ ++ (FIRAuthCredential *)credentialWithIDToken:(NSString *)IDToken + accessToken:(NSString *)accessToken; + +/** @fn init + @brief This class should not be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRTwitterAuthProvider.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRTwitterAuthProvider.h new file mode 100755 index 0000000..6d1e993 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRTwitterAuthProvider.h @@ -0,0 +1,40 @@ +/** @file FIRTwitterAuthProvider.h + @brief Firebase Auth SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Twitter identity provider. + */ +extern NSString *const FIRTwitterAuthProviderID; + +/** @class FIRTwitterAuthProvider + @brief Utility class for constructing Twitter credentials. + */ +@interface FIRTwitterAuthProvider : NSObject + +/** @fn credentialWithToken:secret: + @brief Creates an @c FIRAuthCredential for a Twitter sign in. + + @param token The Twitter OAuth token. + @param secret The Twitter OAuth secret. + @return A FIRAuthCredential containing the Twitter credential. + */ ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token secret:(NSString *)secret; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUser.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUser.h new file mode 100755 index 0000000..a137701 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUser.h @@ -0,0 +1,376 @@ +/** @file FIRUser.h + @brief Firebase Auth SDK + @copyright Copyright 2015 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +#import "FIRAuth.h" +#import "FIRUserInfo.h" + +@class FIRUserProfileChangeRequest; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthTokenCallback + @brief The type of block called when a token is ready for use. + @see FIRUser.getTokenWithCompletion: + @see FIRUser.getTokenForcingRefresh:withCompletion: + + @param token Optionally; an access token if the request was successful. + @param error Optionally; the error which occurred - or nil if the request was successful. + + @remarks One of: @c token or @c error will always be non-nil. + */ +typedef void (^FIRAuthTokenCallback)(NSString *_Nullable token, NSError *_Nullable error); + +/** @typedef FIRUserProfileChangeCallback + @brief The type of block called when a user profile change has finished. + + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRUserProfileChangeCallback)(NSError *_Nullable error); + +/** @typedef FIRSendEmailVerificationCallback + @brief The type of block called when a request to send an email verification has finished. + + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRSendEmailVerificationCallback)(NSError *_Nullable error); + +/** @class FIRUser + @brief Represents a user. + @remarks This class is thread-safe. + */ +@interface FIRUser : NSObject + +/** @property anonymous + @brief Indicates the user represents an anonymous user. + */ +@property(nonatomic, readonly, getter=isAnonymous) BOOL anonymous; + +/** @property emailVerified + @brief Indicates the email address associated with this user has been verified. + */ +@property(nonatomic, readonly, getter=isEmailVerified) BOOL emailVerified; + +/** @property refreshToken + @brief A refresh token; useful for obtaining new access tokens independently. + @remarks This property should only be used for advanced scenarios, and is not typically needed. + */ +@property(nonatomic, readonly, nullable) NSString *refreshToken; + +/** @property providerData + @brief Profile data for each identity provider, if any. + @remarks This data is cached on sign-in and updated when linking or unlinking. + */ +@property(nonatomic, readonly, nonnull) NSArray> *providerData; + +/** @fn init + @brief This class should not be instantiated. + @remarks To retrieve the current user, use @c FIRAuth.currentUser. To sign a user + in or out, use the methods on @c FIRAuth. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn updateEmail:completion: + @brief Updates the email address for the user. On success, the cached user profile data is + updated. + @remarks May fail if there is already an account with this email address that was created using + email and password authentication. + + @param email The email address for the user. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidRecipientEmail - Indicates an invalid recipient email was + sent in the request. +
  • +
  • @c FIRAuthErrorCodeInvalidSender - Indicates an invalid sender email is set in + the console for this action. +
  • +
  • @c FIRAuthErrorCodeInvalidMessagePayload - Indicates an invalid email template for + sending update email. +
  • +
  • @c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email is already in use by another + account. +
  • +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed. +
  • +
  • @c FIRAuthErrorCodeRequiresRecentLogin - Updating a user’s email is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + invoking reauthenticateWithCredential:completion: on FIRUser. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + */ +- (void)updateEmail:(NSString *)email completion:(nullable FIRUserProfileChangeCallback)completion; + +/** @fn updatePassword:completion: + @brief Updates the password for the user. On success, the cached user profile data is updated. + + @param password The new password for the user. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates the administrator disabled + sign in with the specified identity provider. +
  • +
  • @c FIRAuthErrorCodeRequiresRecentLogin - Updating a user’s password is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + invoking reauthenticateWithCredential:completion: on FIRUser. +
  • +
  • @c FIRAuthErrorCodeWeakPassword - Indicates an attempt to set a password that is + considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo + dictionary object will contain more detailed explanation that can be shown to the user. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + */ +- (void)updatePassword:(NSString *)password + completion:(nullable FIRUserProfileChangeCallback)completion; + +/** @fn profileChangeRequest + @brief Creates an object which may be used to change the user's profile data. + + @remarks Set the properties of the returned object, then call + @c FIRUserProfileChangeRequest.commitChangesWithCallback: to perform the updates atomically. + + @return An object which may be used to change the user's profile data atomically. + */ +- (FIRUserProfileChangeRequest *)profileChangeRequest; + +/** @fn reloadWithCompletion: + @brief Reloads the user's profile data from the server. + + @param completion Optionally; the block invoked when the reload has finished. Invoked + asynchronously on the main thread in the future. + + @remarks May fail with a @c FIRAuthErrorCodeRequiresRecentLogin error code. In this case + you should call @c FIRUser.reauthenticateWithCredential:completion: before re-invoking + @c FIRUser.updateEmail:completion:. + + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)reloadWithCompletion:(nullable FIRUserProfileChangeCallback)completion; + +/** @fn reauthenticateWithCredential:completion: + @brief Renews the user's authentication tokens by validating a fresh set of credentials supplied + by the user. + + @param credential A user-supplied credential, which will be validated by the server. This can be + a successful third-party identity provider sign-in, or an email address and password. + @param completion Optionally; the block invoked when the re-authentication operation has + finished. Invoked asynchronously on the main thread in the future. + + @remarks If the user associated with the supplied credential is different from the current user, + or if the validation of the supplied credentials fails; an error is returned and the current + user remains signed in. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidCredential - Indicates the supplied credential is invalid. + This could happen if it has expired or it is malformed. +
  • +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that accounts with the + identity provider represented by the credential are not enabled. Enable them in the + Auth section of the Firebase console. +
  • +
  • @c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email asserted by the credential + (e.g. the email in a Facebook access token) is already in use by an existing account, + that cannot be authenticated with this method. Call fetchProvidersForEmail for + this user’s email and then prompt them to sign in with any of the sign-in providers + returned. This error will only be thrown if the "One account per email address" + setting is enabled in the Firebase console, under Auth settings. Please note that the + error code raised in this specific situation may not be the same on Web and Android. +
  • +
  • @c FIRAuthErrorCodeUserDisabled - Indicates the user's account is disabled. +
  • +
  • @c FIRAuthErrorCodeWrongPassword - Indicates the user attempted reauthentication with + an incorrect password, if credential is of the type EmailPasswordAuthCredential. +
  • +
  • @c FIRAuthErrorCodeUserMismatch - Indicates that an attempt was made to + reauthenticate with a user which is not the current user. +
  • +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed.
  • +
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)reauthenticateWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRUserProfileChangeCallback)completion; + +/** @fn getTokenWithCompletion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)getTokenWithCompletion:(nullable FIRAuthTokenCallback)completion; + +/** @fn getTokenForcingRefresh:completion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason + other than an expiration. + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks The authentication token will be refreshed (by making a network request) if it has + expired, or if @c forceRefresh is YES. + + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)getTokenForcingRefresh:(BOOL)forceRefresh + completion:(nullable FIRAuthTokenCallback)completion; + +/** @fn linkWithCredential:completion: + @brief Associates a user account from a third-party identity provider with this user. + + @param credential The credential for the identity provider. + @param completion Optionally; the block invoked when the unlinking is complete, or fails. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeProviderAlreadyLinked - Indicates an attempt to link a provider of a + type already linked to this account. +
  • +
  • @c FIRAuthErrorCodeCredentialAlreadyInUse - Indicates an attempt to link with a + credential + that has already been linked with a different Firebase account. +
  • +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that accounts with the identity + provider represented by the credential are not enabled. Enable them in the Auth section + of the Firebase console. +
  • +
+ + @remarks This method may also return error codes associated with updateEmail:completion: and + updatePassword:completion: on FIRUser. + + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + */ +- (void)linkWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn unlinkFromProvider:completion: + @brief Disassociates a user account from a third-party identity provider with this user. + + @param provider The provider ID of the provider to unlink. + @param completion Optionally; the block invoked when the unlinking is complete, or fails. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeNoSuchProvider - Indicates an attempt to unlink a provider + that is not linked to the account. +
  • +
  • @c FIRAuthErrorCodeRequiresRecentLogin - Updating email is a security sensitive + operation that requires a recent login from the user. This error indicates the user + has not signed in recently enough. To resolve, reauthenticate the user by invoking + reauthenticateWithCredential:completion: on FIRUser. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + */ +- (void)unlinkFromProvider:(NSString *)provider + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn sendEmailVerificationWithCompletion: + @brief Initiates email verification for the user. + + @param completion Optionally; the block invoked when the request to send an email verification + is complete, or fails. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidRecipientEmail - Indicates an invalid recipient email was + sent in the request. +
  • +
  • @c FIRAuthErrorCodeInvalidSender - Indicates an invalid sender email is set in + the console for this action. +
  • +
  • @c FIRAuthErrorCodeInvalidMessagePayload - Indicates an invalid email template for + sending update email. +
  • +
  • @c FIRAuthErrorCodeUserNotFound - Indicates the user account was not found.
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + */ +- (void)sendEmailVerificationWithCompletion:(nullable FIRSendEmailVerificationCallback)completion; + +/** @fn deleteWithCompletion: + @brief Deletes the user account (also signs out the user, if this was the current user). + + @param completion Optionally; the block invoked when the request to delete the account is + complete, or fails. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeRequiresRecentLogin - Updating email is a security sensitive + operation that requires a recent login from the user. This error indicates the user + has not signed in recently enough. To resolve, reauthenticate the user by invoking + reauthenticateWithCredential:completion: on FIRUser. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + + */ +- (void)deleteWithCompletion:(nullable FIRUserProfileChangeCallback)completion; + +@end + +/** @class FIRUserProfileChangeRequest + @brief Represents an object capable of updating a user's profile data. + @remarks Properties are marked as being part of a profile update when they are set. Setting a + property value to nil is not the same as leaving the property unassigned. + */ +@interface FIRUserProfileChangeRequest : NSObject + +/** @fn init + @brief Please use @c FIRUser.profileChangeRequest + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @property displayName + @brief The user's display name. + @remarks It is an error to set this property after calling + @c FIRUserProfileChangeRequest.commitChangesWithCallback: + */ +@property(nonatomic, copy, nullable) NSString *displayName; + +/** @property photoURL + @brief The user's photo URL. + @remarks It is an error to set this property after calling + @c FIRUserProfileChangeRequest.commitChangesWithCallback: + */ +@property(nonatomic, copy, nullable) NSURL *photoURL; + +/** @fn commitChangesWithCompletion: + @brief Commits any pending changes. + @remarks This method should only be called once. Once called, property values should not be + changed. + + @param completion Optionally; the block invoked when the user profile change has been applied. + Invoked asynchronously on the main thread in the future. + */ +- (void)commitChangesWithCompletion:(nullable FIRUserProfileChangeCallback)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUserInfo.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUserInfo.h new file mode 100755 index 0000000..3dfac18 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUserInfo.h @@ -0,0 +1,44 @@ +/** @file FIRUserInfo.h + @brief Firebase Auth SDK + @copyright Copyright 2015 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief Represents user data returned from an identity provider. + */ +@protocol FIRUserInfo + +/** @property providerID + @brief The provider identifier. + */ +@property(nonatomic, copy, readonly) NSString *providerID; + +/** @property uid + @brief The provider's user ID for the user. + */ +@property(nonatomic, copy, readonly) NSString *uid; + +/** @property displayName + @brief The name of the user. + */ +@property(nonatomic, copy, readonly, nullable) NSString *displayName; + +/** @property photoURL + @brief The URL of the user's profile photo. + */ +@property(nonatomic, copy, readonly, nullable) NSURL *photoURL; + +/** @property email + @brief The user's email address. + */ +@property(nonatomic, copy, readonly, nullable) NSString *email; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuth.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuth.h new file mode 100755 index 0000000..2e0a35c --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuth.h @@ -0,0 +1,11 @@ +#import "FIREmailPasswordAuthProvider.h" +#import "FIRFacebookAuthProvider.h" +#import "FIRGitHubAuthProvider.h" +#import "FIRGoogleAuthProvider.h" +#import "FIRTwitterAuthProvider.h" +#import "FIRAuth.h" +#import "FIRAuthCredential.h" +#import "FIRAuthErrors.h" +#import "FIRUser.h" +#import "FIRUserInfo.h" +#import "FirebaseAuthVersion.h" diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuthVersion.h b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuthVersion.h new file mode 100755 index 0000000..3f29d7b --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuthVersion.h @@ -0,0 +1,18 @@ +/*! @file FirebaseAuthVersion.h + @brief Firebase SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +/** + Version number for FirebaseAuth. + */ +extern const double FirebaseAuthVersionNumber; + +/** + Version string for FirebaseAuth. + */ +extern const unsigned char *const FirebaseAuthVersionString; diff --git a/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Modules/module.modulemap b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Modules/module.modulemap new file mode 100755 index 0000000..c58f30e --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module FirebaseAuth { + umbrella header "FirebaseAuth.h" + export * + module * { export *} + link "z" + link framework "CoreGraphics" + link framework "Foundation" + link framework "Security" + link framework "UIKit" +} \ No newline at end of file diff --git a/Old Old Task Master/Pods/FirebaseAuth/README.md b/Old Old Task Master/Pods/FirebaseAuth/README.md new file mode 100755 index 0000000..e766949 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseAuth/README.md @@ -0,0 +1,8 @@ +# Firebase Auth for iOS + +Firebase Auth enables apps to easily support multiple authentication options +for their end users. + +Please visit [our developer site](https://developers.google.com/) for +integration instructions, documentation, support information, and terms of +service. diff --git a/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/FirebaseCore b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/FirebaseCore new file mode 100755 index 0000000..18fad71 Binary files /dev/null and b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/FirebaseCore differ diff --git a/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRAnalyticsConfiguration.h b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRAnalyticsConfiguration.h new file mode 100755 index 0000000..667d5a4 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRAnalyticsConfiguration.h @@ -0,0 +1,38 @@ +#import + +/** + * This class provides configuration fields for Firebase Analytics. + */ +@interface FIRAnalyticsConfiguration : NSObject + +/** + * Returns the shared instance of FIRAnalyticsConfiguration. + */ ++ (FIRAnalyticsConfiguration *)sharedInstance; + +/** + * Sets the minimum engagement time in seconds required to start a new session. The default value + * is 10 seconds. + */ +- (void)setMinimumSessionInterval:(NSTimeInterval)minimumSessionInterval; + +/** + * Sets the interval of inactivity in seconds that terminates the current session. The default + * value is 1800 seconds (30 minutes). + */ +- (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/** + * Sets whether analytics collection is enabled for this app on this device. This setting is + * persisted across app sessions. By default it is enabled. + */ +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/** + * Deprecated. Sets whether measurement and reporting are enabled for this app on this device. By + * default they are enabled. + */ +- (void)setIsEnabled:(BOOL)isEnabled + DEPRECATED_MSG_ATTRIBUTE("Use setAnalyticsCollectionEnabled: instead."); + +@end diff --git a/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRApp.h b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRApp.h new file mode 100755 index 0000000..263c4be --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRApp.h @@ -0,0 +1,98 @@ +#import +#import + +@class FIROptions; + +NS_ASSUME_NONNULL_BEGIN + +/** A block that takes a BOOL and has no return value. */ +typedef void (^FIRAppVoidBoolCallback)(BOOL success); + +/** + * The entry point of Firebase SDKs. + * + * Initialize and configure FIRApp using +[FIRApp configure] + * or other customized ways as shown below. + * + * The logging system has two modes: default mode and debug mode. In default mode, only logs with + * log level Notice, Warning and Error will be sent to device. In debug mode, all logs will be sent + * to device. The log levels that Firebase uses are consistent with the ASL log levels. + * + * Enable debug mode by passing the -FIRDebugEnabled argument to the application. You can add this + * argument in the application's Xcode scheme. When debug mode is enabled via -FIRDebugEnabled, + * further executions of the application will also be in debug mode. In order to return to default + * mode, you must explicitly disable the debug mode with the application argument -FIRDebugDisabled. + * + * It is also possible to change the default logging level in code by calling setLoggerLevel: on + * the FIRConfiguration interface. + */ +@interface FIRApp : NSObject + +/** + * Configures a default Firebase app. Raises an exception if any configuration step fails. The + * default app is named "__FIRAPP_DEFAULT". This method should be called after the app is launched + * and before using Firebase services. This method is thread safe. + */ ++ (void)configure; + +/** + * Configures the default Firebase app with the provided options. The default app is named + * "__FIRAPP_DEFAULT". Raises an exception if any configuration step fails. This method is thread + * safe. + * + * @param options The Firebase application options used to configure the service. + */ ++ (void)configureWithOptions:(FIROptions *)options; + +/** + * Configures a Firebase app with the given name and options. Raises an exception if any + * configuration step fails. This method is thread safe. + * + * @param name The application's name given by the developer. The name should should only contain + Letters, Numbers and Underscore. + * @param options The Firebase application options used to configure the services. + */ ++ (void)configureWithName:(NSString *)name options:(FIROptions *)options; + +/** + * Returns the default app, or nil if the default app does not exist. + */ ++ (nullable FIRApp *)defaultApp NS_SWIFT_NAME(defaultApp()); + +/** + * Returns a previously created FIRApp instance with the given name, or nil if no such app exists. + * This method is thread safe. + */ ++ (nullable FIRApp *)appNamed:(NSString *)name; + +/** + * Returns the set of all extant FIRApp instances, or nil if there are no FIRApp instances. This + * method is thread safe. + */ ++ (nullable NSDictionary *)allApps; + +/** + * Cleans up the current FIRApp, freeing associated data and returning its name to the pool for + * future use. This method is thread safe. + */ +- (void)deleteApp:(FIRAppVoidBoolCallback)completion; + +/** + * FIRApp instances should not be initialized directly. Call +[FIRApp configure], + * +[FIRApp configureWithOptions:], or +[FIRApp configureWithNames:options:] directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Gets the name of this app. + */ +@property(nonatomic, copy, readonly) NSString *name; + +/** + * Gets the options for this app. + */ +@property(nonatomic, readonly) FIROptions *options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRConfiguration.h b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRConfiguration.h new file mode 100755 index 0000000..a25647b --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRConfiguration.h @@ -0,0 +1,52 @@ +#import + +#import "FIRAnalyticsConfiguration.h" +#import "FIRLoggerLevel.h" + +/** + * The log levels used by FIRConfiguration. + */ +typedef NS_ENUM(NSInteger, FIRLogLevel) { + /** Error */ + kFIRLogLevelError __deprecated = 0, + /** Warning */ + kFIRLogLevelWarning __deprecated, + /** Info */ + kFIRLogLevelInfo __deprecated, + /** Debug */ + kFIRLogLevelDebug __deprecated, + /** Assert */ + kFIRLogLevelAssert __deprecated, + /** Max */ + kFIRLogLevelMax __deprecated = kFIRLogLevelAssert +} DEPRECATED_MSG_ATTRIBUTE( + "Use -FIRDebugEnabled and -FIRDebugDisabled or setLoggerLevel. See FIRApp.h for more details."); + +/** + * This interface provides global level properties that the developer can tweak, and the singleton + * of the Firebase Analytics configuration class. + */ +@interface FIRConfiguration : NSObject + +/** Returns the shared configuration object. */ ++ (FIRConfiguration *)sharedInstance; + +/** The configuration class for Firebase Analytics. */ +@property(nonatomic, readwrite) FIRAnalyticsConfiguration *analyticsConfiguration; + +/** Global log level. Defaults to kFIRLogLevelError. */ +@property(nonatomic, readwrite, assign) FIRLogLevel logLevel DEPRECATED_MSG_ATTRIBUTE( + "Use -FIRDebugEnabled and -FIRDebugDisabled or setLoggerLevel. See FIRApp.h for more details."); + +/** + * Sets the logging level for internal Firebase logging. Firebase will only log messages + * that are logged at or below loggerLevel. The messages are logged both to the Xcode + * console and to the device's log. Note that if an app is running from AppStore, it will + * never log above FIRLoggerLevelNotice even if loggerLevel is set to a higher (more verbose) + * setting. + * + * @param loggerLevel The maximum logging level. The default level is set to FIRLoggerLevelNotice. + */ +- (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel; + +@end diff --git a/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRLoggerLevel.h b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRLoggerLevel.h new file mode 100755 index 0000000..ddf683f --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRLoggerLevel.h @@ -0,0 +1,12 @@ +/** + * The log levels used by internal logging. + */ +typedef NS_ENUM(NSInteger, FIRLoggerLevel) { + FIRLoggerLevelError = 3 /*ASL_LEVEL_ERR*/, + FIRLoggerLevelWarning = 4 /*ASL_LEVEL_WARNING*/, + FIRLoggerLevelNotice = 5 /*ASL_LEVEL_NOTICE*/, + FIRLoggerLevelInfo = 6 /*ASL_LEVEL_INFO*/, + FIRLoggerLevelDebug = 7 /*ASL_LEVEL_DEBUG*/, + FIRLoggerLevelMin = FIRLoggerLevelError, + FIRLoggerLevelMax = FIRLoggerLevelDebug +}; diff --git a/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIROptions.h b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIROptions.h new file mode 100755 index 0000000..083082a --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIROptions.h @@ -0,0 +1,93 @@ +#import + +/** + * This class provides constant fields of Google APIs. + */ +@interface FIROptions : NSObject + +/** + * Returns the default options. + */ ++ (FIROptions *)defaultOptions; + +/** + * An iOS API key used for authenticating requests from your app, e.g. + * @"AIzaSyDdVgKwhZl0sTTTLZ7iTmt1r3N2cJLnaDk", used to identify your app to Google servers. + */ +@property(nonatomic, readonly, copy) NSString *APIKey; + +/** + * The OAuth2 client ID for iOS application used to authenticate Google users, for example + * @"12345.apps.googleusercontent.com", used for signing in with Google. + */ +@property(nonatomic, readonly, copy) NSString *clientID; + +/** + * The tracking ID for Google Analytics, e.g. @"UA-12345678-1", used to configure Google Analytics. + */ +@property(nonatomic, readonly, copy) NSString *trackingID; + +/** + * The Project Number from the Google Developer's console, for example @"012345678901", used to + * configure Google Cloud Messaging. + */ +@property(nonatomic, readonly, copy) NSString *GCMSenderID; + +/** + * The Project ID from the Firebase console, for example @"abc-xyz-123". Currently only populated + * when using [FIROptions defaultOptions]. + */ +@property(nonatomic, readonly, copy) NSString *projectID; + +/** + * The Android client ID used in Google AppInvite when an iOS app has its Android version, for + * example @"12345.apps.googleusercontent.com". + */ +@property(nonatomic, readonly, copy) NSString *androidClientID; + +/** + * The Google App ID that is used to uniquely identify an instance of an app. + */ +@property(nonatomic, readonly, copy) NSString *googleAppID; + +/** + * The database root URL, e.g. @"http://abc-xyz-123.firebaseio.com". + */ +@property(nonatomic, readonly, copy) NSString *databaseURL; + +/** + * The URL scheme used to set up Durable Deep Link service. + */ +@property(nonatomic, readwrite, copy) NSString *deepLinkURLScheme; + +/** + * The Google Cloud Storage bucket name, e.g. @"abc-xyz-123.storage.firebase.com". + */ +@property(nonatomic, readonly, copy) NSString *storageBucket; + +/** + * Initializes a customized instance of FIROptions with keys. googleAppID, bundleID and GCMSenderID + * are required. Other keys may required for configuring specific services. + */ +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + bundleID:(NSString *)bundleID + GCMSenderID:(NSString *)GCMSenderID + APIKey:(NSString *)APIKey + clientID:(NSString *)clientID + trackingID:(NSString *)trackingID + androidClientID:(NSString *)androidClientID + databaseURL:(NSString *)databaseURL + storageBucket:(NSString *)storageBucket + deepLinkURLScheme:(NSString *)deepLinkURLScheme; + +/** + * Initializes a customized instance of FIROptions from the file at the given plist file path. + * For example, + * NSString *filePath = + * [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"]; + * FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath]; + * Returns nil if the plist file does not exist or is invalid. + */ +- (instancetype)initWithContentsOfFile:(NSString *)plistPath; + +@end diff --git a/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FirebaseCore.h b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FirebaseCore.h new file mode 100755 index 0000000..52a222f --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FirebaseCore.h @@ -0,0 +1,5 @@ +#import "FIRAnalyticsConfiguration.h" +#import "FIRApp.h" +#import "FIRConfiguration.h" +#import "FIRLoggerLevel.h" +#import "FIROptions.h" diff --git a/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Modules/module.modulemap b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Modules/module.modulemap new file mode 100755 index 0000000..b2936ab --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Modules/module.modulemap @@ -0,0 +1,7 @@ +framework module FirebaseCore { + umbrella header "FirebaseCore.h" + export * + module * { export *} + link "c++" + link "z" +} \ No newline at end of file diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/FirebaseDatabase b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/FirebaseDatabase new file mode 100755 index 0000000..a10bc3d Binary files /dev/null and b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/FirebaseDatabase differ diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataEventType.h b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataEventType.h new file mode 100755 index 0000000..245fd2d --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataEventType.h @@ -0,0 +1,48 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Firebase_FIRDataEventType_h +#define Firebase_FIRDataEventType_h + +/** + * This enum is the set of events that you can observe at a Firebase Database location. + */ +typedef NS_ENUM(NSInteger, FIRDataEventType) { + /// A new child node is added to a location. + FIRDataEventTypeChildAdded, + /// A child node is removed from a location. + FIRDataEventTypeChildRemoved, + /// A child node at a location changes. + FIRDataEventTypeChildChanged, + /// A child node moves relative to the other child nodes at a location. + FIRDataEventTypeChildMoved, + /// Any data changes at a location or, recursively, at any child node. + FIRDataEventTypeValue +}; + +#endif diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataSnapshot.h b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataSnapshot.h new file mode 100755 index 0000000..5890dd4 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataSnapshot.h @@ -0,0 +1,158 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class FIRDatabaseReference; + +/** + * A FIRDataSnapshot contains data from a Firebase Database location. Any time you read + * Firebase data, you receive the data as a FIRDataSnapshot. + * + * FIRDataSnapshots are passed to the blocks you attach with observeEventType:withBlock: or observeSingleEvent:withBlock:. + * They are efficiently-generated immutable copies of the data at a Firebase Database location. + * They can't be modified and will never change. To modify data at a location, + * use a FIRDatabaseReference (e.g. with setValue:). + */ +@interface FIRDataSnapshot : NSObject + + +#pragma mark - Navigating and inspecting a snapshot + +/** + * Gets a FIRDataSnapshot for the location at the specified relative path. + * The relative path can either be a simple child key (e.g. 'fred') + * or a deeper slash-separated path (e.g. 'fred/name/first'). If the child + * location has no data, an empty FIRDataSnapshot is returned. + * + * @param childPathString A relative path to the location of child data. + * @return The FIRDataSnapshot for the child location. + */ +- (FIRDataSnapshot *)childSnapshotForPath:(NSString *)childPathString; + + +/** + * Return YES if the specified child exists. + * + * @param childPathString A relative path to the location of a potential child. + * @return YES if data exists at the specified childPathString, else NO. + */ +- (BOOL) hasChild:(NSString *)childPathString; + + +/** + * Return YES if the DataSnapshot has any children. + * + * @return YES if this snapshot has any children, else NO. + */ +- (BOOL) hasChildren; + + +/** + * Return YES if the DataSnapshot contains a non-null value. + * + * @return YES if this snapshot contains a non-null value, else NO. + */ +- (BOOL) exists; + + +#pragma mark - Data export + +/** + * Returns the raw value at this location, coupled with any metadata, such as priority. + * + * Priorities, where they exist, are accessible under the ".priority" key in instances of NSDictionary. + * For leaf locations with priorities, the value will be under the ".value" key. + */ +- (id __nullable) valueInExportFormat; + + +#pragma mark - Properties + +/** + * Returns the contents of this data snapshot as native types. + * + * Data types returned: + * + NSDictionary + * + NSArray + * + NSNumber (also includes booleans) + * + NSString + * + * @return The data as a native object. + */ +@property (strong, readonly, nonatomic, nullable) id value; + + +/** + * Gets the number of children for this DataSnapshot. + * + * @return An integer indicating the number of children. + */ +@property (readonly, nonatomic) NSUInteger childrenCount; + + +/** + * Gets a FIRDatabaseReference for the location that this data came from. + * + * @return A FIRDatabaseReference instance for the location of this data. + */ +@property (nonatomic, readonly, strong) FIRDatabaseReference * ref; + + +/** + * The key of the location that generated this FIRDataSnapshot. + * + * @return An NSString containing the key for the location of this FIRDataSnapshot. + */ +@property (strong, readonly, nonatomic) NSString* key; + + +/** + * An iterator for snapshots of the child nodes in this snapshot. + * You can use the native for..in syntax: + * + * for (FIRDataSnapshot* child in snapshot.children) { + * ... + * } + * + * @return An NSEnumerator of the children. + */ +@property (strong, readonly, nonatomic) NSEnumerator* children; + +/** + * The priority of the data in this FIRDataSnapshot. + * + * @return The priority as a string, or nil if no priority was set. + */ +@property (strong, readonly, nonatomic, nullable) id priority; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabase.h b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabase.h new file mode 100755 index 0000000..237d52d --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabase.h @@ -0,0 +1,150 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "FIRDatabaseReference.h" + +@class FIRApp; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The entry point for accessing a Firebase Database. You can get an instance by calling + * [FIRDatabase database]. To access a location in the database and read or write data, + * use [FIRDatabase reference]. + */ +@interface FIRDatabase : NSObject + +/** + * Gets the instance of FIRDatabase for the default FIRApp. + * + * @return A FIRDatabase instance. + */ ++ (FIRDatabase *) database NS_SWIFT_NAME(database()); + +/** + * Gets an instance of FIRDatabase for a specific FIRApp. + * + * @param app The FIRApp to get a FIRDatabase for. + * @return A FIRDatabase instance. + */ ++ (FIRDatabase *) databaseForApp:(FIRApp*)app NS_SWIFT_NAME(database(app:)); + +/** The FIRApp instance to which this FIRDatabase belongs. */ +@property (weak, readonly, nonatomic) FIRApp *app; + +/** + * Gets a FIRDatabaseReference for the root of your Firebase Database. + */ +- (FIRDatabaseReference *) reference; + +/** + * Gets a FIRDatabaseReference for the provided path. + * + * @param path Path to a location in your Firebase Database. + * @return A FIRDatabaseReference pointing to the specified path. + */ +- (FIRDatabaseReference *) referenceWithPath:(NSString *)path; + +/** + * Gets a FIRDatabaseReference for the provided URL. The URL must be a URL to a path + * within this Firebase Database. To create a FIRDatabaseReference to a different database, + * create a FIRApp} with a FIROptions object configured with the appropriate database URL. + * + * @param url A URL to a path within your database. + * @return A FIRDatabaseReference for the provided URL. +*/ +- (FIRDatabaseReference *) referenceFromURL:(NSString *)databaseUrl; + +/** + * The Firebase Database client automatically queues writes and sends them to the server at the earliest opportunity, + * depending on network connectivity. In some cases (e.g. offline usage) there may be a large number of writes + * waiting to be sent. Calling this method will purge all outstanding writes so they are abandoned. + * + * All writes will be purged, including transactions and onDisconnect writes. The writes will + * be rolled back locally, perhaps triggering events for affected event listeners, and the client will not + * (re-)send them to the Firebase Database backend. + */ +- (void)purgeOutstandingWrites; + +/** + * Shuts down our connection to the Firebase Database backend until goOnline is called. + */ +- (void)goOffline; + +/** + * Resumes our connection to the Firebase Database backend after a previous goOffline call. + */ +- (void)goOnline; + +/** + * The Firebase Database client will cache synchronized data and keep track of all writes you've + * initiated while your application is running. It seamlessly handles intermittent network + * connections and re-sends write operations when the network connection is restored. + * + * However by default your write operations and cached data are only stored in-memory and will + * be lost when your app restarts. By setting this value to `YES`, the data will be persisted + * to on-device (disk) storage and will thus be available again when the app is restarted + * (even when there is no network connectivity at that time). Note that this property must be + * set before creating your first Database reference and only needs to be called once per + * application. + * + */ +@property (nonatomic) BOOL persistenceEnabled; + +/** + * By default the Firebase Database client will use up to 10MB of disk space to cache data. If the cache grows beyond + * this size, the client will start removing data that hasn't been recently used. If you find that your application + * caches too little or too much data, call this method to change the cache size. This property must be set before + * creating your first FIRDatabaseReference and only needs to be called once per application. + * + * Note that the specified cache size is only an approximation and the size on disk may temporarily exceed it + * at times. Cache sizes smaller than 1 MB or greater than 100 MB are not supported. + */ +@property (nonatomic) NSUInteger persistenceCacheSizeBytes; + +/** + * Sets the dispatch queue on which all events are raised. The default queue is the main queue. + * + * Note that this must be set before creating your first Database reference. + */ +@property (nonatomic, strong) dispatch_queue_t callbackQueue; + +/** + * Enables verbose diagnostic logging. + * + * @param enabled YES to enable logging, NO to disable. + */ ++ (void) setLoggingEnabled:(BOOL)enabled; + +/** Retrieve the Firebase Database SDK version. */ ++ (NSString *) sdkVersion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseQuery.h b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseQuery.h new file mode 100755 index 0000000..9e0acf8 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseQuery.h @@ -0,0 +1,325 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "FIRDataEventType.h" +#import "FIRDataSnapshot.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * A FIRDatabaseHandle is used to identify listeners of Firebase Database events. These handles + * are returned by observeEventType: and and can later be passed to removeObserverWithHandle: to + * stop receiving updates. + */ +typedef NSUInteger FIRDatabaseHandle; + +/** + * A FIRDatabaseQuery instance represents a query over the data at a particular location. + * + * You create one by calling one of the query methods (queryOrderedByChild:, queryStartingAtValue:, etc.) + * on a FIRDatabaseReference. The query methods can be chained to further specify the data you are interested in + * observing + */ +@interface FIRDatabaseQuery : NSObject + + +#pragma mark - Attach observers to read data + +/** + * observeEventType:withBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot + * and the previous child's key. + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; + + +/** + * observeEventType:withBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. + * + * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that should be called if this client no longer has permission to receive these events + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot + * and the previous child's key. + * @param cancelBlock The block that should be called if this client no longer has permission to receive these events + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * + * The cancelBlock will be called if you do not have permission to read data at this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that will be called if you don't have permission to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you do not have permission to read data at this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that will be called if you don't have permission to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +#pragma mark - Detaching observers + +/** + * Detach a block previously attached with observeEventType:withBlock:. + * + * @param handle The handle returned by the call to observeEventType:withBlock: which we are trying to remove. + */ +- (void) removeObserverWithHandle:(FIRDatabaseHandle)handle; + + +/** + * Detach all blocks previously attached to this Firebase Database location with observeEventType:withBlock: + */ +- (void) removeAllObservers; + +/** + * By calling `keepSynced:YES` on a location, the data for that location will automatically be downloaded and + * kept in sync, even when no listeners are attached for that location. Additionally, while a location is kept + * synced, it will not be evicted from the persistent disk cache. + * + * @param keepSynced Pass YES to keep this location synchronized, pass NO to stop synchronization. +*/ + - (void) keepSynced:(BOOL)keepSynced; + + +#pragma mark - Querying and limiting + +/** +* queryLimitedToFirst: is used to generate a reference to a limited view of the data at this location. +* The FIRDatabaseQuery instance returned by queryLimitedToFirst: will respond to at most the first limit child nodes. +* +* @param limit The upper bound, inclusive, for the number of child nodes to receive events for +* @return A FIRDatabaseQuery instance, limited to at most limit child nodes. +*/ +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit; + + +/** +* queryLimitedToLast: is used to generate a reference to a limited view of the data at this location. +* The FIRDatabaseQuery instance returned by queryLimitedToLast: will respond to at most the last limit child nodes. +* +* @param limit The upper bound, inclusive, for the number of child nodes to receive events for +* @return A FIRDatabaseQuery instance, limited to at most limit child nodes. +*/ +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit; + +/** + * queryOrderBy: is used to generate a reference to a view of the data that's been sorted by the values of + * a particular child key. This method is intended to be used in combination with queryStartingAtValue:, + * queryEndingAtValue:, or queryEqualToValue:. + * + * @param key The child key to use in ordering data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, ordered by the values of the specified child key. +*/ +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key; + +/** + * queryOrderedByKey: is used to generate a reference to a view of the data that's been sorted by child key. + * This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, + * or queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child keys. + */ +- (FIRDatabaseQuery *) queryOrderedByKey; + +/** + * queryOrderedByValue: is used to generate a reference to a view of the data that's been sorted by child value. + * This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, + * or queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child value. + */ +- (FIRDatabaseQuery *) queryOrderedByValue; + +/** + * queryOrderedByPriority: is used to generate a reference to a view of the data that's been sorted by child + * priority. This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, + * or queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child priorities. + */ +- (FIRDatabaseQuery *) queryOrderedByPriority; + +/** + * queryStartingAtValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryStartingAtValue: will respond to events at nodes with a value + * greater than or equal to startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue; + +/** + * queryStartingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryStartingAtValue:childKey will respond to events at nodes with a value + * greater than startValue, or equal to startValue and with a key greater than or equal to childKey. This is most + * useful when implementing pagination in a case where multiple nodes can match the startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @param childKey The lower bound, inclusive, for the key of nodes with value equal to startValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue childKey:(nullable NSString *)childKey; + +/** + * queryEndingAtValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEndingAtValue: will respond to events at nodes with a value + * less than or equal to endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue; + +/** + * queryEndingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEndingAtValue:childKey will respond to events at nodes with a value + * less than endValue, or equal to endValue and with a key less than or equal to childKey. This is most useful when + * implementing pagination in a case where multiple nodes can match the endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @param childKey The upper bound, inclusive, for the key of nodes with value equal to endValue + * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue childKey:(nullable NSString *)childKey; + +/** + * queryEqualToValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEqualToValue: will respond to events at nodes with a value equal + * to the supplied argument. + * + * @param value The value that the data returned by this FIRDatabaseQuery will have + * @return A FIRDatabaseQuery instance, limited to data with the supplied value. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value; + +/** + * queryEqualToValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEqualToValue:childKey will respond to events at nodes with a value + * equal to the supplied argument and with their key equal to childKey. There will be at most one node that matches + * because child keys are unique. + * + * @param value The value that the data returned by this FIRDatabaseQuery will have + * @param childKey The name of nodes with the right value + * @return A FIRDatabaseQuery instance, limited to data with the supplied value and the key. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value childKey:(nullable NSString *)childKey; + + +#pragma mark - Properties + +/** +* Gets a FIRDatabaseReference for the location of this query. +* +* @return A FIRDatabaseReference for the location of this query. +*/ +@property (nonatomic, readonly, strong) FIRDatabaseReference * ref; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseReference.h b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseReference.h new file mode 100755 index 0000000..44e697d --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseReference.h @@ -0,0 +1,730 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#import +#import "FIRDatabaseQuery.h" +#import "FIRDatabase.h" +#import "FIRDataSnapshot.h" +#import "FIRMutableData.h" +#import "FIRTransactionResult.h" +#import "FIRServerValue.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRDatabase; + +/** + * A FIRDatabaseReference represents a particular location in your Firebase Database + * and can be used for reading or writing data to that Firebase Database location. + * + * This class is the starting point for all Firebase Database operations. After you've + * obtained your first FIRDatabaseReference via [FIRDatabase reference], you can use it + * to read data (ie. observeEventType:withBlock:), write data (ie. setValue:), and to + * create new FIRDatabaseReferences (ie. child:). + */ +@interface FIRDatabaseReference : FIRDatabaseQuery + + +#pragma mark - Getting references to children locations + +/** + * Gets a FIRDatabaseReference for the location at the specified relative path. + * The relative path can either be a simple child key (e.g. 'fred') or a + * deeper slash-separated path (e.g. 'fred/name/first'). + * + * @param pathString A relative path from this location to the desired child location. + * @return A FIRDatabaseReference for the specified relative path. + */ +- (FIRDatabaseReference *)child:(NSString *)pathString; + +/** + * childByAppendingPath: is deprecated, use child: instead. + */ +- (FIRDatabaseReference *)childByAppendingPath:(NSString *)pathString __deprecated_msg("use child: instead"); + +/** + * childByAutoId generates a new child location using a unique key and returns a + * FIRDatabaseReference to it. This is useful when the children of a Firebase Database + * location represent a list of items. + * + * The unique key generated by childByAutoId: is prefixed with a client-generated + * timestamp so that the resulting list will be chronologically-sorted. + * + * @return A FIRDatabaseReference for the generated location. + */ +- (FIRDatabaseReference *) childByAutoId; + + +#pragma mark - Writing data + +/** Write data to this Firebase Database location. + +This will overwrite any data at this location and all child locations. + +Data types that can be set are: + +- NSString -- @"Hello World" +- NSNumber (also includes boolean) -- @YES, @43, @4.333 +- NSDictionary -- @{@"key": @"value", @"nested": @{@"another": @"value"} } +- NSArray + +The effect of the write will be visible immediately and the corresponding +events will be triggered. Synchronization of the data to the Firebase Database +servers will also be started. + +Passing null for the new value is equivalent to calling remove:; +all data at this location or any child location will be deleted. + +Note that setValue: will remove any priority stored at this location, so if priority +is meant to be preserved, you should use setValue:andPriority: instead. + +@param value The value to be written. + */ +- (void) setValue:(nullable id)value; + + +/** + * The same as setValue: with a block that gets triggered after the write operation has + * been committed to the Firebase Database servers. + * + * @param value The value to be written. + * @param block The block to be called after the write has been committed to the Firebase Database servers. + */ +- (void) setValue:(nullable id)value withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +/** + * The same as setValue: with an additional priority to be attached to the data being written. + * Priorities are used to order items. + * + * @param value The value to be written. + * @param priority The priority to be attached to that data. + */ +- (void) setValue:(nullable id)value andPriority:(nullable id)priority; + + +/** + * The same as setValue:andPriority: with a block that gets triggered after the write operation has + * been committed to the Firebase Database servers. + * + * @param value The value to be written. + * @param priority The priority to be attached to that data. + * @param block The block to be called after the write has been committed to the Firebase Database servers. + */ +- (void) setValue:(nullable id)value andPriority:(nullable id)priority withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +/** + * Remove the data at this Firebase Database location. Any data at child locations will also be deleted. + * + * The effect of the delete will be visible immediately and the corresponding events + * will be triggered. Synchronization of the delete to the Firebase Database servers will + * also be started. + * + * remove: is equivalent to calling setValue:nil + */ +- (void) removeValue; + + +/** + * The same as remove: with a block that gets triggered after the remove operation has + * been committed to the Firebase Database servers. + * + * @param block The block to be called after the remove has been committed to the Firebase Database servers. + */ +- (void) removeValueWithCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + +/** + * Sets a priority for the data at this Firebase Database location. + * Priorities can be used to provide a custom ordering for the children at a location + * (if no priorities are specified, the children are ordered by key). + * + * You cannot set a priority on an empty location. For this reason + * setValue:andPriority: should be used when setting initial data with a specific priority + * and setPriority: should be used when updating the priority of existing data. + * + * Children are sorted based on this priority using the following rules: + * + * Children with no priority come first. + * Children with a number as their priority come next. They are sorted numerically by priority (small to large). + * Children with a string as their priority come last. They are sorted lexicographically by priority. + * Whenever two children have the same priority (including no priority), they are sorted by key. Numeric + * keys come first (sorted numerically), followed by the remaining keys (sorted lexicographically). + * + * Note that priorities are parsed and ordered as IEEE 754 double-precision floating-point numbers. + * Keys are always stored as strings and are treated as numbers only when they can be parsed as a + * 32-bit integer + * + * @param priority The priority to set at the specified location. + */ +- (void) setPriority:(nullable id)priority; + + +/** + * The same as setPriority: with a block that is called once the priority has + * been committed to the Firebase Database servers. + * + * @param priority The priority to set at the specified location. + * @param block The block that is triggered after the priority has been written on the servers. + */ +- (void) setPriority:(nullable id)priority withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + +/** + * Updates the values at the specified paths in the dictionary without overwriting other + * keys at this location. + * + * @param values A dictionary of the keys to change and their new values + */ +- (void) updateChildValues:(NSDictionary *)values; + +/** + * The same as update: with a block that is called once the update has been committed to the + * Firebase Database servers + * + * @param values A dictionary of the keys to change and their new values + * @param block The block that is triggered after the update has been written on the Firebase Database servers + */ +- (void) updateChildValues:(NSDictionary *)values withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +#pragma mark - Attaching observers to read data + +/** + * observeEventType:withBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. + * + * Use removeObserverWithHandle: to stop receiving updates. + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot + * and the previous child's key. + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; + + +/** + * observeEventType:withBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. + * + * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that should be called if this client no longer has permission to receive these events + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot + * and the previous child's key. + * @param cancelBlock The block that should be called if this client no longer has permission to receive these events + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * + * The cancelBlock will be called if you do not have permission to read data at this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that will be called if you don't have permission to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you do not have permission to read data at this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that will be called if you don't have permission to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + +#pragma mark - Detaching observers + +/** + * Detach a block previously attached with observeEventType:withBlock:. + * + * @param handle The handle returned by the call to observeEventType:withBlock: which we are trying to remove. + */ +- (void) removeObserverWithHandle:(FIRDatabaseHandle)handle; + +/** + * By calling `keepSynced:YES` on a location, the data for that location will automatically be downloaded and + * kept in sync, even when no listeners are attached for that location. Additionally, while a location is kept + * synced, it will not be evicted from the persistent disk cache. + * + * @param keepSynced Pass YES to keep this location synchronized, pass NO to stop synchronization. + */ +- (void) keepSynced:(BOOL)keepSynced; + + +/** + * Removes all observers at the current reference, but does not remove any observers at child references. + * removeAllObservers must be called again for each child reference where a listener was established to remove the observers. + */ +- (void) removeAllObservers; + +#pragma mark - Querying and limiting + + +/** + * queryLimitedToFirst: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryLimitedToFirst: will respond to at most the first limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit; + + +/** + * queryLimitedToLast: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryLimitedToLast: will respond to at most the last limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit; + +/** + * queryOrderBy: is used to generate a reference to a view of the data that's been sorted by the values of + * a particular child key. This method is intended to be used in combination with queryStartingAtValue:, + * queryEndingAtValue:, or queryEqualToValue:. + * + * @param key The child key to use in ordering data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, ordered by the values of the specified child key. + */ +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key; + +/** + * queryOrderedByKey: is used to generate a reference to a view of the data that's been sorted by child key. + * This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, + * or queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child keys. + */ +- (FIRDatabaseQuery *) queryOrderedByKey; + +/** + * queryOrderedByPriority: is used to generate a reference to a view of the data that's been sorted by child + * priority. This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, + * or queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child priorities. + */ +- (FIRDatabaseQuery *) queryOrderedByPriority; + +/** + * queryStartingAtValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryStartingAtValue: will respond to events at nodes with a value + * greater than or equal to startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue; + +/** + * queryStartingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryStartingAtValue:childKey will respond to events at nodes with a value + * greater than startValue, or equal to startValue and with a key greater than or equal to childKey. + * + * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @param childKey The lower bound, inclusive, for the key of nodes with value equal to startValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue childKey:(nullable NSString *)childKey; + +/** + * queryEndingAtValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEndingAtValue: will respond to events at nodes with a value + * less than or equal to endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue; + +/** + * queryEndingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEndingAtValue:childKey will respond to events at nodes with a value + * less than endValue, or equal to endValue and with a key less than or equal to childKey. + * + * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @param childKey The upper bound, inclusive, for the key of nodes with value equal to endValue + * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue childKey:(nullable NSString *)childKey; + +/** + * queryEqualToValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEqualToValue: will respond to events at nodes with a value equal + * to the supplied argument. + * + * @param value The value that the data returned by this FIRDatabaseQuery will have + * @return A FIRDatabaseQuery instance, limited to data with the supplied value. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value; + +/** + * queryEqualToValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEqualToValue:childKey will respond to events at nodes with a value + * equal to the supplied argument with a key equal to childKey. There will be at most one node that matches because + * child keys are unique. + * + * @param value The value that the data returned by this FIRDatabaseQuery will have + * @param childKey The key of nodes with the right value + * @return A FIRDatabaseQuery instance, limited to data with the supplied value and the key. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value childKey:(nullable NSString *)childKey; + +#pragma mark - Managing presence + +/** + * Ensure the data at this location is set to the specified value when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * onDisconnectSetValue: is especially useful for implementing "presence" systems, + * where a value should be changed or cleared when a user disconnects + * so that he appears "offline" to other users. + * + * @param value The value to be set after the connection is lost. + */ +- (void) onDisconnectSetValue:(nullable id)value; + + +/** + * Ensure the data at this location is set to the specified value when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * The completion block will be triggered when the operation has been successfully queued up on the Firebase Database servers + * + * @param value The value to be set after the connection is lost. + * @param block Block to be triggered when the operation has been queued up on the Firebase Database servers + */ +- (void) onDisconnectSetValue:(nullable id)value withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +/** + * Ensure the data at this location is set to the specified value and priority when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * @param value The value to be set after the connection is lost. + * @param priority The priority to be set after the connection is lost. + */ +- (void) onDisconnectSetValue:(nullable id)value andPriority:(id)priority; + + +/** + * Ensure the data at this location is set to the specified value and priority when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * The completion block will be triggered when the operation has been successfully queued up on the Firebase Database servers + * + * @param value The value to be set after the connection is lost. + * @param priority The priority to be set after the connection is lost. + * @param block Block to be triggered when the operation has been queued up on the Firebase Database servers + */ +- (void) onDisconnectSetValue:(nullable id)value andPriority:(nullable id)priority withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +/** + * Ensure the data at this location is removed when + * the client is disconnected (due to closing the app, navigating + * to a new page, or network issues). + * + * onDisconnectRemoveValue is especially useful for implementing "presence" systems. + */ +- (void) onDisconnectRemoveValue; + + +/** + * Ensure the data at this location is removed when + * the client is disconnected (due to closing the app, navigating + * to a new page, or network issues). + * + * onDisconnectRemoveValueWithCompletionBlock: is especially useful for implementing "presence" systems. + * + * @param block Block to be triggered when the operation has been queued up on the Firebase Database servers + */ +- (void) onDisconnectRemoveValueWithCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + + +/** + * Ensure the data has the specified child values updated when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * + * @param values A dictionary of child node keys and the values to set them to after the connection is lost. + */ +- (void) onDisconnectUpdateChildValues:(NSDictionary *)values; + + +/** + * Ensure the data has the specified child values updated when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * + * @param values A dictionary of child node keys and the values to set them to after the connection is lost. + * @param block A block that will be called once the operation has been queued up on the Firebase Database servers + */ +- (void) onDisconnectUpdateChildValues:(NSDictionary *)values withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +/** + * Cancel any operations that are set to run on disconnect. If you previously called onDisconnectSetValue:, + * onDisconnectRemoveValue:, or onDisconnectUpdateChildValues:, and no longer want the values updated when the + * connection is lost, call cancelDisconnectOperations: + */ +- (void) cancelDisconnectOperations; + + +/** + * Cancel any operations that are set to run on disconnect. If you previously called onDisconnectSetValue:, + * onDisconnectRemoveValue:, or onDisconnectUpdateChildValues:, and no longer want the values updated when the + * connection is lost, call cancelDisconnectOperations: + * + * @param block A block that will be triggered once the Firebase Database servers have acknowledged the cancel request. + */ +- (void) cancelDisconnectOperationsWithCompletionBlock:(nullable void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +#pragma mark - Manual Connection Management + +/** + * Manually disconnect the Firebase Database client from the server and disable automatic reconnection. + * + * The Firebase Database client automatically maintains a persistent connection to the Firebase Database server, + * which will remain active indefinitely and reconnect when disconnected. However, the goOffline( ) + * and goOnline( ) methods may be used to manually control the client connection in cases where + * a persistent connection is undesirable. + * + * While offline, the Firebase Database client will no longer receive data updates from the server. However, + * all database operations performed locally will continue to immediately fire events, allowing + * your application to continue behaving normally. Additionally, each operation performed locally + * will automatically be queued and retried upon reconnection to the Firebase Database server. + * + * To reconnect to the Firebase Database server and begin receiving remote events, see goOnline( ). + * Once the connection is reestablished, the Firebase Database client will transmit the appropriate data + * and fire the appropriate events so that your client "catches up" automatically. + * + * Note: Invoking this method will impact all Firebase Database connections. + */ ++ (void) goOffline; + +/** + * Manually reestablish a connection to the Firebase Database server and enable automatic reconnection. + * + * The Firebase Database client automatically maintains a persistent connection to the Firebase Database server, + * which will remain active indefinitely and reconnect when disconnected. However, the goOffline( ) + * and goOnline( ) methods may be used to manually control the client connection in cases where + * a persistent connection is undesirable. + * + * This method should be used after invoking goOffline( ) to disable the active connection. + * Once reconnected, the Firebase Database client will automatically transmit the proper data and fire + * the appropriate events so that your client "catches up" automatically. + * + * To disconnect from the Firebase Database server, see goOffline( ). + * + * Note: Invoking this method will impact all Firebase Database connections. + */ ++ (void) goOnline; + + +#pragma mark - Transactions + +/** + * Performs an optimistic-concurrency transactional update to the data at this location. Your block will be called with a FIRMutableData + * instance that contains the current data at this location. Your block should update this data to the value you + * wish to write to this location, and then return an instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had stale data, your block will be run + * again with the latest data from the server. + * + * When your block is run, you may decide to abort the transaction by returning [FIRTransactionResult abort]. + * + * @param block This block receives the current data at this location and must return an instance of FIRTransactionResult + */ +- (void) runTransactionBlock:(FIRTransactionResult * (^) (FIRMutableData* currentData))block; + + +/** + * Performs an optimistic-concurrency transactional update to the data at this location. Your block will be called with a FIRMutableData + * instance that contains the current data at this location. Your block should update this data to the value you + * wish to write to this location, and then return an instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had stale data, your block will be run + * again with the latest data from the server. + * + * When your block is run, you may decide to abort the transaction by returning [FIRTransactionResult abort]. + * + * @param block This block receives the current data at this location and must return an instance of FIRTransactionResult + * @param completionBlock This block will be triggered once the transaction is complete, whether it was successful or not. It will indicate if there was an error, whether or not the data was committed, and what the current value of the data at this location is. + */ +- (void)runTransactionBlock:(FIRTransactionResult * (^) (FIRMutableData* currentData))block andCompletionBlock:(void (^) (NSError *__nullable error, BOOL committed, FIRDataSnapshot *__nullable snapshot))completionBlock; + + + +/** + * Performs an optimistic-concurrency transactional update to the data at this location. Your block will be called with a FIRMutableData + * instance that contains the current data at this location. Your block should update this data to the value you + * wish to write to this location, and then return an instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had stale data, your block will be run + * again with the latest data from the server. + * + * When your block is run, you may decide to abort the transaction by return [FIRTransactionResult abort]. + * + * Since your block may be run multiple times, this client could see several immediate states that don't exist on the server. You can suppress those immediate states until the server confirms the final state of the transaction. + * + * @param block This block receives the current data at this location and must return an instance of FIRTransactionResult + * @param completionBlock This block will be triggered once the transaction is complete, whether it was successful or not. It will indicate if there was an error, whether or not the data was committed, and what the current value of the data at this location is. + * @param localEvents Set this to NO to suppress events raised for intermediate states, and only get events based on the final state of the transaction. + */ +- (void)runTransactionBlock:(FIRTransactionResult * (^) (FIRMutableData* currentData))block andCompletionBlock:(nullable void (^) (NSError *__nullable error, BOOL committed, FIRDataSnapshot *__nullable snapshot))completionBlock withLocalEvents:(BOOL)localEvents; + + +#pragma mark - Retrieving String Representation + +/** + * Gets the absolute URL of this Firebase Database location. + * + * @return The absolute URL of the referenced Firebase Database location. + */ +- (NSString *) description; + +#pragma mark - Properties + +/** + * Gets a FIRDatabaseReference for the parent location. + * If this instance refers to the root of your Firebase Database, it has no parent, + * and therefore parent( ) will return null. + * + * @return A FIRDatabaseReference for the parent location. + */ +@property (strong, readonly, nonatomic, nullable) FIRDatabaseReference * parent; + + +/** + * Gets a FIRDatabaseReference for the root location + * + * @return A new FIRDatabaseReference to root location. + */ +@property (strong, readonly, nonatomic) FIRDatabaseReference * root; + + +/** + * Gets the last token in a Firebase Database location (e.g. 'fred' in https://SampleChat.firebaseIO-demo.com/users/fred) + * + * @return The key of the location this reference points to. + */ +@property (strong, readonly, nonatomic) NSString* key; + +/** + * Gets the URL for the Firebase Database location referenced by this FIRDatabaseReference. + * + * @return The url of the location this reference points to. + */ +@property (strong, readonly, nonatomic) NSString* URL; + +/** + * Gets the FIRDatabase instance associated with this reference. + * + * @return The FIRDatabase object for this reference. + */ +@property (strong, readonly, nonatomic) FIRDatabase *database; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRMutableData.h b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRMutableData.h new file mode 100755 index 0000000..fc42ec9 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRMutableData.h @@ -0,0 +1,140 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A FIRMutableData instance is populated with data from a Firebase Database location. + * When you are using runTransactionBlock:, you will be given an instance containing the current + * data at that location. Your block will be responsible for updating that instance to the data + * you wish to save at that location, and then returning using [FIRTransactionResult successWithValue:]. + * + * To modify the data, set its value property to any of the native types support by Firebase Database: + * + * + NSNumber (includes BOOL) + * + NSDictionary + * + NSArray + * + NSString + * + nil / NSNull to remove the data + * + * Note that changes made to a child FIRMutableData instance will be visible to the parent. + */ +@interface FIRMutableData : NSObject + + +#pragma mark - Inspecting and navigating the data + + +/** + * Returns boolean indicating whether this mutable data has children. + * + * @return YES if this data contains child nodes. + */ +- (BOOL) hasChildren; + + +/** + * Indicates whether this mutable data has a child at the given path. + * + * @param path A path string, consisting either of a single segment, like 'child', or multiple segments, 'a/deeper/child' + * @return YES if this data contains a child at the specified relative path + */ +- (BOOL) hasChildAtPath:(NSString *)path; + + +/** + * Used to obtain a FIRMutableData instance that encapsulates the data at the given relative path. + * Note that changes made to the child will be visible to the parent. + * + * @param path A path string, consisting either of a single segment, like 'child', or multiple segments, 'a/deeper/child' + * @return A FIRMutableData instance containing the data at the given path + */ +- (FIRMutableData *)childDataByAppendingPath:(NSString *)path; + + +#pragma mark - Properties + + +/** + * To modify the data contained by this instance of FIRMutableData, set this to any of the native types supported by Firebase Database: + * + * + NSNumber (includes BOOL) + * + NSDictionary + * + NSArray + * + NSString + * + nil / NSNull to remove the data + * + * Note that setting this value will override the priority at this location. + * + * @return The current data at this location as a native object + */ +@property (strong, nonatomic, nullable) id value; + + +/** + * Set this property to update the priority of the data at this location. Can be set to the following types: + * + * + NSNumber + * + NSString + * + nil / NSNull to remove the priority + * + * @return The priority of the data at this location + */ +@property (strong, nonatomic, nullable) id priority; + + +/** + * @return The number of child nodes at this location + */ +@property (readonly, nonatomic) NSUInteger childrenCount; + + +/** + * Used to iterate over the children at this location. You can use the native for .. in syntax: + * + * for (FIRMutableData* child in data.children) { + * ... + * } + * + * Note that this enumerator operates on an immutable copy of the child list. So, you can modify the instance + * during iteration, but the new additions will not be visible until you get a new enumerator. + */ +@property (readonly, nonatomic, strong) NSEnumerator* children; + + +/** + * @return The key name of this node, or nil if it is the top-most location + */ +@property (readonly, nonatomic, strong, nullable) NSString* key; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRServerValue.h b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRServerValue.h new file mode 100755 index 0000000..c93a524 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRServerValue.h @@ -0,0 +1,44 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +NS_ASSUME_NONNULL_BEGIN + +/** + * Placeholder values you may write into Firebase Database as a value or priority + * that will automatically be populated by the Firebase Database server. + */ +@interface FIRServerValue : NSObject + +/** + * Placeholder value for the number of milliseconds since the Unix epoch + */ ++ (NSDictionary *) timestamp; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRTransactionResult.h b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRTransactionResult.h new file mode 100755 index 0000000..07439e1 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRTransactionResult.h @@ -0,0 +1,57 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "FIRMutableData.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Used for runTransactionBlock:. An FIRTransactionResult instance is a container for the results of the transaction. + */ +@interface FIRTransactionResult : NSObject + +/** + * Used for runTransactionBlock:. Indicates that the new value should be saved at this location + * + * @param value A FIRMutableData instance containing the new value to be set + * @return An FIRTransactionResult instance that can be used as a return value from the block given to runTransactionBlock: + */ ++ (FIRTransactionResult *)successWithValue:(FIRMutableData *)value; + + +/** + * Used for runTransactionBlock:. Indicates that the current transaction should no longer proceed. + * + * @return An FIRTransactionResult instance that can be used as a return value from the block given to runTransactionBlock: + */ ++ (FIRTransactionResult *) abort; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FirebaseDatabase.h b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FirebaseDatabase.h new file mode 100755 index 0000000..d903c1b --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FirebaseDatabase.h @@ -0,0 +1,41 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2016 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FirebaseDatabase_h +#define FirebaseDatabase_h + +#import "FIRDatabase.h" +#import "FIRDatabaseQuery.h" +#import "FIRDatabaseReference.h" +#import "FIRDataEventType.h" +#import "FIRDataSnapshot.h" +#import "FIRMutableData.h" +#import "FIRServerValue.h" +#import "FIRTransactionResult.h" + +#endif /* FirebaseDatabase_h */ diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Info.plist b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Info.plist new file mode 100755 index 0000000..4174f41 Binary files /dev/null and b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Info.plist differ diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Modules/module.modulemap b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Modules/module.modulemap new file mode 100755 index 0000000..28b323e --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Modules/module.modulemap @@ -0,0 +1,13 @@ +framework module FirebaseDatabase { + umbrella header "FirebaseDatabase.h" + + export * + module * { export * } + + link framework "CFNetwork" + link framework "Security" + link framework "SystemConfiguration" + + link "c++" + link "icucore" +} diff --git a/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/NOTICE b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/NOTICE new file mode 100755 index 0000000..410cbd6 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/NOTICE @@ -0,0 +1,47 @@ +Google LevelDB +Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +* Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-- + +Square Socket Rocket +Copyright 2012 Square Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +-- + +APLevelDB +Created by Adam Preble on 1/23/12. +Copyright (c) 2012 Adam Preble. All rights reserved. + +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/Old Old Task Master/Pods/FirebaseInstanceID/CHANGELOG.md b/Old Old Task Master/Pods/FirebaseInstanceID/CHANGELOG.md new file mode 100755 index 0000000..adb6b81 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseInstanceID/CHANGELOG.md @@ -0,0 +1,40 @@ +# 2017-03-31 -- v1.0.10 + +- Improvements to token-fetching logic +- Fixed some warnings in Instance ID +- Improved error messages if Instance ID couldn't be initialized properly +- Improvements to console logging + +# 2017-01-31 -- v1.0.9 + +- Removed an error being mistakenly logged to the console. + +# 2016-07-06 -- v1.0.8 + +- Don't store InstanceID plists in Documents folder. + +# 2016-06-19 -- v1.0.7 + +- Fix remote-notifications warning on app submission. + +# 2016-05-16 -- v1.0.6 + +- Fix CocoaPod linter issues for InstanceID pod. + +# 2016-05-13 -- v1.0.5 + +- Fix Authorization errors for InstanceID tokens. + +# 2016-05-11 -- v1.0.4 + +- Reduce wait for InstanceID token during parallel requests. + +# 2016-04-18 -- v1.0.3 + +- Change flag to disable swizzling to *FirebaseAppDelegateProxyEnabled*. +- Fix incessant Keychain errors while accessing InstanceID. +- Fix max retries for fetching IID token. + +# 2016-04-18 -- v1.0.2 + +- Register for remote notifications on iOS8+ in the SDK itself. diff --git a/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/FirebaseInstanceID b/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/FirebaseInstanceID new file mode 100755 index 0000000..7c22eea Binary files /dev/null and b/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/FirebaseInstanceID differ diff --git a/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FIRInstanceID.h b/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FIRInstanceID.h new file mode 100755 index 0000000..342b154 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FIRInstanceID.h @@ -0,0 +1,245 @@ +#import + +/** + * @memberof FIRInstanceID + * + * The scope to be used when fetching/deleting a token for Firebase Messaging. + */ +FOUNDATION_EXPORT NSString * __nonnull const kFIRInstanceIDScopeFirebaseMessaging; + +/** + * Called when the system determines that tokens need to be refreshed. + * This method is also called if Instance ID has been reset in which + * case, tokens and FCM topic subscriptions also need to be refreshed. + * + * Instance ID service will throttle the refresh event across all devices + * to control the rate of token updates on application servers. + */ +FOUNDATION_EXPORT NSString * __nonnull const kFIRInstanceIDTokenRefreshNotification; + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the InstanceID token returns. If + * the call fails we return the appropriate `error code` as described below. + * + * @param token The valid token as returned by InstanceID backend. + * + * @param error The error describing why generating a new token + * failed. See the error codes below for a more detailed + * description. + */ +typedef void(^FIRInstanceIDTokenHandler)( NSString * __nullable token, NSError * __nullable error); + + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the InstanceID `deleteToken` returns. If + * the call fails we return the appropriate `error code` as described below + * + * @param error The error describing why deleting the token failed. + * See the error codes below for a more detailed description. + */ +typedef void(^FIRInstanceIDDeleteTokenHandler)(NSError * __nullable error); + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the app identity is created. If the + * identity wasn't created for some reason we return the appropriate error code. + * + * @param identity A valid identity for the app instance, nil if there was an error + * while creating an identity. + * @param error The error if fetching the identity fails else nil. + */ +typedef void(^FIRInstanceIDHandler)(NSString * __nullable identity, NSError * __nullable error); + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the app identity and all the tokens associated + * with it are deleted. Returns a valid error object in case of failure else nil. + * + * @param error The error if deleting the identity and all the tokens associated with + * it fails else nil. + */ +typedef void(^FIRInstanceIDDeleteHandler)(NSError * __nullable error); + +/** + * @enum FIRInstanceIDError + */ +typedef NS_ENUM(NSUInteger, FIRInstanceIDError) { + // Http related errors. + + /// Unknown error. + FIRInstanceIDErrorUnknown = 0, + + /// Auth Error -- GCM couldn't validate request from this client. + FIRInstanceIDErrorAuthentication = 1, + + /// NoAccess -- InstanceID service cannot be accessed. + FIRInstanceIDErrorNoAccess = 2, + + /// Timeout -- Request to InstanceID backend timed out. + FIRInstanceIDErrorTimeout = 3, + + /// Network -- No network available to reach the servers. + FIRInstanceIDErrorNetwork = 4, + + /// OperationInProgress -- Another similar operation in progress, + /// bailing this one. + FIRInstanceIDErrorOperationInProgress = 5, + + /// InvalidRequest -- Some parameters of the request were invalid. + FIRInstanceIDErrorInvalidRequest = 7, +}; + +/** + * The APNS token type for the app. If the token type is set to `UNKNOWN` + * InstanceID will implicitly try to figure out what the actual token type + * is from the provisioning profile. + */ +typedef NS_ENUM(NSInteger, FIRInstanceIDAPNSTokenType) { + /// Unknown token type. + FIRInstanceIDAPNSTokenTypeUnknown, + /// Sandbox token type. + FIRInstanceIDAPNSTokenTypeSandbox, + /// Production token type. + FIRInstanceIDAPNSTokenTypeProd, +}; + +/** + * Instance ID provides a unique identifier for each app instance and a mechanism + * to authenticate and authorize actions (for example, sending an FCM message). + * + * Instance ID is long lived but, may be reset if the device is not used for + * a long time or the Instance ID service detects a problem. + * If Instance ID is reset, the app will be notified via + * `kFIRInstanceIDTokenRefreshNotification`. + * + * If the Instance ID has become invalid, the app can request a new one and + * send it to the app server. + * To prove ownership of Instance ID and to allow servers to access data or + * services associated with the app, call + * `[FIRInstanceID tokenWithAuthorizedEntity:scope:options:handler]`. + */ +@interface FIRInstanceID : NSObject + +/** + * FIRInstanceID. + * + * @return A shared instance of FIRInstanceID. + */ ++ (nonnull instancetype)instanceID NS_SWIFT_NAME(instanceID()); + +/** + * Unavailable. Use +instanceID instead. + */ +- (nonnull instancetype)init __attribute__((unavailable("Use +instanceID instead."))); + +/** + * Set APNS token for the application. This APNS token will be used to register + * with Firebase Messaging using `token` or + * `tokenWithAuthorizedEntity:scope:options:handler`. If the token type is set to + * `FIRInstanceIDAPNSTokenTypeUnknown` InstanceID will read the provisioning profile + * to find out the token type. + * + * @param token The APNS token for the application. + * @param type The APNS token type for the above token. + */ +- (void)setAPNSToken:(nonnull NSData *)token + type:(FIRInstanceIDAPNSTokenType)type; + +#pragma mark - Tokens + +/** + * Returns a Firebase Messaging scoped token for the firebase app. + * + * @return Null Returns null if the device has not yet been registerd with + * Firebase Message else returns a valid token. + */ +- (nullable NSString *)token; + +/** + * Returns a token that authorizes an Entity (example: cloud service) to perform + * an action on behalf of the application identified by Instance ID. + * + * This is similar to an OAuth2 token except, it applies to the + * application instance instead of a user. + * + * This is an asynchronous call. If the token fetching fails for some reason + * we invoke the completion callback with nil `token` and the appropriate + * error. + * + * Note, you can only have one `token` or `deleteToken` call for a given + * authorizedEntity and scope at any point of time. Making another such call with the + * same authorizedEntity and scope before the last one finishes will result in an + * error with code `OperationInProgress`. + * + * @see FIRInstanceID deleteTokenWithAuthorizedEntity:scope:handler: + * + * @param authorizedEntity Entity authorized by the token. + * @param scope Action authorized for authorizedEntity. + * @param options The extra options to be sent with your token request. The + * value for the `apns_token` should be the NSData object + * passed to UIApplication's + * `didRegisterForRemoteNotificationsWithDeviceToken` method. + * All other keys and values in the options dict need to be + * instances of NSString or else they will be discarded. Bundle + * keys starting with 'GCM.' and 'GOOGLE.' are reserved. + * @param handler The callback handler which is invoked when the token is + * successfully fetched. In case of success a valid `token` and + * `nil` error are returned. In case of any error the `token` + * is nil and a valid `error` is returned. The valid error + * codes have been documented above. + */ +- (void)tokenWithAuthorizedEntity:(nonnull NSString *)authorizedEntity + scope:(nonnull NSString *)scope + options:(nullable NSDictionary *)options + handler:(nonnull FIRInstanceIDTokenHandler)handler; + +/** + * Revokes access to a scope (action) for an entity previously + * authorized by `[FIRInstanceID tokenWithAuthorizedEntity:scope:options:handler]`. + * + * This is an asynchronous call. Call this on the main thread since InstanceID lib + * is not thread safe. In case token deletion fails for some reason we invoke the + * `handler` callback passed in with the appropriate error code. + * + * Note, you can only have one `token` or `deleteToken` call for a given + * authorizedEntity and scope at a point of time. Making another such call with the + * same authorizedEntity and scope before the last one finishes will result in an error + * with code `OperationInProgress`. + * + * @param authorizedEntity Entity that must no longer have access. + * @param scope Action that entity is no longer authorized to perform. + * @param handler The handler that is invoked once the unsubscribe call ends. + * In case of error an appropriate error object is returned + * else error is nil. + */ +- (void)deleteTokenWithAuthorizedEntity:(nonnull NSString *)authorizedEntity + scope:(nonnull NSString *)scope + handler:(nonnull FIRInstanceIDDeleteTokenHandler)handler; + +#pragma mark - Identity + +/** + * Asynchronously fetch a stable identifier that uniquely identifies the app + * instance. If the identifier has been revoked or has expired, this method will + * return a new identifier. + * + * + * @param handler The handler to invoke once the identifier has been fetched. + * In case of error an appropriate error object is returned else + * a valid identifier is returned and a valid identifier for the + * application instance. + */ +- (void)getIDWithHandler:(nonnull FIRInstanceIDHandler)handler; + +/** + * Resets Instance ID and revokes all tokens. + */ +- (void)deleteIDWithHandler:(nonnull FIRInstanceIDDeleteHandler)handler; + +@end diff --git a/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FirebaseInstanceID.h b/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FirebaseInstanceID.h new file mode 100755 index 0000000..053ec2b --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FirebaseInstanceID.h @@ -0,0 +1 @@ +#import "FIRInstanceID.h" diff --git a/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Modules/module.modulemap b/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Modules/module.modulemap new file mode 100755 index 0000000..4b3b912 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Modules/module.modulemap @@ -0,0 +1,7 @@ +framework module FirebaseInstanceID { + umbrella header "FirebaseInstanceID.h" + export * + module * { export *} + link "c++" + link "z" +} \ No newline at end of file diff --git a/Old Old Task Master/Pods/FirebaseInstanceID/README.md b/Old Old Task Master/Pods/FirebaseInstanceID/README.md new file mode 100755 index 0000000..25fe219 --- /dev/null +++ b/Old Old Task Master/Pods/FirebaseInstanceID/README.md @@ -0,0 +1,10 @@ +# InstanceID SDK for iOS + +Instance ID provides a unique ID per instance of your apps and also provides a +mechanism to authenticate and authorize actions, like sending messages via +Firebase Cloud Messaging (FCM). + + +Please visit [our developer +site](https://developers.google.com/instance-id/) for integration instructions, +documentation, support information, and terms of service. diff --git a/Old Old Task Master/Pods/GTMSessionFetcher/LICENSE b/Old Old Task Master/Pods/GTMSessionFetcher/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Old Old Task Master/Pods/GTMSessionFetcher/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Old Old Task Master/Pods/GTMSessionFetcher/README.md b/Old Old Task Master/Pods/GTMSessionFetcher/README.md new file mode 100644 index 0000000..478efde --- /dev/null +++ b/Old Old Task Master/Pods/GTMSessionFetcher/README.md @@ -0,0 +1,23 @@ +# Google Toolbox for Mac - Session Fetcher # + +**Project site**
+**Discussion group** + +[![Build Status](https://travis-ci.org/google/gtm-session-fetcher.svg?branch=master)](https://travis-ci.org/google/gtm-session-fetcher) + +`GTMSessionFetcher` makes it easy for Cocoa applications to perform http +operations. The fetcher is implemented as a wrapper on `NSURLSession`, so its +behavior is asynchronous and uses operating-system settings on iOS and Mac OS X. + +Features include: +- Simple to build; only one source/header file pair is required +- Simple to use: takes just two lines of code to fetch a request +- Supports upload and download sessions +- Flexible cookie storage +- Automatic retry on errors, with exponential backoff +- Support for generating multipart MIME upload streams +- Easy, convenient logging of http requests and responses +- Supports plug-in authentication such as with GTMAppAuth +- Easily testable; self-mocking +- Automatic rate limiting when created by the `GTMSessionFetcherService` factory class +- Fully independent of other projects diff --git a/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h new file mode 100644 index 0000000..a649cf0 --- /dev/null +++ b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h @@ -0,0 +1,1308 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// GTMSessionFetcher is a wrapper around NSURLSession for http operations. +// +// What does this offer on top of of NSURLSession? +// +// - Block-style callbacks for useful functionality like progress rather +// than delegate methods. +// - Out-of-process uploads and downloads using NSURLSession, including +// management of fetches after relaunch. +// - Integration with GTMAppAuth for invisible management and refresh of +// authorization tokens. +// - Pretty-printed http logging. +// - Cookies handling that does not interfere with or get interfered with +// by WebKit cookies or on Mac by Safari and other apps. +// - Credentials handling for the http operation. +// - Rate-limiting and cookie grouping when fetchers are created with +// GTMSessionFetcherService. +// +// If the bodyData or bodyFileURL property is set, then a POST request is assumed. +// +// Each fetcher is assumed to be for a one-shot fetch request; don't reuse the object +// for a second fetch. +// +// The fetcher will be self-retained as long as a connection is pending. +// +// To keep user activity private, URLs must have an https scheme (unless the property +// allowedInsecureSchemes is set to permit the scheme.) +// +// Callbacks will be released when the fetch completes or is stopped, so there is no need +// to use weak self references in the callback blocks. +// +// Sample usage: +// +// _fetcherService = [[GTMSessionFetcherService alloc] init]; +// +// GTMSessionFetcher *myFetcher = [_fetcherService fetcherWithURLString:myURLString]; +// myFetcher.retryEnabled = YES; +// myFetcher.comment = @"First profile image"; +// +// // Optionally specify a file URL or NSData for the request body to upload. +// myFetcher.bodyData = [postString dataUsingEncoding:NSUTF8StringEncoding]; +// +// [myFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { +// if (error != nil) { +// // Server status code or network error. +// // +// // If the domain is kGTMSessionFetcherStatusDomain then the error code +// // is a failure status from the server. +// } else { +// // Fetch succeeded. +// } +// }]; +// +// There is also a beginFetch call that takes a pointer and selector for the completion handler; +// a pointer and selector is a better style when the callback is a substantial, separate method. +// +// NOTE: Fetches may retrieve data from the server even though the server +// returned an error, so the criteria for success is a non-nil error. +// The completion handler is called when the server status is >= 300 with an NSError +// having domain kGTMSessionFetcherStatusDomain and code set to the server status. +// +// Status codes are at +// +// +// Background session support: +// +// Out-of-process uploads and downloads may be created by setting the fetcher's +// useBackgroundSession property. Data to be uploaded should be provided via +// the uploadFileURL property; the download destination should be specified with +// the destinationFileURL. NOTE: Background upload files should be in a location +// that will be valid even after the device is restarted, so the file should not +// be uploaded from a system temporary or cache directory. +// +// Background session transfers are slower, and should typically be used only +// for very large downloads or uploads (hundreds of megabytes). +// +// When background sessions are used in iOS apps, the application delegate must +// pass through the parameters from UIApplicationDelegate's +// application:handleEventsForBackgroundURLSession:completionHandler: to the +// fetcher class. +// +// When the application has been relaunched, it may also create a new fetcher +// instance to handle completion of the transfers. +// +// - (void)application:(UIApplication *)application +// handleEventsForBackgroundURLSession:(NSString *)identifier +// completionHandler:(void (^)())completionHandler { +// // Application was re-launched on completing an out-of-process download. +// +// // Pass the URLSession info related to this re-launch to the fetcher class. +// [GTMSessionFetcher application:application +// handleEventsForBackgroundURLSession:identifier +// completionHandler:completionHandler]; +// +// // Get a fetcher related to this re-launch and re-hook up a completionHandler to it. +// GTMSessionFetcher *fetcher = [GTMSessionFetcher fetcherWithSessionIdentifier:identifier]; +// NSURL *destinationFileURL = fetcher.destinationFileURL; +// fetcher.completionHandler = ^(NSData *data, NSError *error) { +// [self downloadCompletedToFile:destinationFileURL error:error]; +// }; +// } +// +// +// Threading and queue support: +// +// Networking always happens on a background thread; there is no advantage to +// changing thread or queue to create or start a fetcher. +// +// Callbacks are run on the main thread; alternatively, the app may set the +// fetcher's callbackQueue to a dispatch queue. +// +// Once the fetcher's beginFetch method has been called, the fetcher's methods and +// properties may be accessed from any thread. +// +// Downloading to disk: +// +// To have downloaded data saved directly to disk, specify a file URL for the +// destinationFileURL property. +// +// HTTP methods and headers: +// +// Alternative HTTP methods, like PUT, and custom headers can be specified by +// creating the fetcher with an appropriate NSMutableURLRequest. +// +// +// Caching: +// +// The fetcher avoids caching. That is best for API requests, but may hurt +// repeat fetches of static data. Apps may enable a persistent disk cache by +// customizing the config: +// +// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher, +// NSURLSessionConfiguration *config) { +// config.URLCache = [NSURLCache sharedURLCache]; +// }; +// +// Or use the standard system config to share cookie storage with web views +// and to enable disk caching: +// +// fetcher.configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; +// +// +// Cookies: +// +// There are three supported mechanisms for remembering cookies between fetches. +// +// By default, a standalone GTMSessionFetcher uses a mutable array held +// statically to track cookies for all instantiated fetchers. This avoids +// cookies being set by servers for the application from interfering with +// Safari and WebKit cookie settings, and vice versa. +// The fetcher cookies are lost when the application quits. +// +// To rely instead on WebKit's global NSHTTPCookieStorage, set the fetcher's +// cookieStorage property: +// myFetcher.cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; +// +// To share cookies with other apps, use the method introduced in iOS 9/OS X 10.11: +// myFetcher.cookieStorage = +// [NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:kMyCompanyContainedID]; +// +// To ignore existing cookies and only have cookies related to the single fetch +// be applied, make a temporary cookie storage object: +// myFetcher.cookieStorage = [[GTMSessionCookieStorage alloc] init]; +// +// Note: cookies set while following redirects will be sent to the server, as +// the redirects are followed by the fetcher. +// +// To completely disable cookies, similar to setting cookieStorageMethod to +// kGTMHTTPFetcherCookieStorageMethodNone, adjust the session configuration +// appropriately in the fetcher or fetcher service: +// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher, +// NSURLSessionConfiguration *config) { +// config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever; +// config.HTTPShouldSetCookies = NO; +// }; +// +// If the fetcher is created from a GTMSessionFetcherService object +// then the cookie storage mechanism is set to use the cookie storage in the +// service object rather than the static storage. Disabling cookies in the +// session configuration set on a service object will disable cookies for all +// fetchers created from that GTMSessionFetcherService object, since the session +// configuration is propagated to the fetcher. +// +// +// Monitoring data transfers. +// +// The fetcher supports a variety of properties for progress monitoring +// progress with callback blocks. +// GTMSessionFetcherSendProgressBlock sendProgressBlock +// GTMSessionFetcherReceivedProgressBlock receivedProgressBlock +// GTMSessionFetcherDownloadProgressBlock downloadProgressBlock +// +// If supplied by the server, the anticipated total download size is available +// as [[myFetcher response] expectedContentLength] (and may be -1 for unknown +// download sizes.) +// +// +// Automatic retrying of fetches +// +// The fetcher can optionally create a timer and reattempt certain kinds of +// fetch failures (status codes 408, request timeout; 502, gateway failure; +// 503, service unavailable; 504, gateway timeout; networking errors +// NSURLErrorTimedOut and NSURLErrorNetworkConnectionLost.) The user may +// set a retry selector to customize the type of errors which will be retried. +// +// Retries are done in an exponential-backoff fashion (that is, after 1 second, +// 2, 4, 8, and so on.) +// +// Enabling automatic retries looks like this: +// myFetcher.retryEnabled = YES; +// +// With retries enabled, the completion callbacks are called only +// when no more retries will be attempted. Calling the fetcher's stopFetching +// method will terminate the retry timer, without the finished or failure +// selectors being invoked. +// +// Optionally, the client may set the maximum retry interval: +// myFetcher.maxRetryInterval = 60.0; // in seconds; default is 60 seconds +// // for downloads, 600 for uploads +// +// Servers should never send a 400 or 500 status for errors that are retryable +// by clients, as those values indicate permanent failures. In nearly all +// cases, the default standard retry behavior is correct for clients, and no +// custom client retry behavior is needed or appropriate. Servers that send +// non-retryable status codes and expect the client to retry the request are +// faulty. +// +// Still, the client may provide a block to determine if a status code or other +// error should be retried. The block returns YES to set the retry timer or NO +// to fail without additional fetch attempts. +// +// The retry method may return the |suggestedWillRetry| argument to get the +// default retry behavior. Server status codes are present in the +// error argument, and have the domain kGTMSessionFetcherStatusDomain. The +// user's method may look something like this: +// +// myFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *error, +// GTMSessionFetcherRetryResponse response) { +// // Perhaps examine error.domain and error.code, or fetcher.retryCount +// // +// // Respond with YES to start the retry timer, NO to proceed to the failure +// // callback, or suggestedWillRetry to get default behavior for the +// // current error domain and code values. +// response(suggestedWillRetry); +// }; + + +#import + +#if TARGET_OS_IPHONE +#import +#endif +#if TARGET_OS_WATCH +#import +#endif + +// By default it is stripped from non DEBUG builds. Developers can override +// this in their project settings. +#ifndef STRIP_GTM_FETCH_LOGGING + #if !DEBUG + #define STRIP_GTM_FETCH_LOGGING 1 + #else + #define STRIP_GTM_FETCH_LOGGING 0 + #endif +#endif + +// Logs in debug builds. +#ifndef GTMSESSION_LOG_DEBUG + #if DEBUG + #define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__) + #else + #define GTMSESSION_LOG_DEBUG(...) do { } while (0) + #endif +#endif + +// Asserts in debug builds (or logs in debug builds if GTMSESSION_ASSERT_AS_LOG +// or NS_BLOCK_ASSERTIONS are defined.) +#ifndef GTMSESSION_ASSERT_DEBUG + #if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG + #undef GTMSESSION_ASSERT_AS_LOG + #define GTMSESSION_ASSERT_AS_LOG 1 + #endif + + #if DEBUG && !GTMSESSION_ASSERT_AS_LOG + #define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__) + #elif DEBUG + #define GTMSESSION_ASSERT_DEBUG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); } + #else + #define GTMSESSION_ASSERT_DEBUG(pred, ...) do { } while (0) + #endif +#endif + +// Asserts in debug builds, logs in release builds (or logs in debug builds if +// GTMSESSION_ASSERT_AS_LOG is defined.) +#ifndef GTMSESSION_ASSERT_DEBUG_OR_LOG + #if DEBUG && !GTMSESSION_ASSERT_AS_LOG + #define GTMSESSION_ASSERT_DEBUG_OR_LOG(...) NSAssert(__VA_ARGS__) + #else + #define GTMSESSION_ASSERT_DEBUG_OR_LOG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); } + #endif +#endif + +// Macro useful for examining messages from NSURLSession during debugging. +#if 0 +#define GTM_LOG_SESSION_DELEGATE(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__) +#else +#define GTM_LOG_SESSION_DELEGATE(...) +#endif + +#ifndef GTM_NULLABLE + #if __has_feature(nullability) // Available starting in Xcode 6.3 + #define GTM_NULLABLE_TYPE __nullable + #define GTM_NONNULL_TYPE __nonnull + #define GTM_NULLABLE nullable + #define GTM_NONNULL_DECL nonnull // GTM_NONNULL is used by GTMDefines.h + #define GTM_NULL_RESETTABLE null_resettable + + #define GTM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN + #define GTM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END + #else + #define GTM_NULLABLE_TYPE + #define GTM_NONNULL_TYPE + #define GTM_NULLABLE + #define GTM_NONNULL_DECL + #define GTM_NULL_RESETTABLE + #define GTM_ASSUME_NONNULL_BEGIN + #define GTM_ASSUME_NONNULL_END + #endif // __has_feature(nullability) +#endif // GTM_NULLABLE + +#if (TARGET_OS_TV \ + || TARGET_OS_WATCH \ + || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0)) +#define GTMSESSION_DEPRECATE_ON_2016_SDKS(_MSG) __attribute__((deprecated("" _MSG))) +#else +#define GTMSESSION_DEPRECATE_ON_2016_SDKS(_MSG) +#endif + +#ifndef GTM_DECLARE_GENERICS + #if __has_feature(objc_generics) + #define GTM_DECLARE_GENERICS 1 + #else + #define GTM_DECLARE_GENERICS 0 + #endif +#endif + +#ifndef GTM_NSArrayOf + #if GTM_DECLARE_GENERICS + #define GTM_NSArrayOf(value) NSArray + #define GTM_NSDictionaryOf(key, value) NSDictionary + #else + #define GTM_NSArrayOf(value) NSArray + #define GTM_NSDictionaryOf(key, value) NSDictionary + #endif // __has_feature(objc_generics) +#endif // GTM_NSArrayOf + +// For iOS, the fetcher can declare itself a background task to allow fetches +// to finish when the app leaves the foreground. +// +// (This is unrelated to providing a background configuration, which allows +// out-of-process uploads and downloads.) +// +// To disallow use of background tasks during fetches, the target should define +// GTM_BACKGROUND_TASK_FETCHING to 0, or alternatively may set the +// skipBackgroundTask property to YES. +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !defined(GTM_BACKGROUND_TASK_FETCHING) + #define GTM_BACKGROUND_TASK_FETCHING 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if (TARGET_OS_TV \ + || TARGET_OS_WATCH \ + || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0)) + #ifndef GTM_USE_SESSION_FETCHER + #define GTM_USE_SESSION_FETCHER 1 + #endif +#endif + +#if !defined(GTMBridgeFetcher) + // These bridge macros should be identical in GTMHTTPFetcher.h and GTMSessionFetcher.h + #if GTM_USE_SESSION_FETCHER + // Macros to new fetcher class. + #define GTMBridgeFetcher GTMSessionFetcher + #define GTMBridgeFetcherService GTMSessionFetcherService + #define GTMBridgeFetcherServiceProtocol GTMSessionFetcherServiceProtocol + #define GTMBridgeAssertValidSelector GTMSessionFetcherAssertValidSelector + #define GTMBridgeCookieStorage GTMSessionCookieStorage + #define GTMBridgeCleanedUserAgentString GTMFetcherCleanedUserAgentString + #define GTMBridgeSystemVersionString GTMFetcherSystemVersionString + #define GTMBridgeApplicationIdentifier GTMFetcherApplicationIdentifier + #define kGTMBridgeFetcherStatusDomain kGTMSessionFetcherStatusDomain + #define kGTMBridgeFetcherStatusBadRequest GTMSessionFetcherStatusBadRequest + #else + // Macros to old fetcher class. + #define GTMBridgeFetcher GTMHTTPFetcher + #define GTMBridgeFetcherService GTMHTTPFetcherService + #define GTMBridgeFetcherServiceProtocol GTMHTTPFetcherServiceProtocol + #define GTMBridgeAssertValidSelector GTMAssertSelectorNilOrImplementedWithArgs + #define GTMBridgeCookieStorage GTMCookieStorage + #define GTMBridgeCleanedUserAgentString GTMCleanedUserAgentString + #define GTMBridgeSystemVersionString GTMSystemVersionString + #define GTMBridgeApplicationIdentifier GTMApplicationIdentifier + #define kGTMBridgeFetcherStatusDomain kGTMHTTPFetcherStatusDomain + #define kGTMBridgeFetcherStatusBadRequest kGTMHTTPFetcherStatusBadRequest + #endif // GTM_USE_SESSION_FETCHER +#endif + +GTM_ASSUME_NONNULL_BEGIN + +// Notifications +// +// Fetch started and stopped, and fetch retry delay started and stopped. +extern NSString *const kGTMSessionFetcherStartedNotification; +extern NSString *const kGTMSessionFetcherStoppedNotification; +extern NSString *const kGTMSessionFetcherRetryDelayStartedNotification; +extern NSString *const kGTMSessionFetcherRetryDelayStoppedNotification; + +// Completion handler notification. This is intended for use by code capturing +// and replaying fetch requests and results for testing. For fetches where +// destinationFileURL or accumulateDataBlock is set for the fetcher, the data +// will be nil for successful fetches. +// +// This notification is posted on the main thread. +extern NSString *const kGTMSessionFetcherCompletionInvokedNotification; +extern NSString *const kGTMSessionFetcherCompletionDataKey; +extern NSString *const kGTMSessionFetcherCompletionErrorKey; + +// Constants for NSErrors created by the fetcher (excluding server status errors, +// and error objects originating in the OS.) +extern NSString *const kGTMSessionFetcherErrorDomain; + +// The fetcher turns server error status values (3XX, 4XX, 5XX) into NSErrors +// with domain kGTMSessionFetcherStatusDomain. +// +// Any server response body data accompanying the status error is added to the +// userInfo dictionary with key kGTMSessionFetcherStatusDataKey. +extern NSString *const kGTMSessionFetcherStatusDomain; +extern NSString *const kGTMSessionFetcherStatusDataKey; + +// When a fetch fails with an error, these keys are included in the error userInfo +// dictionary if retries were attempted. +extern NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey; +extern NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey; + +// Background session support requires access to NSUserDefaults. +// If [NSUserDefaults standardUserDefaults] doesn't yield the correct NSUserDefaults for your usage, +// ie for an App Extension, then implement this class/method to return the correct NSUserDefaults. +// https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW6 +@interface GTMSessionFetcherUserDefaultsFactory : NSObject + ++ (NSUserDefaults *)fetcherUserDefaults; + +@end + +#ifdef __cplusplus +} +#endif + +typedef NS_ENUM(NSInteger, GTMSessionFetcherError) { + GTMSessionFetcherErrorDownloadFailed = -1, + GTMSessionFetcherErrorUploadChunkUnavailable = -2, + GTMSessionFetcherErrorBackgroundExpiration = -3, + GTMSessionFetcherErrorBackgroundFetchFailed = -4, + GTMSessionFetcherErrorInsecureRequest = -5, + GTMSessionFetcherErrorTaskCreationFailed = -6, +}; + +typedef NS_ENUM(NSInteger, GTMSessionFetcherStatus) { + // Standard http status codes. + GTMSessionFetcherStatusNotModified = 304, + GTMSessionFetcherStatusBadRequest = 400, + GTMSessionFetcherStatusUnauthorized = 401, + GTMSessionFetcherStatusForbidden = 403, + GTMSessionFetcherStatusPreconditionFailed = 412 +}; + +#ifdef __cplusplus +extern "C" { +#endif + +@class GTMSessionCookieStorage; +@class GTMSessionFetcher; + +// The configuration block is for modifying the NSURLSessionConfiguration only. +// DO NOT change any fetcher properties in the configuration block. +typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher, + NSURLSessionConfiguration *configuration); +typedef void (^GTMSessionFetcherSystemCompletionHandler)(void); +typedef void (^GTMSessionFetcherCompletionHandler)(NSData * GTM_NULLABLE_TYPE data, + NSError * GTM_NULLABLE_TYPE error); +typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream); +typedef void (^GTMSessionFetcherBodyStreamProvider)(GTMSessionFetcherBodyStreamProviderResponse response); +typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)(NSURLSessionResponseDisposition disposition); +typedef void (^GTMSessionFetcherDidReceiveResponseBlock)(NSURLResponse *response, + GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock); +typedef void (^GTMSessionFetcherChallengeDispositionBlock)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential); +typedef void (^GTMSessionFetcherChallengeBlock)(GTMSessionFetcher *fetcher, + NSURLAuthenticationChallenge *challenge, + GTMSessionFetcherChallengeDispositionBlock dispositionBlock); +typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest * GTM_NULLABLE_TYPE redirectedRequest); +typedef void (^GTMSessionFetcherWillRedirectBlock)(NSHTTPURLResponse *redirectResponse, + NSURLRequest *redirectRequest, + GTMSessionFetcherWillRedirectResponse response); +typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData * GTM_NULLABLE_TYPE buffer); +typedef void (^GTMSessionFetcherSimulateByteTransferBlock)(NSData * GTM_NULLABLE_TYPE buffer, + int64_t bytesWritten, + int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite); +typedef void (^GTMSessionFetcherReceivedProgressBlock)(int64_t bytesWritten, + int64_t totalBytesWritten); +typedef void (^GTMSessionFetcherDownloadProgressBlock)(int64_t bytesWritten, + int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite); +typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent, + int64_t totalBytesSent, + int64_t totalBytesExpectedToSend); +typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)(NSCachedURLResponse * GTM_NULLABLE_TYPE cachedResponse); +typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)(NSCachedURLResponse *proposedResponse, + GTMSessionFetcherWillCacheURLResponseResponse responseBlock); +typedef void (^GTMSessionFetcherRetryResponse)(BOOL shouldRetry); +typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry, + NSError * GTM_NULLABLE_TYPE error, + GTMSessionFetcherRetryResponse response); + +typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse * GTM_NULLABLE_TYPE response, + NSData * GTM_NULLABLE_TYPE data, + NSError * GTM_NULLABLE_TYPE error); +typedef void (^GTMSessionFetcherTestBlock)(GTMSessionFetcher *fetcherToTest, + GTMSessionFetcherTestResponse testResponse); + +void GTMSessionFetcherAssertValidSelector(id GTM_NULLABLE_TYPE obj, SEL GTM_NULLABLE_TYPE sel, ...); + +// Utility functions for applications self-identifying to servers via a +// user-agent header + +// The "standard" user agent includes the application identifier, taken from the bundle, +// followed by a space and the system version string. Pass nil to use +mainBundle as the source +// of the bundle identifier. +// +// Applications may use this as a starting point for their own user agent strings, perhaps +// with additional sections appended. Use GTMFetcherCleanedUserAgentString() below to +// clean up any string being added to the user agent. +NSString *GTMFetcherStandardUserAgentString(NSBundle * GTM_NULLABLE_TYPE bundle); + +// Make a generic name and version for the current application, like +// com.example.MyApp/1.2.3 relying on the bundle identifier and the +// CFBundleShortVersionString or CFBundleVersion. +// +// The bundle ID may be overridden as the base identifier string by +// adding to the bundle's Info.plist a "GTMUserAgentID" key. +// +// If no bundle ID or override is available, the process name preceded +// by "proc_" is used. +NSString *GTMFetcherApplicationIdentifier(NSBundle * GTM_NULLABLE_TYPE bundle); + +// Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1 hw/iPod1_1" +NSString *GTMFetcherSystemVersionString(void); + +// Make a parseable user-agent identifier from the given string, replacing whitespace +// and commas with underscores, and removing other characters that may interfere +// with parsing of the full user-agent string. +// +// For example, @"[My App]" would become @"My_App" +NSString *GTMFetcherCleanedUserAgentString(NSString *str); + +// Grab the data from an input stream. Since streams cannot be assumed to be rewindable, +// this may be destructive; the caller can try to rewind the stream (by setting the +// NSStreamFileCurrentOffsetKey property) or can just use the NSData to make a new +// NSInputStream. This function is intended to facilitate testing rather than be used in +// production. +// +// This function operates synchronously on the current thread. Depending on how the +// input stream is implemented, it may be appropriate to dispatch to a different +// queue before calling this function. +// +// Failure is indicated by a returned data value of nil. +NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError); + +#ifdef __cplusplus +} // extern "C" +#endif + + +#if !GTM_USE_SESSION_FETCHER +@protocol GTMHTTPFetcherServiceProtocol; +#endif + +// This protocol allows abstract references to the fetcher service, primarily for +// fetchers (which may be compiled without the fetcher service class present.) +// +// Apps should not need to use this protocol. +@protocol GTMSessionFetcherServiceProtocol +// This protocol allows us to call into the service without requiring +// GTMSessionFetcherService sources in this project + +@property(atomic, strong) dispatch_queue_t callbackQueue; + +- (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher; + +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request; +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher; + +@property(atomic, assign) BOOL reuseSession; +- (GTM_NULLABLE NSURLSession *)session; +- (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation; +- (GTM_NULLABLE id)sessionDelegate; +- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate; + +// Methods for compatibility with the old GTMHTTPFetcher. +@property(readonly, strong, GTM_NULLABLE) NSOperationQueue *delegateQueue; + +@end // @protocol GTMSessionFetcherServiceProtocol + +#ifndef GTM_FETCHER_AUTHORIZATION_PROTOCOL +#define GTM_FETCHER_AUTHORIZATION_PROTOCOL 1 +@protocol GTMFetcherAuthorizationProtocol +@required +// This protocol allows us to call the authorizer without requiring its sources +// in this project. +- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request + delegate:(id)delegate + didFinishSelector:(SEL)sel; + +- (void)stopAuthorization; + +- (void)stopAuthorizationForRequest:(NSURLRequest *)request; + +- (BOOL)isAuthorizingRequest:(NSURLRequest *)request; + +- (BOOL)isAuthorizedRequest:(NSURLRequest *)request; + +@property(strong, readonly, GTM_NULLABLE) NSString *userEmail; + +@optional + +// Indicate if authorization may be attempted. Even if this succeeds, +// authorization may fail if the user's permissions have been revoked. +@property(readonly) BOOL canAuthorize; + +// For development only, allow authorization of non-SSL requests, allowing +// transmission of the bearer token unencrypted. +@property(assign) BOOL shouldAuthorizeAllRequests; + +- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request + completionHandler:(void (^)(NSError * GTM_NULLABLE_TYPE error))handler; + +#if GTM_USE_SESSION_FETCHER +@property (weak, GTM_NULLABLE) id fetcherService; +#else +@property (weak, GTM_NULLABLE) id fetcherService; +#endif + +- (BOOL)primeForRefresh; + +@end +#endif // GTM_FETCHER_AUTHORIZATION_PROTOCOL + +#if TARGET_OS_IPHONE +// A protocol for an alternative target for messages from GTMSessionFetcher to UIApplication. +// Set the target using +[GTMSessionFetcher setSubstituteUIApplication:] +@protocol GTMUIApplicationProtocol +- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName + expirationHandler:(void(^ __nullable)(void))handler; +- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier; +@end +#endif + +#pragma mark - + +// GTMSessionFetcher objects are used for async retrieval of an http get or post +// +// See additional comments at the beginning of this file +@interface GTMSessionFetcher : NSObject + +// Create a fetcher +// +// fetcherWithRequest will return an autoreleased fetcher, but if +// the connection is successfully created, the connection should retain the +// fetcher for the life of the connection as well. So the caller doesn't have +// to retain the fetcher explicitly unless they want to be able to cancel it. ++ (instancetype)fetcherWithRequest:(GTM_NULLABLE NSURLRequest *)request; + +// Convenience methods that make a request, like +fetcherWithRequest ++ (instancetype)fetcherWithURL:(NSURL *)requestURL; ++ (instancetype)fetcherWithURLString:(NSString *)requestURLString; + +// Methods for creating fetchers to continue previous fetches. ++ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData; ++ (GTM_NULLABLE instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier; + +// Returns an array of currently active fetchers for background sessions, +// both restarted and newly created ones. ++ (GTM_NSArrayOf(GTMSessionFetcher *) *)fetchersForBackgroundSessions; + +// Designated initializer. +// +// Applications should create fetchers with a "fetcherWith..." method on a fetcher +// service or a class method, not with this initializer. +// +// The configuration should typically be nil. Applications needing to customize +// the configuration may do so by setting the configurationBlock property. +- (instancetype)initWithRequest:(GTM_NULLABLE NSURLRequest *)request + configuration:(GTM_NULLABLE NSURLSessionConfiguration *)configuration; + +// The fetcher's request. This may not be set after beginFetch has been invoked. The request +// may change due to redirects. +@property(strong, GTM_NULLABLE) NSURLRequest *request; + +// Set a header field value on the request. Header field value changes will not +// affect a fetch after the fetch has begun. +- (void)setRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field; + +// The fetcher's request (deprecated.) +// +// Exposing a mutable object in the interface was convenient but a bad design decision due +// to thread-safety requirements. Clients should use the request property and +// setRequestValue:forHTTPHeaderField: instead. +@property(atomic, readonly, GTM_NULLABLE) NSMutableURLRequest *mutableRequest + GTMSESSION_DEPRECATE_ON_2016_SDKS("use 'request' or '-setRequestValue:forHTTPHeaderField:'"); + +// Data used for resuming a download task. +@property(atomic, readonly, GTM_NULLABLE) NSData *downloadResumeData; + +// The configuration; this must be set before the fetch begins. If no configuration is +// set or inherited from the fetcher service, then the fetcher uses an ephemeral config. +// +// NOTE: This property should typically be nil. Applications needing to customize +// the configuration should do so by setting the configurationBlock property. +// That allows the fetcher to pick an appropriate base configuration, with the +// application setting only the configuration properties it needs to customize. +@property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration; + +// A block the client may use to customize the configuration used to create the session. +// +// This is called synchronously, either on the thread that begins the fetch or, during a retry, +// on the main thread. The configuration block may be called repeatedly if multiple fetchers are +// created. +// +// The configuration block is for modifying the NSURLSessionConfiguration only. +// DO NOT change any fetcher properties in the configuration block. Fetcher properties +// may be set in the fetcher service prior to fetcher creation, or on the fetcher prior +// to invoking beginFetch. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock; + +// A session is created as needed by the fetcher. A fetcher service object +// may maintain sessions for multiple fetches to the same host. +@property(atomic, strong, GTM_NULLABLE) NSURLSession *session; + +// The task in flight. +@property(atomic, readonly, GTM_NULLABLE) NSURLSessionTask *sessionTask; + +// The background session identifier. +@property(atomic, readonly, GTM_NULLABLE) NSString *sessionIdentifier; + +// Indicates a fetcher created to finish a background session task. +@property(atomic, readonly) BOOL wasCreatedFromBackgroundSession; + +// Additional user-supplied data to encode into the session identifier. Since session identifier +// length limits are unspecified, this should be kept small. Key names beginning with an underscore +// are reserved for use by the fetcher. +@property(atomic, strong, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *sessionUserInfo; + +// The human-readable description to be assigned to the task. +@property(atomic, copy, GTM_NULLABLE) NSString *taskDescription; + +// The priority assigned to the task, if any. Use NSURLSessionTaskPriorityLow, +// NSURLSessionTaskPriorityDefault, or NSURLSessionTaskPriorityHigh. +@property(atomic, assign) float taskPriority; + +// The fetcher encodes information used to resume a session in the session identifier. +// This method, intended for internal use returns the encoded information. The sessionUserInfo +// dictionary is stored as identifier metadata. +- (GTM_NULLABLE GTM_NSDictionaryOf(NSString *, NSString *) *)sessionIdentifierMetadata; + +#if TARGET_OS_IPHONE +// The app should pass to this method the completion handler passed in the app delegate method +// application:handleEventsForBackgroundURLSession:completionHandler: ++ (void)application:(UIApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler; +#endif + +// Indicate that a newly created session should be a background session. +// A new session identifier will be created by the fetcher. +// +// Warning: The only thing background sessions are for is rare download +// of huge, batched files of data. And even just for those, there's a lot +// of pain and hackery needed to get transfers to actually happen reliably +// with background sessions. +// +// Don't try to upload or download in many background sessions, since the system +// will impose an exponentially increasing time penalty to prevent the app from +// getting too much background execution time. +// +// References: +// +// "Moving to Fewer, Larger Transfers" +// https://forums.developer.apple.com/thread/14853 +// +// "NSURLSession’s Resume Rate Limiter" +// https://forums.developer.apple.com/thread/14854 +// +// "Background Session Task state persistence" +// https://forums.developer.apple.com/thread/11554 +// +@property(assign) BOOL useBackgroundSession; + +// Indicates if the fetcher was started using a background session. +@property(atomic, readonly, getter=isUsingBackgroundSession) BOOL usingBackgroundSession; + +// Indicates if uploads should use an upload task. This is always set for file or stream-provider +// bodies, but may be set explicitly for NSData bodies. +@property(atomic, assign) BOOL useUploadTask; + +// Indicates that the fetcher is using a session that may be shared with other fetchers. +@property(atomic, readonly) BOOL canShareSession; + +// By default, the fetcher allows only secure (https) schemes unless this +// property is set, or the GTM_ALLOW_INSECURE_REQUESTS build flag is set. +// +// For example, during debugging when fetching from a development server that lacks SSL support, +// this may be set to @[ @"http" ], or when the fetcher is used to retrieve local files, +// this may be set to @[ @"file" ]. +// +// This should be left as nil for release builds to avoid creating the opportunity for +// leaking private user behavior and data. If a server is providing insecure URLs +// for fetching by the client app, report the problem as server security & privacy bug. +// +// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when +// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist. +@property(atomic, copy, GTM_NULLABLE) GTM_NSArrayOf(NSString *) *allowedInsecureSchemes; + +// By default, the fetcher prohibits localhost requests unless this property is set, +// or the GTM_ALLOW_INSECURE_REQUESTS build flag is set. +// +// For localhost requests, the URL scheme is not checked when this property is set. +// +// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when +// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist. +@property(atomic, assign) BOOL allowLocalhostRequest; + +// By default, the fetcher requires valid server certs. This may be bypassed +// temporarily for development against a test server with an invalid cert. +@property(atomic, assign) BOOL allowInvalidServerCertificates; + +// Cookie storage object for this fetcher. If nil, the fetcher will use a static cookie +// storage instance shared among fetchers. If this fetcher was created by a fetcher service +// object, it will be set to use the service object's cookie storage. See Cookies section above for +// the full discussion. +// +// Because as of Jan 2014 standalone instances of NSHTTPCookieStorage do not actually +// store any cookies (Radar 15735276) we use our own subclass, GTMSessionCookieStorage, +// to hold cookies in memory. +@property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage; + +// Setting the credential is optional; it is used if the connection receives +// an authentication challenge. +@property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential; + +// Setting the proxy credential is optional; it is used if the connection +// receives an authentication challenge from a proxy. +@property(atomic, strong, GTM_NULLABLE) NSURLCredential *proxyCredential; + +// If body data, body file URL, or body stream provider is not set, then a GET request +// method is assumed. +@property(atomic, strong, GTM_NULLABLE) NSData *bodyData; + +// File to use as the request body. This forces use of an upload task. +@property(atomic, strong, GTM_NULLABLE) NSURL *bodyFileURL; + +// Length of body to send, expected or actual. +@property(atomic, readonly) int64_t bodyLength; + +// The body stream provider may be called repeatedly to provide a body. +// Setting a body stream provider forces use of an upload task. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherBodyStreamProvider bodyStreamProvider; + +// Object to add authorization to the request, if needed. +// +// This may not be changed once beginFetch has been invoked. +@property(atomic, strong, GTM_NULLABLE) id authorizer; + +// The service object that created and monitors this fetcher, if any. +@property(atomic, strong) id service; + +// The host, if any, used to classify this fetcher in the fetcher service. +@property(atomic, copy, GTM_NULLABLE) NSString *serviceHost; + +// The priority, if any, used for starting fetchers in the fetcher service. +// +// Lower values are higher priority; the default is 0, and values may +// be negative or positive. This priority affects only the start order of +// fetchers that are being delayed by a fetcher service when the running fetchers +// exceeds the service's maxRunningFetchersPerHost. A priority of NSIntegerMin will +// exempt this fetcher from delay. +@property(atomic, assign) NSInteger servicePriority; + +// The delegate's optional didReceiveResponse block may be used to inspect or alter +// the session task response. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock; + +// The delegate's optional challenge block may be used to inspect or alter +// the session task challenge. +// +// If this block is not set, the fetcher's default behavior for the NSURLSessionTask +// didReceiveChallenge: delegate method is to use the fetcher's respondToChallenge: method +// which relies on the fetcher's credential and proxyCredential properties. +// +// Warning: This may be called repeatedly if the challenge fails. Check +// challenge.previousFailureCount to identify repeated invocations. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock; + +// The delegate's optional willRedirect block may be used to inspect or alter +// the redirection. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillRedirectBlock willRedirectBlock; + +// The optional send progress block reports body bytes uploaded. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherSendProgressBlock sendProgressBlock; + +// The optional accumulate block may be set by clients wishing to accumulate data +// themselves rather than let the fetcher append each buffer to an NSData. +// +// When this is called with nil data (such as on redirect) the client +// should empty its accumulation buffer. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherAccumulateDataBlock accumulateDataBlock; + +// The optional received progress block may be used to monitor data +// received from a data task. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherReceivedProgressBlock receivedProgressBlock; + +// The delegate's optional downloadProgress block may be used to monitor download +// progress in writing to disk. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDownloadProgressBlock downloadProgressBlock; + +// The delegate's optional willCacheURLResponse block may be used to alter the cached +// NSURLResponse. The user may prevent caching by passing nil to the block's response. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock; + +// Enable retrying; see comments at the top of this file. Setting +// retryEnabled=YES resets the min and max retry intervals. +@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled; + +// Retry block is optional for retries. +// +// If present, this block should call the response block with YES to cause a retry or NO to end the +// fetch. +// See comments at the top of this file. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherRetryBlock retryBlock; + +// Retry intervals must be strictly less than maxRetryInterval, else +// they will be limited to maxRetryInterval and no further retries will +// be attempted. Setting maxRetryInterval to 0.0 will reset it to the +// default value, 60 seconds for downloads and 600 seconds for uploads. +@property(atomic, assign) NSTimeInterval maxRetryInterval; + +// Starting retry interval. Setting minRetryInterval to 0.0 will reset it +// to a random value between 1.0 and 2.0 seconds. Clients should normally not +// set this except for unit testing. +@property(atomic, assign) NSTimeInterval minRetryInterval; + +// Multiplier used to increase the interval between retries, typically 2.0. +// Clients should not need to set this. +@property(atomic, assign) double retryFactor; + +// Number of retries attempted. +@property(atomic, readonly) NSUInteger retryCount; + +// Interval delay to precede next retry. +@property(atomic, readonly) NSTimeInterval nextRetryInterval; + +#if GTM_BACKGROUND_TASK_FETCHING +// Skip use of a UIBackgroundTask, thus requiring fetches to complete when the app is in the +// foreground. +// +// Targets should define GTM_BACKGROUND_TASK_FETCHING to 0 to avoid use of a UIBackgroundTask +// on iOS to allow fetches to complete in the background. This property is available when +// it's not practical to set the preprocessor define. +@property(atomic, assign) BOOL skipBackgroundTask; +#endif // GTM_BACKGROUND_TASK_FETCHING + +// Begin fetching the request +// +// The delegate may optionally implement the callback or pass nil for the selector or handler. +// +// The delegate and all callback blocks are retained between the beginFetch call until after the +// finish callback, or until the fetch is stopped. +// +// An error is passed to the callback for server statuses 300 or +// higher, with the status stored as the error object's code. +// +// finishedSEL has a signature like: +// - (void)fetcher:(GTMSessionFetcher *)fetcher +// finishedWithData:(NSData *)data +// error:(NSError *)error; +// +// If the application has specified a destinationFileURL or an accumulateDataBlock +// for the fetcher, the data parameter passed to the callback will be nil. + +- (void)beginFetchWithDelegate:(GTM_NULLABLE id)delegate + didFinishSelector:(GTM_NULLABLE SEL)finishedSEL; + +- (void)beginFetchWithCompletionHandler:(GTM_NULLABLE GTMSessionFetcherCompletionHandler)handler; + +// Returns YES if this fetcher is in the process of fetching a URL. +@property(atomic, readonly, getter=isFetching) BOOL fetching; + +// Cancel the fetch of the request that's currently in progress. The completion handler +// will not be called. +- (void)stopFetching; + +// A block to be called when the fetch completes. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherCompletionHandler completionHandler; + +// A block to be called if download resume data becomes available. +@property(atomic, strong, GTM_NULLABLE) void (^resumeDataBlock)(NSData *); + +// Return the status code from the server response. +@property(atomic, readonly) NSInteger statusCode; + +// Return the http headers from the response. +@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *responseHeaders; + +// The response, once it's been received. +@property(atomic, strong, readonly, GTM_NULLABLE) NSURLResponse *response; + +// Bytes downloaded so far. +@property(atomic, readonly) int64_t downloadedLength; + +// Buffer of currently-downloaded data, if available. +@property(atomic, readonly, strong, GTM_NULLABLE) NSData *downloadedData; + +// Local path to which the downloaded file will be moved. +// +// If a file already exists at the path, it will be overwritten. +// Will create the enclosing folders if they are not present. +@property(atomic, strong, GTM_NULLABLE) NSURL *destinationFileURL; + +// The time this fetcher originally began fetching. This is useful as a time +// barrier for ignoring irrelevant fetch notifications or callbacks. +@property(atomic, strong, readonly, GTM_NULLABLE) NSDate *initialBeginFetchDate; + +// userData is retained solely for the convenience of the client. +@property(atomic, strong, GTM_NULLABLE) id userData; + +// Stored property values are retained solely for the convenience of the client. +@property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties; + +- (void)setProperty:(GTM_NULLABLE id)obj forKey:(NSString *)key; // Pass nil for obj to remove the property. +- (GTM_NULLABLE id)propertyForKey:(NSString *)key; + +- (void)addPropertiesFromDictionary:(GTM_NSDictionaryOf(NSString *, id) *)dict; + +// Comments are useful for logging, so are strongly recommended for each fetcher. +@property(atomic, copy, GTM_NULLABLE) NSString *comment; + +- (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2); + +// Log of request and response, if logging is enabled +@property(atomic, copy, GTM_NULLABLE) NSString *log; + +// Callbacks are run on this queue. If none is supplied, the main queue is used. +@property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue; + +// The queue used internally by the session to invoke its delegate methods in the fetcher. +// +// Application callbacks are always called by the fetcher on the callbackQueue above, +// not on this queue. Apps should generally not change this queue. +// +// The default delegate queue is the main queue. +// +// This value is ignored after the session has been created, so this +// property should be set in the fetcher service rather in the fetcher as it applies +// to a shared session. +@property(atomic, strong, GTM_NULL_RESETTABLE) NSOperationQueue *sessionDelegateQueue; + +// Spin the run loop or sleep the thread, discarding events, until the fetch has completed. +// +// This is only for use in testing or in tools without a user interface. +// +// Note: Synchronous fetches should never be used by shipping apps; they are +// sufficient reason for rejection from the app store. +// +// Returns NO if timed out. +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds; + +// Test block is optional for testing. +// +// If present, this block will cause the fetcher to skip starting the session, and instead +// use the test block response values when calling the completion handler and delegate code. +// +// Test code can set this on the fetcher or on the fetcher service. For testing libraries +// that use a fetcher without exposing either the fetcher or the fetcher service, the global +// method setGlobalTestBlock: will set the block for all fetchers that do not have a test +// block set. +// +// The test code can pass nil for all response parameters to indicate that the fetch +// should proceed. +// +// Applications can exclude test block support by setting GTM_DISABLE_FETCHER_TEST_BLOCK. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock; + ++ (void)setGlobalTestBlock:(GTM_NULLABLE GTMSessionFetcherTestBlock)block; + +// When using the testBlock, |testBlockAccumulateDataChunkCount| is the desired number of chunks to +// divide the response data into if the client has streaming enabled. The data will be divided up to +// |testBlockAccumulateDataChunkCount| chunks; however, the exact amount may vary depending on the +// size of the response data (e.g. a 1-byte response can only be divided into one chunk). +@property(atomic, readwrite) NSUInteger testBlockAccumulateDataChunkCount; + +#if TARGET_OS_IPHONE +// For testing or to override UIApplication invocations, apps may specify an alternative +// target for messages to UIApplication. ++ (void)setSubstituteUIApplication:(nullable id)substituteUIApplication; ++ (nullable id)substituteUIApplication; +#endif // TARGET_OS_IPHONE + +// Exposed for testing. ++ (GTMSessionCookieStorage *)staticCookieStorage; ++ (BOOL)appAllowsInsecureRequests; + +#if STRIP_GTM_FETCH_LOGGING +// If logging is stripped, provide a stub for the main method +// for controlling logging. ++ (void)setLoggingEnabled:(BOOL)flag; ++ (BOOL)isLoggingEnabled; + +#else + +// These methods let an application log specific body text, such as the text description of a binary +// request or response. The application should set the fetcher to defer response body logging until +// the response has been received and the log response body has been set by the app. For example: +// +// fetcher.logRequestBody = [binaryObject stringDescription]; +// fetcher.deferResponseBodyLogging = YES; +// [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { +// if (error == nil) { +// fetcher.logResponseBody = [[[MyThing alloc] initWithData:data] stringDescription]; +// } +// fetcher.deferResponseBodyLogging = NO; +// }]; + +@property(atomic, copy, GTM_NULLABLE) NSString *logRequestBody; +@property(atomic, assign) BOOL deferResponseBodyLogging; +@property(atomic, copy, GTM_NULLABLE) NSString *logResponseBody; + +// Internal logging support. +@property(atomic, readonly) NSData *loggedStreamData; +@property(atomic, assign) BOOL hasLoggedError; +@property(atomic, strong, GTM_NULLABLE) NSURL *redirectedFromURL; +- (void)appendLoggedStreamData:(NSData *)dataToAdd; +- (void)clearLoggedStreamData; + +#endif // STRIP_GTM_FETCH_LOGGING + +@end + +@interface GTMSessionFetcher (BackwardsCompatibilityOnly) +// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves. +// This method is just for compatibility with the old GTMHTTPFetcher class. +- (void)setCookieStorageMethod:(NSInteger)method; +@end + +// Until we can just instantiate NSHTTPCookieStorage for local use, we'll +// implement all the public methods ourselves. This stores cookies only in +// memory. Additional methods are provided for testing. +// +// iOS 9/OS X 10.11 added +[NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:] +// which may also be used to create cookie storage. +@interface GTMSessionCookieStorage : NSHTTPCookieStorage + +// Add the array off cookies to the storage, replacing duplicates. +// Also removes expired cookies from the storage. +- (void)setCookies:(GTM_NULLABLE GTM_NSArrayOf(NSHTTPCookie *) *)cookies; + +- (void)removeAllCookies; + +@end + +// Macros to monitor synchronization blocks in debug builds. +// These report problems using GTMSessionCheckDebug. +// +// GTMSessionMonitorSynchronized Start monitoring a top-level-only +// @sync scope. +// GTMSessionMonitorRecursiveSynchronized Start monitoring a top-level or +// recursive @sync scope. +// GTMSessionCheckSynchronized Verify that the current execution +// is inside a @sync scope. +// GTMSessionCheckNotSynchronized Verify that the current execution +// is not inside a @sync scope. +// +// Example usage: +// +// - (void)myExternalMethod { +// @synchronized(self) { +// GTMSessionMonitorSynchronized(self) +// +// - (void)myInternalMethod { +// GTMSessionCheckSynchronized(self); +// +// - (void)callMyCallbacks { +// GTMSessionCheckNotSynchronized(self); +// +// GTMSessionCheckNotSynchronized is available for verifying the code isn't +// in a deadlockable @sync state when posting notifications and invoking +// callbacks. Don't use GTMSessionCheckNotSynchronized immediately before a +// @sync scope; the normal recursiveness check of GTMSessionMonitorSynchronized +// can catch those. + +#ifdef __OBJC__ +#if DEBUG + #define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) \ + varname ## counter + #define __GTMSessionMonitorSynchronizedVariable(varname, counter) \ + __GTMSessionMonitorSynchronizedVariableInner(varname, counter) + + #define GTMSessionMonitorSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id \ + __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:NO \ + functionName:__func__] + + #define GTMSessionMonitorRecursiveSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id \ + __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:YES \ + functionName:__func__] + + #define GTMSessionCheckSynchronized(obj) { \ + GTMSESSION_ASSERT_DEBUG( \ + [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \ + @" on " #obj " in %s. Call stack:\n%@", \ + __func__, [NSThread callStackSymbols]); \ + } + + #define GTMSessionCheckNotSynchronized(obj) { \ + GTMSESSION_ASSERT_DEBUG( \ + ![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \ + @" on " #obj " in %s by %@. Call stack:\n%@", __func__, \ + [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + [NSThread callStackSymbols]); \ + } + +// GTMSessionSyncMonitorInternal is a private class that keeps track of the +// beginning and end of synchronized scopes. +// +// This class should not be used directly, but only via the +// GTMSessionMonitorSynchronized macro. +@interface GTMSessionSyncMonitorInternal : NSObject +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName; +// Return the names of the functions that hold sync on the object, or nil if none. ++ (NSArray *)functionsHoldingSynchronizationOnObject:(id)object; +@end + +#else + #define GTMSessionMonitorSynchronized(obj) do { } while (0) + #define GTMSessionMonitorRecursiveSynchronized(obj) do { } while (0) + #define GTMSessionCheckSynchronized(obj) do { } while (0) + #define GTMSessionCheckNotSynchronized(obj) do { } while (0) +#endif // !DEBUG +#endif // __OBJC__ + + +GTM_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m new file mode 100644 index 0000000..e3f52d8 --- /dev/null +++ b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m @@ -0,0 +1,4549 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcher.h" + +#import + +#ifndef STRIP_GTM_FETCH_LOGGING + #error GTMSessionFetcher headers should have defaulted this if it wasn't already defined. +#endif + +GTM_ASSUME_NONNULL_BEGIN + +NSString *const kGTMSessionFetcherStartedNotification = @"kGTMSessionFetcherStartedNotification"; +NSString *const kGTMSessionFetcherStoppedNotification = @"kGTMSessionFetcherStoppedNotification"; +NSString *const kGTMSessionFetcherRetryDelayStartedNotification = @"kGTMSessionFetcherRetryDelayStartedNotification"; +NSString *const kGTMSessionFetcherRetryDelayStoppedNotification = @"kGTMSessionFetcherRetryDelayStoppedNotification"; + +NSString *const kGTMSessionFetcherCompletionInvokedNotification = @"kGTMSessionFetcherCompletionInvokedNotification"; +NSString *const kGTMSessionFetcherCompletionDataKey = @"data"; +NSString *const kGTMSessionFetcherCompletionErrorKey = @"error"; + +NSString *const kGTMSessionFetcherErrorDomain = @"com.google.GTMSessionFetcher"; +NSString *const kGTMSessionFetcherStatusDomain = @"com.google.HTTPStatus"; +NSString *const kGTMSessionFetcherStatusDataKey = @"data"; // data returned with a kGTMSessionFetcherStatusDomain error + +NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey = @"kGTMSessionFetcherNumberOfRetriesDoneKey"; +NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey = @"kGTMSessionFetcherElapsedIntervalWithRetriesKey"; + +static NSString *const kGTMSessionIdentifierPrefix = @"com.google.GTMSessionFetcher"; +static NSString *const kGTMSessionIdentifierDestinationFileURLMetadataKey = @"_destURL"; +static NSString *const kGTMSessionIdentifierBodyFileURLMetadataKey = @"_bodyURL"; + +// The default max retry interview is 10 minutes for uploads (POST/PUT/PATCH), +// 1 minute for downloads. +static const NSTimeInterval kUnsetMaxRetryInterval = -1.0; +static const NSTimeInterval kDefaultMaxDownloadRetryInterval = 60.0; +static const NSTimeInterval kDefaultMaxUploadRetryInterval = 60.0 * 10.; + +#ifdef GTMSESSION_PERSISTED_DESTINATION_KEY +// Projects using unique class names should also define a unique persisted destination key. +static NSString * const kGTMSessionFetcherPersistedDestinationKey = + GTMSESSION_PERSISTED_DESTINATION_KEY; +#else +static NSString * const kGTMSessionFetcherPersistedDestinationKey = + @"com.google.GTMSessionFetcher.downloads"; +#endif + +GTM_ASSUME_NONNULL_END + +// +// GTMSessionFetcher +// + +#if 0 +#define GTM_LOG_BACKGROUND_SESSION(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__) +#else +#define GTM_LOG_BACKGROUND_SESSION(...) +#endif + +#ifndef GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY + #if (TARGET_OS_TV \ + || TARGET_OS_WATCH \ + || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0)) + #define GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY 1 + #endif +#endif + +@interface GTMSessionFetcher () + +@property(atomic, strong, readwrite, GTM_NULLABLE) NSData *downloadedData; +@property(atomic, strong, readwrite, GTM_NULLABLE) NSData *downloadResumeData; + +#if GTM_BACKGROUND_TASK_FETCHING +// Should always be accessed within an @synchranized(self). +@property(assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier; +#endif + +@property(atomic, readwrite, getter=isUsingBackgroundSession) BOOL usingBackgroundSession; + +@end + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (GTMSessionFetcherLoggingInternal) +- (void)logFetchWithError:(NSError *)error; +- (void)logNowWithError:(GTM_NULLABLE NSError *)error; +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream; +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider; +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +GTM_ASSUME_NONNULL_BEGIN + +static NSTimeInterval InitialMinRetryInterval(void) { + return 1.0 + ((double)(arc4random_uniform(0x0FFFF)) / (double) 0x0FFFF); +} + +static BOOL IsLocalhost(NSString * GTM_NULLABLE_TYPE host) { + // We check if there's host, and then make the comparisons. + if (host == nil) return NO; + return ([host caseInsensitiveCompare:@"localhost"] == NSOrderedSame + || [host isEqual:@"::1"] + || [host isEqual:@"127.0.0.1"]); +} + +static GTMSessionFetcherTestBlock GTM_NULLABLE_TYPE gGlobalTestBlock; + +@implementation GTMSessionFetcher { + NSMutableURLRequest *_request; // after beginFetch, changed only in delegate callbacks + BOOL _useUploadTask; // immutable after beginFetch + NSURL *_bodyFileURL; // immutable after beginFetch + GTMSessionFetcherBodyStreamProvider _bodyStreamProvider; // immutable after beginFetch + NSURLSession *_session; + BOOL _shouldInvalidateSession; // immutable after beginFetch + NSURLSession *_sessionNeedingInvalidation; + NSURLSessionConfiguration *_configuration; + NSURLSessionTask *_sessionTask; + NSString *_taskDescription; + float _taskPriority; + NSURLResponse *_response; + NSString *_sessionIdentifier; + BOOL _wasCreatedFromBackgroundSession; + BOOL _didCreateSessionIdentifier; + NSString *_sessionIdentifierUUID; + BOOL _userRequestedBackgroundSession; + BOOL _usingBackgroundSession; + NSMutableData * GTM_NULLABLE_TYPE _downloadedData; + NSError *_downloadFinishedError; + NSData *_downloadResumeData; // immutable after construction + NSURL *_destinationFileURL; + int64_t _downloadedLength; + NSURLCredential *_credential; // username & password + NSURLCredential *_proxyCredential; // credential supplied to proxy servers + BOOL _isStopNotificationNeeded; // set when start notification has been sent + BOOL _isUsingTestBlock; // set when a test block was provided (remains set when the block is released) + id _userData; // retained, if set by caller + NSMutableDictionary *_properties; // more data retained for caller + dispatch_queue_t _callbackQueue; + dispatch_group_t _callbackGroup; // read-only after creation + NSOperationQueue *_delegateQueue; // immutable after beginFetch + + id _authorizer; // immutable after beginFetch + + // The service object that created and monitors this fetcher, if any. + id _service; // immutable; set by the fetcher service upon creation + NSString *_serviceHost; + NSInteger _servicePriority; // immutable after beginFetch + BOOL _hasStoppedFetching; // counterpart to _initialBeginFetchDate + BOOL _userStoppedFetching; + + BOOL _isRetryEnabled; // user wants auto-retry + NSTimer *_retryTimer; + NSUInteger _retryCount; + NSTimeInterval _maxRetryInterval; // default 60 (download) or 600 (upload) seconds + NSTimeInterval _minRetryInterval; // random between 1 and 2 seconds + NSTimeInterval _retryFactor; // default interval multiplier is 2 + NSTimeInterval _lastRetryInterval; + NSDate *_initialBeginFetchDate; // date that beginFetch was first invoked; immutable after initial beginFetch + NSDate *_initialRequestDate; // date of first request to the target server (ignoring auth) + BOOL _hasAttemptedAuthRefresh; // accessed only in shouldRetryNowForStatus: + + NSString *_comment; // comment for log + NSString *_log; +#if !STRIP_GTM_FETCH_LOGGING + NSMutableData *_loggedStreamData; + NSURL *_redirectedFromURL; + NSString *_logRequestBody; + NSString *_logResponseBody; + BOOL _hasLoggedError; + BOOL _deferResponseBodyLogging; +#endif +} + +#if !GTMSESSION_UNIT_TESTING ++ (void)load { + [self fetchersForBackgroundSessions]; +} +#endif + ++ (instancetype)fetcherWithRequest:(GTM_NULLABLE NSURLRequest *)request { + return [[self alloc] initWithRequest:request configuration:nil]; +} + ++ (instancetype)fetcherWithURL:(NSURL *)requestURL { + return [self fetcherWithRequest:[NSURLRequest requestWithURL:requestURL]]; +} + ++ (instancetype)fetcherWithURLString:(NSString *)requestURLString { + return [self fetcherWithURL:(NSURL *)[NSURL URLWithString:requestURLString]]; +} + ++ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData { + GTMSessionFetcher *fetcher = [self fetcherWithRequest:nil]; + fetcher.comment = @"Resuming download"; + fetcher.downloadResumeData = resumeData; + return fetcher; +} + ++ (GTM_NULLABLE instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (!fetcher && [sessionIdentifier hasPrefix:kGTMSessionIdentifierPrefix]) { + fetcher = [self fetcherWithRequest:nil]; + [fetcher setSessionIdentifier:sessionIdentifier]; + [sessionIdentifierToFetcherMap setObject:fetcher forKey:sessionIdentifier]; + fetcher->_wasCreatedFromBackgroundSession = YES; + [fetcher setCommentWithFormat:@"Resuming %@", + fetcher && fetcher->_sessionIdentifierUUID ? fetcher->_sessionIdentifierUUID : @"?"]; + } + return fetcher; +} + ++ (NSMapTable *)sessionIdentifierToFetcherMap { + // TODO: What if a service is involved in creating the fetcher? Currently, when re-creating + // fetchers, if a service was involved, it is not re-created. Should the service maintain a map? + static NSMapTable *gSessionIdentifierToFetcherMap = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gSessionIdentifierToFetcherMap = [NSMapTable strongToWeakObjectsMapTable]; + }); + return gSessionIdentifierToFetcherMap; +} + +#if !GTM_ALLOW_INSECURE_REQUESTS ++ (BOOL)appAllowsInsecureRequests { + // If the main bundle Info.plist key NSAppTransportSecurity is present, and it specifies + // NSAllowsArbitraryLoads, then we need to explicitly enforce secure schemes. +#if GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY + static BOOL allowsInsecureRequests; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSBundle *mainBundle = [NSBundle mainBundle]; + NSDictionary *appTransportSecurity = + [mainBundle objectForInfoDictionaryKey:@"NSAppTransportSecurity"]; + allowsInsecureRequests = + [[appTransportSecurity objectForKey:@"NSAllowsArbitraryLoads"] boolValue]; + }); + return allowsInsecureRequests; +#else + // For builds targeting iOS 8 or 10.10 and earlier, we want to require fetcher + // security checks. + return YES; +#endif // GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY +} +#else // GTM_ALLOW_INSECURE_REQUESTS ++ (BOOL)appAllowsInsecureRequests { + return YES; +} +#endif // !GTM_ALLOW_INSECURE_REQUESTS + + +- (instancetype)init { + return [self initWithRequest:nil configuration:nil]; +} + +- (instancetype)initWithRequest:(NSURLRequest *)request { + return [self initWithRequest:request configuration:nil]; +} + +- (instancetype)initWithRequest:(GTM_NULLABLE NSURLRequest *)request + configuration:(GTM_NULLABLE NSURLSessionConfiguration *)configuration { + self = [super init]; + if (self) { + if (![NSURLSession class]) { + Class oldFetcherClass = NSClassFromString(@"GTMHTTPFetcher"); + if (oldFetcherClass && request) { + self = [[oldFetcherClass alloc] initWithRequest:(NSURLRequest *)request]; + } else { + self = nil; + } + return self; + } +#if GTM_BACKGROUND_TASK_FETCHING + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; +#endif + _request = [request mutableCopy]; + _configuration = configuration; + + NSData *bodyData = request.HTTPBody; + if (bodyData) { + _bodyLength = (int64_t)bodyData.length; + } else { + _bodyLength = NSURLSessionTransferSizeUnknown; + } + + _callbackQueue = dispatch_get_main_queue(); + _callbackGroup = dispatch_group_create(); + _delegateQueue = [NSOperationQueue mainQueue]; + + _minRetryInterval = InitialMinRetryInterval(); + _maxRetryInterval = kUnsetMaxRetryInterval; + + _taskPriority = -1.0f; // Valid values if set are 0.0...1.0. + + _testBlockAccumulateDataChunkCount = 1; + +#if !STRIP_GTM_FETCH_LOGGING + // Encourage developers to set the comment property or use + // setCommentWithFormat: by providing a default string. + _comment = @"(No fetcher comment set)"; +#endif + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + // disallow use of fetchers in a copy property + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (NSString *)description { + NSString *requestStr = self.request.URL.description; + if (requestStr.length == 0) { + if (self.downloadResumeData.length > 0) { + requestStr = @""; + } else if (_wasCreatedFromBackgroundSession) { + requestStr = @""; + } else { + requestStr = @""; + } + } + return [NSString stringWithFormat:@"%@ %p (%@)", [self class], self, requestStr]; +} + +- (void)dealloc { + GTMSESSION_ASSERT_DEBUG(!_isStopNotificationNeeded, + @"unbalanced fetcher notification for %@", _request.URL); + [self forgetSessionIdentifierForFetcherWithoutSyncCheck]; + + // Note: if a session task or a retry timer was pending, then this instance + // would be retained by those so it wouldn't be getting dealloc'd, + // hence we don't need to stopFetch here +} + +#pragma mark - + +// Begin fetching the URL (or begin a retry fetch). The delegate is retained +// for the duration of the fetch connection. + +- (void)beginFetchWithCompletionHandler:(GTM_NULLABLE GTMSessionFetcherCompletionHandler)handler { + GTMSessionCheckNotSynchronized(self); + + _completionHandler = [handler copy]; + + // The user may have called setDelegate: earlier if they want to use other + // delegate-style callbacks during the fetch; otherwise, the delegate is nil, + // which is fine. + [self beginFetchMayDelay:YES mayAuthorize:YES]; +} + +- (GTMSessionFetcherCompletionHandler)completionHandlerWithTarget:(GTM_NULLABLE_TYPE id)target + didFinishSelector:(GTM_NULLABLE_TYPE SEL)finishedSelector { + GTMSessionFetcherAssertValidSelector(target, finishedSelector, @encode(GTMSessionFetcher *), + @encode(NSData *), @encode(NSError *), 0); + GTMSessionFetcherCompletionHandler completionHandler = ^(NSData *data, NSError *error) { + if (target && finishedSelector) { + id selfArg = self; // Placate ARC. + NSMethodSignature *sig = [target methodSignatureForSelector:finishedSelector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setSelector:(SEL)finishedSelector]; + [invocation setTarget:target]; + [invocation setArgument:&selfArg atIndex:2]; + [invocation setArgument:&data atIndex:3]; + [invocation setArgument:&error atIndex:4]; + [invocation invoke]; + } + }; + return completionHandler; +} + +- (void)beginFetchWithDelegate:(GTM_NULLABLE_TYPE id)target + didFinishSelector:(GTM_NULLABLE_TYPE SEL)finishedSelector { + GTMSessionCheckNotSynchronized(self); + + GTMSessionFetcherCompletionHandler handler = [self completionHandlerWithTarget:target + didFinishSelector:finishedSelector]; + [self beginFetchWithCompletionHandler:handler]; +} + +- (void)beginFetchMayDelay:(BOOL)mayDelay + mayAuthorize:(BOOL)mayAuthorize { + // This is the internal entry point for re-starting fetches. + GTMSessionCheckNotSynchronized(self); + + NSMutableURLRequest *fetchRequest = _request; // The request property is now externally immutable. + NSURL *fetchRequestURL = fetchRequest.URL; + NSString *priorSessionIdentifier = self.sessionIdentifier; + + // A utility block for creating error objects when we fail to start the fetch. + NSError *(^beginFailureError)(NSInteger) = ^(NSInteger code){ + NSString *urlString = fetchRequestURL.absoluteString; + NSDictionary *userInfo = @{ + NSURLErrorFailingURLStringErrorKey : (urlString ? urlString : @"(missing URL)") + }; + return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:code + userInfo:userInfo]; + }; + + // Catch delegate queue maxConcurrentOperationCount values other than 1, particularly + // NSOperationQueueDefaultMaxConcurrentOperationCount (-1), to avoid the additional complexity + // of simultaneous or out-of-order delegate callbacks. + GTMSESSION_ASSERT_DEBUG(_delegateQueue.maxConcurrentOperationCount == 1, + @"delegate queue %@ should support one concurrent operation, not %zd", + _delegateQueue.name, _delegateQueue.maxConcurrentOperationCount); + + if (!_initialBeginFetchDate) { + // This ivar is set only here on the initial beginFetch so need not be synchronized. + _initialBeginFetchDate = [[NSDate alloc] init]; + } + + if (self.sessionTask != nil) { + // If cached fetcher returned through fetcherWithSessionIdentifier:, then it's + // already begun, but don't consider this a failure, since the user need not know this. + if (self.sessionIdentifier != nil) { + return; + } + GTMSESSION_ASSERT_DEBUG(NO, @"Fetch object %@ being reused; this should never happen", self); + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorDownloadFailed)]; + return; + } + + if (fetchRequestURL == nil && !_downloadResumeData && !priorSessionIdentifier) { + GTMSESSION_ASSERT_DEBUG(NO, @"Beginning a fetch requires a request with a URL"); + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorDownloadFailed)]; + return; + } + + // We'll respect the user's request for a background session (unless this is + // an upload fetcher, which does its initial request foreground.) + self.usingBackgroundSession = self.useBackgroundSession && [self canFetchWithBackgroundSession]; + + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSError *fileCheckError; + if (![bodyFileURL checkResourceIsReachableAndReturnError:&fileCheckError]) { + // This assert fires when the file being uploaded no longer exists once + // the fetcher is ready to start the upload. + GTMSESSION_ASSERT_DEBUG_OR_LOG(0, @"Body file is unreachable: %@\n %@", + bodyFileURL.path, fileCheckError); + [self failToBeginFetchWithError:fileCheckError]; + return; + } + } + + NSString *requestScheme = fetchRequestURL.scheme; + BOOL isDataRequest = [requestScheme isEqual:@"data"]; + if (isDataRequest) { + // NSURLSession does not support data URLs in background sessions. +#if DEBUG + if (priorSessionIdentifier || self.sessionIdentifier) { + GTMSESSION_LOG_DEBUG(@"Converting background to foreground session for %@", + fetchRequest); + } +#endif + [self setSessionIdentifierInternal:nil]; + self.useBackgroundSession = NO; + } + +#if GTM_ALLOW_INSECURE_REQUESTS + BOOL shouldCheckSecurity = NO; +#else + BOOL shouldCheckSecurity = (fetchRequestURL != nil + && !isDataRequest + && [[self class] appAllowsInsecureRequests]); +#endif + + if (shouldCheckSecurity) { + // Allow https only for requests, unless overridden by the client. + // + // Non-https requests may too easily be snooped, so we disallow them by default. + // + // file: and data: schemes are usually safe if they are hardcoded in the client or provided + // by a trusted source, but since it's fairly rare to need them, it's safest to make clients + // explicitly whitelist them. + BOOL isSecure = + requestScheme != nil && [requestScheme caseInsensitiveCompare:@"https"] == NSOrderedSame; + if (!isSecure) { + BOOL allowRequest = NO; + NSString *host = fetchRequestURL.host; + + // Check schemes first. A file scheme request may be allowed here, or as a localhost request. + for (NSString *allowedScheme in _allowedInsecureSchemes) { + if (requestScheme != nil && + [requestScheme caseInsensitiveCompare:allowedScheme] == NSOrderedSame) { + allowRequest = YES; + break; + } + } + if (!allowRequest) { + // Check for localhost requests. Security checks only occur for non-https requests, so + // this check won't happen for an https request to localhost. + BOOL isLocalhostRequest = (host.length == 0 && [fetchRequestURL isFileURL]) || IsLocalhost(host); + if (isLocalhostRequest) { + if (self.allowLocalhostRequest) { + allowRequest = YES; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Fetch request for localhost but fetcher" + @" allowLocalhostRequest is not set: %@", fetchRequestURL); + } + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Insecure fetch request has a scheme (%@)" + @" not found in fetcher allowedInsecureSchemes (%@): %@", + requestScheme, _allowedInsecureSchemes ?: @" @[] ", fetchRequestURL); + } + } + + if (!allowRequest) { +#if !DEBUG + NSLog(@"Insecure fetch disallowed for %@", fetchRequestURL.description ?: @"nil request URL"); +#endif + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorInsecureRequest)]; + return; + } + } // !isSecure + } // (requestURL != nil) && !isDataRequest + + if (self.cookieStorage == nil) { + self.cookieStorage = [[self class] staticCookieStorage]; + } + + BOOL isRecreatingSession = (self.sessionIdentifier != nil) && (fetchRequest == nil); + + self.canShareSession = !isRecreatingSession && !self.usingBackgroundSession; + + if (!self.session && self.canShareSession) { + self.session = [_service sessionForFetcherCreation]; + // If _session is nil, then the service's session creation semaphore will block + // until this fetcher invokes fetcherDidCreateSession: below, so this *must* invoke + // that method, even if the session fails to be created. + } + + if (!self.session) { + // Create a session. + if (!_configuration) { + if (priorSessionIdentifier || self.usingBackgroundSession) { + NSString *sessionIdentifier = priorSessionIdentifier; + if (!sessionIdentifier) { + sessionIdentifier = [self createSessionIdentifierWithMetadata:nil]; + } + NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap]; + [sessionIdentifierToFetcherMap setObject:self forKey:self.sessionIdentifier]; + +#if (TARGET_OS_TV \ + || TARGET_OS_WATCH \ + || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0)) + // iOS 8/10.10 builds require the new backgroundSessionConfiguration method name. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionIdentifier]; +#elif (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0) + // Do a runtime check to avoid a deprecation warning about using + // +backgroundSessionConfiguration: on iOS 8. + if ([NSURLSessionConfiguration respondsToSelector:@selector(backgroundSessionConfigurationWithIdentifier:)]) { + // Running on iOS 8+/OS X 10.10+. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionIdentifier]; + } else { + // Running on iOS 7/OS X 10.9. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier]; + } +#else + // Building with an SDK earlier than iOS 8/OS X 10.10. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier]; +#endif + self.usingBackgroundSession = YES; + self.canShareSession = NO; + } else { + _configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + } +#if !GTM_ALLOW_INSECURE_REQUESTS + _configuration.TLSMinimumSupportedProtocol = kTLSProtocol12; +#endif + } // !_configuration + _configuration.HTTPCookieStorage = self.cookieStorage; + + if (_configurationBlock) { + _configurationBlock(self, _configuration); + } + + id delegate = [_service sessionDelegate]; + if (!delegate || !self.canShareSession) { + delegate = self; + } + self.session = [NSURLSession sessionWithConfiguration:_configuration + delegate:delegate + delegateQueue:self.sessionDelegateQueue]; + GTMSESSION_ASSERT_DEBUG(self.session, @"Couldn't create session"); + + // Tell the service about the session created by this fetcher. This also signals the + // service's semaphore to allow other fetchers to request this session. + [_service fetcherDidCreateSession:self]; + + // If this assertion fires, the client probably tried to use a session identifier that was + // already used. The solution is to make the client use a unique identifier (or better yet let + // the session fetcher assign the identifier). + GTMSESSION_ASSERT_DEBUG(self.session.delegate == delegate, @"Couldn't assign delegate."); + + if (self.session) { + BOOL isUsingSharedDelegate = (delegate != self); + if (!isUsingSharedDelegate) { + _shouldInvalidateSession = YES; + } + } + } + + if (isRecreatingSession) { + _shouldInvalidateSession = YES; + + // Let's make sure there are tasks still running or if not that we get a callback from a + // completed one; otherwise, we assume the tasks failed. + // This is the observed behavior perhaps 25% of the time within the Simulator running 7.0.3 on + // exiting the app after starting an upload and relaunching the app if we manage to relaunch + // after the task has completed, but before the system relaunches us in the background. + [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, + NSArray *downloadTasks) { + if (dataTasks.count == 0 && uploadTasks.count == 0 && downloadTasks.count == 0) { + double const kDelayInSeconds = 1.0; // We should get progress indication or completion soon + dispatch_time_t checkForFeedbackDelay = + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelayInSeconds * NSEC_PER_SEC)); + dispatch_after(checkForFeedbackDelay, dispatch_get_main_queue(), ^{ + if (!self.sessionTask && !fetchRequest) { + // If our task and/or request haven't been restored, then we assume task feedback lost. + [self removePersistedBackgroundSessionFromDefaults]; + NSError *sessionError = + [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorBackgroundFetchFailed + userInfo:nil]; + [self failToBeginFetchWithError:sessionError]; + } + }); + } + }]; + return; + } + + self.downloadedData = nil; + self.downloadedLength = 0; + + if (_servicePriority == NSIntegerMin) { + mayDelay = NO; + } + if (mayDelay && _service) { + BOOL shouldFetchNow = [_service fetcherShouldBeginFetching:self]; + if (!shouldFetchNow) { + // The fetch is deferred, but will happen later. + // + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after the fetcher is restarted. + if (self.canShareSession) { + self.session = nil; + } + return; + } + } + + NSString *effectiveHTTPMethod = [fetchRequest valueForHTTPHeaderField:@"X-HTTP-Method-Override"]; + if (effectiveHTTPMethod == nil) { + effectiveHTTPMethod = fetchRequest.HTTPMethod; + } + BOOL isEffectiveHTTPGet = (effectiveHTTPMethod == nil + || [effectiveHTTPMethod isEqual:@"GET"]); + + BOOL needsUploadTask = (self.useUploadTask || self.bodyFileURL || self.bodyStreamProvider); + if (_bodyData || self.bodyStreamProvider || fetchRequest.HTTPBodyStream) { + if (isEffectiveHTTPGet) { + fetchRequest.HTTPMethod = @"POST"; + isEffectiveHTTPGet = NO; + } + + if (_bodyData) { + if (!needsUploadTask) { + fetchRequest.HTTPBody = _bodyData; + } +#if !STRIP_GTM_FETCH_LOGGING + } else if (fetchRequest.HTTPBodyStream) { + if ([self respondsToSelector:@selector(loggedInputStreamForInputStream:)]) { + fetchRequest.HTTPBodyStream = + [self performSelector:@selector(loggedInputStreamForInputStream:) + withObject:fetchRequest.HTTPBodyStream]; + } +#endif + } + } + + // We authorize after setting up the http method and body in the request + // because OAuth 1 may need to sign the request body + if (mayAuthorize && _authorizer && !isDataRequest) { + BOOL isAuthorized = [_authorizer isAuthorizedRequest:fetchRequest]; + if (!isAuthorized) { + // Authorization needed. + // + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after authorization completes. + if (self.canShareSession) { + self.session = nil; + } + + // Authorizing the request will recursively call this beginFetch:mayDelay: + // or failToBeginFetchWithError:. + [self authorizeRequest]; + return; + } + } + + // set the default upload or download retry interval, if necessary + if ([self isRetryEnabled] && self.maxRetryInterval <= 0) { + if (isEffectiveHTTPGet || [effectiveHTTPMethod isEqual:@"HEAD"]) { + [self setMaxRetryInterval:kDefaultMaxDownloadRetryInterval]; + } else { + [self setMaxRetryInterval:kDefaultMaxUploadRetryInterval]; + } + } + + // finally, start the connection + NSURLSessionTask *newSessionTask; + BOOL needsDataAccumulator = NO; + if (_downloadResumeData) { + newSessionTask = [_session downloadTaskWithResumeData:_downloadResumeData]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed downloadTaskWithResumeData for %@, resume data %tu bytes", + _session, _downloadResumeData.length); + } else if (_destinationFileURL && !isDataRequest) { + newSessionTask = [_session downloadTaskWithRequest:fetchRequest]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, @"Failed downloadTaskWithRequest for %@, %@", + _session, fetchRequest); + } else if (needsUploadTask) { + if (bodyFileURL) { + newSessionTask = [_session uploadTaskWithRequest:fetchRequest + fromFile:bodyFileURL]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithRequest for %@, %@, file %@", + _session, fetchRequest, bodyFileURL.path); + } else if (self.bodyStreamProvider) { + newSessionTask = [_session uploadTaskWithStreamedRequest:fetchRequest]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithStreamedRequest for %@, %@", + _session, fetchRequest); + } else { + GTMSESSION_ASSERT_DEBUG_OR_LOG(_bodyData != nil, + @"Upload task needs body data, %@", fetchRequest); + newSessionTask = [_session uploadTaskWithRequest:fetchRequest + fromData:(NSData * GTM_NONNULL_TYPE)_bodyData]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithRequest for %@, %@, body data %tu bytes", + _session, fetchRequest, _bodyData.length); + } + needsDataAccumulator = YES; + } else { + newSessionTask = [_session dataTaskWithRequest:fetchRequest]; + needsDataAccumulator = YES; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, @"Failed dataTaskWithRequest for %@, %@", + _session, fetchRequest); + } + self.sessionTask = newSessionTask; + + if (!newSessionTask) { + // We shouldn't get here; if we're here, an earlier assertion should have fired to explain + // which session task creation failed. + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorTaskCreationFailed)]; + return; + } + + if (needsDataAccumulator && _accumulateDataBlock == nil) { + self.downloadedData = [NSMutableData data]; + } + if (_taskDescription) { + newSessionTask.taskDescription = _taskDescription; + } + if (_taskPriority >= 0) { +#if TARGET_OS_TV || TARGET_OS_WATCH + BOOL hasTaskPriority = YES; +#elif (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0) + BOOL hasTaskPriority = YES; +#else + BOOL hasTaskPriority = [newSessionTask respondsToSelector:@selector(setPriority:)]; +#endif + if (hasTaskPriority) { + newSessionTask.priority = _taskPriority; + } + } + +#if GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSESSION_ASSERT_DEBUG(_testBlock == nil && gGlobalTestBlock == nil, @"test blocks disabled"); + _testBlock = nil; +#else + if (!_testBlock) { + if (gGlobalTestBlock) { + // Note that the test block may pass nil for all of its response parameters, + // indicating that the fetch should actually proceed. This is useful when the + // global test block has been set, and the app is only testing a specific + // fetcher. The block simulation code will then resume the task. + _testBlock = gGlobalTestBlock; + } + } + _isUsingTestBlock = (_testBlock != nil); +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK + +#if GTM_BACKGROUND_TASK_FETCHING + id app = [[self class] fetcherUIApplication]; + // Background tasks seem to interfere with out-of-process uploads and downloads. + if (app && !self.skipBackgroundTask && !self.useBackgroundSession) { + // Tell UIApplication that we want to continue even when the app is in the + // background. +#if DEBUG + NSString *bgTaskName = [NSString stringWithFormat:@"%@-%@", + [self class], fetchRequest.URL.host]; +#else + NSString *bgTaskName = @"GTMSessionFetcher"; +#endif + __block UIBackgroundTaskIdentifier bgTaskID = [app beginBackgroundTaskWithName:bgTaskName + expirationHandler:^{ + // Background task expiration callback - this block is always invoked by + // UIApplication on the main thread. + if (bgTaskID != UIBackgroundTaskInvalid) { + @synchronized(self) { + if (bgTaskID == self.backgroundTaskIdentifier) { + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + } + [app endBackgroundTask:bgTaskID]; + } + }]; + @synchronized(self) { + self.backgroundTaskIdentifier = bgTaskID; + } + } +#endif + + if (!_initialRequestDate) { + _initialRequestDate = [[NSDate alloc] init]; + } + + // We don't expect to reach here even on retry or auth until a stop notification has been sent + // for the previous task, but we should ensure that we don't unbalance that. + GTMSESSION_ASSERT_DEBUG(!_isStopNotificationNeeded, @"Start notification without a prior stop"); + [self sendStopNotificationIfNeeded]; + + [self addPersistedBackgroundSessionToDefaults]; + + [self setStopNotificationNeeded:YES]; + + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherStartedNotification + userInfo:nil + requireAsync:NO]; + + // The service needs to know our task if it is serving as NSURLSession delegate. + [_service fetcherDidBeginFetching:self]; + + if (_testBlock) { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + [self simulateFetchForTestBlock]; +#endif + } else { + // We resume the session task after posting the notification since the + // delegate callbacks may happen immediately if the fetch is started off + // the main thread or the session delegate queue is on a background thread, + // and we don't want to post a start notification after a premature finish + // of the session task. + [newSessionTask resume]; + } +} + +NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError) { + NSMutableData *data = [NSMutableData data]; + + [inputStream open]; + NSInteger numberOfBytesRead = 0; + while ([inputStream hasBytesAvailable]) { + uint8_t buffer[512]; + numberOfBytesRead = [inputStream read:buffer maxLength:sizeof(buffer)]; + if (numberOfBytesRead > 0) { + [data appendBytes:buffer length:(NSUInteger)numberOfBytesRead]; + } else { + break; + } + } + [inputStream close]; + NSError *streamError = inputStream.streamError; + + if (streamError) { + data = nil; + } + if (outError) { + *outError = streamError; + } + return data; +} + +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + +- (void)simulateFetchForTestBlock { + // This is invoked on the same thread as the beginFetch method was. + // + // Callbacks will all occur on the callback queue. + _testBlock(self, ^(NSURLResponse *response, NSData *responseData, NSError *error) { + // Callback from test block. + if (response == nil && responseData == nil && error == nil) { + // Assume the fetcher should execute rather than be tested. + _testBlock = nil; + _isUsingTestBlock = NO; + [_sessionTask resume]; + return; + } + + GTMSessionFetcherBodyStreamProvider bodyStreamProvider = self.bodyStreamProvider; + if (bodyStreamProvider) { + bodyStreamProvider(^(NSInputStream *bodyStream){ + // Read from the input stream into an NSData buffer. We'll drain the stream + // explicitly on a background queue. + [self invokeOnCallbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) + afterUserStopped:NO + block:^{ + NSError *streamError; + NSData *streamedData = GTMDataFromInputStream(bodyStream, &streamError); + + dispatch_async(dispatch_get_main_queue(), ^{ + // Continue callbacks on the main thread, since serial behavior + // is more reliable for tests. + [self simulateDataCallbacksForTestBlockWithBodyData:streamedData + response:response + responseData:responseData + error:(error ?: streamError)]; + }); + }]; + }); + } else { + // No input stream; use the supplied data or file URL. + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSError *readError; + _bodyData = [NSData dataWithContentsOfURL:bodyFileURL + options:NSDataReadingMappedIfSafe + error:&readError]; + error = readError; + } + + // No stream provider. + + // In real fetches, nothing happens until the run loop spins, so apps have leeway to + // set callbacks after they call beginFetch. We'll mirror that fetcher behavior by + // delaying callbacks here at least to the next spin of the run loop. That keeps + // immediate, synchronous setting of callback blocks after beginFetch working in tests. + dispatch_async(dispatch_get_main_queue(), ^{ + [self simulateDataCallbacksForTestBlockWithBodyData:_bodyData + response:response + responseData:responseData + error:error]; + }); + } + }); +} + +- (void)simulateByteTransferReportWithDataLength:(int64_t)totalDataLength + block:(GTMSessionFetcherSendProgressBlock)block { + // This utility method simulates transfer progress with up to three callbacks. + // It is used to call back to any of the progress blocks. + int64_t sendReportSize = totalDataLength / 3 + 1; + int64_t totalSent = 0; + while (totalSent < totalDataLength) { + int64_t bytesRemaining = totalDataLength - totalSent; + sendReportSize = MIN(sendReportSize, bytesRemaining); + totalSent += sendReportSize; + [self invokeOnCallbackQueueUnlessStopped:^{ + block(sendReportSize, totalSent, totalDataLength); + }]; + } +} + +- (void)simulateDataCallbacksForTestBlockWithBodyData:(NSData * GTM_NULLABLE_TYPE)bodyData + response:(NSURLResponse *)response + responseData:(NSData *)suppliedData + error:(NSError *)suppliedError { + __block NSData *responseData = suppliedData; + __block NSError *responseError = suppliedError; + + // This method does the test simulation of callbacks once the upload + // and download data are known. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Get copies of ivars we'll access in async invocations. This simulation assumes + // they won't change during fetcher execution. + NSURL *destinationFileURL = _destinationFileURL; + GTMSessionFetcherWillRedirectBlock willRedirectBlock = _willRedirectBlock; + GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock = _didReceiveResponseBlock; + GTMSessionFetcherSendProgressBlock sendProgressBlock = _sendProgressBlock; + GTMSessionFetcherDownloadProgressBlock downloadProgressBlock = _downloadProgressBlock; + GTMSessionFetcherAccumulateDataBlock accumulateDataBlock = _accumulateDataBlock; + GTMSessionFetcherReceivedProgressBlock receivedProgressBlock = _receivedProgressBlock; + GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock = + _willCacheURLResponseBlock; + + // Simulate receipt of redirection. + if (willRedirectBlock) { + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + willRedirectBlock((NSHTTPURLResponse *)response, _request, + ^(NSURLRequest *redirectRequest) { + // For simulation, we'll assume the app will just continue. + }); + }]; + } + + // If the fetcher has a challenge block, simulate a challenge. + // + // It might be nice to eventually let the user determine which testBlock + // fetches get challenged rather than always executing the supplied + // challenge block. + if (_challengeBlock) { + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + if (_challengeBlock) { + NSURL *requestURL = _request.URL; + NSString *host = requestURL.host; + NSURLProtectionSpace *pspace = + [[NSURLProtectionSpace alloc] initWithHost:host + port:requestURL.port.integerValue + protocol:requestURL.scheme + realm:nil + authenticationMethod:NSURLAuthenticationMethodHTTPBasic]; + id unusedSender = + (id)[NSNull null]; + NSURLAuthenticationChallenge *challenge = + [[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:pspace + proposedCredential:nil + previousFailureCount:0 + failureResponse:nil + error:nil + sender:unusedSender]; + _challengeBlock(self, challenge, ^(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential){ + // We could change the responseData and responseError based on the disposition, + // but it's easier for apps to just supply the expected data and error + // directly to the test block. So this simulation ignores the disposition. + }); + } + }]; + } + + // Simulate receipt of an initial response. + if (response && didReceiveResponseBlock) { + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + didReceiveResponseBlock(response, ^(NSURLSessionResponseDisposition desiredDisposition) { + // For simulation, we'll assume the disposition is to continue. + }); + }]; + } + + // Simulate reporting send progress. + if (sendProgressBlock) { + [self simulateByteTransferReportWithDataLength:(int64_t)bodyData.length + block:^(int64_t bytesSent, + int64_t totalBytesSent, + int64_t totalBytesExpectedToSend) { + // This is invoked on the callback queue unless stopped. + sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpectedToSend); + }]; + } + + if (destinationFileURL) { + // Simulate download to file progress. + if (downloadProgressBlock) { + [self simulateByteTransferReportWithDataLength:(int64_t)responseData.length + block:^(int64_t bytesDownloaded, + int64_t totalBytesDownloaded, + int64_t totalBytesExpectedToDownload) { + // This is invoked on the callback queue unless stopped. + downloadProgressBlock(bytesDownloaded, totalBytesDownloaded, + totalBytesExpectedToDownload); + }]; + } + + NSError *writeError; + [responseData writeToURL:destinationFileURL + options:NSDataWritingAtomic + error:&writeError]; + if (writeError) { + // Tell the test code that writing failed. + responseError = writeError; + } + } else { + // Simulate download to NSData progress. + if ((accumulateDataBlock || receivedProgressBlock) && responseData) { + [self simulateByteTransferWithData:responseData + block:^(NSData *data, + int64_t bytesReceived, + int64_t totalBytesReceived, + int64_t totalBytesExpectedToReceive) { + // This is invoked on the callback queue unless stopped. + if (accumulateDataBlock) { + accumulateDataBlock(data); + } + + if (receivedProgressBlock) { + receivedProgressBlock(bytesReceived, totalBytesReceived); + } + }]; + } + + if (!accumulateDataBlock) { + _downloadedData = [responseData mutableCopy]; + } + + if (willCacheURLResponseBlock) { + // Simulate letting the client inspect and alter the cached response. + NSData *cachedData = responseData ?: [[NSData alloc] init]; // Always have non-nil data. + NSCachedURLResponse *cachedResponse = + [[NSCachedURLResponse alloc] initWithResponse:response + data:cachedData]; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + willCacheURLResponseBlock(cachedResponse, ^(NSCachedURLResponse *responseToCache){ + // The app may provide an alternative response, or nil to defeat caching. + }); + }]; + } + } + _response = response; + } // @synchronized(self) + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + // Rather than invoke failToBeginFetchWithError: we want to simulate completion of + // a connection that started and ended, so we'll call down to finishWithError: + NSInteger status = responseError ? responseError.code : 200; + if (status >= 200 && status <= 399) { + [self finishWithError:nil shouldRetry:NO]; + } else { + [self shouldRetryNowForStatus:status + error:responseError + forceAssumeRetry:NO + response:^(BOOL shouldRetry) { + [self finishWithError:responseError shouldRetry:shouldRetry]; + }]; + } + }]; +} + +- (void)simulateByteTransferWithData:(NSData *)responseData + block:(GTMSessionFetcherSimulateByteTransferBlock)transferBlock { + // This utility method simulates transfering data to the client. It divides the data into at most + // "chunkCount" chunks and then passes each chunk along with a progress update to transferBlock. + // This function can be used with accumulateDataBlock or receivedProgressBlock. + + NSUInteger chunkCount = MAX(self.testBlockAccumulateDataChunkCount, (NSUInteger) 1); + NSUInteger totalDataLength = responseData.length; + NSUInteger sendDataSize = totalDataLength / chunkCount + 1; + NSUInteger totalSent = 0; + while (totalSent < totalDataLength) { + NSUInteger bytesRemaining = totalDataLength - totalSent; + sendDataSize = MIN(sendDataSize, bytesRemaining); + NSData *chunkData = [responseData subdataWithRange:NSMakeRange(totalSent, sendDataSize)]; + totalSent += sendDataSize; + [self invokeOnCallbackQueueUnlessStopped:^{ + transferBlock(chunkData, + (int64_t)sendDataSize, + (int64_t)totalSent, + (int64_t)totalDataLength); + }]; + } +} + +#endif // !GTM_DISABLE_FETCHER_TEST_BLOCK + +- (void)setSessionTask:(NSURLSessionTask *)sessionTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionTask != sessionTask) { + _sessionTask = sessionTask; + if (_sessionTask) { + // Request could be nil on restoring this fetcher from a background session. + if (!_request) { + _request = [_sessionTask.originalRequest mutableCopy]; + } + } + } + } // @synchronized(self) +} + +- (NSURLSessionTask * GTM_NULLABLE_TYPE)sessionTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionTask; + } // @synchronized(self) +} + ++ (NSUserDefaults *)fetcherUserDefaults { + static NSUserDefaults *gFetcherUserDefaults = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class fetcherUserDefaultsClass = NSClassFromString(@"GTMSessionFetcherUserDefaultsFactory"); + if (fetcherUserDefaultsClass) { + gFetcherUserDefaults = [fetcherUserDefaultsClass fetcherUserDefaults]; + } else { + gFetcherUserDefaults = [NSUserDefaults standardUserDefaults]; + } + }); + return gFetcherUserDefaults; +} + +- (void)addPersistedBackgroundSessionToDefaults { + NSString *sessionIdentifier = self.sessionIdentifier; + if (!sessionIdentifier) { + return; + } + NSArray *oldBackgroundSessions = [[self class] activePersistedBackgroundSessions]; + if ([oldBackgroundSessions containsObject:_sessionIdentifier]) { + return; + } + NSMutableArray *newBackgroundSessions = + [NSMutableArray arrayWithArray:oldBackgroundSessions]; + [newBackgroundSessions addObject:sessionIdentifier]; + GTM_LOG_BACKGROUND_SESSION(@"Add to background sessions: %@", newBackgroundSessions); + + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + [userDefaults setObject:newBackgroundSessions + forKey:kGTMSessionFetcherPersistedDestinationKey]; + [userDefaults synchronize]; +} + +- (void)removePersistedBackgroundSessionFromDefaults { + NSString *sessionIdentifier = self.sessionIdentifier; + if (!sessionIdentifier) return; + + NSArray *oldBackgroundSessions = [[self class] activePersistedBackgroundSessions]; + if (!oldBackgroundSessions) { + return; + } + NSMutableArray *newBackgroundSessions = + [NSMutableArray arrayWithArray:oldBackgroundSessions]; + NSUInteger sessionIndex = [newBackgroundSessions indexOfObject:sessionIdentifier]; + if (sessionIndex == NSNotFound) { + return; + } + [newBackgroundSessions removeObjectAtIndex:sessionIndex]; + GTM_LOG_BACKGROUND_SESSION(@"Remove from background sessions: %@", newBackgroundSessions); + + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + if (newBackgroundSessions.count == 0) { + [userDefaults removeObjectForKey:kGTMSessionFetcherPersistedDestinationKey]; + } else { + [userDefaults setObject:newBackgroundSessions + forKey:kGTMSessionFetcherPersistedDestinationKey]; + } + [userDefaults synchronize]; +} + ++ (GTM_NULLABLE NSArray *)activePersistedBackgroundSessions { + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + NSArray *oldBackgroundSessions = + [userDefaults arrayForKey:kGTMSessionFetcherPersistedDestinationKey]; + if (oldBackgroundSessions.count == 0) { + return nil; + } + NSMutableArray *activeBackgroundSessions = nil; + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + for (NSString *sessionIdentifier in oldBackgroundSessions) { + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (fetcher) { + if (!activeBackgroundSessions) { + activeBackgroundSessions = [[NSMutableArray alloc] init]; + } + [activeBackgroundSessions addObject:sessionIdentifier]; + } + } + return activeBackgroundSessions; +} + ++ (NSArray *)fetchersForBackgroundSessions { + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + NSArray *backgroundSessions = + [userDefaults arrayForKey:kGTMSessionFetcherPersistedDestinationKey]; + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + NSMutableArray *fetchers = [NSMutableArray array]; + for (NSString *sessionIdentifier in backgroundSessions) { + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (!fetcher) { + fetcher = [self fetcherWithSessionIdentifier:sessionIdentifier]; + GTMSESSION_ASSERT_DEBUG(fetcher != nil, + @"Unexpected invalid session identifier: %@", sessionIdentifier); + [fetcher beginFetchWithCompletionHandler:nil]; + } + GTM_LOG_BACKGROUND_SESSION(@"%@ restoring session %@ by creating fetcher %@ %p", + [self class], sessionIdentifier, fetcher, fetcher); + if (fetcher != nil) { + [fetchers addObject:fetcher]; + } + } + return fetchers; +} + +#if TARGET_OS_IPHONE ++ (void)application:(UIApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler { + GTMSessionFetcher *fetcher = [self fetcherWithSessionIdentifier:identifier]; + if (fetcher != nil) { + fetcher.systemCompletionHandler = completionHandler; + } else { + GTM_LOG_BACKGROUND_SESSION(@"%@ did not create background session identifier: %@", + [self class], identifier); + } +} +#endif + +- (NSString * GTM_NULLABLE_TYPE)sessionIdentifier { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionIdentifier; + } // @synchronized(self) +} + +- (void)setSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(!_session, @"Unable to set session identifier after session created"); + _sessionIdentifier = [sessionIdentifier copy]; + _usingBackgroundSession = YES; + _canShareSession = NO; + [self restoreDefaultStateForSessionIdentifierMetadata]; + } // @synchronized(self) +} + +- (void)setSessionIdentifierInternal:(GTM_NULLABLE NSString *)sessionIdentifier { + // This internal method only does a synchronized set of the session identifier. + // It does not have side effects on the background session, shared session, or + // session identifier metadata. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _sessionIdentifier = [sessionIdentifier copy]; + } // @synchronized(self) +} + +- (NSDictionary * GTM_NULLABLE_TYPE)sessionUserInfo { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionUserInfo == nil) { + // We'll return the metadata dictionary with internal keys removed. This avoids the user + // re-using the userInfo dictionary later and accidentally including the internal keys. + NSMutableDictionary *metadata = [[self sessionIdentifierMetadataUnsynchronized] mutableCopy]; + NSSet *keysToRemove = [metadata keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) { + return [key hasPrefix:@"_"]; + }]; + [metadata removeObjectsForKeys:[keysToRemove allObjects]]; + if (metadata.count > 0) { + _sessionUserInfo = metadata; + } + } + return _sessionUserInfo; + } // @synchronized(self) +} + +- (void)setSessionUserInfo:(NSDictionary * GTM_NULLABLE_TYPE)dictionary { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(_sessionIdentifier == nil, @"Too late to assign userInfo"); + _sessionUserInfo = dictionary; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSDictionary *)sessionIdentifierDefaultMetadata { + GTMSessionCheckSynchronized(self); + + NSMutableDictionary *defaultUserInfo = [[NSMutableDictionary alloc] init]; + if (_destinationFileURL) { + defaultUserInfo[kGTMSessionIdentifierDestinationFileURLMetadataKey] = + [_destinationFileURL absoluteString]; + } + if (_bodyFileURL) { + defaultUserInfo[kGTMSessionIdentifierBodyFileURLMetadataKey] = [_bodyFileURL absoluteString]; + } + return (defaultUserInfo.count > 0) ? defaultUserInfo : nil; +} + +- (void)restoreDefaultStateForSessionIdentifierMetadata { + GTMSessionCheckSynchronized(self); + + NSDictionary *metadata = [self sessionIdentifierMetadataUnsynchronized]; + NSString *destinationFileURLString = metadata[kGTMSessionIdentifierDestinationFileURLMetadataKey]; + if (destinationFileURLString) { + _destinationFileURL = [NSURL URLWithString:destinationFileURLString]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring destination file URL: %@", _destinationFileURL); + } + NSString *bodyFileURLString = metadata[kGTMSessionIdentifierBodyFileURLMetadataKey]; + if (bodyFileURLString) { + _bodyFileURL = [NSURL URLWithString:bodyFileURLString]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring body file URL: %@", _bodyFileURL); + } +} + +- (NSDictionary * GTM_NULLABLE_TYPE)sessionIdentifierMetadata { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [self sessionIdentifierMetadataUnsynchronized]; + } +} + +- (NSDictionary * GTM_NULLABLE_TYPE)sessionIdentifierMetadataUnsynchronized { + GTMSessionCheckSynchronized(self); + + // Session Identifier format: "com.google.__ + if (!_sessionIdentifier) { + return nil; + } + NSScanner *metadataScanner = [NSScanner scannerWithString:_sessionIdentifier]; + [metadataScanner setCharactersToBeSkipped:nil]; + NSString *metadataString; + NSString *uuid; + if ([metadataScanner scanUpToString:@"_" intoString:NULL] && + [metadataScanner scanString:@"_" intoString:NULL] && + [metadataScanner scanUpToString:@"_" intoString:&uuid] && + [metadataScanner scanString:@"_" intoString:NULL] && + [metadataScanner scanUpToString:@"\n" intoString:&metadataString]) { + _sessionIdentifierUUID = uuid; + NSData *metadataData = [metadataString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *error; + NSDictionary *metadataDict = + [NSJSONSerialization JSONObjectWithData:metadataData + options:0 + error:&error]; + GTM_LOG_BACKGROUND_SESSION(@"User Info from session identifier: %@ %@", + metadataDict, error ? error : @""); + return metadataDict; + } + return nil; +} + +- (NSString *)createSessionIdentifierWithMetadata:(NSDictionary * GTM_NULLABLE_TYPE)metadataToInclude { + NSString *result; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Session Identifier format: "com.google.__ + GTMSESSION_ASSERT_DEBUG(!_sessionIdentifier, @"Session identifier already created"); + _sessionIdentifierUUID = [[NSUUID UUID] UUIDString]; + _sessionIdentifier = + [NSString stringWithFormat:@"%@_%@", kGTMSessionIdentifierPrefix, _sessionIdentifierUUID]; + // Start with user-supplied keys so they cannot accidentally override the fetcher's keys. + NSMutableDictionary *metadataDict = + [NSMutableDictionary dictionaryWithDictionary:(NSDictionary * GTM_NONNULL_TYPE)_sessionUserInfo]; + + if (metadataToInclude) { + [metadataDict addEntriesFromDictionary:(NSDictionary *)metadataToInclude]; + } + NSDictionary *defaultMetadataDict = [self sessionIdentifierDefaultMetadata]; + if (defaultMetadataDict) { + [metadataDict addEntriesFromDictionary:defaultMetadataDict]; + } + if (metadataDict.count > 0) { + NSData *metadataData = [NSJSONSerialization dataWithJSONObject:metadataDict + options:0 + error:NULL]; + GTMSESSION_ASSERT_DEBUG(metadataData != nil, + @"Session identifier user info failed to convert to JSON"); + if (metadataData.length > 0) { + NSString *metadataString = [[NSString alloc] initWithData:metadataData + encoding:NSUTF8StringEncoding]; + _sessionIdentifier = + [_sessionIdentifier stringByAppendingFormat:@"_%@", metadataString]; + } + } + _didCreateSessionIdentifier = YES; + result = _sessionIdentifier; + } // @synchronized(self) + return result; +} + +- (void)failToBeginFetchWithError:(NSError *)error { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _hasStoppedFetching = YES; + } + + if (error == nil) { + error = [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorDownloadFailed + userInfo:nil]; + } + + [self invokeFetchCallbacksOnCallbackQueueWithData:nil + error:error]; + [self releaseCallbacks]; + + [_service fetcherDidStop:self]; + + self.authorizer = nil; +} + ++ (GTMSessionCookieStorage *)staticCookieStorage { + static GTMSessionCookieStorage *gCookieStorage = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gCookieStorage = [[GTMSessionCookieStorage alloc] init]; + }); + return gCookieStorage; +} + +#if GTM_BACKGROUND_TASK_FETCHING + +- (void)endBackgroundTask { + // Whenever the connection stops or background execution expires, + // we need to tell UIApplication we're done. + UIBackgroundTaskIdentifier bgTaskID; + @synchronized(self) { + bgTaskID = self.backgroundTaskIdentifier; + if (bgTaskID != UIBackgroundTaskInvalid) { + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + } + + if (bgTaskID != UIBackgroundTaskInvalid) { + id app = [[self class] fetcherUIApplication]; + [app endBackgroundTask:bgTaskID]; + } +} + +#endif // GTM_BACKGROUND_TASK_FETCHING + +- (void)authorizeRequest { + GTMSessionCheckNotSynchronized(self); + + id authorizer = self.authorizer; + SEL asyncAuthSel = @selector(authorizeRequest:delegate:didFinishSelector:); + if ([authorizer respondsToSelector:asyncAuthSel]) { + SEL callbackSel = @selector(authorizer:request:finishedWithError:); + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + [authorizer authorizeRequest:mutableRequest + delegate:self + didFinishSelector:callbackSel]; + } else { + GTMSESSION_ASSERT_DEBUG(authorizer == nil, @"invalid authorizer for fetch"); + + // No authorizing possible, and authorizing happens only after any delay; + // just begin fetching + [self beginFetchMayDelay:NO + mayAuthorize:NO]; + } +} + +- (void)authorizer:(id)auth + request:(NSMutableURLRequest *)authorizedRequest + finishedWithError:(NSError *)error { + GTMSessionCheckNotSynchronized(self); + + if (error != nil) { + // We can't fetch without authorization + [self failToBeginFetchWithError:error]; + } else { + @synchronized(self) { + _request = authorizedRequest; + } + [self beginFetchMayDelay:NO + mayAuthorize:NO]; + } +} + + +- (BOOL)canFetchWithBackgroundSession { + // Subclasses may override. + return YES; +} + +// Returns YES if the fetcher has been started and has not yet stopped. +// +// Fetching includes waiting for authorization or for retry, waiting to be allowed by the +// service object to start the request, and actually fetching the request. +- (BOOL)isFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [self isFetchingUnsynchronized]; + } +} + +- (BOOL)isFetchingUnsynchronized { + GTMSessionCheckSynchronized(self); + + BOOL hasBegun = (_initialBeginFetchDate != nil); + return hasBegun && !_hasStoppedFetching; +} + +- (NSURLResponse * GTM_NULLABLE_TYPE)response { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + return response; + } // @synchronized(self) +} + +- (NSURLResponse * GTM_NULLABLE_TYPE)responseUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = _sessionTask.response; + if (!response) response = _response; + return response; +} + +- (NSInteger)statusCode { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSInteger statusCode = [self statusCodeUnsynchronized]; + return statusCode; + } // @synchronized(self) +} + +- (NSInteger)statusCodeUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + NSInteger statusCode; + + if ([response respondsToSelector:@selector(statusCode)]) { + statusCode = [(NSHTTPURLResponse *)response statusCode]; + } else { + // Default to zero, in hopes of hinting "Unknown" (we can't be + // sure that things are OK enough to use 200). + statusCode = 0; + } + return statusCode; +} + +- (NSDictionary * GTM_NULLABLE_TYPE)responseHeaders { + GTMSessionCheckNotSynchronized(self); + + NSURLResponse *response = self.response; + if ([response respondsToSelector:@selector(allHeaderFields)]) { + NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; + return headers; + } + return nil; +} + +- (NSDictionary * GTM_NULLABLE_TYPE)responseHeadersUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + if ([response respondsToSelector:@selector(allHeaderFields)]) { + NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; + return headers; + } + return nil; +} + +- (void)releaseCallbacks { + // Avoid releasing blocks in the sync section since objects dealloc'd by + // the blocks being released may call back into the fetcher or fetcher + // service. + dispatch_queue_t NS_VALID_UNTIL_END_OF_SCOPE holdCallbackQueue; + GTMSessionFetcherCompletionHandler NS_VALID_UNTIL_END_OF_SCOPE holdCompletionHandler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + holdCallbackQueue = _callbackQueue; + holdCompletionHandler = _completionHandler; + + _callbackQueue = nil; + _completionHandler = nil; // Setter overridden in upload. Setter assumed to be used externally. + } + + // Set local callback pointers to nil here rather than let them release at the end of the scope + // to make any problems due to the blocks being released be a bit more obvious in a stack trace. + holdCallbackQueue = nil; + holdCompletionHandler = nil; + + self.configurationBlock = nil; + self.didReceiveResponseBlock = nil; + self.challengeBlock = nil; + self.willRedirectBlock = nil; + self.sendProgressBlock = nil; + self.receivedProgressBlock = nil; + self.downloadProgressBlock = nil; + self.accumulateDataBlock = nil; + self.willCacheURLResponseBlock = nil; + self.retryBlock = nil; + self.testBlock = nil; + self.resumeDataBlock = nil; +} + +- (void)forgetSessionIdentifierForFetcher { + GTMSessionCheckSynchronized(self); + [self forgetSessionIdentifierForFetcherWithoutSyncCheck]; +} + +- (void)forgetSessionIdentifierForFetcherWithoutSyncCheck { + // This should be called inside a @synchronized block (except during dealloc.) + if (_sessionIdentifier) { + NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap]; + [sessionIdentifierToFetcherMap removeObjectForKey:_sessionIdentifier]; + _sessionIdentifier = nil; + _didCreateSessionIdentifier = NO; + } +} + +// External stop method +- (void)stopFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Prevent enqueued callbacks from executing. + _userStoppedFetching = YES; + } // @synchronized(self) + [self stopFetchReleasingCallbacks:YES]; +} + +// Cancel the fetch of the URL that's currently in progress. +// +// If shouldReleaseCallbacks is NO then the fetch will be retried so the callbacks +// need to still be retained. +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks { + [self removePersistedBackgroundSessionFromDefaults]; + + id service; + NSMutableURLRequest *request; + + // If the task or the retry timer is all that's retaining the fetcher, + // we want to be sure this instance survives stopping at least long enough for + // the stack to unwind. + __autoreleasing GTMSessionFetcher *holdSelf = self; + + BOOL hasCanceledTask = NO; + + [holdSelf destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _hasStoppedFetching = YES; + + service = _service; + request = _request; + + if (_sessionTask) { + // In case cancelling the task or session calls this recursively, we want + // to ensure that we'll only release the task and delegate once, + // so first set _sessionTask to nil + // + // This may be called in a callback from the task, so use autorelease to avoid + // releasing the task in its own callback. + __autoreleasing NSURLSessionTask *oldTask = _sessionTask; + if (!_isUsingTestBlock) { + _response = _sessionTask.response; + } + _sessionTask = nil; + + if ([oldTask state] != NSURLSessionTaskStateCompleted) { + // For download tasks, when the fetch is stopped, we may provide resume data that can + // be used to create a new session. + BOOL mayResume = (_resumeDataBlock + && [oldTask respondsToSelector:@selector(cancelByProducingResumeData:)]); + if (!mayResume) { + [oldTask cancel]; + // A side effect of stopping the task is that URLSession:task:didCompleteWithError: + // will be invoked asynchronously on the delegate queue. + } else { + void (^resumeBlock)(NSData *) = _resumeDataBlock; + _resumeDataBlock = nil; + + // Save callbackQueue since releaseCallbacks clears it. + dispatch_queue_t callbackQueue = _callbackQueue; + dispatch_group_enter(_callbackGroup); + [(NSURLSessionDownloadTask *)oldTask cancelByProducingResumeData:^(NSData *resumeData) { + [self invokeOnCallbackQueue:callbackQueue + afterUserStopped:YES + block:^{ + resumeBlock(resumeData); + dispatch_group_leave(_callbackGroup); + }]; + }]; + } + hasCanceledTask = YES; + } + } + + // If the task was canceled, wait until the URLSession:task:didCompleteWithError: to call + // finishTasksAndInvalidate, since calling it immediately tends to crash, see radar 18471901. + if (_session) { + BOOL shouldInvalidate = _shouldInvalidateSession; +#if TARGET_OS_IPHONE + // Don't invalidate if we've got a systemCompletionHandler, since + // URLSessionDidFinishEventsForBackgroundURLSession: won't be called if invalidated. + shouldInvalidate = shouldInvalidate && !self.systemCompletionHandler; +#endif + if (shouldInvalidate) { + __autoreleasing NSURLSession *oldSession = _session; + _session = nil; + + if (!hasCanceledTask) { + [oldSession finishTasksAndInvalidate]; + } else { + _sessionNeedingInvalidation = oldSession; + } + } + } + } // @synchronized(self) + + // send the stopped notification + [self sendStopNotificationIfNeeded]; + + [_authorizer stopAuthorizationForRequest:request]; + + if (shouldReleaseCallbacks) { + [self releaseCallbacks]; + + self.authorizer = nil; + } + + [service fetcherDidStop:self]; + +#if GTM_BACKGROUND_TASK_FETCHING + [self endBackgroundTask]; +#endif +} + +- (void)setStopNotificationNeeded:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _isStopNotificationNeeded = flag; + } // @synchronized(self) +} + +- (void)sendStopNotificationIfNeeded { + BOOL sendNow = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_isStopNotificationNeeded) { + _isStopNotificationNeeded = NO; + sendNow = YES; + } + } // @synchronized(self) + + if (sendNow) { + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherStoppedNotification + userInfo:nil + requireAsync:NO]; + } +} + +- (void)retryFetch { + [self stopFetchReleasingCallbacks:NO]; + + GTMSessionFetcherCompletionHandler completionHandler; + + // A retry will need a configuration with a fresh session identifier. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionIdentifier && _didCreateSessionIdentifier) { + [self forgetSessionIdentifierForFetcher]; + _configuration = nil; + } + + if (_canShareSession) { + // Force a grab of the current session from the fetcher service in case + // the service's old one has become invalid. + _session = nil; + } + + completionHandler = _completionHandler; + } // @synchronized(self) + + [self beginFetchWithCompletionHandler:completionHandler]; +} + +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds { + // Uncovered in upload fetcher testing, because the chunk fetcher is being waited on, and gets + // released by the upload code. The uploader just holds onto it with an ivar, and that gets + // nilled in the chunk fetcher callback. + // Used once in while loop just to avoid unused variable compiler warning. + __autoreleasing GTMSessionFetcher *holdSelf = self; + + NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + + BOOL shouldSpinRunLoop = ([NSThread isMainThread] && + (!self.callbackQueue + || self.callbackQueue == dispatch_get_main_queue())); + BOOL expired = NO; + + // Loop until the callbacks have been called and released, and until + // the connection is no longer pending, until there are no callback dispatches + // in flight, or until the timeout has expired. + int64_t delta = (int64_t)(100 * NSEC_PER_MSEC); // 100 ms + while (1) { + BOOL isTaskInProgress = (holdSelf->_sessionTask + && [_sessionTask state] != NSURLSessionTaskStateCompleted); + BOOL needsToCallCompletion = (_completionHandler != nil); + BOOL isCallbackInProgress = (_callbackGroup + && dispatch_group_wait(_callbackGroup, dispatch_time(DISPATCH_TIME_NOW, delta))); + + if (!isTaskInProgress && !needsToCallCompletion && !isCallbackInProgress) break; + + expired = ([giveUpDate timeIntervalSinceNow] < 0); + if (expired) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher waitForCompletionWithTimeout:%0.1f expired -- " + @"%@%@%@", timeoutInSeconds, + isTaskInProgress ? @"taskInProgress " : @"", + needsToCallCompletion ? @"needsToCallCompletion " : @"", + isCallbackInProgress ? @"isCallbackInProgress" : @""); + break; + } + + // Run the current run loop 1/1000 of a second to give the networking + // code a chance to work + const NSTimeInterval kSpinInterval = 0.001; + if (shouldSpinRunLoop) { + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:kSpinInterval]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + [NSThread sleepForTimeInterval:kSpinInterval]; + } + } + return !expired; +} + ++ (void)setGlobalTestBlock:(GTMSessionFetcherTestBlock GTM_NULLABLE_TYPE)block { +#if GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSESSION_ASSERT_DEBUG(block == nil, @"test blocks disabled"); +#endif + gGlobalTestBlock = [block copy]; +} + +#if TARGET_OS_IPHONE + +static GTM_NULLABLE_TYPE id gSubstituteUIApp; + ++ (void)setSubstituteUIApplication:(nullable id)app { + gSubstituteUIApp = app; +} + ++ (nullable id)substituteUIApplication { + return gSubstituteUIApp; +} + ++ (nullable id)fetcherUIApplication { + id app = gSubstituteUIApp; + if (app) return app; + + // iOS App extensions should not call [UIApplication sharedApplication], even + // if UIApplication responds to it. + + static Class applicationClass = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + BOOL isAppExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + if (!isAppExtension) { + Class cls = NSClassFromString(@"UIApplication"); + if (cls && [cls respondsToSelector:NSSelectorFromString(@"sharedApplication")]) { + applicationClass = cls; + } + } + }); + + if (applicationClass) { + app = (id)[applicationClass sharedApplication]; + } + return app; +} +#endif // TARGET_OS_IPHONE + +#pragma mark NSURLSession Delegate Methods + +// NSURLSession documentation indicates that redirectRequest can be passed to the handler +// but empirically redirectRequest lacks the HTTP body, so passing it will break POSTs. +// Instead, we construct a new request, a copy of the original, with overrides from the +// redirect. + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +willPerformHTTPRedirection:(NSHTTPURLResponse *)redirectResponse + newRequest:(NSURLRequest *)redirectRequest + completionHandler:(void (^)(NSURLRequest * GTM_NULLABLE_TYPE))handler { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ willPerformHTTPRedirection:%@ newRequest:%@", + [self class], self, session, task, redirectResponse, redirectRequest); + + if ([self userStoppedFetching]) { + handler(nil); + return; + } + if (redirectRequest && redirectResponse) { + // Copy the original request, including the body. + NSURLRequest *originalRequest = self.request; + NSMutableURLRequest *newRequest = [originalRequest mutableCopy]; + + // Disallow scheme changes (say, from https to http). + NSURL *originalRequestURL = originalRequest.URL; + NSURL *redirectRequestURL = redirectRequest.URL; + + NSString *originalScheme = originalRequestURL.scheme; + NSString *redirectScheme = redirectRequestURL.scheme; + + if (originalScheme != nil + && [originalScheme caseInsensitiveCompare:@"http"] == NSOrderedSame + && redirectScheme != nil + && [redirectScheme caseInsensitiveCompare:@"https"] == NSOrderedSame) { + // Allow the change from http to https. + } else { + // Disallow any other scheme changes. + redirectScheme = originalScheme; + } + // The new requests's URL overrides the original's URL. + NSURLComponents *components = [NSURLComponents componentsWithURL:redirectRequestURL + resolvingAgainstBaseURL:NO]; + components.scheme = redirectScheme; + NSURL *newURL = components.URL; + [newRequest setURL:newURL]; + + // Any headers in the redirect override headers in the original. + NSDictionary *redirectHeaders = redirectRequest.allHTTPHeaderFields; + for (NSString *key in redirectHeaders) { + NSString *value = [redirectHeaders objectForKey:key]; + [newRequest setValue:value forHTTPHeaderField:key]; + } + + redirectRequest = newRequest; + + // Log the response we just received + [self setResponse:redirectResponse]; + [self logNowWithError:nil]; + + GTMSessionFetcherWillRedirectBlock willRedirectBlock = self.willRedirectBlock; + if (willRedirectBlock) { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + willRedirectBlock(redirectResponse, redirectRequest, ^(NSURLRequest *clientRequest) { + + // Update the request for future logging. + [self updateMutableRequest:[clientRequest mutableCopy]]; + + handler(clientRequest); + }); + }]; + } // @synchronized(self) + return; + } + // Continues here if the client did not provide a redirect block. + + // Update the request for future logging. + [self updateMutableRequest:[redirectRequest mutableCopy]]; + } + handler(redirectRequest); +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))handler { + [self setSessionTask:dataTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didReceiveResponse:%@", + [self class], self, session, dataTask, response); + void (^accumulateAndFinish)(NSURLSessionResponseDisposition) = + ^(NSURLSessionResponseDisposition dispositionValue) { + // This method is called when the server has determined that it + // has enough information to create the NSURLResponse + // it can be called multiple times, for example in the case of a + // redirect, so each time we reset the data. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL hadPreviousData = _downloadedLength > 0; + + [_downloadedData setLength:0]; + _downloadedLength = 0; + + if (hadPreviousData && (dispositionValue != NSURLSessionResponseCancel)) { + // Tell the accumulate block to discard prior data. + GTMSessionFetcherAccumulateDataBlock accumulateBlock = _accumulateDataBlock; + if (accumulateBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateBlock(nil); + }]; + } + } + } // @synchronized(self) + handler(dispositionValue); + }; + + GTMSessionFetcherDidReceiveResponseBlock receivedResponseBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + receivedResponseBlock = _didReceiveResponseBlock; + if (receivedResponseBlock) { + // We will ultimately need to call back to NSURLSession's handler with the disposition value + // for this delegate method even if the user has stopped the fetcher. + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + receivedResponseBlock(response, ^(NSURLSessionResponseDisposition desiredDisposition) { + accumulateAndFinish(desiredDisposition); + }); + }]; + } + } // @synchronized(self) + + if (receivedResponseBlock == nil) { + accumulateAndFinish(NSURLSessionResponseAllow); + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didBecomeDownloadTask:%@", + [self class], self, session, dataTask, downloadTask); + [self setSessionTask:downloadTask]; +} + + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential))handler { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didReceiveChallenge:%@", + [self class], self, session, task, challenge); + + GTMSessionFetcherChallengeBlock challengeBlock = self.challengeBlock; + if (challengeBlock) { + // The fetcher user has provided custom challenge handling. + // + // We will ultimately need to call back to NSURLSession's handler with the disposition value + // for this delegate method even if the user has stopped the fetcher. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + challengeBlock(self, challenge, handler); + }]; + } + } else { + // No challenge block was provided by the client. + [self respondToChallenge:challenge + completionHandler:handler]; + } +} + +- (void)respondToChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential))handler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSInteger previousFailureCount = [challenge previousFailureCount]; + if (previousFailureCount <= 2) { + NSURLProtectionSpace *protectionSpace = [challenge protectionSpace]; + NSString *authenticationMethod = [protectionSpace authenticationMethod]; + if ([authenticationMethod isEqual:NSURLAuthenticationMethodServerTrust]) { + // SSL. + // + // Background sessions seem to require an explicit check of the server trust object + // rather than default handling. + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + if (serverTrust == NULL) { + // No server trust information is available. + handler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } else { + // Server trust information is available. + void (^callback)(SecTrustRef, BOOL) = ^(SecTrustRef trustRef, BOOL allow){ + if (allow) { + NSURLCredential *trustCredential = [NSURLCredential credentialForTrust:trustRef]; + handler(NSURLSessionAuthChallengeUseCredential, trustCredential); + } else { + GTMSESSION_LOG_DEBUG(@"Cancelling authentication challenge for %@", _request.URL); + handler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + }; + if (_allowInvalidServerCertificates) { + callback(serverTrust, YES); + } else { + [[self class] evaluateServerTrust:serverTrust + forRequest:_request + completionHandler:callback]; + } + } + return; + } + + NSURLCredential *credential = _credential; + + if ([[challenge protectionSpace] isProxy] && _proxyCredential != nil) { + credential = _proxyCredential; + } + + if (credential) { + handler(NSURLSessionAuthChallengeUseCredential, credential); + } else { + // The credential is still nil; tell the OS to use the default handling. This is needed + // for things that can come out of the keychain (proxies, client certificates, etc.). + // + // Note: Looking up a credential with NSURLCredentialStorage's + // defaultCredentialForProtectionSpace: is *not* the same invoking the handler with + // NSURLSessionAuthChallengePerformDefaultHandling. In the case of + // NSURLAuthenticationMethodClientCertificate, you can get nil back from + // NSURLCredentialStorage, while using this code path instead works. + handler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } + + } else { + // We've failed auth 3 times. The completion handler will be called with code + // NSURLErrorCancelled. + handler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + } // @synchronized(self) +} + +// Validate the certificate chain. +// +// This may become a public method if it appears to be useful to users. ++ (void)evaluateServerTrust:(SecTrustRef)serverTrust + forRequest:(NSURLRequest *)request + completionHandler:(void (^)(SecTrustRef trustRef, BOOL allow))handler { + // Retain the trust object to avoid a SecTrustEvaluate() crash on iOS 7. + CFRetain(serverTrust); + + // Evaluate the certificate chain. + // + // The delegate queue may be the main thread. Trust evaluation could cause some + // blocking network activity, so we must evaluate async, as documented at + // https://developer.apple.com/library/ios/technotes/tn2232/ + // + // We must also avoid multiple uses of the trust object, per docs: + // "It is not safe to call this function concurrently with any other function that uses + // the same trust management object, or to re-enter this function for the same trust + // management object." + // + // SecTrustEvaluateAsync both does sync execution of Evaluate and calls back on the + // queue passed to it, according to at sources in + // http://www.opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-55050.9/lib/SecTrust.cpp + // It would require a global serial queue to ensure the evaluate happens only on a + // single thread at a time, so we'll stick with using SecTrustEvaluate on a background + // thread. + dispatch_queue_t evaluateBackgroundQueue = + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(evaluateBackgroundQueue, ^{ + // It looks like the implementation of SecTrustEvaluate() on Mac grabs a global lock, + // so it may be redundant for us to also lock, but it's easy to synchronize here + // anyway. + SecTrustResultType trustEval = kSecTrustResultInvalid; + BOOL shouldAllow; + OSStatus trustError; + @synchronized([GTMSessionFetcher class]) { + GTMSessionMonitorSynchronized([GTMSessionFetcher class]); + + trustError = SecTrustEvaluate(serverTrust, &trustEval); + } + if (trustError != errSecSuccess) { + GTMSESSION_LOG_DEBUG(@"Error %d evaluating trust for %@", + (int)trustError, request); + shouldAllow = NO; + } else { + // Having a trust level "unspecified" by the user is the usual result, described at + // https://developer.apple.com/library/mac/qa/qa1360 + if (trustEval == kSecTrustResultUnspecified + || trustEval == kSecTrustResultProceed) { + shouldAllow = YES; + } else { + shouldAllow = NO; + GTMSESSION_LOG_DEBUG(@"Challenge SecTrustResultType %u for %@, properties: %@", + trustEval, request.URL.host, + CFBridgingRelease(SecTrustCopyProperties(serverTrust))); + } + } + handler(serverTrust, shouldAllow); + + CFRelease(serverTrust); + }); +} + +- (void)invokeOnCallbackQueueUnlessStopped:(void (^)(void))block { + [self invokeOnCallbackQueueAfterUserStopped:NO + block:block]; +} + +- (void)invokeOnCallbackQueueAfterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + GTMSessionCheckSynchronized(self); + + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:afterStopped + block:block]; +} + +- (void)invokeOnCallbackUnsynchronizedQueueAfterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + // testBlock simulation code may not be synchronizing when this is invoked. + [self invokeOnCallbackQueue:_callbackQueue + afterUserStopped:afterStopped + block:block]; +} + +- (void)invokeOnCallbackQueue:(dispatch_queue_t)callbackQueue + afterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + if (callbackQueue) { + dispatch_group_async(_callbackGroup, callbackQueue, ^{ + if (!afterStopped) { + NSDate *serviceStoppedAllDate = [_service stoppedAllFetchersDate]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Avoid a race between stopFetching and the callback. + if (_userStoppedFetching) { + return; + } + + // Also avoid calling back if the service has stopped all fetchers + // since this one was created. The fetcher may have stopped before + // stopAllFetchers was invoked, so _userStoppedFetching wasn't set, + // but the app still won't expect the callback to fire after + // the service's stopAllFetchers was invoked. + if (serviceStoppedAllDate + && [_initialBeginFetchDate compare:serviceStoppedAllDate] != NSOrderedDescending) { + // stopAllFetchers was called after this fetcher began. + return; + } + } // @synchronized(self) + } + block(); + }); + } +} + +- (void)invokeFetchCallbacksOnCallbackQueueWithData:(GTM_NULLABLE NSData *)data + error:(GTM_NULLABLE NSError *)error { + // Callbacks will be released in the method stopFetchReleasingCallbacks: + GTMSessionFetcherCompletionHandler handler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + handler = _completionHandler; + + if (handler) { + [self invokeOnCallbackQueueUnlessStopped:^{ + handler(data, error); + + // Post a notification, primarily to allow code to collect responses for + // testing. + // + // The observing code is not likely on the fetcher's callback + // queue, so this posts explicitly to the main queue. + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (data) { + userInfo[kGTMSessionFetcherCompletionDataKey] = data; + } + if (error) { + userInfo[kGTMSessionFetcherCompletionErrorKey] = error; + } + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherCompletionInvokedNotification + userInfo:userInfo + requireAsync:NO]; + }]; + } + } // @synchronized(self) +} + +- (void)postNotificationOnMainThreadWithName:(NSString *)noteName + userInfo:(GTM_NULLABLE NSDictionary *)userInfo + requireAsync:(BOOL)requireAsync { + dispatch_block_t postBlock = ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:noteName + object:self + userInfo:userInfo]; + }; + + if ([NSThread isMainThread] && !requireAsync) { + // Post synchronously for compatibility with older code using the fetcher. + + // Avoid calling out to other code from inside a sync block to avoid risk + // of a deadlock or of recursive sync. + GTMSessionCheckNotSynchronized(self); + + postBlock(); + } else { + dispatch_async(dispatch_get_main_queue(), postBlock); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)uploadTask + needNewBodyStream:(void (^)(NSInputStream * GTM_NULLABLE_TYPE bodyStream))completionHandler { + [self setSessionTask:uploadTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ needNewBodyStream:", + [self class], self, session, uploadTask); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSessionFetcherBodyStreamProvider provider = _bodyStreamProvider; +#if !STRIP_GTM_FETCH_LOGGING + if ([self respondsToSelector:@selector(loggedStreamProviderForStreamProvider:)]) { + provider = [self performSelector:@selector(loggedStreamProviderForStreamProvider:) + withObject:provider]; + } +#endif + if (provider) { + [self invokeOnCallbackQueueUnlessStopped:^{ + provider(completionHandler); + }]; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"NSURLSession expects a stream provider"); + + completionHandler(nil); + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didSendBodyData:%lld" + @" totalBytesSent:%lld totalBytesExpectedToSend:%lld", + [self class], self, session, task, bytesSent, totalBytesSent, + totalBytesExpectedToSend); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (!_sendProgressBlock) { + return; + } + // We won't hold on to send progress block; it's ok to not send it if the upload finishes. + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherSendProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = _sendProgressBlock; + } + if (progressBlock) { + progressBlock(bytesSent, totalBytesSent, totalBytesExpectedToSend); + } + }]; + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + [self setSessionTask:dataTask]; + NSUInteger bufferLength = data.length; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didReceiveData:%p (%llu bytes)", + [self class], self, session, dataTask, data, + (unsigned long long)bufferLength); + if (bufferLength == 0) { + // Observed on completing an out-of-process upload. + return; + } + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSessionFetcherAccumulateDataBlock accumulateBlock = _accumulateDataBlock; + if (accumulateBlock) { + // Let the client accumulate the data. + _downloadedLength += bufferLength; + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateBlock(data); + }]; + } else if (!_userStoppedFetching) { + // Append to the mutable data buffer unless the fetch has been cancelled. + + // Resumed upload tasks may not yet have a data buffer. + if (_downloadedData == nil) { + // Using NSClassFromString for iOS 6 compatibility. + GTMSESSION_ASSERT_DEBUG( + ![dataTask isKindOfClass:NSClassFromString(@"NSURLSessionDownloadTask")], + @"Resumed download tasks should not receive data bytes"); + _downloadedData = [[NSMutableData alloc] init]; + } + + [_downloadedData appendData:data]; + _downloadedLength = (int64_t)_downloadedData.length; + + // We won't hold on to receivedProgressBlock here; it's ok to not send + // it if the transfer finishes. + if (_receivedProgressBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherReceivedProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = _receivedProgressBlock; + } + if (progressBlock) { + progressBlock((int64_t)bufferLength, _downloadedLength); + } + }]; + } + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ willCacheResponse:%@ %@", + [self class], self, session, dataTask, + proposedResponse, proposedResponse.response); + GTMSessionFetcherWillCacheURLResponseBlock callback; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + callback = _willCacheURLResponseBlock; + + if (callback) { + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + callback(proposedResponse, completionHandler); + }]; + } + } // @synchronized(self) + if (!callback) { + completionHandler(proposedResponse); + } +} + + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalBytesWritten +totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didWriteData:%lld" + @" bytesWritten:%lld totalBytesExpectedToWrite:%lld", + [self class], self, session, downloadTask, bytesWritten, + totalBytesWritten, totalBytesExpectedToWrite); + [self setSessionTask:downloadTask]; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if ((totalBytesExpectedToWrite != NSURLSessionTransferSizeUnknown) && + (totalBytesExpectedToWrite < totalBytesWritten)) { + // Have observed cases were bytesWritten == totalBytesExpectedToWrite, + // but totalBytesWritten > totalBytesExpectedToWrite, so setting to unkown in these cases. + totalBytesExpectedToWrite = NSURLSessionTransferSizeUnknown; + } + // We won't hold on to download progress block during the enqueue; + // it's ok to not send it if the upload finishes. + + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherDownloadProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = _downloadProgressBlock; + } + if (progressBlock) { + progressBlock(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + } + }]; + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset +expectedTotalBytes:(int64_t)expectedTotalBytes { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didResumeAtOffset:%lld" + @" expectedTotalBytes:%lld", + [self class], self, session, downloadTask, fileOffset, + expectedTotalBytes); + [self setSessionTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask +didFinishDownloadingToURL:(NSURL *)downloadLocationURL { + // Download may have relaunched app, so update _sessionTask. + [self setSessionTask:downloadTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didFinishDownloadingToURL:%@", + [self class], self, session, downloadTask, downloadLocationURL); + NSNumber *fileSizeNum; + [downloadLocationURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:NULL]; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURL *destinationURL = _destinationFileURL; + + _downloadedLength = fileSizeNum.longLongValue; + + // Overwrite any previous file at the destination URL. + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSError *removeError; + if (![fileMgr removeItemAtURL:destinationURL error:&removeError] + && removeError.code != NSFileNoSuchFileError) { + GTMSESSION_LOG_DEBUG(@"Could not remove previous file at %@ due to %@", + downloadLocationURL.path, removeError); + } + + NSInteger statusCode = [self statusCodeUnsynchronized]; + if (statusCode < 200 || statusCode > 399) { + // In OS X 10.11, the response body is written to a file even on a server + // status error. For convenience of the fetcher client, we'll skip saving the + // downloaded body to the destination URL so that clients do not need to know + // to delete the file following fetch errors. A downside of this is that + // the server may have included error details in the response body, and + // abandoning the downloaded file here means that the details from the + // body are not available to the fetcher client. + GTMSESSION_LOG_DEBUG(@"Abandoning download due to status %zd, file %@", + statusCode, downloadLocationURL.path); + } else { + NSError *moveError; + NSURL *destinationFolderURL = [destinationURL URLByDeletingLastPathComponent]; + BOOL didMoveDownload = NO; + if ([fileMgr createDirectoryAtURL:destinationFolderURL + withIntermediateDirectories:YES + attributes:nil + error:&moveError]) { + didMoveDownload = [fileMgr moveItemAtURL:downloadLocationURL + toURL:destinationURL + error:&moveError]; + } + if (!didMoveDownload) { + _downloadFinishedError = moveError; + } + GTM_LOG_BACKGROUND_SESSION(@"%@ %p Moved download from \"%@\" to \"%@\" %@", + [self class], self, + downloadLocationURL.path, destinationURL.path, + error ? error : @""); + } + } // @synchronized(self) +} + +/* Sent as the last message related to a specific task. Error may be + * nil, which implies that no error occurred and this task is complete. + */ +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didCompleteWithError:%@", + [self class], self, session, task, error); + + NSInteger status = self.statusCode; + BOOL forceAssumeRetry = NO; + BOOL succeeded = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + // The task is never resumed when a testBlock is used. When the session is destroyed, + // we should ignore the callback, since the testBlock support code itself invokes + // shouldRetryNowForStatus: and finishWithError:shouldRetry: + if (_isUsingTestBlock) return; +#endif + + if (error == nil) { + error = _downloadFinishedError; + } + succeeded = (error == nil && status >= 0 && status < 300); + if (succeeded) { + // Succeeded. + _bodyLength = task.countOfBytesSent; + } + } // @synchronized(self) + + if (succeeded) { + [self finishWithError:nil shouldRetry:NO]; + return; + } + // For background redirects, no delegate method is called, so we cannot restore a stripped + // Authorization header, so if a 403 ("Forbidden") was generated due to a missing OAuth 2 header, + // set the current request's URL to the redirected URL, so we in effect restore the Authorization + // header. + if ((status == 403) && self.usingBackgroundSession) { + NSURL *redirectURL = self.response.URL; + NSURLRequest *request = self.request; + if (![request.URL isEqual:redirectURL]) { + NSString *authorizationHeader = [request.allHTTPHeaderFields objectForKey:@"Authorization"]; + if (authorizationHeader != nil) { + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + mutableRequest.URL = redirectURL; + [self updateMutableRequest:mutableRequest]; + // Avoid assuming the session is still valid. + self.session = nil; + forceAssumeRetry = YES; + } + } + } + + // If invalidating the session was deferred in stopFetchReleasingCallbacks: then do it now. + NSURLSession *oldSession = self.sessionNeedingInvalidation; + if (oldSession) { + [self setSessionNeedingInvalidation:NULL]; + [oldSession finishTasksAndInvalidate]; + } + + // Failed. + [self shouldRetryNowForStatus:status + error:error + forceAssumeRetry:forceAssumeRetry + response:^(BOOL shouldRetry) { + [self finishWithError:error shouldRetry:shouldRetry]; + }]; +} + +#if TARGET_OS_IPHONE +- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSessionDidFinishEventsForBackgroundURLSession:%@", + [self class], self, session); + [self removePersistedBackgroundSessionFromDefaults]; + + GTMSessionFetcherSystemCompletionHandler handler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + handler = self.systemCompletionHandler; + self.systemCompletionHandler = nil; + } // @synchronized(self) + if (handler) { + GTM_LOG_BACKGROUND_SESSION(@"%@ %p Calling system completionHandler", [self class], self); + handler(); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLSession *oldSession = _session; + _session = nil; + if (_shouldInvalidateSession) { + [oldSession finishTasksAndInvalidate]; + } + } // @synchronized(self) + } +} +#endif + +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(GTM_NULLABLE NSError *)error { + // This may happen repeatedly for retries. On authentication callbacks, the retry + // may begin before the prior session sends the didBecomeInvalid delegate message. + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", + [self class], self, session, error); + if (session == (NSURLSession *)self.session) { + GTM_LOG_SESSION_DELEGATE(@" Unexpected retained invalid session: %@", session); + self.session = nil; + } +} + +- (void)finishWithError:(GTM_NULLABLE NSError *)error shouldRetry:(BOOL)shouldRetry { + [self removePersistedBackgroundSessionFromDefaults]; + + BOOL shouldStopFetching = YES; + NSData *downloadedData = nil; +#if !STRIP_GTM_FETCH_LOGGING + BOOL shouldDeferLogging = NO; +#endif + BOOL shouldBeginRetryTimer = NO; + NSInteger status = [self statusCode]; + NSURL *destinationURL = self.destinationFileURL; + + BOOL fetchSucceeded = (error == nil && status >= 0 && status < 300); + +#if !STRIP_GTM_FETCH_LOGGING + if (!fetchSucceeded) { + if (!shouldDeferLogging && !self.hasLoggedError) { + [self logNowWithError:error]; + self.hasLoggedError = YES; + } + } +#endif // !STRIP_GTM_FETCH_LOGGING + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if !STRIP_GTM_FETCH_LOGGING + shouldDeferLogging = _deferResponseBodyLogging; +#endif + if (fetchSucceeded) { + // Success + if ((_downloadedData.length > 0) && (destinationURL != nil)) { + // Overwrite any previous file at the destination URL. + NSFileManager *fileMgr = [NSFileManager defaultManager]; + [fileMgr removeItemAtURL:destinationURL + error:NULL]; + NSURL *destinationFolderURL = [destinationURL URLByDeletingLastPathComponent]; + BOOL didMoveDownload = NO; + if ([fileMgr createDirectoryAtURL:destinationFolderURL + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + didMoveDownload = [_downloadedData writeToURL:destinationURL + options:NSDataWritingAtomic + error:&error]; + } + if (didMoveDownload) { + _downloadedData = nil; + } else { + _downloadFinishedError = error; + } + } + downloadedData = _downloadedData; + } else { + // Unsuccessful with error or status over 300. Retry or notify the delegate of failure + if (shouldRetry) { + // Retrying. + shouldBeginRetryTimer = YES; + shouldStopFetching = NO; + } else { + if (error == nil) { + // Create an error. + NSDictionary *userInfo = nil; + if (_downloadedData.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : _downloadedData }; + } + error = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:status + userInfo:userInfo]; + } else { + // If the error had resume data, and the client supplied a resume block, pass the + // data to the client. + void (^resumeBlock)(NSData *) = _resumeDataBlock; + _resumeDataBlock = nil; + if (resumeBlock) { + NSData *resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]; + if (resumeData) { + [self invokeOnCallbackQueueAfterUserStopped:YES block:^{ + resumeBlock(resumeData); + }]; + } + } + } + if (_downloadedData.length > 0) { + downloadedData = _downloadedData; + } + // If the error occurred after retries, report the number and duration of the + // retries. This provides a clue to a developer looking at the error description + // that the fetcher did retry before failing with this error. + if (_retryCount > 0) { + NSMutableDictionary *userInfoWithRetries = + [NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)error.userInfo]; + NSTimeInterval timeSinceInitialRequest = -[_initialRequestDate timeIntervalSinceNow]; + [userInfoWithRetries setObject:@(timeSinceInitialRequest) + forKey:kGTMSessionFetcherElapsedIntervalWithRetriesKey]; + [userInfoWithRetries setObject:@(_retryCount) + forKey:kGTMSessionFetcherNumberOfRetriesDoneKey]; + error = [NSError errorWithDomain:(NSString *)error.domain + code:error.code + userInfo:userInfoWithRetries]; + } + } + } + } // @synchronized(self) + + if (shouldBeginRetryTimer) { + [self beginRetryTimer]; + } + + // We want to send the stop notification before calling the delegate's + // callback selector, since the callback selector may release all of + // the fetcher properties that the client is using to track the fetches. + // + // We'll also stop now so that, to any observers watching the notifications, + // it doesn't look like our wait for a retry (which may be long, + // 30 seconds or more) is part of the network activity. + [self sendStopNotificationIfNeeded]; + + if (shouldStopFetching) { + [self invokeFetchCallbacksOnCallbackQueueWithData:downloadedData + error:error]; + // The upload subclass doesn't want to release callbacks until upload chunks have completed. + BOOL shouldRelease = [self shouldReleaseCallbacksUponCompletion]; + [self stopFetchReleasingCallbacks:shouldRelease]; + } + +#if !STRIP_GTM_FETCH_LOGGING + // _hasLoggedError is only set by this method + if (!shouldDeferLogging && !_hasLoggedError) { + [self logNowWithError:error]; + } +#endif +} + +- (BOOL)shouldReleaseCallbacksUponCompletion { + // A subclass can override this to keep callbacks around after the + // connection has finished successfully + return YES; +} + +- (void)logNowWithError:(GTM_NULLABLE NSError *)error { + GTMSessionCheckNotSynchronized(self); + + // If the logging category is available, then log the current request, + // response, data, and error + if ([self respondsToSelector:@selector(logFetchWithError:)]) { + [self performSelector:@selector(logFetchWithError:) withObject:error]; + } +} + +#pragma mark Retries + +- (BOOL)isRetryError:(NSError *)error { + struct RetryRecord { + __unsafe_unretained NSString *const domain; + NSInteger code; + }; + + struct RetryRecord retries[] = { + { kGTMSessionFetcherStatusDomain, 408 }, // request timeout + { kGTMSessionFetcherStatusDomain, 502 }, // failure gatewaying to another server + { kGTMSessionFetcherStatusDomain, 503 }, // service unavailable + { kGTMSessionFetcherStatusDomain, 504 }, // request timeout + { NSURLErrorDomain, NSURLErrorTimedOut }, + { NSURLErrorDomain, NSURLErrorNetworkConnectionLost }, + { nil, 0 } + }; + + // NSError's isEqual always returns false for equal but distinct instances + // of NSError, so we have to compare the domain and code values explicitly + NSString *domain = error.domain; + NSInteger code = error.code; + for (int idx = 0; retries[idx].domain != nil; idx++) { + if (code == retries[idx].code && [domain isEqual:retries[idx].domain]) { + return YES; + } + } + return NO; +} + +// shouldRetryNowForStatus:error: responds with YES if the user has enabled retries +// and the status or error is one that is suitable for retrying. "Suitable" +// means either the isRetryError:'s list contains the status or error, or the +// user's retry block is present and returns YES when called, or the +// authorizer may be able to fix. +- (void)shouldRetryNowForStatus:(NSInteger)status + error:(NSError *)error + forceAssumeRetry:(BOOL)forceAssumeRetry + response:(GTMSessionFetcherRetryResponse)response { + // Determine if a refreshed authorizer may avoid an authorization error + BOOL willRetry = NO; + + // We assume _authorizer is immutable after beginFetch, and _hasAttemptedAuthRefresh is modified + // only in this method, and this method is invoked on the serial delegate queue. + // + // We want to avoid calling the authorizer from inside a sync block. + BOOL isFirstAuthError = (_authorizer != nil + && !_hasAttemptedAuthRefresh + && status == GTMSessionFetcherStatusUnauthorized); // 401 + + BOOL hasPrimed = NO; + if (isFirstAuthError) { + if ([_authorizer respondsToSelector:@selector(primeForRefresh)]) { + hasPrimed = [_authorizer primeForRefresh]; + } + } + + BOOL shouldRetryForAuthRefresh = NO; + if (hasPrimed) { + shouldRetryForAuthRefresh = YES; + _hasAttemptedAuthRefresh = YES; + [self updateRequestValue:nil forHTTPHeaderField:@"Authorization"]; + } + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL shouldDoRetry = [self isRetryEnabledUnsynchronized]; + if (shouldDoRetry && ![self hasRetryAfterInterval]) { + + // Determine if we're doing exponential backoff retries + shouldDoRetry = [self nextRetryIntervalUnsynchronized] < _maxRetryInterval; + + if (shouldDoRetry) { + // If an explicit max retry interval was set, we expect repeated backoffs to take + // up to roughly twice that for repeated fast failures. If the initial attempt is + // already more than 3 times the max retry interval, then failures have taken a long time + // (such as from network timeouts) so don't retry again to avoid the app becoming + // unexpectedly unresponsive. + if (_maxRetryInterval > 0) { + NSTimeInterval maxAllowedIntervalBeforeRetry = _maxRetryInterval * 3; + NSTimeInterval timeSinceInitialRequest = -[_initialRequestDate timeIntervalSinceNow]; + if (timeSinceInitialRequest > maxAllowedIntervalBeforeRetry) { + shouldDoRetry = NO; + } + } + } + } + BOOL canRetry = shouldRetryForAuthRefresh || forceAssumeRetry || shouldDoRetry; + if (canRetry) { + NSDictionary *userInfo = nil; + if (_downloadedData.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : _downloadedData }; + } + NSError *statusError = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:status + userInfo:userInfo]; + if (error == nil) { + error = statusError; + } + willRetry = shouldRetryForAuthRefresh || + forceAssumeRetry || + [self isRetryError:error] || + ((error != statusError) && [self isRetryError:statusError]); + + // If the user has installed a retry callback, consult that. + GTMSessionFetcherRetryBlock retryBlock = _retryBlock; + if (retryBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + retryBlock(willRetry, error, response); + }]; + return; + } + } + } // @synchronized(self) + response(willRetry); +} + +- (BOOL)hasRetryAfterInterval { + GTMSessionCheckSynchronized(self); + + NSDictionary *responseHeaders = [self responseHeadersUnsynchronized]; + NSString *retryAfterValue = [responseHeaders valueForKey:@"Retry-After"]; + return (retryAfterValue != nil); +} + +- (NSTimeInterval)retryAfterInterval { + GTMSessionCheckSynchronized(self); + + NSDictionary *responseHeaders = [self responseHeadersUnsynchronized]; + NSString *retryAfterValue = [responseHeaders valueForKey:@"Retry-After"]; + if (retryAfterValue == nil) { + return 0; + } + // Retry-After formatted as HTTP-date | delta-seconds + // Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + NSDateFormatter *rfc1123DateFormatter = [[NSDateFormatter alloc] init]; + rfc1123DateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; + rfc1123DateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + rfc1123DateFormatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss z"; + NSDate *retryAfterDate = [rfc1123DateFormatter dateFromString:retryAfterValue]; + NSTimeInterval retryAfterInterval = (retryAfterDate != nil) ? + retryAfterDate.timeIntervalSinceNow : retryAfterValue.intValue; + retryAfterInterval = MAX(0, retryAfterInterval); + return retryAfterInterval; +} + +- (void)beginRetryTimer { + if (![NSThread isMainThread]) { + // Defer creating and starting the timer until we're on the main thread to ensure it has + // a run loop. + dispatch_group_async(_callbackGroup, dispatch_get_main_queue(), ^{ + [self beginRetryTimer]; + }); + return; + } + + [self destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval nextInterval = [self nextRetryIntervalUnsynchronized]; + NSTimeInterval maxInterval = _maxRetryInterval; + NSTimeInterval newInterval = MIN(nextInterval, (maxInterval > 0 ? maxInterval : DBL_MAX)); + NSTimeInterval newIntervalTolerance = (newInterval / 10) > 1.0 ?: 1.0; + + _lastRetryInterval = newInterval; + + _retryTimer = [NSTimer timerWithTimeInterval:newInterval + target:self + selector:@selector(retryTimerFired:) + userInfo:nil + repeats:NO]; + _retryTimer.tolerance = newIntervalTolerance; + [[NSRunLoop mainRunLoop] addTimer:_retryTimer + forMode:NSDefaultRunLoopMode]; + } // @synchronized(self) + + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherRetryDelayStartedNotification + userInfo:nil + requireAsync:NO]; +} + +- (void)retryTimerFired:(NSTimer *)timer { + [self destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _retryCount++; + } // @synchronized(self) + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + [self retryFetch]; + }]; +} + +- (void)destroyRetryTimer { + BOOL shouldNotify = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_retryTimer) { + [_retryTimer invalidate]; + _retryTimer = nil; + shouldNotify = YES; + } + } + + if (shouldNotify) { + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherRetryDelayStoppedNotification + userInfo:nil + requireAsync:NO]; + } +} + +- (NSUInteger)retryCount { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _retryCount; + } // @synchronized(self) +} + +- (NSTimeInterval)nextRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval interval = [self nextRetryIntervalUnsynchronized]; + return interval; + } // @synchronized(self) +} + +- (NSTimeInterval)nextRetryIntervalUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSInteger statusCode = [self statusCodeUnsynchronized]; + if ((statusCode == 503) && [self hasRetryAfterInterval]) { + NSTimeInterval secs = [self retryAfterInterval]; + return secs; + } + // The next wait interval is the factor (2.0) times the last interval, + // but never less than the minimum interval. + NSTimeInterval secs = _lastRetryInterval * _retryFactor; + if (_maxRetryInterval > 0) { + secs = MIN(secs, _maxRetryInterval); + } + secs = MAX(secs, _minRetryInterval); + + return secs; +} + +- (NSTimer *)retryTimer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _retryTimer; + } // @synchronized(self) +} + +- (BOOL)isRetryEnabled { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isRetryEnabled; + } // @synchronized(self) +} + +- (BOOL)isRetryEnabledUnsynchronized { + GTMSessionCheckSynchronized(self); + + return _isRetryEnabled; +} + +- (void)setRetryEnabled:(BOOL)flag { + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag && !_isRetryEnabled) { + // We defer initializing these until the user calls setRetryEnabled + // to avoid using the random number generator if it's not needed. + // However, this means min and max intervals for this fetcher are reset + // as a side effect of calling setRetryEnabled. + // + // Make an initial retry interval random between 1.0 and 2.0 seconds + _minRetryInterval = InitialMinRetryInterval(); + _maxRetryInterval = kUnsetMaxRetryInterval; + _retryFactor = 2.0; + _lastRetryInterval = 0.0; + } + _isRetryEnabled = flag; + } // @synchronized(self) +}; + +- (NSTimeInterval)maxRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _maxRetryInterval; + } // @synchronized(self) +} + +- (void)setMaxRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _maxRetryInterval = secs; + } else { + _maxRetryInterval = kUnsetMaxRetryInterval; + } + } // @synchronized(self) +} + +- (double)minRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _minRetryInterval; + } // @synchronized(self) +} + +- (void)setMinRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _minRetryInterval = secs; + } else { + // Set min interval to a random value between 1.0 and 2.0 seconds + // so that if multiple clients start retrying at the same time, they'll + // repeat at different times and avoid overloading the server + _minRetryInterval = InitialMinRetryInterval(); + } + } // @synchronized(self) + +} + +#pragma mark iOS System Completion Handlers + +#if TARGET_OS_IPHONE +static NSMutableDictionary *gSystemCompletionHandlers = nil; + +- (GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler { + return [[self class] systemCompletionHandlerForSessionIdentifier:_sessionIdentifier]; +} + +- (void)setSystemCompletionHandler:(GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler { + [[self class] setSystemCompletionHandler:systemCompletionHandler + forSessionIdentifier:_sessionIdentifier]; +} + ++ (void)setSystemCompletionHandler:(GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler + forSessionIdentifier:(NSString *)sessionIdentifier { + if (!sessionIdentifier) { + NSLog(@"%s with nil identifier", __PRETTY_FUNCTION__); + return; + } + + @synchronized([GTMSessionFetcher class]) { + if (gSystemCompletionHandlers == nil && systemCompletionHandler != nil) { + gSystemCompletionHandlers = [[NSMutableDictionary alloc] init]; + } + // Use setValue: to remove the object if completionHandler is nil. + [gSystemCompletionHandlers setValue:systemCompletionHandler + forKey:sessionIdentifier]; + } +} + ++ (GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandlerForSessionIdentifier:(NSString *)sessionIdentifier { + if (!sessionIdentifier) { + return nil; + } + @synchronized([GTMSessionFetcher class]) { + return [gSystemCompletionHandlers objectForKey:sessionIdentifier]; + } +} +#endif // TARGET_OS_IPHONE + +#pragma mark Getters and Setters + +@synthesize downloadResumeData = _downloadResumeData, + configuration = _configuration, + configurationBlock = _configurationBlock, + sessionTask = _sessionTask, + wasCreatedFromBackgroundSession = _wasCreatedFromBackgroundSession, + sessionUserInfo = _sessionUserInfo, + taskDescription = _taskDescription, + taskPriority = _taskPriority, + usingBackgroundSession = _usingBackgroundSession, + canShareSession = _canShareSession, + completionHandler = _completionHandler, + credential = _credential, + proxyCredential = _proxyCredential, + bodyData = _bodyData, + bodyLength = _bodyLength, + service = _service, + serviceHost = _serviceHost, + accumulateDataBlock = _accumulateDataBlock, + receivedProgressBlock = _receivedProgressBlock, + downloadProgressBlock = _downloadProgressBlock, + resumeDataBlock = _resumeDataBlock, + didReceiveResponseBlock = _didReceiveResponseBlock, + challengeBlock = _challengeBlock, + willRedirectBlock = _willRedirectBlock, + sendProgressBlock = _sendProgressBlock, + willCacheURLResponseBlock = _willCacheURLResponseBlock, + retryBlock = _retryBlock, + retryFactor = _retryFactor, + allowedInsecureSchemes = _allowedInsecureSchemes, + allowLocalhostRequest = _allowLocalhostRequest, + allowInvalidServerCertificates = _allowInvalidServerCertificates, + cookieStorage = _cookieStorage, + callbackQueue = _callbackQueue, + initialBeginFetchDate = _initialBeginFetchDate, + testBlock = _testBlock, + testBlockAccumulateDataChunkCount = _testBlockAccumulateDataChunkCount, + comment = _comment, + log = _log; + +#if !STRIP_GTM_FETCH_LOGGING +@synthesize redirectedFromURL = _redirectedFromURL, + logRequestBody = _logRequestBody, + logResponseBody = _logResponseBody, + hasLoggedError = _hasLoggedError; +#endif + +#if GTM_BACKGROUND_TASK_FETCHING +@synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier, + skipBackgroundTask = _skipBackgroundTask; +#endif + +- (GTM_NULLABLE NSURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_request copy]; + } // @synchronized(self) +} + +- (void)setRequest:(GTM_NULLABLE NSURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (![self isFetchingUnsynchronized]) { + _request = [request mutableCopy]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"request may not be set after beginFetch has been invoked"); + } + } // @synchronized(self) +} + +- (GTM_NULLABLE NSMutableURLRequest *)mutableRequestForTesting { + // Allow tests only to modify the request, useful during retries. + return _request; +} + +- (GTM_NULLABLE NSMutableURLRequest *)mutableRequest { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_LOG_DEBUG(@"[GTMSessionFetcher mutableRequest] is deprecated; use -request or" + @" -setRequestValue:forHTTPHeaderField:"); + + return _request; + } // @synchronized(self) +} + +- (void)setMutableRequest:(GTM_NULLABLE NSMutableURLRequest *)request { + GTMSESSION_LOG_DEBUG(@"[GTMSessionFetcher setMutableRequest:] is deprecated; use -request or" + @" -setRequestValue:forHTTPHeaderField:"); + + GTMSESSION_ASSERT_DEBUG(![self isFetching], + @"mutableRequest should not change after beginFetch has been invoked"); + [self updateMutableRequest:request]; +} + +// Internal method for updating the request property such as on redirects. +- (void)updateMutableRequest:(GTM_NULLABLE NSMutableURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _request = request; + } // @synchronized(self) +} + +// Set a header field value on the request. Header field value changes will not +// affect a fetch after the fetch has begun. +- (void)setRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field { + if (![self isFetching]) { + [self updateRequestValue:value forHTTPHeaderField:field]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"request may not be set after beginFetch has been invoked"); + } +} + +// Internal method for updating request headers. +- (void)updateRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_request setValue:value forHTTPHeaderField:field]; + } // @synchronized(self) +} + +- (void)setResponse:(GTM_NULLABLE NSURLResponse *)response { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _response = response; + } // @synchronized(self) +} + +- (int64_t)bodyLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_bodyLength == NSURLSessionTransferSizeUnknown) { + if (_bodyData) { + _bodyLength = (int64_t)_bodyData.length; + } else if (_bodyFileURL) { + NSNumber *fileSizeNum = nil; + NSError *fileSizeError = nil; + if ([_bodyFileURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:&fileSizeError]) { + _bodyLength = [fileSizeNum longLongValue]; + } + } + } + return _bodyLength; + } // @synchronized(self) +} + +- (BOOL)useUploadTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _useUploadTask; + } // @synchronized(self) +} + +- (void)setUseUploadTask:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag != _useUploadTask) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"useUploadTask should not change after beginFetch has been invoked"); + _useUploadTask = flag; + } + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURL *)bodyFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _bodyFileURL; + } // @synchronized(self) +} + +- (void)setBodyFileURL:(GTM_NULLABLE NSURL *)fileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // The comparison here is a trivial optimization and forgiveness for any client that + // repeatedly sets the property, so it just uses pointer comparison rather than isEqual:. + if (fileURL != _bodyFileURL) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"fileURL should not change after beginFetch has been invoked"); + + _bodyFileURL = fileURL; + } + } // @synchronized(self) +} + +- (GTM_NULLABLE GTMSessionFetcherBodyStreamProvider)bodyStreamProvider { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _bodyStreamProvider; + } // @synchronized(self) +} + +- (void)setBodyStreamProvider:(GTM_NULLABLE GTMSessionFetcherBodyStreamProvider)block { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"stream provider should not change after beginFetch has been invoked"); + + _bodyStreamProvider = [block copy]; + } // @synchronized(self) +} + +- (GTM_NULLABLE id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _authorizer; + } // @synchronized(self) +} + +- (void)setAuthorizer:(GTM_NULLABLE id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (authorizer != _authorizer) { + if ([self isFetchingUnsynchronized]) { + GTMSESSION_ASSERT_DEBUG(0, @"authorizer should not change after beginFetch has been invoked"); + } else { + _authorizer = authorizer; + } + } + } // @synchronized(self) +} + +- (GTM_NULLABLE NSData *)downloadedData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _downloadedData; + } // @synchronized(self) +} + +- (void)setDownloadedData:(GTM_NULLABLE NSData *)data { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _downloadedData = [data mutableCopy]; + } // @synchronized(self) +} + +- (int64_t)downloadedLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _downloadedLength; + } // @synchronized(self) +} + +- (void)setDownloadedLength:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _downloadedLength = length; + } // @synchronized(self) +} + +- (dispatch_queue_t GTM_NONNULL_TYPE)callbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _callbackQueue; + } // @synchronized(self) +} + +- (void)setCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _callbackQueue = queue ?: dispatch_get_main_queue(); + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _session; + } // @synchronized(self) +} + +- (NSInteger)servicePriority { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _servicePriority; + } // @synchronized(self) +} + +- (void)setServicePriority:(NSInteger)value { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (value != _servicePriority) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"servicePriority should not change after beginFetch has been invoked"); + + _servicePriority = value; + } + } // @synchronized(self) +} + + +- (void)setSession:(GTM_NULLABLE NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = session; + } // @synchronized(self) +} + +- (BOOL)canShareSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _canShareSession; + } // @synchronized(self) +} + +- (void)setCanShareSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _canShareSession = flag; + } // @synchronized(self) +} + +- (BOOL)useBackgroundSession { + // This reflects if the user requested a background session, not necessarily + // if one was created. That is tracked with _usingBackgroundSession. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userRequestedBackgroundSession; + } // @synchronized(self) +} + +- (void)setUseBackgroundSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag != _userRequestedBackgroundSession) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"useBackgroundSession should not change after beginFetch has been invoked"); + + _userRequestedBackgroundSession = flag; + } + } // @synchronized(self) +} + +- (BOOL)isUsingBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _usingBackgroundSession; + } // @synchronized(self) +} + +- (void)setUsingBackgroundSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _usingBackgroundSession = flag; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURLSession *)sessionNeedingInvalidation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionNeedingInvalidation; + } // @synchronized(self) +} + +- (void)setSessionNeedingInvalidation:(GTM_NULLABLE NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _sessionNeedingInvalidation = session; + } // @synchronized(self) +} + +- (NSOperationQueue * GTM_NONNULL_TYPE)sessionDelegateQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateQueue; + } // @synchronized(self) +} + +- (void)setSessionDelegateQueue:(NSOperationQueue * GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (queue != _delegateQueue) { + if ([self isFetchingUnsynchronized]) { + GTMSESSION_ASSERT_DEBUG(0, @"sessionDelegateQueue should not change after fetch begins"); + } else { + _delegateQueue = queue ?: [NSOperationQueue mainQueue]; + } + } + } // @synchronized(self) +} + +- (BOOL)userStoppedFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userStoppedFetching; + } // @synchronized(self) +} + +- (GTM_NULLABLE id)userData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userData; + } // @synchronized(self) +} + +- (void)setUserData:(GTM_NULLABLE id)theObj { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _userData = theObj; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURL *)destinationFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _destinationFileURL; + } // @synchronized(self) +} + +- (void)setDestinationFileURL:(GTM_NULLABLE NSURL *)destinationFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (((_destinationFileURL == nil) && (destinationFileURL == nil)) || + [_destinationFileURL isEqual:destinationFileURL]) { + return; + } + if (_sessionIdentifier) { + // This is something we don't expect to happen in production. + // However if it ever happen, leave a system log. + NSLog(@"%@: Destination File URL changed from (%@) to (%@) after session identifier has " + @"been created.", + [self class], _destinationFileURL, destinationFileURL); +#if DEBUG + // On both the simulator and devices, the path can change to the download file, but the name + // shouldn't change. Technically, this isn't supported in the fetcher, but the change of + // URL is expected to happen only across development runs through Xcode. + NSString *oldFilename = [_destinationFileURL lastPathComponent]; + NSString *newFilename = [destinationFileURL lastPathComponent]; + #pragma unused(oldFilename) + #pragma unused(newFilename) + GTMSESSION_ASSERT_DEBUG([oldFilename isEqualToString:newFilename], + @"Destination File URL cannot be changed after session identifier has been created"); +#endif + } + _destinationFileURL = destinationFileURL; + } // @synchronized(self) +} + +- (void)setProperties:(GTM_NULLABLE NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _properties = [dict mutableCopy]; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSDictionary *)properties { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _properties; + } // @synchronized(self) +} + +- (void)setProperty:(GTM_NULLABLE id)obj forKey:(NSString *)key { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_properties == nil && obj != nil) { + _properties = [[NSMutableDictionary alloc] init]; + } + [_properties setValue:obj forKey:key]; + } // @synchronized(self) +} + +- (GTM_NULLABLE id)propertyForKey:(NSString *)key { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_properties objectForKey:key]; + } // @synchronized(self) +} + +- (void)addPropertiesFromDictionary:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_properties == nil && dict != nil) { + [self setProperties:[dict mutableCopy]]; + } else { + [_properties addEntriesFromDictionary:dict]; + } + } // @synchronized(self) +} + +- (void)setCommentWithFormat:(id)format, ... { +#if !STRIP_GTM_FETCH_LOGGING + NSString *result = format; + if (format) { + va_list argList; + va_start(argList, format); + + result = [[NSString alloc] initWithFormat:format + arguments:argList]; + va_end(argList); + } + [self setComment:result]; +#endif +} + +#if !STRIP_GTM_FETCH_LOGGING +- (NSData *)loggedStreamData { + return _loggedStreamData; +} + +- (void)appendLoggedStreamData:dataToAdd { + if (!_loggedStreamData) { + _loggedStreamData = [NSMutableData data]; + } + [_loggedStreamData appendData:dataToAdd]; +} + +- (void)clearLoggedStreamData { + _loggedStreamData = nil; +} + +- (void)setDeferResponseBodyLogging:(BOOL)deferResponseBodyLogging { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (deferResponseBodyLogging != _deferResponseBodyLogging) { + _deferResponseBodyLogging = deferResponseBodyLogging; + if (!deferResponseBodyLogging && !self.hasLoggedError) { + [_delegateQueue addOperationWithBlock:^{ + [self logNowWithError:nil]; + }]; + } + } + } // @synchronized(self) +} + +- (BOOL)deferResponseBodyLogging { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _deferResponseBodyLogging; + } // @synchronized(self) +} + +#else ++ (void)setLoggingEnabled:(BOOL)flag { +} + ++ (BOOL)isLoggingEnabled { + return NO; +} +#endif // STRIP_GTM_FETCH_LOGGING + +@end + +@implementation GTMSessionFetcher (BackwardsCompatibilityOnly) + +- (void)setCookieStorageMethod:(NSInteger)method { + // For backwards compatibility with the old fetcher, we'll support the old constants. + // + // Clients using the GTMSessionFetcher class should set the cookie storage explicitly + // themselves. + NSHTTPCookieStorage *storage = nil; + switch(method) { + case 0: // kGTMHTTPFetcherCookieStorageMethodStatic + // nil storage will use [[self class] staticCookieStorage] when the fetch begins. + break; + case 1: // kGTMHTTPFetcherCookieStorageMethodFetchHistory + // Do nothing; use whatever was set by the fetcher service. + return; + case 2: // kGTMHTTPFetcherCookieStorageMethodSystemDefault + storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + break; + case 3: // kGTMHTTPFetcherCookieStorageMethodNone + // Create temporary storage for this fetcher only. + storage = [[GTMSessionCookieStorage alloc] init]; + break; + default: + GTMSESSION_ASSERT_DEBUG(0, @"Invalid cookie storage method: %d", (int)method); + } + self.cookieStorage = storage; +} + +@end + +@implementation GTMSessionCookieStorage { + NSMutableArray *_cookies; + NSHTTPCookieAcceptPolicy _policy; +} + +- (id)init { + self = [super init]; + if (self != nil) { + _cookies = [[NSMutableArray alloc] init]; + } + return self; +} + +- (GTM_NULLABLE NSArray *)cookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_cookies copy]; + } // @synchronized(self) +} + +- (void)setCookie:(NSHTTPCookie *)cookie { + if (!cookie) return; + if (_policy == NSHTTPCookieAcceptPolicyNever) return; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self internalSetCookie:cookie]; + } // @synchronized(self) +} + +// Note: this should only be called from inside a @synchronized(self) block. +- (void)internalSetCookie:(NSHTTPCookie *)newCookie { + GTMSessionCheckSynchronized(self); + + if (_policy == NSHTTPCookieAcceptPolicyNever) return; + + BOOL isValidCookie = (newCookie.name.length > 0 + && newCookie.domain.length > 0 + && newCookie.path.length > 0); + GTMSESSION_ASSERT_DEBUG(isValidCookie, @"invalid cookie: %@", newCookie); + + if (isValidCookie) { + // Remove the cookie if it's currently in the array. + NSHTTPCookie *oldCookie = [self cookieMatchingCookie:newCookie]; + if (oldCookie) { + [_cookies removeObjectIdenticalTo:oldCookie]; + } + + if (![[self class] hasCookieExpired:newCookie]) { + [_cookies addObject:newCookie]; + } + } +} + +// Add all cookies in the new cookie array to the storage, +// replacing stored cookies as appropriate. +// +// Side effect: removes expired cookies from the storage array. +- (void)setCookies:(GTM_NULLABLE NSArray *)newCookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self removeExpiredCookies]; + + for (NSHTTPCookie *newCookie in newCookies) { + [self internalSetCookie:newCookie]; + } + } // @synchronized(self) +} + +- (void)setCookies:(NSArray *)cookies forURL:(GTM_NULLABLE NSURL *)URL mainDocumentURL:(GTM_NULLABLE NSURL *)mainDocumentURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_policy == NSHTTPCookieAcceptPolicyNever) { + return; + } + + if (_policy == NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain) { + NSString *mainHost = mainDocumentURL.host; + NSString *associatedHost = URL.host; + if (!mainHost || ![associatedHost hasSuffix:mainHost]) { + return; + } + } + } // @synchronized(self) + [self setCookies:cookies]; +} + +- (void)deleteCookie:(NSHTTPCookie *)cookie { + if (!cookie) return; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSHTTPCookie *foundCookie = [self cookieMatchingCookie:cookie]; + if (foundCookie) { + [_cookies removeObjectIdenticalTo:foundCookie]; + } + } // @synchronized(self) +} + +// Retrieve all cookies appropriate for the given URL, considering +// domain, path, cookie name, expiration, security setting. +// Side effect: removed expired cookies from the storage array. +- (GTM_NULLABLE NSArray *)cookiesForURL:(NSURL *)theURL { + NSMutableArray *foundCookies = nil; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self removeExpiredCookies]; + + // We'll prepend "." to the desired domain, since we want the + // actual domain "nytimes.com" to still match the cookie domain + // ".nytimes.com" when we check it below with hasSuffix. + NSString *host = theURL.host.lowercaseString; + NSString *path = theURL.path; + NSString *scheme = [theURL scheme]; + + NSString *requestingDomain = nil; + BOOL isLocalhostRetrieval = NO; + + if (IsLocalhost(host)) { + isLocalhostRetrieval = YES; + } else { + if (host.length > 0) { + requestingDomain = [@"." stringByAppendingString:host]; + } + } + + for (NSHTTPCookie *storedCookie in _cookies) { + NSString *cookieDomain = storedCookie.domain.lowercaseString; + NSString *cookiePath = storedCookie.path; + BOOL cookieIsSecure = [storedCookie isSecure]; + + BOOL isDomainOK; + + if (isLocalhostRetrieval) { + // Prior to 10.5.6, the domain stored into NSHTTPCookies for localhost + // is "localhost.local" + isDomainOK = (IsLocalhost(cookieDomain) + || [cookieDomain isEqual:@"localhost.local"]); + } else { + // Ensure we're matching exact domain names. We prepended a dot to the + // requesting domain, so we can also prepend one here if needed before + // checking if the request contains the cookie domain. + if (![cookieDomain hasPrefix:@"."]) { + cookieDomain = [@"." stringByAppendingString:cookieDomain]; + } + isDomainOK = [requestingDomain hasSuffix:cookieDomain]; + } + + BOOL isPathOK = [cookiePath isEqual:@"/"] || [path hasPrefix:cookiePath]; + BOOL isSecureOK = (!cookieIsSecure + || [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame); + + if (isDomainOK && isPathOK && isSecureOK) { + if (foundCookies == nil) { + foundCookies = [NSMutableArray array]; + } + [foundCookies addObject:storedCookie]; + } + } + } // @synchronized(self) + return foundCookies; +} + +// Override methods from the NSHTTPCookieStorage (NSURLSessionTaskAdditions) category. +- (void)storeCookies:(NSArray *)cookies forTask:(NSURLSessionTask *)task { + NSURLRequest *currentRequest = task.currentRequest; + [self setCookies:cookies forURL:currentRequest.URL mainDocumentURL:nil]; +} + +- (void)getCookiesForTask:(NSURLSessionTask *)task + completionHandler:(void (^)(GTM_NSArrayOf(NSHTTPCookie *) *))completionHandler { + if (completionHandler) { + NSURLRequest *currentRequest = task.currentRequest; + NSURL *currentRequestURL = currentRequest.URL; + NSArray *cookies = [self cookiesForURL:currentRequestURL]; + completionHandler(cookies); + } +} + +// Return a cookie from the array with the same name, domain, and path as the +// given cookie, or else return nil if none found. +// +// Both the cookie being tested and all cookies in the storage array should +// be valid (non-nil name, domains, paths). +// +// Note: this should only be called from inside a @synchronized(self) block +- (GTM_NULLABLE NSHTTPCookie *)cookieMatchingCookie:(NSHTTPCookie *)cookie { + GTMSessionCheckSynchronized(self); + + NSString *name = cookie.name; + NSString *domain = cookie.domain; + NSString *path = cookie.path; + + GTMSESSION_ASSERT_DEBUG(name && domain && path, + @"Invalid stored cookie (name:%@ domain:%@ path:%@)", name, domain, path); + + for (NSHTTPCookie *storedCookie in _cookies) { + if ([storedCookie.name isEqual:name] + && [storedCookie.domain isEqual:domain] + && [storedCookie.path isEqual:path]) { + return storedCookie; + } + } + return nil; +} + +// Internal routine to remove any expired cookies from the array, excluding +// cookies with nil expirations. +// +// Note: this should only be called from inside a @synchronized(self) block +- (void)removeExpiredCookies { + GTMSessionCheckSynchronized(self); + + // Count backwards since we're deleting items from the array + for (NSInteger idx = (NSInteger)_cookies.count - 1; idx >= 0; idx--) { + NSHTTPCookie *storedCookie = [_cookies objectAtIndex:(NSUInteger)idx]; + if ([[self class] hasCookieExpired:storedCookie]) { + [_cookies removeObjectAtIndex:(NSUInteger)idx]; + } + } +} + ++ (BOOL)hasCookieExpired:(NSHTTPCookie *)cookie { + NSDate *expiresDate = [cookie expiresDate]; + if (expiresDate == nil) { + // Cookies seem to have a Expires property even when the expiresDate method returns nil. + id expiresVal = [[cookie properties] objectForKey:NSHTTPCookieExpires]; + if ([expiresVal isKindOfClass:[NSDate class]]) { + expiresDate = expiresVal; + } + } + BOOL hasExpired = (expiresDate != nil && [expiresDate timeIntervalSinceNow] < 0); + return hasExpired; +} + +- (void)removeAllCookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_cookies removeAllObjects]; + } // @synchronized(self) +} + +- (NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _policy; + } // @synchronized(self) +} + +- (void)setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _policy = cookieAcceptPolicy; + } // @synchronized(self) +} + +@end + +void GTMSessionFetcherAssertValidSelector(id GTM_NULLABLE_TYPE obj, SEL GTM_NULLABLE_TYPE sel, ...) { + // Verify that the object's selector is implemented with the proper + // number and type of arguments +#if DEBUG + va_list argList; + va_start(argList, sel); + + if (obj && sel) { + // Check that the selector is implemented + if (![obj respondsToSelector:sel]) { + NSLog(@"\"%@\" selector \"%@\" is unimplemented or misnamed", + NSStringFromClass([(id)obj class]), + NSStringFromSelector((SEL)sel)); + NSCAssert(0, @"callback selector unimplemented or misnamed"); + } else { + const char *expectedArgType; + unsigned int argCount = 2; // skip self and _cmd + NSMethodSignature *sig = [obj methodSignatureForSelector:sel]; + + // Check that each expected argument is present and of the correct type + while ((expectedArgType = va_arg(argList, const char*)) != 0) { + + if ([sig numberOfArguments] > argCount) { + const char *foundArgType = [sig getArgumentTypeAtIndex:argCount]; + + if (0 != strncmp(foundArgType, expectedArgType, strlen(expectedArgType))) { + NSLog(@"\"%@\" selector \"%@\" argument %d should be type %s", + NSStringFromClass([(id)obj class]), + NSStringFromSelector((SEL)sel), (argCount - 2), expectedArgType); + NSCAssert(0, @"callback selector argument type mistake"); + } + } + argCount++; + } + + // Check that the proper number of arguments are present in the selector + if (argCount != [sig numberOfArguments]) { + NSLog(@"\"%@\" selector \"%@\" should have %d arguments", + NSStringFromClass([(id)obj class]), + NSStringFromSelector((SEL)sel), (argCount - 2)); + NSCAssert(0, @"callback selector arguments incorrect"); + } + } + } + + va_end(argList); +#endif +} + +NSString *GTMFetcherCleanedUserAgentString(NSString *str) { + // Reference http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html + // and http://www-archive.mozilla.org/build/user-agent-strings.html + + if (str == nil) return @""; + + NSMutableString *result = [NSMutableString stringWithString:str]; + + // Replace spaces and commas with underscores + [result replaceOccurrencesOfString:@" " + withString:@"_" + options:0 + range:NSMakeRange(0, result.length)]; + [result replaceOccurrencesOfString:@"," + withString:@"_" + options:0 + range:NSMakeRange(0, result.length)]; + + // Delete http token separators and remaining whitespace + static NSCharacterSet *charsToDelete = nil; + if (charsToDelete == nil) { + // Make a set of unwanted characters + NSString *const kSeparators = @"()<>@;:\\\"/[]?={}"; + + NSMutableCharacterSet *mutableChars = + [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy]; + [mutableChars addCharactersInString:kSeparators]; + charsToDelete = [mutableChars copy]; // hang on to an immutable copy + } + + while (1) { + NSRange separatorRange = [result rangeOfCharacterFromSet:charsToDelete]; + if (separatorRange.location == NSNotFound) break; + + [result deleteCharactersInRange:separatorRange]; + }; + + return result; +} + +NSString *GTMFetcherSystemVersionString(void) { + static NSString *sSavedSystemString; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // The Xcode 8 SDKs finally cleaned up this mess by providing TARGET_OS_OSX + // and TARGET_OS_IOS, but to build with older SDKs, those don't exist and + // instead one has to rely on TARGET_OS_MAC (which is true for iOS, watchOS, + // and tvOS) and TARGET_OS_IPHONE (which is true for iOS, watchOS, tvOS). So + // one has to order these carefully so you pick off the specific things + // first. + // If the code can ever assume Xcode 8 or higher (even when building for + // older OSes), then + // TARGET_OS_MAC -> TARGET_OS_OSX + // TARGET_OS_IPHONE -> TARGET_OS_IOS + // TARGET_IPHONE_SIMULATOR -> TARGET_OS_SIMULATOR +#if TARGET_OS_WATCH + // watchOS - WKInterfaceDevice + + WKInterfaceDevice *currentDevice = [WKInterfaceDevice currentDevice]; + + NSString *rawModel = [currentDevice model]; + NSString *model = GTMFetcherCleanedUserAgentString(rawModel); + + NSString *systemVersion = [currentDevice systemVersion]; + +#if TARGET_OS_SIMULATOR + NSString *hardwareModel = @"sim"; +#else + NSString *hardwareModel; + struct utsname unameRecord; + if (uname(&unameRecord) == 0) { + NSString *machineName = @(unameRecord.machine); + hardwareModel = GTMFetcherCleanedUserAgentString(machineName); + } + if (hardwareModel.length == 0) { + hardwareModel = @"unk"; + } +#endif + + sSavedSystemString = [[NSString alloc] initWithFormat:@"%@/%@ hw/%@", + model, systemVersion, hardwareModel]; + // Example: Apple_Watch/3.0 hw/Watch1_2 +#elif TARGET_OS_TV || TARGET_OS_IPHONE + // iOS and tvOS have UIDevice, use that. + UIDevice *currentDevice = [UIDevice currentDevice]; + + NSString *rawModel = [currentDevice model]; + NSString *model = GTMFetcherCleanedUserAgentString(rawModel); + + NSString *systemVersion = [currentDevice systemVersion]; + +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_SIMULATOR + NSString *hardwareModel = @"sim"; +#else + NSString *hardwareModel; + struct utsname unameRecord; + if (uname(&unameRecord) == 0) { + NSString *machineName = @(unameRecord.machine); + hardwareModel = GTMFetcherCleanedUserAgentString(machineName); + } + if (hardwareModel.length == 0) { + hardwareModel = @"unk"; + } +#endif + + sSavedSystemString = [[NSString alloc] initWithFormat:@"%@/%@ hw/%@", + model, systemVersion, hardwareModel]; + // Example: iPod_Touch/2.2 hw/iPod1_1 + // Example: Apple_TV/9.2 hw/AppleTV5,3 +#elif TARGET_OS_MAC + // Mac build + NSProcessInfo *procInfo = [NSProcessInfo processInfo]; +#if !defined(MAC_OS_X_VERSION_10_10) + BOOL hasOperatingSystemVersion = NO; +#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10 + BOOL hasOperatingSystemVersion = + [procInfo respondsToSelector:@selector(operatingSystemVersion)]; +#else + BOOL hasOperatingSystemVersion = YES; +#endif + NSString *versString; + if (hasOperatingSystemVersion) { +#if defined(MAC_OS_X_VERSION_10_10) + // A reference to NSOperatingSystemVersion requires the 10.10 SDK. + NSOperatingSystemVersion version = procInfo.operatingSystemVersion; + versString = [NSString stringWithFormat:@"%zd.%zd.%zd", + version.majorVersion, version.minorVersion, version.patchVersion]; +#else +#pragma unused(procInfo) +#endif + } else { + // With Gestalt inexplicably deprecated in 10.8, we're reduced to reading + // the system plist file. + NSString *const kPath = @"/System/Library/CoreServices/SystemVersion.plist"; + NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:kPath]; + versString = [plist objectForKey:@"ProductVersion"]; + if (versString.length == 0) { + versString = @"10.?.?"; + } + } + + sSavedSystemString = [[NSString alloc] initWithFormat:@"MacOSX/%@", versString]; +#elif defined(_SYS_UTSNAME_H) + // Foundation-only build + struct utsname unameRecord; + uname(&unameRecord); + + sSavedSystemString = [NSString stringWithFormat:@"%s/%s", + unameRecord.sysname, unameRecord.release]; // "Darwin/8.11.1" +#else +#error No branch taken for a default user agent +#endif + }); + return sSavedSystemString; +} + +NSString *GTMFetcherStandardUserAgentString(NSBundle * GTM_NULLABLE_TYPE bundle) { + NSString *result = [NSString stringWithFormat:@"%@ %@", + GTMFetcherApplicationIdentifier(bundle), + GTMFetcherSystemVersionString()]; + return result; +} + +NSString *GTMFetcherApplicationIdentifier(NSBundle * GTM_NULLABLE_TYPE bundle) { + @synchronized([GTMSessionFetcher class]) { + static NSMutableDictionary *sAppIDMap = nil; + + // If there's a bundle ID, use that; otherwise, use the process name + if (bundle == nil) { + bundle = [NSBundle mainBundle]; + } + NSString *bundleID = [bundle bundleIdentifier]; + if (bundleID == nil) { + bundleID = @""; + } + + NSString *identifier = [sAppIDMap objectForKey:bundleID]; + if (identifier) return identifier; + + // Apps may add a string to the info.plist to uniquely identify different builds. + identifier = [bundle objectForInfoDictionaryKey:@"GTMUserAgentID"]; + if (identifier.length == 0) { + if (bundleID.length > 0) { + identifier = bundleID; + } else { + // Fall back on the procname, prefixed by "proc" to flag that it's + // autogenerated and perhaps unreliable + NSString *procName = [[NSProcessInfo processInfo] processName]; + identifier = [NSString stringWithFormat:@"proc_%@", procName]; + } + } + + // Clean up whitespace and special characters + identifier = GTMFetcherCleanedUserAgentString(identifier); + + // If there's a version number, append that + NSString *version = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + if (version.length == 0) { + version = [bundle objectForInfoDictionaryKey:@"CFBundleVersion"]; + } + + // Clean up whitespace and special characters + version = GTMFetcherCleanedUserAgentString(version); + + // Glue the two together (cleanup done above or else cleanup would strip the + // slash) + if (version.length > 0) { + identifier = [identifier stringByAppendingFormat:@"/%@", version]; + } + + if (sAppIDMap == nil) { + sAppIDMap = [[NSMutableDictionary alloc] init]; + } + [sAppIDMap setObject:identifier forKey:bundleID]; + return identifier; + } +} + +#if DEBUG +@implementation GTMSessionSyncMonitorInternal { + NSValue *_objectKey; // The synchronize target object. + const char *_functionName; // The function containing the monitored sync block. +} + +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName { + self = [super init]; + if (self) { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + _objectKey = [NSValue valueWithNonretainedObject:object]; + _functionName = functionName; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + if (counters == nil) { + counters = [NSMutableDictionary dictionary]; + threadDict[(id)threadKey] = counters; + } + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSUInteger numberOfSyncingFunctions = functionNamesCounter.count; + + if (!allowRecursive) { + BOOL isTopLevelSyncScope = (numberOfSyncingFunctions == 0); + NSArray *stack = [NSThread callStackSymbols]; + GTMSESSION_ASSERT_DEBUG(isTopLevelSyncScope, + @"*** Recursive sync on %@ at %s; previous sync at %@\n%@", + [object class], functionName, functionNamesCounter.allObjects, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + } + + if (!functionNamesCounter) { + functionNamesCounter = [NSCountedSet set]; + counters[_objectKey] = functionNamesCounter; + } + [functionNamesCounter addObject:@(functionName)]; + } + return self; +} + +- (void)dealloc { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSString *functionNameStr = @(_functionName); + NSUInteger numberOfSyncsByThisFunction = [functionNamesCounter countForObject:functionNameStr]; + NSArray *stack = [NSThread callStackSymbols]; + GTMSESSION_ASSERT_DEBUG(numberOfSyncsByThisFunction > 0, @"Sync not found on %@ at %s\n%@", + [_objectKey.nonretainedObjectValue class], _functionName, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + [functionNamesCounter removeObject:functionNameStr]; + if (functionNamesCounter.count == 0) { + [counters removeObjectForKey:_objectKey]; + } +} + ++ (NSArray *)functionsHoldingSynchronizationOnObject:(id)object { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + NSValue *localObjectKey = [NSValue valueWithNonretainedObject:object]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[localObjectKey]; + return functionNamesCounter.count > 0 ? functionNamesCounter.allObjects : nil; +} +@end +#endif // DEBUG +GTM_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h new file mode 100644 index 0000000..bc0a65c --- /dev/null +++ b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h @@ -0,0 +1,107 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GTMSessionFetcher.h" + +// GTM HTTP Logging +// +// All traffic using GTMSessionFetcher can be easily logged. Call +// +// [GTMSessionFetcher setLoggingEnabled:YES]; +// +// to begin generating log files. +// +// Log files are put into a folder on the desktop called "GTMHTTPDebugLogs" +// unless another directory is specified with +setLoggingDirectory. +// +// In the iPhone simulator, the default logs location is the user's home +// directory in ~/Library/Application Support. On the iPhone device, the +// default logs location is the application's documents directory on the device. +// +// Tip: use the Finder's "Sort By Date" to find the most recent logs. +// +// Each run of an application gets a separate set of log files. An html +// file is generated to simplify browsing the run's http transactions. +// The html file includes javascript links for inline viewing of uploaded +// and downloaded data. +// +// A symlink is created in the logs folder to simplify finding the html file +// for the latest run of the application; the symlink is called +// +// AppName_http_log_newest.html +// +// For better viewing of XML logs, use Camino or Firefox rather than Safari. +// +// Each fetcher may be given a comment to be inserted as a label in the logs, +// such as +// [fetcher setCommentWithFormat:@"retrieve item %@", itemName]; +// +// Projects may define STRIP_GTM_FETCH_LOGGING to remove logging code. + +#if !STRIP_GTM_FETCH_LOGGING + +@interface GTMSessionFetcher (GTMSessionFetcherLogging) + +// Note: the default logs directory is ~/Desktop/GTMHTTPDebugLogs; it will be +// created as needed. If a custom directory is set, the directory should +// already exist. ++ (void)setLoggingDirectory:(NSString *)path; ++ (NSString *)loggingDirectory; + +// client apps can turn logging on and off ++ (void)setLoggingEnabled:(BOOL)isLoggingEnabled; ++ (BOOL)isLoggingEnabled; + +// client apps can turn off logging to a file if they want to only check +// the fetcher's log property ++ (void)setLoggingToFileEnabled:(BOOL)isLoggingToFileEnabled; ++ (BOOL)isLoggingToFileEnabled; + +// client apps can optionally specify process name and date string used in +// log file names ++ (void)setLoggingProcessName:(NSString *)processName; ++ (NSString *)loggingProcessName; + ++ (void)setLoggingDateStamp:(NSString *)dateStamp; ++ (NSString *)loggingDateStamp; + +// client apps can specify the directory for the log for this specific run, +// typically to match the directory used by another fetcher class, like: +// +// [GTMSessionFetcher setLogDirectoryForCurrentRun:[GTMHTTPFetcher logDirectoryForCurrentRun]]; +// +// Setting this overrides the logging directory, process name, and date stamp when writing +// the log file. ++ (void)setLogDirectoryForCurrentRun:(NSString *)logDirectoryForCurrentRun; ++ (NSString *)logDirectoryForCurrentRun; + +// Prunes old log directories that have not been modified since the provided date. +// This will not delete the current run's log directory. ++ (void)deleteLogDirectoriesOlderThanDate:(NSDate *)date; + +// internal; called by fetcher +- (void)logFetchWithError:(NSError *)error; +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream; +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider; + +// internal; accessors useful for viewing logs ++ (NSString *)processNameLogPrefix; ++ (NSString *)symlinkNameSuffix; ++ (NSString *)htmlFileName; + +@end + +#endif // !STRIP_GTM_FETCH_LOGGING diff --git a/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m new file mode 100644 index 0000000..02b46b6 --- /dev/null +++ b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m @@ -0,0 +1,976 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#include +#include + +#import "GTMSessionFetcherLogging.h" + +#ifndef STRIP_GTM_FETCH_LOGGING + #error GTMSessionFetcher headers should have defaulted this if it wasn't already defined. +#endif + +#if !STRIP_GTM_FETCH_LOGGING + +// Sensitive credential strings are replaced in logs with _snip_ +// +// Apps that must see the contents of sensitive tokens can set this to 1 +#ifndef SKIP_GTM_FETCH_LOGGING_SNIPPING +#define SKIP_GTM_FETCH_LOGGING_SNIPPING 0 +#endif + +// If GTMReadMonitorInputStream is available, it can be used for +// capturing uploaded streams of data +// +// We locally declare methods of GTMReadMonitorInputStream so we +// do not need to import the header, as some projects may not have it available +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMReadMonitorInputStream : NSInputStream + ++ (instancetype)inputStreamWithStream:(NSInputStream *)input; + +@property (assign) id readDelegate; +@property (assign) SEL readSelector; + +@end +#else +@class GTMReadMonitorInputStream; +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionFetcher (GTMHTTPFetcherLoggingUtilities) + ++ (NSString *)headersStringForDictionary:(NSDictionary *)dict; ++ (NSString *)snipSubstringOfString:(NSString *)originalStr + betweenStartString:(NSString *)startStr + endString:(NSString *)endStr; +- (void)inputStream:(GTMReadMonitorInputStream *)stream + readIntoBuffer:(void *)buffer + length:(int64_t)length; + +@end + +@implementation GTMSessionFetcher (GTMSessionFetcherLogging) + +// fetchers come and fetchers go, but statics are forever +static BOOL gIsLoggingEnabled = NO; +static BOOL gIsLoggingToFile = YES; +static NSString *gLoggingDirectoryPath = nil; +static NSString *gLogDirectoryForCurrentRun = nil; +static NSString *gLoggingDateStamp = nil; +static NSString *gLoggingProcessName = nil; + ++ (void)setLoggingDirectory:(NSString *)path { + gLoggingDirectoryPath = [path copy]; +} + ++ (NSString *)loggingDirectory { + if (!gLoggingDirectoryPath) { + NSArray *paths = nil; +#if TARGET_IPHONE_SIMULATOR + // default to a directory called GTMHTTPDebugLogs into a sandbox-safe + // directory that a developer can find easily, the application home + paths = @[ NSHomeDirectory() ]; +#elif TARGET_OS_IPHONE + // Neither ~/Desktop nor ~/Home is writable on an actual iOS, watchOS, or tvOS device. + // Put it in ~/Documents. + paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); +#else + // default to a directory called GTMHTTPDebugLogs in the desktop folder + paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES); +#endif + + NSString *desktopPath = paths.firstObject; + if (desktopPath) { + NSString *const kGTMLogFolderName = @"GTMHTTPDebugLogs"; + NSString *logsFolderPath = [desktopPath stringByAppendingPathComponent:kGTMLogFolderName]; + + NSFileManager *fileMgr = [NSFileManager defaultManager]; + BOOL isDir; + BOOL doesFolderExist = [fileMgr fileExistsAtPath:logsFolderPath isDirectory:&isDir]; + if (!doesFolderExist) { + // make the directory + doesFolderExist = [fileMgr createDirectoryAtPath:logsFolderPath + withIntermediateDirectories:YES + attributes:nil + error:NULL]; + } + if (doesFolderExist) { + // it's there; store it in the global + gLoggingDirectoryPath = [logsFolderPath copy]; + } + } + } + return gLoggingDirectoryPath; +} + ++ (void)setLogDirectoryForCurrentRun:(NSString *)logDirectoryForCurrentRun { + // Set the path for this run's logs. + gLogDirectoryForCurrentRun = [logDirectoryForCurrentRun copy]; +} + ++ (NSString *)logDirectoryForCurrentRun { + // make a directory for this run's logs, like SyncProto_logs_10-16_01-56-58PM + if (gLogDirectoryForCurrentRun) return gLogDirectoryForCurrentRun; + + NSString *parentDir = [self loggingDirectory]; + NSString *logNamePrefix = [self processNameLogPrefix]; + NSString *dateStamp = [self loggingDateStamp]; + NSString *dirName = [NSString stringWithFormat:@"%@%@", logNamePrefix, dateStamp]; + NSString *logDirectory = [parentDir stringByAppendingPathComponent:dirName]; + + if (gIsLoggingToFile) { + NSFileManager *fileMgr = [NSFileManager defaultManager]; + // Be sure that the first time this app runs, it's not writing to a preexisting folder + static BOOL gShouldReuseFolder = NO; + if (!gShouldReuseFolder) { + gShouldReuseFolder = YES; + NSString *origLogDir = logDirectory; + for (int ctr = 2; ctr < 20; ++ctr) { + if (![fileMgr fileExistsAtPath:logDirectory]) break; + + // append a digit + logDirectory = [origLogDir stringByAppendingFormat:@"_%d", ctr]; + } + } + if (![fileMgr createDirectoryAtPath:logDirectory + withIntermediateDirectories:YES + attributes:nil + error:NULL]) return nil; + } + gLogDirectoryForCurrentRun = logDirectory; + + return gLogDirectoryForCurrentRun; +} + ++ (void)setLoggingEnabled:(BOOL)isLoggingEnabled { + gIsLoggingEnabled = isLoggingEnabled; +} + ++ (BOOL)isLoggingEnabled { + return gIsLoggingEnabled; +} + ++ (void)setLoggingToFileEnabled:(BOOL)isLoggingToFileEnabled { + gIsLoggingToFile = isLoggingToFileEnabled; +} + ++ (BOOL)isLoggingToFileEnabled { + return gIsLoggingToFile; +} + ++ (void)setLoggingProcessName:(NSString *)processName { + gLoggingProcessName = [processName copy]; +} + ++ (NSString *)loggingProcessName { + // get the process name (once per run) replacing spaces with underscores + if (!gLoggingProcessName) { + NSString *procName = [[NSProcessInfo processInfo] processName]; + gLoggingProcessName = [procName stringByReplacingOccurrencesOfString:@" " withString:@"_"]; + } + return gLoggingProcessName; +} + ++ (void)setLoggingDateStamp:(NSString *)dateStamp { + gLoggingDateStamp = [dateStamp copy]; +} + ++ (NSString *)loggingDateStamp { + // We'll pick one date stamp per run, so a run that starts at a later second + // will get a unique results html file + if (!gLoggingDateStamp) { + // produce a string like 08-21_01-41-23PM + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + [formatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [formatter setDateFormat:@"M-dd_hh-mm-ssa"]; + + gLoggingDateStamp = [formatter stringFromDate:[NSDate date]]; + } + return gLoggingDateStamp; +} + ++ (NSString *)processNameLogPrefix { + static NSString *gPrefix = nil; + if (!gPrefix) { + NSString *processName = [self loggingProcessName]; + gPrefix = [[NSString alloc] initWithFormat:@"%@_log_", processName]; + } + return gPrefix; +} + ++ (NSString *)symlinkNameSuffix { + return @"_log_newest.html"; +} + ++ (NSString *)htmlFileName { + return @"aperçu_http_log.html"; +} + ++ (void)deleteLogDirectoriesOlderThanDate:(NSDate *)cutoffDate { + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSURL *parentDir = [NSURL fileURLWithPath:[[self class] loggingDirectory]]; + NSURL *logDirectoryForCurrentRun = + [NSURL fileURLWithPath:[[self class] logDirectoryForCurrentRun]]; + NSError *error; + NSArray *contents = [fileMgr contentsOfDirectoryAtURL:parentDir + includingPropertiesForKeys:@[ NSURLContentModificationDateKey ] + options:0 + error:&error]; + for (NSURL *itemURL in contents) { + if ([itemURL isEqual:logDirectoryForCurrentRun]) continue; + + NSDate *modDate; + if ([itemURL getResourceValue:&modDate + forKey:NSURLContentModificationDateKey + error:&error]) { + if ([modDate compare:cutoffDate] == NSOrderedAscending) { + if (![fileMgr removeItemAtURL:itemURL error:&error]) { + NSLog(@"deleteLogDirectoriesOlderThanDate failed to delete %@: %@", + itemURL.path, error); + } + } + } else { + NSLog(@"deleteLogDirectoriesOlderThanDate failed to get mod date of %@: %@", + itemURL.path, error); + } + } +} + +// formattedStringFromData returns a prettyprinted string for XML or JSON input, +// and a plain string for other input data +- (NSString *)formattedStringFromData:(NSData *)inputData + contentType:(NSString *)contentType + JSON:(NSDictionary **)outJSON { + if (!inputData) return nil; + + // if the content type is JSON and we have the parsing class available, use that + if ([contentType hasPrefix:@"application/json"] && inputData.length > 5) { + // convert from JSON string to NSObjects and back to a formatted string + NSMutableDictionary *obj = [NSJSONSerialization JSONObjectWithData:inputData + options:NSJSONReadingMutableContainers + error:NULL]; + if (obj) { + if (outJSON) *outJSON = obj; + if ([obj isKindOfClass:[NSMutableDictionary class]]) { + // for security and privacy, omit OAuth 2 response access and refresh tokens + if ([obj valueForKey:@"refresh_token"] != nil) { + [obj setObject:@"_snip_" forKey:@"refresh_token"]; + } + if ([obj valueForKey:@"access_token"] != nil) { + [obj setObject:@"_snip_" forKey:@"access_token"]; + } + } + NSData *data = [NSJSONSerialization dataWithJSONObject:obj + options:NSJSONWritingPrettyPrinted + error:NULL]; + if (data) { + NSString *jsonStr = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + return jsonStr; + } + } + } + +#if !TARGET_OS_IPHONE && !GTM_SKIP_LOG_XMLFORMAT + // verify that this data starts with the bytes indicating XML + + NSString *const kXMLLintPath = @"/usr/bin/xmllint"; + static BOOL gHasCheckedAvailability = NO; + static BOOL gIsXMLLintAvailable = NO; + + if (!gHasCheckedAvailability) { + gIsXMLLintAvailable = [[NSFileManager defaultManager] fileExistsAtPath:kXMLLintPath]; + gHasCheckedAvailability = YES; + } + if (gIsXMLLintAvailable + && inputData.length > 5 + && strncmp(inputData.bytes, " 0) { + // success + inputData = formattedData; + } + } +#else + // we can't call external tasks on the iPhone; leave the XML unformatted +#endif + + NSString *dataStr = [[NSString alloc] initWithData:inputData + encoding:NSUTF8StringEncoding]; + return dataStr; +} + +// stringFromStreamData creates a string given the supplied data +// +// If NSString can create a UTF-8 string from the data, then that is returned. +// +// Otherwise, this routine tries to find a MIME boundary at the beginning of the data block, and +// uses that to break up the data into parts. Each part will be used to try to make a UTF-8 string. +// For parts that fail, a replacement string showing the part header and <> is supplied +// in place of the binary data. + +- (NSString *)stringFromStreamData:(NSData *)data + contentType:(NSString *)contentType { + + if (!data) return nil; + + // optimistically, see if the whole data block is UTF-8 + NSString *streamDataStr = [self formattedStringFromData:data + contentType:contentType + JSON:NULL]; + if (streamDataStr) return streamDataStr; + + // Munge a buffer by replacing non-ASCII bytes with underscores, and turn that munged buffer an + // NSString. That gives us a string we can use with NSScanner. + NSMutableData *mutableData = [NSMutableData dataWithData:data]; + unsigned char *bytes = (unsigned char *)mutableData.mutableBytes; + + for (unsigned int idx = 0; idx < mutableData.length; ++idx) { + if (bytes[idx] > 0x7F || bytes[idx] == 0) { + bytes[idx] = '_'; + } + } + + NSString *mungedStr = [[NSString alloc] initWithData:mutableData + encoding:NSUTF8StringEncoding]; + if (mungedStr) { + + // scan for the boundary string + NSString *boundary = nil; + NSScanner *scanner = [NSScanner scannerWithString:mungedStr]; + + if ([scanner scanUpToString:@"\r\n" intoString:&boundary] + && [boundary hasPrefix:@"--"]) { + + // we found a boundary string; use it to divide the string into parts + NSArray *mungedParts = [mungedStr componentsSeparatedByString:boundary]; + + // look at each munged part in the original string, and try to convert those into UTF-8 + NSMutableArray *origParts = [NSMutableArray array]; + NSUInteger offset = 0; + for (NSString *mungedPart in mungedParts) { + NSUInteger partSize = mungedPart.length; + NSData *origPartData = [data subdataWithRange:NSMakeRange(offset, partSize)]; + NSString *origPartStr = [[NSString alloc] initWithData:origPartData + encoding:NSUTF8StringEncoding]; + if (origPartStr) { + // we could make this original part into UTF-8; use the string + [origParts addObject:origPartStr]; + } else { + // this part can't be made into UTF-8; scan the header, if we can + NSString *header = nil; + NSScanner *headerScanner = [NSScanner scannerWithString:mungedPart]; + if (![headerScanner scanUpToString:@"\r\n\r\n" intoString:&header]) { + // we couldn't find a header + header = @""; + } + // make a part string with the header and <> + NSString *binStr = [NSString stringWithFormat:@"\r%@\r<<%lu bytes>>\r", + header, (long)(partSize - header.length)]; + [origParts addObject:binStr]; + } + offset += partSize + boundary.length; + } + // rejoin the original parts + streamDataStr = [origParts componentsJoinedByString:boundary]; + } + } + if (!streamDataStr) { + // give up; just make a string showing the uploaded bytes + streamDataStr = [NSString stringWithFormat:@"<<%u bytes>>", (unsigned int)data.length]; + } + return streamDataStr; +} + +// logFetchWithError is called following a successful or failed fetch attempt +// +// This method does all the work for appending to and creating log files + +- (void)logFetchWithError:(NSError *)error { + if (![[self class] isLoggingEnabled]) return; + NSString *logDirectory = [[self class] logDirectoryForCurrentRun]; + if (!logDirectory) return; + NSString *processName = [[self class] loggingProcessName]; + + // TODO: add Javascript to display response data formatted in hex + + // each response's NSData goes into its own xml or txt file, though all responses for this run of + // the app share a main html file. This counter tracks all fetch responses for this app run. + // + // we'll use a local variable since this routine may be reentered while waiting for XML formatting + // to be completed by an external task + static int gResponseCounter = 0; + int responseCounter = ++gResponseCounter; + + NSURLResponse *response = [self response]; + NSDictionary *responseHeaders = [self responseHeaders]; + NSString *responseDataStr = nil; + NSDictionary *responseJSON = nil; + + // if there's response data, decide what kind of file to put it in based on the first bytes of the + // file or on the mime type supplied by the server + NSString *responseMIMEType = [response MIMEType]; + BOOL isResponseImage = NO; + + // file name for an image data file + NSString *responseDataFileName = nil; + + int64_t responseDataLength = self.downloadedLength; + if (responseDataLength > 0) { + NSData *downloadedData = self.downloadedData; + if (downloadedData == nil + && responseDataLength > 0 + && responseDataLength < 20000 + && self.destinationFileURL) { + // There's a download file that's not too big, so get the data to display from the downloaded + // file. + NSURL *destinationURL = self.destinationFileURL; + downloadedData = [NSData dataWithContentsOfURL:destinationURL]; + } + NSString *responseType = [responseHeaders valueForKey:@"Content-Type"]; + responseDataStr = [self formattedStringFromData:downloadedData + contentType:responseType + JSON:&responseJSON]; + NSString *responseDataExtn = nil; + NSData *dataToWrite = nil; + if (responseDataStr) { + // we were able to make a UTF-8 string from the response data + if ([responseMIMEType isEqual:@"application/atom+xml"] + || [responseMIMEType hasSuffix:@"/xml"]) { + responseDataExtn = @"xml"; + dataToWrite = [responseDataStr dataUsingEncoding:NSUTF8StringEncoding]; + } + } else if ([responseMIMEType isEqual:@"image/jpeg"]) { + responseDataExtn = @"jpg"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else if ([responseMIMEType isEqual:@"image/gif"]) { + responseDataExtn = @"gif"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else if ([responseMIMEType isEqual:@"image/png"]) { + responseDataExtn = @"png"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else { + // add more non-text types here + } + // if we have an extension, save the raw data in a file with that extension + if (responseDataExtn && dataToWrite) { + // generate a response file base name like + NSString *responseBaseName = [NSString stringWithFormat:@"fetch_%d_response", responseCounter]; + responseDataFileName = [responseBaseName stringByAppendingPathExtension:responseDataExtn]; + NSString *responseDataFilePath = [logDirectory stringByAppendingPathComponent:responseDataFileName]; + + NSError *downloadedError = nil; + if (gIsLoggingToFile && ![dataToWrite writeToFile:responseDataFilePath + options:0 + error:&downloadedError]) { + NSLog(@"%@ logging write error:%@ (%@)", [self class], downloadedError, responseDataFileName); + } + } + } + // we'll have one main html file per run of the app + NSString *htmlName = [[self class] htmlFileName]; + NSString *htmlPath =[logDirectory stringByAppendingPathComponent:htmlName]; + + // if the html file exists (from logging previous fetches) we don't need + // to re-write the header or the scripts + NSFileManager *fileMgr = [NSFileManager defaultManager]; + BOOL didFileExist = [fileMgr fileExistsAtPath:htmlPath]; + + NSMutableString* outputHTML = [NSMutableString string]; + + // we need a header to say we'll have UTF-8 text + if (!didFileExist) { + [outputHTML appendFormat:@"%@ HTTP fetch log %@", + processName, [[self class] loggingDateStamp]]; + } + // now write the visible html elements + NSString *copyableFileName = [NSString stringWithFormat:@"fetch_%d.txt", responseCounter]; + + NSDate *now = [NSDate date]; + // write the date & time, the comment, and the link to the plain-text (copyable) log + [outputHTML appendFormat:@"%@      ", now]; + + NSString *comment = [self comment]; + if (comment.length > 0) { + [outputHTML appendFormat:@"%@      ", comment]; + } + [outputHTML appendFormat:@"request/response log
", copyableFileName]; + NSTimeInterval elapsed = -self.initialBeginFetchDate.timeIntervalSinceNow; + [outputHTML appendFormat:@"elapsed: %5.3fsec
", elapsed]; + + // write the request URL + NSURLRequest *request = self.request; + NSString *requestMethod = request.HTTPMethod; + NSURL *requestURL = request.URL; + + // Save the request URL for next time in case this redirects. + NSString *redirectedFromURLString = [self.redirectedFromURL absoluteString]; + self.redirectedFromURL = [requestURL copy]; + if (redirectedFromURLString) { + [outputHTML appendFormat:@"redirected from %@
", + redirectedFromURLString]; + } + [outputHTML appendFormat:@"request: %@ %@
\n", requestMethod, requestURL]; + + // write the request headers + NSDictionary *requestHeaders = request.allHTTPHeaderFields; + NSUInteger numberOfRequestHeaders = requestHeaders.count; + if (numberOfRequestHeaders > 0) { + // Indicate if the request is authorized; warn if the request is authorized but non-SSL + NSString *auth = [requestHeaders objectForKey:@"Authorization"]; + NSString *headerDetails = @""; + if (auth) { + BOOL isInsecure = [[requestURL scheme] isEqual:@"http"]; + if (isInsecure) { + // 26A0 = ⚠ + headerDetails = + @"   authorized, non-SSL "; + } else { + headerDetails = @"   authorized"; + } + } + NSString *cookiesHdr = [requestHeaders objectForKey:@"Cookie"]; + if (cookiesHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   cookies"]; + } + NSString *matchHdr = [requestHeaders objectForKey:@"If-Match"]; + if (matchHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   if-match"]; + } + matchHdr = [requestHeaders objectForKey:@"If-None-Match"]; + if (matchHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   if-none-match"]; + } + [outputHTML appendFormat:@"   headers: %d %@
", + (int)numberOfRequestHeaders, headerDetails]; + } else { + [outputHTML appendFormat:@"   headers: none
"]; + } + // write the request post data + NSData *bodyData = nil; + NSData *loggedStreamData = self.loggedStreamData; + if (loggedStreamData) { + bodyData = loggedStreamData; + } else { + bodyData = self.bodyData; + if (bodyData == nil) { + bodyData = self.request.HTTPBody; + } + } + uint64_t bodyDataLength = bodyData.length; + + if (bodyData.length == 0) { + // If the data is in a body upload file URL, read that in if it's not huge. + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSNumber *fileSizeNum = nil; + NSError *fileSizeError = nil; + if ([bodyFileURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:&fileSizeError]) { + bodyDataLength = [fileSizeNum unsignedLongLongValue]; + if (bodyDataLength > 0 && bodyDataLength < 50000) { + bodyData = [NSData dataWithContentsOfURL:bodyFileURL + options:NSDataReadingUncached + error:&fileSizeError]; + } + } + } + } + NSString *bodyDataStr = nil; + NSString *postType = [requestHeaders valueForKey:@"Content-Type"]; + + if (bodyDataLength > 0) { + [outputHTML appendFormat:@"   data: %llu bytes, %@
\n", + bodyDataLength, postType ? postType : @"(no type)"]; + NSString *logRequestBody = self.logRequestBody; + if (logRequestBody) { + bodyDataStr = [logRequestBody copy]; + self.logRequestBody = nil; + } else { + bodyDataStr = [self stringFromStreamData:bodyData + contentType:postType]; + if (bodyDataStr) { + // remove OAuth 2 client secret and refresh token + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"client_secret=" + endString:@"&"]; + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"refresh_token=" + endString:@"&"]; + // remove ClientLogin password + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"&Passwd=" + endString:@"&"]; + } + } + } else { + // no post data + } + // write the response status, MIME type, URL + NSInteger status = [self statusCode]; + if (response) { + NSString *statusString = @""; + if (status != 0) { + if (status == 200 || status == 201) { + statusString = [NSString stringWithFormat:@"%ld", (long)status]; + + // report any JSON-RPC error + if ([responseJSON isKindOfClass:[NSDictionary class]]) { + NSDictionary *jsonError = [responseJSON objectForKey:@"error"]; + if ([jsonError isKindOfClass:[NSDictionary class]]) { + NSString *jsonCode = [[jsonError valueForKey:@"code"] description]; + NSString *jsonMessage = [jsonError valueForKey:@"message"]; + if (jsonCode || jsonMessage) { + // 2691 = ⚑ + NSString *const jsonErrFmt = + @"   JSON error: %@ %@  ⚑"; + statusString = [statusString stringByAppendingFormat:jsonErrFmt, + jsonCode ? jsonCode : @"", + jsonMessage ? jsonMessage : @""]; + } + } + } + } else { + // purple for anything other than 200 or 201 + NSString *flag = status >= 400 ? @" ⚑" : @""; // 2691 = ⚑ + NSString *explanation = [NSHTTPURLResponse localizedStringForStatusCode:status]; + NSString *const statusFormat = @"%ld %@ %@"; + statusString = [NSString stringWithFormat:statusFormat, (long)status, explanation, flag]; + } + } + // show the response URL only if it's different from the request URL + NSString *responseURLStr = @""; + NSURL *responseURL = response.URL; + + if (responseURL && ![responseURL isEqual:request.URL]) { + NSString *const responseURLFormat = + @"response URL: %@
\n"; + responseURLStr = [NSString stringWithFormat:responseURLFormat, [responseURL absoluteString]]; + } + [outputHTML appendFormat:@"response:  status %@
\n%@", + statusString, responseURLStr]; + // Write the response headers + NSUInteger numberOfResponseHeaders = responseHeaders.count; + if (numberOfResponseHeaders > 0) { + // Indicate if the server is setting cookies + NSString *cookiesSet = [responseHeaders valueForKey:@"Set-Cookie"]; + NSString *cookiesStr = + cookiesSet ? @"  sets cookies" : @""; + // Indicate if the server is redirecting + NSString *location = [responseHeaders valueForKey:@"Location"]; + BOOL isRedirect = status >= 300 && status <= 399 && location != nil; + NSString *redirectsStr = + isRedirect ? @"  redirects" : @""; + [outputHTML appendFormat:@"   headers: %d %@ %@
\n", + (int)numberOfResponseHeaders, cookiesStr, redirectsStr]; + } else { + [outputHTML appendString:@"   headers: none
\n"]; + } + } + // error + if (error) { + [outputHTML appendFormat:@"Error: %@
\n", error.description]; + } + // Write the response data + if (responseDataFileName) { + if (isResponseImage) { + // Make a small inline image that links to the full image file + [outputHTML appendFormat:@"   data: %lld bytes, %@
", + responseDataLength, responseMIMEType]; + NSString *const fmt = + @"image\n"; + [outputHTML appendFormat:fmt, responseDataFileName, responseDataFileName]; + } else { + // The response data was XML; link to the xml file + NSString *const fmt = + @"   data: %lld bytes, %@   %@\n"; + [outputHTML appendFormat:fmt, responseDataLength, responseMIMEType, + responseDataFileName, [responseDataFileName pathExtension]]; + } + } else { + // The response data was not an image; just show the length and MIME type + [outputHTML appendFormat:@"   data: %lld bytes, %@\n", + responseDataLength, responseMIMEType ? responseMIMEType : @"(no response type)"]; + } + // Make a single string of the request and response, suitable for copying + // to the clipboard and pasting into a bug report + NSMutableString *copyable = [NSMutableString string]; + if (comment) { + [copyable appendFormat:@"%@\n\n", comment]; + } + [copyable appendFormat:@"%@ elapsed: %5.3fsec\n", now, elapsed]; + if (redirectedFromURLString) { + [copyable appendFormat:@"Redirected from %@\n", redirectedFromURLString]; + } + [copyable appendFormat:@"Request: %@ %@\n", requestMethod, requestURL]; + if (requestHeaders.count > 0) { + [copyable appendFormat:@"Request headers:\n%@\n", + [[self class] headersStringForDictionary:requestHeaders]]; + } + if (bodyDataLength > 0) { + [copyable appendFormat:@"Request body: (%llu bytes)\n", bodyDataLength]; + if (bodyDataStr) { + [copyable appendFormat:@"%@\n", bodyDataStr]; + } + [copyable appendString:@"\n"]; + } + if (response) { + [copyable appendFormat:@"Response: status %d\n", (int) status]; + [copyable appendFormat:@"Response headers:\n%@\n", + [[self class] headersStringForDictionary:responseHeaders]]; + [copyable appendFormat:@"Response body: (%lld bytes)\n", responseDataLength]; + if (responseDataLength > 0) { + NSString *logResponseBody = self.logResponseBody; + if (logResponseBody) { + // The user has provided the response body text. + responseDataStr = [logResponseBody copy]; + self.logResponseBody = nil; + } + if (responseDataStr != nil) { + [copyable appendFormat:@"%@\n", responseDataStr]; + } else { + // Even though it's redundant, we'll put in text to indicate that all the bytes are binary. + if (self.destinationFileURL) { + [copyable appendFormat:@"<<%lld bytes>> to file %@\n", + responseDataLength, self.destinationFileURL.path]; + } else { + [copyable appendFormat:@"<<%lld bytes>>\n", responseDataLength]; + } + } + } + } + if (error) { + [copyable appendFormat:@"Error: %@\n", error]; + } + // Save to log property before adding the separator + self.log = copyable; + + [copyable appendString:@"-----------------------------------------------------------\n"]; + + // Write the copyable version to another file (linked to at the top of the html file, above) + // + // Ideally, something to just copy this to the clipboard like + // Copy here." + // would work everywhere, but it only works in Safari as of 8/2010 + if (gIsLoggingToFile) { + NSString *parentDir = [[self class] loggingDirectory]; + NSString *copyablePath = [logDirectory stringByAppendingPathComponent:copyableFileName]; + NSError *copyableError = nil; + if (![copyable writeToFile:copyablePath + atomically:NO + encoding:NSUTF8StringEncoding + error:©ableError]) { + // Error writing to file + NSLog(@"%@ logging write error:%@ (%@)", [self class], copyableError, copyablePath); + } + [outputHTML appendString:@"

"]; + + // Append the HTML to the main output file + const char* htmlBytes = outputHTML.UTF8String; + NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:htmlPath + append:YES]; + [stream open]; + [stream write:(const uint8_t *) htmlBytes maxLength:strlen(htmlBytes)]; + [stream close]; + + // Make a symlink to the latest html + NSString *const symlinkNameSuffix = [[self class] symlinkNameSuffix]; + NSString *symlinkName = [processName stringByAppendingString:symlinkNameSuffix]; + NSString *symlinkPath = [parentDir stringByAppendingPathComponent:symlinkName]; + + [fileMgr removeItemAtPath:symlinkPath error:NULL]; + [fileMgr createSymbolicLinkAtPath:symlinkPath + withDestinationPath:htmlPath + error:NULL]; +#if TARGET_OS_IPHONE + static BOOL gReportedLoggingPath = NO; + if (!gReportedLoggingPath) { + gReportedLoggingPath = YES; + NSLog(@"GTMSessionFetcher logging to \"%@\"", parentDir); + } +#endif + } +} + +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream { + if (!inputStream) return nil; + if (![GTMSessionFetcher isLoggingEnabled]) return inputStream; + + [self clearLoggedStreamData]; // Clear any previous data. + Class monitorClass = NSClassFromString(@"GTMReadMonitorInputStream"); + if (!monitorClass) { + NSString const *str = @"<>"; + NSData *stringData = [str dataUsingEncoding:NSUTF8StringEncoding]; + [self appendLoggedStreamData:stringData]; + return inputStream; + } + inputStream = [monitorClass inputStreamWithStream:inputStream]; + + GTMReadMonitorInputStream *readMonitorInputStream = (GTMReadMonitorInputStream *)inputStream; + [readMonitorInputStream setReadDelegate:self]; + SEL readSel = @selector(inputStream:readIntoBuffer:length:); + [readMonitorInputStream setReadSelector:readSel]; + + return inputStream; +} + +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider { + if (!streamProvider) return nil; + if (![GTMSessionFetcher isLoggingEnabled]) return streamProvider; + + [self clearLoggedStreamData]; // Clear any previous data. + Class monitorClass = NSClassFromString(@"GTMReadMonitorInputStream"); + if (!monitorClass) { + NSString const *str = @"<>"; + NSData *stringData = [str dataUsingEncoding:NSUTF8StringEncoding]; + [self appendLoggedStreamData:stringData]; + return streamProvider; + } + GTMSessionFetcherBodyStreamProvider loggedStreamProvider = + ^(GTMSessionFetcherBodyStreamProviderResponse response) { + streamProvider(^(NSInputStream *bodyStream) { + bodyStream = [self loggedInputStreamForInputStream:bodyStream]; + response(bodyStream); + }); + }; + return loggedStreamProvider; +} + +@end + +@implementation GTMSessionFetcher (GTMSessionFetcherLoggingUtilities) + +- (void)inputStream:(GTMReadMonitorInputStream *)stream + readIntoBuffer:(void *)buffer + length:(int64_t)length { + // append the captured data + NSData *data = [NSData dataWithBytesNoCopy:buffer + length:(NSUInteger)length + freeWhenDone:NO]; + [self appendLoggedStreamData:data]; +} + +#pragma mark Fomatting Utilities + ++ (NSString *)snipSubstringOfString:(NSString *)originalStr + betweenStartString:(NSString *)startStr + endString:(NSString *)endStr { +#if SKIP_GTM_FETCH_LOGGING_SNIPPING + return originalStr; +#else + if (!originalStr) return nil; + + // Find the start string, and replace everything between it + // and the end string (or the end of the original string) with "_snip_" + NSRange startRange = [originalStr rangeOfString:startStr]; + if (startRange.location == NSNotFound) return originalStr; + + // We found the start string + NSUInteger originalLength = originalStr.length; + NSUInteger startOfTarget = NSMaxRange(startRange); + NSRange targetAndRest = NSMakeRange(startOfTarget, originalLength - startOfTarget); + NSRange endRange = [originalStr rangeOfString:endStr + options:0 + range:targetAndRest]; + NSRange replaceRange; + if (endRange.location == NSNotFound) { + // Found no end marker so replace to end of string + replaceRange = targetAndRest; + } else { + // Replace up to the endStr + replaceRange = NSMakeRange(startOfTarget, endRange.location - startOfTarget); + } + NSString *result = [originalStr stringByReplacingCharactersInRange:replaceRange + withString:@"_snip_"]; + return result; +#endif // SKIP_GTM_FETCH_LOGGING_SNIPPING +} + ++ (NSString *)headersStringForDictionary:(NSDictionary *)dict { + // Format the dictionary in http header style, like + // Accept: application/json + // Cache-Control: no-cache + // Content-Type: application/json; charset=utf-8 + // + // Pad the key names, but not beyond 16 chars, since long custom header + // keys just create too much whitespace + NSArray *keys = [dict.allKeys sortedArrayUsingSelector:@selector(compare:)]; + + NSMutableString *str = [NSMutableString string]; + for (NSString *key in keys) { + NSString *value = [dict valueForKey:key]; + if ([key isEqual:@"Authorization"]) { + // Remove OAuth 1 token + value = [[self class] snipSubstringOfString:value + betweenStartString:@"oauth_token=\"" + endString:@"\""]; + + // Remove OAuth 2 bearer token (draft 16, and older form) + value = [[self class] snipSubstringOfString:value + betweenStartString:@"Bearer " + endString:@"\n"]; + value = [[self class] snipSubstringOfString:value + betweenStartString:@"OAuth " + endString:@"\n"]; + + // Remove Google ClientLogin + value = [[self class] snipSubstringOfString:value + betweenStartString:@"GoogleLogin auth=" + endString:@"\n"]; + } + [str appendFormat:@" %@: %@\n", key, value]; + } + return str; +} + +@end + +#endif // !STRIP_GTM_FETCH_LOGGING diff --git a/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h new file mode 100644 index 0000000..a696ac7 --- /dev/null +++ b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h @@ -0,0 +1,190 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// For best performance and convenient usage, fetchers should be generated by a common +// GTMSessionFetcherService instance, like +// +// _fetcherService = [[GTMSessionFetcherService alloc] init]; +// GTMSessionFetcher* myFirstFetcher = [_fetcherService fetcherWithRequest:request1]; +// GTMSessionFetcher* mySecondFetcher = [_fetcherService fetcherWithRequest:request2]; + +#import "GTMSessionFetcher.h" + +GTM_ASSUME_NONNULL_BEGIN + +// Notifications. + +// This notification indicates a reusable session has become invalid. It is intended mainly for the +// service's unit tests. +// +// The notification object is the fetcher service. +// The invalid session is provided via the userInfo kGTMSessionFetcherServiceSessionKey key. +extern NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification; +extern NSString *const kGTMSessionFetcherServiceSessionKey; + +@interface GTMSessionFetcherService : NSObject + +// Queues of delayed and running fetchers. Each dictionary contains arrays +// of GTMSessionFetcher *fetchers, keyed by NSString *host +@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSArray *) *delayedFetchersByHost; +@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSArray *) *runningFetchersByHost; + +// A max value of 0 means no fetchers should be delayed. +// The default limit is 10 simultaneous fetchers targeting each host. +// This does not apply to fetchers whose useBackgroundSession property is YES. Since services are +// not resurrected on an app relaunch, delayed fetchers would effectively be abandoned. +@property(atomic, assign) NSUInteger maxRunningFetchersPerHost; + +// Properties to be applied to each fetcher; see GTMSessionFetcher.h for descriptions +@property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration; +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock; +@property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage; +@property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue; +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock; +@property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential; +@property(atomic, strong) NSURLCredential *proxyCredential; +@property(atomic, copy, GTM_NULLABLE) GTM_NSArrayOf(NSString *) *allowedInsecureSchemes; +@property(atomic, assign) BOOL allowLocalhostRequest; +@property(atomic, assign) BOOL allowInvalidServerCertificates; +@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled; +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherRetryBlock retryBlock; +@property(atomic, assign) NSTimeInterval maxRetryInterval; +@property(atomic, assign) NSTimeInterval minRetryInterval; +@property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties; + +#if GTM_BACKGROUND_TASK_FETCHING +@property(atomic, assign) BOOL skipBackgroundTask; +#endif + +// A default useragent of GTMFetcherStandardUserAgentString(nil) will be given to each fetcher +// created by this service unless the request already has a user-agent header set. +// This default will be added starting with builds with the SDKs for OS X 10.11 and iOS 9. +// +// To use the configuration's default user agent, set this property to nil. +@property(atomic, copy, GTM_NULLABLE) NSString *userAgent; + +// The authorizer to attach to the created fetchers. If a specific fetcher should +// not authorize its requests, the fetcher's authorizer property may be set to nil +// before the fetch begins. +@property(atomic, strong, GTM_NULLABLE) id authorizer; + +// Delegate queue used by the session when calling back to the fetcher. The default +// is the main queue. Changing this does not affect the queue used to call back to the +// application; that is specified by the callbackQueue property above. +@property(atomic, strong, GTM_NULL_RESETTABLE) NSOperationQueue *sessionDelegateQueue; + +// When enabled, indicates the same session should be used by subsequent fetchers. +// +// This is enabled by default. +@property(atomic, assign) BOOL reuseSession; + +// Sets the delay until an unused session is invalidated. +// The default interval is 60 seconds. +// +// If the interval is set to 0, then any reused session is not invalidated except by +// explicitly invoking -resetSession. Be aware that setting the interval to 0 thus +// causes the session's delegate to be retained until the session is explicitly reset. +@property(atomic, assign) NSTimeInterval unusedSessionTimeout; + +// If shouldReuseSession is enabled, this will force creation of a new session when future +// fetchers begin. +- (void)resetSession; + +// Create a fetcher +// +// These methods will return a fetcher. If successfully created, the connection +// will hold a strong reference to it for the life of the connection as well. +// So the caller doesn't have to hold onto the fetcher explicitly unless they +// want to be able to monitor or cancel it. +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request; +- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL; +- (GTMSessionFetcher *)fetcherWithURLString:(NSString *)requestURLString; + +// Common method for fetcher creation. +// +// -fetcherWithRequest:fetcherClass: may be overridden to customize creation of +// fetchers. This is the ONLY method in the GTMSessionFetcher library intended to +// be overridden. +- (id)fetcherWithRequest:(NSURLRequest *)request + fetcherClass:(Class)fetcherClass; + +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher; + +- (NSUInteger)numberOfFetchers; // running + delayed fetchers +- (NSUInteger)numberOfRunningFetchers; +- (NSUInteger)numberOfDelayedFetchers; + +// Return a list of all running or delayed fetchers. This includes fetchers created +// by the service which have been started and have not yet stopped. +// +// Returns an array of fetcher objects, or nil if none. +- (GTM_NULLABLE GTM_NSArrayOf(GTMSessionFetcher *) *)issuedFetchers; + +// Search for running or delayed fetchers with the specified URL. +// +// Returns an array of fetcher objects found, or nil if none found. +- (GTM_NULLABLE GTM_NSArrayOf(GTMSessionFetcher *) *)issuedFetchersWithRequestURL:(NSURL *)requestURL; + +- (void)stopAllFetchers; + +// Methods for use by the fetcher class only. +- (GTM_NULLABLE NSURLSession *)session; +- (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation; +- (GTM_NULLABLE id)sessionDelegate; +- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate; + +// The testBlock can inspect its fetcher parameter's request property to +// determine which fetcher is being faked. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock; + +@end + +@interface GTMSessionFetcherService (TestingSupport) + +// Convenience method to create a fetcher service for testing. +// +// Fetchers generated by this mock fetcher service will not perform any +// network operation, but will invoke callbacks and provide the supplied data +// or error to the completion handler. +// +// You can make more customized mocks by setting the test block property of the service +// or fetcher; the test block can inspect the fetcher's request or other properties. +// +// See the description of the testBlock property below. ++ (instancetype)mockFetcherServiceWithFakedData:(GTM_NULLABLE NSData *)fakedDataOrNil + fakedError:(GTM_NULLABLE NSError *)fakedErrorOrNil; + +// Spin the run loop and discard events (or, if not on the main thread, just sleep the thread) +// until all running and delayed fetchers have completed. +// +// This is only for use in testing or in tools without a user interface. +// +// Synchronous fetches should never be done by shipping apps; they are +// sufficient reason for rejection from the app store. +// +// Returns NO if timed out. +- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds; + +@end + +@interface GTMSessionFetcherService (BackwardsCompatibilityOnly) + +// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves. +// This method is just for compatibility with the old fetcher. +@property(atomic, assign) NSInteger cookieStorageMethod; + +@end + +GTM_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m new file mode 100644 index 0000000..fc6e6d9 --- /dev/null +++ b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m @@ -0,0 +1,1352 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcherService.h" + +NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification + = @"kGTMSessionFetcherServiceSessionBecameInvalidNotification"; +NSString *const kGTMSessionFetcherServiceSessionKey + = @"kGTMSessionFetcherServiceSessionKey"; + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (ServiceMethods) +- (BOOL)beginFetchMayDelay:(BOOL)mayDelay + mayAuthorize:(BOOL)mayAuthorize; +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionFetcherService () + +@property(atomic, strong, readwrite) NSDictionary *delayedFetchersByHost; +@property(atomic, strong, readwrite) NSDictionary *runningFetchersByHost; + +@end + +// Since NSURLSession doesn't support a separate delegate per task (!), instances of this +// class serve as a session delegate trampoline. +// +// This class maps a session's tasks to fetchers, and resends delegate messages to the task's +// fetcher. +@interface GTMSessionFetcherSessionDelegateDispatcher : NSObject + +// The session for the tasks in this dispatcher's task-to-fetcher map. +@property(atomic) NSURLSession *session; + +// The timer interval for invalidating a session that has no active tasks. +@property(atomic) NSTimeInterval discardInterval; + +// The current discard timer. +@property(atomic, readonly) NSTimer *discardTimer; + + +- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService + sessionDiscardInterval:(NSTimeInterval)discardInterval; + +- (void)setFetcher:(GTMSessionFetcher *)fetcher + forTask:(NSURLSessionTask *)task; +- (void)removeFetcher:(GTMSessionFetcher *)fetcher; + +// Before using a session, tells the delegate dispatcher to stop the discard timer. +- (void)startSessionUsage; + +// When abandoning a delegate dispatcher, we want to avoid the session retaining +// the delegate after tasks complete. +- (void)abandon; + +@end + + +@implementation GTMSessionFetcherService { + NSMutableDictionary *_delayedFetchersByHost; + NSMutableDictionary *_runningFetchersByHost; + NSUInteger _maxRunningFetchersPerHost; + + // When this ivar is nil, the service will not reuse sessions. + GTMSessionFetcherSessionDelegateDispatcher *_delegateDispatcher; + + // Fetchers will wait on this if another fetcher is creating the shared NSURLSession. + dispatch_semaphore_t _sessionCreationSemaphore; + + dispatch_queue_t _callbackQueue; + NSOperationQueue *_delegateQueue; + NSHTTPCookieStorage *_cookieStorage; + NSString *_userAgent; + NSTimeInterval _timeout; + + NSURLCredential *_credential; // Username & password. + NSURLCredential *_proxyCredential; // Credential supplied to proxy servers. + + NSInteger _cookieStorageMethod; + + id _authorizer; + + // For waitForCompletionOfAllFetchersWithTimeout: we need to wait on stopped fetchers since + // they've not yet finished invoking their queued callbacks. This array is nil except when + // waiting on fetchers. + NSMutableArray *_stoppedFetchersToWaitFor; + + // For fetchers that enqueued their callbacks before stopAllFetchers was called on the service, + // set a barrier so the callbacks know to bail out. + NSDate *_stoppedAllFetchersDate; +} + +@synthesize maxRunningFetchersPerHost = _maxRunningFetchersPerHost, + configuration = _configuration, + configurationBlock = _configurationBlock, + cookieStorage = _cookieStorage, + userAgent = _userAgent, + challengeBlock = _challengeBlock, + credential = _credential, + proxyCredential = _proxyCredential, + allowedInsecureSchemes = _allowedInsecureSchemes, + allowLocalhostRequest = _allowLocalhostRequest, + allowInvalidServerCertificates = _allowInvalidServerCertificates, + retryEnabled = _retryEnabled, + retryBlock = _retryBlock, + maxRetryInterval = _maxRetryInterval, + minRetryInterval = _minRetryInterval, + properties = _properties, + unusedSessionTimeout = _unusedSessionTimeout, + testBlock = _testBlock; + +#if GTM_BACKGROUND_TASK_FETCHING +@synthesize skipBackgroundTask = _skipBackgroundTask; +#endif + +- (instancetype)init { + self = [super init]; + if (self) { + _delayedFetchersByHost = [[NSMutableDictionary alloc] init]; + _runningFetchersByHost = [[NSMutableDictionary alloc] init]; + _maxRunningFetchersPerHost = 10; + _cookieStorageMethod = -1; + _unusedSessionTimeout = 60.0; + _delegateDispatcher = + [[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + _callbackQueue = dispatch_get_main_queue(); + + _delegateQueue = [[NSOperationQueue alloc] init]; + _delegateQueue.maxConcurrentOperationCount = 1; + _delegateQueue.name = @"com.google.GTMSessionFetcher.NSURLSessionDelegateQueue"; + + _sessionCreationSemaphore = dispatch_semaphore_create(1); + + // Starting with the SDKs for OS X 10.11/iOS 9, the service has a default useragent. + // Apps can remove this and get the default system "CFNetwork" useragent by setting the + // fetcher service's userAgent property to nil. +#if (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0) + _userAgent = GTMFetcherStandardUserAgentString(nil); +#endif + } + return self; +} + +- (void)dealloc { + [self detachAuthorizer]; + [_delegateDispatcher abandon]; +} + +#pragma mark Generate a new fetcher + +// Clients may override this method. Clients should not override any other library methods. +- (id)fetcherWithRequest:(NSURLRequest *)request + fetcherClass:(Class)fetcherClass { + GTMSessionFetcher *fetcher = [[fetcherClass alloc] initWithRequest:request + configuration:self.configuration]; + fetcher.callbackQueue = self.callbackQueue; + fetcher.sessionDelegateQueue = self.sessionDelegateQueue; + fetcher.challengeBlock = self.challengeBlock; + fetcher.credential = self.credential; + fetcher.proxyCredential = self.proxyCredential; + fetcher.authorizer = self.authorizer; + fetcher.cookieStorage = self.cookieStorage; + fetcher.allowedInsecureSchemes = self.allowedInsecureSchemes; + fetcher.allowLocalhostRequest = self.allowLocalhostRequest; + fetcher.allowInvalidServerCertificates = self.allowInvalidServerCertificates; + fetcher.configurationBlock = self.configurationBlock; + fetcher.retryEnabled = self.retryEnabled; + fetcher.retryBlock = self.retryBlock; + fetcher.maxRetryInterval = self.maxRetryInterval; + fetcher.minRetryInterval = self.minRetryInterval; + fetcher.properties = self.properties; + fetcher.service = self; + if (self.cookieStorageMethod >= 0) { + [fetcher setCookieStorageMethod:self.cookieStorageMethod]; + } + +#if GTM_BACKGROUND_TASK_FETCHING + fetcher.skipBackgroundTask = self.skipBackgroundTask; +#endif + + NSString *userAgent = self.userAgent; + if (userAgent.length > 0 + && [request valueForHTTPHeaderField:@"User-Agent"] == nil) { + [fetcher setRequestValue:userAgent + forHTTPHeaderField:@"User-Agent"]; + } + fetcher.testBlock = self.testBlock; + + return fetcher; +} + +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request { + return [self fetcherWithRequest:request + fetcherClass:[GTMSessionFetcher class]]; +} + +- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL { + return [self fetcherWithRequest:[NSURLRequest requestWithURL:requestURL]]; +} + +- (GTMSessionFetcher *)fetcherWithURLString:(NSString *)requestURLString { + NSURL *url = [NSURL URLWithString:requestURLString]; + return [self fetcherWithURL:url]; +} + +// Returns a session for the fetcher's host, or nil. +- (NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLSession *session = _delegateDispatcher.session; + return session; + } +} + +// Returns a session for the fetcher's host, or nil. For shared sessions, this +// waits on a semaphore, blocking other fetchers while the caller creates the +// session if needed. +- (NSURLSession *)sessionForFetcherCreation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + if (!_delegateDispatcher) { + // This fetcher is creating a non-shared session, so skip the semaphore usage. + return nil; + } + } + + // Wait if another fetcher is currently creating a session; avoid waiting + // inside the @synchronized block, as that can deadlock. + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Before getting the NSURLSession for task creation, it is + // important to invalidate and nil out the session discard timer; otherwise + // the session can be invalidated between when it is returned to the + // fetcher, and when the fetcher attempts to create its NSURLSessionTask. + [_delegateDispatcher startSessionUsage]; + + NSURLSession *session = _delegateDispatcher.session; + if (session) { + // The calling fetcher will receive a preexisting session, so + // we can allow other fetchers to create a session. + dispatch_semaphore_signal(_sessionCreationSemaphore); + } else { + // No existing session was obtained, so the calling fetcher will create the session; + // it *must* invoke fetcherDidCreateSession: to signal the dispatcher's semaphore after + // the session has been created (or fails to be created) to avoid a hang. + } + return session; + } +} + +- (id)sessionDelegate { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateDispatcher; + } +} + +#pragma mark Queue Management + +- (void)addRunningFetcher:(GTMSessionFetcher *)fetcher + forHost:(NSString *)host { + // Add to the array of running fetchers for this host, creating the array if needed. + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + if (runningForHost == nil) { + runningForHost = [NSMutableArray arrayWithObject:fetcher]; + [_runningFetchersByHost setObject:runningForHost forKey:host]; + } else { + [runningForHost addObject:fetcher]; + } +} + +- (void)addDelayedFetcher:(GTMSessionFetcher *)fetcher + forHost:(NSString *)host { + // Add to the array of delayed fetchers for this host, creating the array if needed. + NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + if (delayedForHost == nil) { + delayedForHost = [NSMutableArray arrayWithObject:fetcher]; + [_delayedFetchersByHost setObject:delayedForHost forKey:host]; + } else { + [delayedForHost addObject:fetcher]; + } +} + +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSString *host = fetcher.request.URL.host; + if (host == nil) { + return NO; + } + NSArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + NSUInteger idx = [delayedForHost indexOfObjectIdenticalTo:fetcher]; + BOOL isDelayed = (delayedForHost != nil) && (idx != NSNotFound); + return isDelayed; + } +} + +- (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher { + // Entry point from the fetcher + NSURL *requestURL = fetcher.request.URL; + NSString *host = requestURL.host; + + // Addresses "file:///path" case where localhost is the implicit host. + if (host.length == 0 && [requestURL isFileURL]) { + host = @"localhost"; + } + + if (host.length == 0) { + // Data URIs legitimately have no host, reject other hostless URLs. + GTMSESSION_ASSERT_DEBUG([[requestURL scheme] isEqual:@"data"], @"%@ lacks host", fetcher); + return YES; + } + + BOOL shouldBeginResult; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + if (runningForHost != nil + && [runningForHost indexOfObjectIdenticalTo:fetcher] != NSNotFound) { + GTMSESSION_ASSERT_DEBUG(NO, @"%@ was already running", fetcher); + return YES; + } + + BOOL shouldRunNow = (fetcher.usingBackgroundSession + || _maxRunningFetchersPerHost == 0 + || _maxRunningFetchersPerHost > + [[self class] numberOfNonBackgroundSessionFetchers:runningForHost]); + if (shouldRunNow) { + [self addRunningFetcher:fetcher forHost:host]; + shouldBeginResult = YES; + } else { + [self addDelayedFetcher:fetcher forHost:host]; + shouldBeginResult = NO; + } + } // @synchronized(self) + + // We'll save the host that serves as the key for this fetcher's array + // to avoid any chance of the underlying request changing, stranding + // the fetcher in the wrong array + fetcher.serviceHost = host; + + return shouldBeginResult; +} + +- (void)startFetcher:(GTMSessionFetcher *)fetcher { + [fetcher beginFetchMayDelay:NO + mayAuthorize:YES]; +} + +// Internal utility. Returns a fetcher's delegate if it's a dispatcher, or nil if the fetcher +// is its own delegate and has no dispatcher. +- (GTMSessionFetcherSessionDelegateDispatcher *)delegateDispatcherForFetcher:(GTMSessionFetcher *)fetcher { + GTMSessionCheckNotSynchronized(self); + + NSURLSession *fetcherSession = fetcher.session; + if (fetcherSession) { + id fetcherDelegate = fetcherSession.delegate; + BOOL hasDispatcher = (fetcherDelegate != nil && fetcherDelegate != fetcher); + if (hasDispatcher) { + GTMSESSION_ASSERT_DEBUG([fetcherDelegate isKindOfClass:[GTMSessionFetcherSessionDelegateDispatcher class]], + @"Fetcher delegate class: %@", [fetcherDelegate class]); + return (GTMSessionFetcherSessionDelegateDispatcher *)fetcherDelegate; + } + } + return nil; +} + +- (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher { + if (fetcher.canShareSession) { + NSURLSession *fetcherSession = fetcher.session; + GTMSESSION_ASSERT_DEBUG(fetcherSession != nil, @"Fetcher missing its session: %@", fetcher); + + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + if (delegateDispatcher) { + GTMSESSION_ASSERT_DEBUG(delegateDispatcher.session == nil, + @"Fetcher made an extra session: %@", fetcher); + + // Save this fetcher's session. + delegateDispatcher.session = fetcherSession; + + // Allow other fetchers to request this session now. + dispatch_semaphore_signal(_sessionCreationSemaphore); + } + } +} + +- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher { + // If this fetcher has a separate delegate with a shared session, then + // this fetcher should be added to the delegate's map of tasks to fetchers. + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + if (delegateDispatcher) { + GTMSESSION_ASSERT_DEBUG(fetcher.canShareSession, + @"Inappropriate shared session: %@", fetcher); + + // There should already be a session, from this or a previous fetcher. + // + // Sanity check that the fetcher's session is the delegate's shared session. + NSURLSession *sharedSession = delegateDispatcher.session; + NSURLSession *fetcherSession = fetcher.session; + GTMSESSION_ASSERT_DEBUG(sharedSession != nil, @"Missing delegate session: %@", fetcher); + GTMSESSION_ASSERT_DEBUG(fetcherSession == sharedSession, + @"Inconsistent session: %@ %@ (shared: %@)", + fetcher, fetcherSession, sharedSession); + + if (sharedSession != nil && fetcherSession == sharedSession) { + NSURLSessionTask *task = fetcher.sessionTask; + GTMSESSION_ASSERT_DEBUG(task != nil, @"Missing session task: %@", fetcher); + + if (task) { + [delegateDispatcher setFetcher:fetcher + forTask:task]; + } + } + } +} + +- (void)stopFetcher:(GTMSessionFetcher *)fetcher { + [fetcher stopFetching]; +} + +- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher { + // Entry point from the fetcher + NSString *host = fetcher.serviceHost; + if (!host) { + // fetcher has been stopped previously + return; + } + + // This removeFetcher: invocation is a fallback; typically, fetchers are removed from the task + // map when the task completes. + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + [delegateDispatcher removeFetcher:fetcher]; + + NSMutableArray *fetchersToStart; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // If a test is waiting for all fetchers to stop, it needs to wait for this one + // to invoke its callbacks on the callback queue. + [_stoppedFetchersToWaitFor addObject:fetcher]; + + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + [runningForHost removeObject:fetcher]; + + NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + [delayedForHost removeObject:fetcher]; + + while (delayedForHost.count > 0 + && [[self class] numberOfNonBackgroundSessionFetchers:runningForHost] + < _maxRunningFetchersPerHost) { + // Start another delayed fetcher running, scanning for the minimum + // priority value, defaulting to FIFO for equal priorities + GTMSessionFetcher *nextFetcher = nil; + for (GTMSessionFetcher *delayedFetcher in delayedForHost) { + if (nextFetcher == nil + || delayedFetcher.servicePriority < nextFetcher.servicePriority) { + nextFetcher = delayedFetcher; + } + } + + if (nextFetcher) { + [self addRunningFetcher:nextFetcher forHost:host]; + runningForHost = [_runningFetchersByHost objectForKey:host]; + + [delayedForHost removeObjectIdenticalTo:nextFetcher]; + + if (!fetchersToStart) { + fetchersToStart = [NSMutableArray array]; + } + [fetchersToStart addObject:nextFetcher]; + } + } + + if (runningForHost.count == 0) { + // None left; remove the empty array + [_runningFetchersByHost removeObjectForKey:host]; + } + + if (delayedForHost.count == 0) { + [_delayedFetchersByHost removeObjectForKey:host]; + } + } // @synchronized(self) + + // Start fetchers outside of the synchronized block to avoid a deadlock. + for (GTMSessionFetcher *nextFetcher in fetchersToStart) { + [self startFetcher:nextFetcher]; + } + + // The fetcher is no longer in the running or the delayed array, + // so remove its host and thread properties + fetcher.serviceHost = nil; +} + +- (NSUInteger)numberOfFetchers { + NSUInteger running = [self numberOfRunningFetchers]; + NSUInteger delayed = [self numberOfDelayedFetchers]; + return running + delayed; +} + +- (NSUInteger)numberOfRunningFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger sum = 0; + for (NSString *host in _runningFetchersByHost) { + NSArray *fetchers = [_runningFetchersByHost objectForKey:host]; + sum += fetchers.count; + } + return sum; + } +} + +- (NSUInteger)numberOfDelayedFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger sum = 0; + for (NSString *host in _delayedFetchersByHost) { + NSArray *fetchers = [_delayedFetchersByHost objectForKey:host]; + sum += fetchers.count; + } + return sum; + } +} + +- (NSArray *)issuedFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSMutableArray *allFetchers = [NSMutableArray array]; + void (^accumulateFetchers)(id, id, BOOL *) = ^(NSString *host, + NSArray *fetchersForHost, + BOOL *stop) { + [allFetchers addObjectsFromArray:fetchersForHost]; + }; + [_runningFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers]; + [_delayedFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers]; + + GTMSESSION_ASSERT_DEBUG(allFetchers.count == [NSSet setWithArray:allFetchers].count, + @"Fetcher appears multiple times\n running: %@\n delayed: %@", + _runningFetchersByHost, _delayedFetchersByHost); + + return allFetchers.count > 0 ? allFetchers : nil; + } +} + +- (NSArray *)issuedFetchersWithRequestURL:(NSURL *)requestURL { + NSString *host = requestURL.host; + if (host.length == 0) return nil; + + NSURL *targetURL = [requestURL absoluteURL]; + + NSArray *allFetchers = [self issuedFetchers]; + NSIndexSet *indexes = [allFetchers indexesOfObjectsPassingTest:^BOOL(GTMSessionFetcher *fetcher, + NSUInteger idx, + BOOL *stop) { + NSURL *fetcherURL = [fetcher.request.URL absoluteURL]; + return [fetcherURL isEqual:targetURL]; + }]; + + NSArray *result = nil; + if (indexes.count > 0) { + result = [allFetchers objectsAtIndexes:indexes]; + } + return result; +} + +- (void)stopAllFetchers { + NSArray *delayedFetchersByHost; + NSArray *runningFetchersByHost; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Set the time barrier so fetchers know not to call back even if + // the stop calls below occur after the fetchers naturally + // stopped and so were removed from _runningFetchersByHost, + // but while the callbacks were already enqueued before stopAllFetchers + // was invoked. + _stoppedAllFetchersDate = [[NSDate alloc] init]; + + // Remove fetchers from the delayed list to avoid fetcherDidStop: from + // starting more fetchers running as a side effect of stopping one + delayedFetchersByHost = _delayedFetchersByHost.allValues; + [_delayedFetchersByHost removeAllObjects]; + + runningFetchersByHost = _runningFetchersByHost.allValues; + [_runningFetchersByHost removeAllObjects]; + } + + for (NSArray *delayedForHost in delayedFetchersByHost) { + for (GTMSessionFetcher *fetcher in delayedForHost) { + [self stopFetcher:fetcher]; + } + } + + for (NSArray *runningForHost in runningFetchersByHost) { + for (GTMSessionFetcher *fetcher in runningForHost) { + [self stopFetcher:fetcher]; + } + } +} + +- (NSDate *)stoppedAllFetchersDate { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _stoppedAllFetchersDate; + } +} + +#pragma mark Accessors + +- (BOOL)reuseSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateDispatcher != nil; + } +} + +- (void)setReuseSession:(BOOL)shouldReuse { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL wasReusing = (_delegateDispatcher != nil); + if (shouldReuse != wasReusing) { + [self abandonDispatcher]; + if (shouldReuse) { + _delegateDispatcher = + [[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + } else { + _delegateDispatcher = nil; + } + } + } +} + +- (void)resetSession { + GTMSessionCheckNotSynchronized(self); + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + [self resetSessionInternal]; + } + + dispatch_semaphore_signal(_sessionCreationSemaphore); +} + +- (void)resetSessionInternal { + GTMSessionCheckSynchronized(self); + + // The old dispatchers may be retained as delegates of any ongoing sessions by those sessions. + if (_delegateDispatcher) { + [self abandonDispatcher]; + _delegateDispatcher = + [[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + } +} + +- (void)resetSessionForDispatcherDiscardTimer:(NSTimer *)timer { + GTMSessionCheckNotSynchronized(self); + + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_delegateDispatcher.discardTimer == timer) { + // If the delegate dispatcher's current discardTimer is the same object as the timer + // that fired, no fetcher has recently attempted to start using the session by calling + // startSessionUsage, which invalidates and nils out the timer. + [self resetSessionInternal]; + } else { + // A fetcher has invalidated the timer between its triggering and now, potentially + // meaning a fetcher has requested access to the NSURLSession, and may be in the process + // of starting a new task. The dispatcher should not be abandoned, as this can lead + // to a race condition between calling -finishTasksAndInvalidate on the NSURLSession + // and the fetcher attempting to create a new task. + } + } + + dispatch_semaphore_signal(_sessionCreationSemaphore); +} + +- (NSTimeInterval)unusedSessionTimeout { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _unusedSessionTimeout; + } +} + +- (void)setUnusedSessionTimeout:(NSTimeInterval)timeout { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _unusedSessionTimeout = timeout; + _delegateDispatcher.discardInterval = timeout; + } +} + +// This method should be called inside of @synchronized(self) +- (void)abandonDispatcher { + GTMSessionCheckSynchronized(self); + [_delegateDispatcher abandon]; +} + +- (NSDictionary *)runningFetchersByHost { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_runningFetchersByHost copy]; + } +} + +- (void)setRunningFetchersByHost:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _runningFetchersByHost = [dict mutableCopy]; + } +} + +- (NSDictionary *)delayedFetchersByHost { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_delayedFetchersByHost copy]; + } +} + +- (void)setDelayedFetchersByHost:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delayedFetchersByHost = [dict mutableCopy]; + } +} + +- (id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _authorizer; + } +} + +- (void)setAuthorizer:(id)obj { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (obj != _authorizer) { + [self detachAuthorizer]; + } + + _authorizer = obj; + } + + // Use the fetcher service for the authorization fetches if the auth + // object supports fetcher services + if ([obj respondsToSelector:@selector(setFetcherService:)]) { +#if GTM_USE_SESSION_FETCHER + [obj setFetcherService:self]; +#else + [obj setFetcherService:(id)self]; +#endif + } +} + +// This should be called inside a @synchronized(self) block except during dealloc. +- (void)detachAuthorizer { + // This method is called by the fetcher service's dealloc and setAuthorizer: + // methods; do not override. + // + // The fetcher service retains the authorizer, and the authorizer has a + // weak pointer to the fetcher service (a non-zeroing pointer for + // compatibility with iOS 4 and Mac OS X 10.5/10.6.) + // + // When this fetcher service no longer uses the authorizer, we want to remove + // the authorizer's dependence on the fetcher service. Authorizers can still + // function without a fetcher service. + if ([_authorizer respondsToSelector:@selector(fetcherService)]) { + id authFetcherService = [_authorizer fetcherService]; + if (authFetcherService == self) { + [_authorizer setFetcherService:nil]; + } + } +} + +- (dispatch_queue_t GTM_NONNULL_TYPE)callbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _callbackQueue; + } // @synchronized(self) +} + +- (void)setCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _callbackQueue = queue ?: dispatch_get_main_queue(); + } // @synchronized(self) +} + +- (NSOperationQueue * GTM_NONNULL_TYPE)sessionDelegateQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateQueue; + } // @synchronized(self) +} + +- (void)setSessionDelegateQueue:(NSOperationQueue * GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateQueue = queue ?: [NSOperationQueue mainQueue]; + } // @synchronized(self) +} + +- (NSOperationQueue *)delegateQueue { + // Provided for compatibility with the old fetcher service. The gtm-oauth2 code respects + // any custom delegate queue for calling the app. + return nil; +} + ++ (NSUInteger)numberOfNonBackgroundSessionFetchers:(NSArray *)fetchers { + NSUInteger sum = 0; + for (GTMSessionFetcher *fetcher in fetchers) { + if (!fetcher.usingBackgroundSession) { + ++sum; + } + } + return sum; +} + +@end + +@implementation GTMSessionFetcherService (TestingSupport) + ++ (instancetype)mockFetcherServiceWithFakedData:(NSData *)fakedDataOrNil + fakedError:(NSError *)fakedErrorOrNil { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + NSURL *url = [NSURL URLWithString:@"http://example.invalid"]; + NSHTTPURLResponse *fakedResponse = + [[NSHTTPURLResponse alloc] initWithURL:url + statusCode:(fakedErrorOrNil ? 500 : 200) + HTTPVersion:@"HTTP/1.1" + headerFields:nil]; + GTMSessionFetcherService *service = [[self alloc] init]; + service.allowedInsecureSchemes = @[ @"http" ]; + service.testBlock = ^(GTMSessionFetcher *fetcherToTest, + GTMSessionFetcherTestResponse testResponse) { + testResponse(fakedResponse, fakedDataOrNil, fakedErrorOrNil); + }; + return service; +#else + GTMSESSION_ASSERT_DEBUG(0, @"Test blocks disabled"); + return nil; +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK +} + +#pragma mark Synchronous Wait for Unit Testing + +- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds { + NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + _stoppedFetchersToWaitFor = [NSMutableArray array]; + + BOOL shouldSpinRunLoop = [NSThread isMainThread]; + const NSTimeInterval kSpinInterval = 0.001; + BOOL didTimeOut = NO; + while (([self numberOfFetchers] > 0 || _stoppedFetchersToWaitFor.count > 0)) { + didTimeOut = [giveUpDate timeIntervalSinceNow] < 0; + if (didTimeOut) break; + + GTMSessionFetcher *stoppedFetcher = _stoppedFetchersToWaitFor.firstObject; + if (stoppedFetcher) { + [_stoppedFetchersToWaitFor removeObject:stoppedFetcher]; + [stoppedFetcher waitForCompletionWithTimeout:10.0 * kSpinInterval]; + } + + if (shouldSpinRunLoop) { + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:kSpinInterval]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + [NSThread sleepForTimeInterval:kSpinInterval]; + } + } + _stoppedFetchersToWaitFor = nil; + + return !didTimeOut; +} + +@end + +@implementation GTMSessionFetcherService (BackwardsCompatibilityOnly) + +- (NSInteger)cookieStorageMethod { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _cookieStorageMethod; + } +} + +- (void)setCookieStorageMethod:(NSInteger)cookieStorageMethod { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _cookieStorageMethod = cookieStorageMethod; + } +} + +@end + +@implementation GTMSessionFetcherSessionDelegateDispatcher { + __weak GTMSessionFetcherService *_parentService; + NSURLSession *_session; + + // The task map maps NSURLSessionTasks to GTMSessionFetchers + NSMutableDictionary *_taskToFetcherMap; + // The discard timer will invalidate sessions after the session's last task completes. + NSTimer *_discardTimer; + NSTimeInterval _discardInterval; +} + +@synthesize discardInterval = _discardInterval, + session = _session; + +- (instancetype)init { + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService + sessionDiscardInterval:(NSTimeInterval)discardInterval { + self = [super init]; + if (self) { + _discardInterval = discardInterval; + _parentService = parentService; + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@ %p %@ %@", + [self class], self, + _session ?: @"", + _taskToFetcherMap.count > 0 ? _taskToFetcherMap : @""]; +} + +- (NSTimer *)discardTimer { + GTMSessionCheckNotSynchronized(self); + @synchronized(self) { + return _discardTimer; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)startDiscardTimer { + GTMSessionCheckSynchronized(self); + [_discardTimer invalidate]; + _discardTimer = nil; + if (_discardInterval > 0) { + _discardTimer = [NSTimer timerWithTimeInterval:_discardInterval + target:self + selector:@selector(discardTimerFired:) + userInfo:nil + repeats:NO]; + [_discardTimer setTolerance:(_discardInterval / 10)]; + [[NSRunLoop mainRunLoop] addTimer:_discardTimer forMode:NSRunLoopCommonModes]; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)destroyDiscardTimer { + GTMSessionCheckSynchronized(self); + [_discardTimer invalidate]; + _discardTimer = nil; +} + +- (void)discardTimerFired:(NSTimer *)timer { + GTMSessionFetcherService *service; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger numberOfTasks = _taskToFetcherMap.count; + if (numberOfTasks == 0) { + service = _parentService; + } + } + + // Inform the service that the discard timer has fired, and should check whether the + // service can abandon us. -resetSession cannot be called directly, as there is a + // race condition that must be guarded against with the NSURLSession being returned + // from sessionForFetcherCreation outside other locks. The service can take steps + // to prevent resetting the session if that has occurred. + // + // The service must be called from outside the @synchronized block. + [service resetSessionForDispatcherDiscardTimer:timer]; +} + +- (void)abandon { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self destroySessionAndTimer]; + } +} + +- (void)startSessionUsage { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self destroyDiscardTimer]; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)destroySessionAndTimer { + GTMSessionCheckSynchronized(self); + [self destroyDiscardTimer]; + + // Break any retain cycle from the session holding the delegate. + [_session finishTasksAndInvalidate]; + + // Immediately clear the session so no new task may be issued with it. + // + // The _taskToFetcherMap needs to stay valid until the outstanding tasks finish. + _session = nil; +} + +- (void)setFetcher:(GTMSessionFetcher *)fetcher forTask:(NSURLSessionTask *)task { + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"missing fetcher"); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_taskToFetcherMap == nil) { + _taskToFetcherMap = [[NSMutableDictionary alloc] init]; + } + + if (fetcher) { + [_taskToFetcherMap setObject:fetcher forKey:task]; + [self destroyDiscardTimer]; + } + } +} + +- (void)removeFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Typically, a fetcher should be removed when its task invokes + // URLSession:task:didCompleteWithError:. + // + // When fetching with a testBlock, though, the task completed delegate + // method may not be invoked, requiring cleanup here. + NSArray *tasks = [_taskToFetcherMap allKeysForObject:fetcher]; + GTMSESSION_ASSERT_DEBUG(tasks.count <= 1, @"fetcher task not unmapped: %@", tasks); + [_taskToFetcherMap removeObjectsForKeys:tasks]; + + if (_taskToFetcherMap.count == 0) { + [self startDiscardTimer]; + } + } +} + +// This helper method provides synchronized access to the task map for the delegate +// methods below. +- (id)fetcherForTask:(NSURLSessionTask *)task { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_taskToFetcherMap objectForKey:task]; + } +} + +- (void)removeTaskFromMap:(NSURLSessionTask *)task { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_taskToFetcherMap removeObjectForKey:task]; + } +} + +- (void)setSession:(NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = session; + } +} + +- (NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _session; + } +} + +- (NSTimeInterval)discardInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _discardInterval; + } +} + +- (void)setDiscardInterval:(NSTimeInterval)interval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _discardInterval = interval; + } +} + +// NSURLSessionDelegate protocol methods. + +// - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session; +// +// TODO(seh): How do we route this to an appropriate fetcher? + + +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", + [self class], self, session, error); + NSDictionary *localTaskToFetcherMap; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = nil; + + localTaskToFetcherMap = [_taskToFetcherMap copy]; + } + + // Any "suspended" tasks may not have received callbacks from NSURLSession when the session + // completes; we'll call them now. + [localTaskToFetcherMap enumerateKeysAndObjectsUsingBlock:^(NSURLSessionTask *task, + GTMSessionFetcher *fetcher, + BOOL *stop) { + if (fetcher.session == session) { + // Our delegate method URLSession:task:didCompleteWithError: will rely on + // _taskToFetcherMap so that should still contain this fetcher. + NSError *canceledError = [NSError errorWithDomain:NSURLErrorDomain + code:NSURLErrorCancelled + userInfo:nil]; + [self URLSession:session task:task didCompleteWithError:canceledError]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"Unexpected session in fetcher: %@ has %@ (expected %@)", + fetcher, fetcher.session, session); + } + }]; + + // Our tests rely on this notification to know the session discard timer fired. + NSDictionary *userInfo = @{ kGTMSessionFetcherServiceSessionKey : session }; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherServiceSessionBecameInvalidNotification + object:_parentService + userInfo:userInfo]; +} + + +#pragma mark - NSURLSessionTaskDelegate + +// NSURLSessionTaskDelegate protocol methods. +// +// We won't test here if the fetcher responds to these since we only want this +// class to implement the same delegate methods the fetcher does (so NSURLSession's +// tests for respondsToSelector: will have the same result whether the session +// delegate is the fetcher or this dispatcher.) + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task +willPerformHTTPRedirection:response + newRequest:request + completionHandler:completionHandler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))handler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + didReceiveChallenge:challenge + completionHandler:handler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + needNewBodyStream:(void (^)(NSInputStream *bodyStream))handler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + needNewBodyStream:handler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + didSendBodyData:bytesSent + totalBytesSent:totalBytesSent +totalBytesExpectedToSend:totalBytesExpectedToSend]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error { + id fetcher = [self fetcherForTask:task]; + + // This is the usual way tasks are removed from the task map. + [self removeTaskFromMap:task]; + + [fetcher URLSession:session + task:task + didCompleteWithError:error]; +} + +// NSURLSessionDataDelegate protocol methods. + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition))handler { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + didReceiveResponse:response + completionHandler:handler]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { + id fetcher = [self fetcherForTask:dataTask]; + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"Missing fetcher for %@", dataTask); + [self removeTaskFromMap:dataTask]; + if (fetcher) { + GTMSESSION_ASSERT_DEBUG([fetcher isKindOfClass:[GTMSessionFetcher class]], + @"Expecting GTMSessionFetcher"); + [self setFetcher:(GTMSessionFetcher *)fetcher forTask:downloadTask]; + } + + [fetcher URLSession:session + dataTask:dataTask +didBecomeDownloadTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + didReceiveData:data]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *))handler { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + willCacheResponse:proposedResponse + completionHandler:handler]; +} + +// NSURLSessionDownloadDelegate protocol methods. + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask +didFinishDownloadingToURL:(NSURL *)location { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask +didFinishDownloadingToURL:location]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalWritten +totalBytesExpectedToWrite:(int64_t)totalExpected { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask + didWriteData:bytesWritten + totalBytesWritten:totalWritten +totalBytesExpectedToWrite:totalExpected]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset +expectedTotalBytes:(int64_t)expectedTotalBytes { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask + didResumeAtOffset:fileOffset + expectedTotalBytes:expectedTotalBytes]; +} + +@end diff --git a/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h new file mode 100644 index 0000000..51372f2 --- /dev/null +++ b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h @@ -0,0 +1,128 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// GTMSessionUploadFetcher implements Google's resumable upload protocol. + +// +// This subclass of GTMSessionFetcher simulates the series of fetches +// needed for chunked upload as a single fetch operation. +// +// Protocol document: TBD +// +// To the client, the only fetcher that exists is this class; the subsidiary +// fetchers needed for uploading chunks are not visible (though the most recent +// chunk fetcher may be accessed via the -activeFetcher or -chunkFetcher methods, and +// -responseHeaders and -statusCode reflect results from the most recent chunk +// fetcher.) +// +// Chunk fetchers are discarded as soon as they have completed. +// + +// Note: Unlike the fetcher superclass, the methods of GTMSessionUploadFetcher should +// only be used from the main thread until further work is done to make this subclass +// thread-safe. + +#import "GTMSessionFetcher.h" +#import "GTMSessionFetcherService.h" + +GTM_ASSUME_NONNULL_BEGIN + +// Unless an application knows it needs a smaller chunk size, it should use the standard +// chunk size, which sends the entire file as a single chunk to minimize upload overhead. +extern int64_t const kGTMSessionUploadFetcherStandardChunkSize; + +// When uploading requires data buffer allocations (such as uploading from an NSData or +// an NSFileHandle) this is the maximum buffer size that will be created by the fetcher. +extern int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize; + +// Notification that the upload location URL was provided by the server. +extern NSString *const kGTMSessionFetcherUploadLocationObtainedNotification; + +// Block to provide data during uploads. +// +// Response data may be allocated with dataWithBytesNoCopy:length:freeWhenDone: for efficiency, +// and released after the response block returns. +// +// Pass nil as the data (and optionally an NSError) for a failure. +typedef void (^GTMSessionUploadFetcherDataProviderResponse)(NSData * GTM_NULLABLE_TYPE data, + NSError * GTM_NULLABLE_TYPE error); +typedef void (^GTMSessionUploadFetcherDataProvider)(int64_t offset, int64_t length, + GTMSessionUploadFetcherDataProviderResponse response); + +@interface GTMSessionUploadFetcher : GTMSessionFetcher + +// Create an upload fetcher specifying either the request or the resume location URL, +// then set an upload data source using one of these: +// +// setUploadFileURL: +// setUploadDataLength:provider: +// setUploadFileHandle: +// setUploadData: + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil; + ++ (instancetype)uploadFetcherWithLocation:(NSURL * GTM_NULLABLE_TYPE)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil; + +- (void)setUploadDataLength:(int64_t)fullLength + provider:(GTM_NULLABLE GTMSessionUploadFetcherDataProvider)block; + ++ (NSArray *)uploadFetchersForBackgroundSessions; ++ (GTM_NULLABLE instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier; + +- (void)pauseFetching; +- (void)resumeFetching; +- (BOOL)isPaused; + +@property(atomic, strong, GTM_NULLABLE) NSURL *uploadLocationURL; +@property(atomic, strong, GTM_NULLABLE) NSData *uploadData; +@property(atomic, strong, GTM_NULLABLE) NSURL *uploadFileURL; +@property(atomic, strong, GTM_NULLABLE) NSFileHandle *uploadFileHandle; +@property(atomic, copy, readonly, GTM_NULLABLE) GTMSessionUploadFetcherDataProvider uploadDataProvider; +@property(atomic, copy) NSString *uploadMIMEType; +@property(atomic, assign) int64_t chunkSize; +@property(atomic, readonly, assign) int64_t currentOffset; + +// The fetcher for the current data chunk, if any +@property(atomic, strong, GTM_NULLABLE) GTMSessionFetcher *chunkFetcher; + +// The active fetcher is the current chunk fetcher, or the upload fetcher itself +// if no chunk fetcher has yet been created. +@property(atomic, readonly) GTMSessionFetcher *activeFetcher; + +// The last request made by an active fetcher. Useful for testing. +@property(atomic, readonly, GTM_NULLABLE) NSURLRequest *lastChunkRequest; + +// The status code from the most recently-completed fetch. +@property(atomic, assign) NSInteger statusCode; + +// Exposed for testing only. +@property(atomic, readonly, GTM_NULLABLE) dispatch_queue_t delegateCallbackQueue; +@property(atomic, readonly, GTM_NULLABLE) GTMSessionFetcherCompletionHandler delegateCompletionHandler; + +@end + +@interface GTMSessionFetcher (GTMSessionUploadFetcherMethods) + +@property(readonly, GTM_NULLABLE) GTMSessionUploadFetcher *parentUploadFetcher; + +@end + +GTM_ASSUME_NONNULL_END diff --git a/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m new file mode 100644 index 0000000..a5ae0dc --- /dev/null +++ b/Old Old Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m @@ -0,0 +1,1804 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionUploadFetcher.h" + +static NSString *const kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey = @"_upChunk"; +static NSString *const kGTMSessionIdentifierUploadFileURLMetadataKey = @"_upFileURL"; +static NSString *const kGTMSessionIdentifierUploadFileLengthMetadataKey = @"_upFileLen"; +static NSString *const kGTMSessionIdentifierUploadLocationURLMetadataKey = @"_upLocURL"; +static NSString *const kGTMSessionIdentifierUploadMIMETypeMetadataKey = @"_uploadMIME"; +static NSString *const kGTMSessionIdentifierUploadChunkSizeMetadataKey = @"_upChSize"; +static NSString *const kGTMSessionIdentifierUploadCurrentOffsetMetadataKey = @"_upOffset"; + +static NSString *const kGTMSessionHeaderXGoogUploadChunkGranularity = @"X-Goog-Upload-Chunk-Granularity"; +static NSString *const kGTMSessionHeaderXGoogUploadCommand = @"X-Goog-Upload-Command"; +static NSString *const kGTMSessionHeaderXGoogUploadContentLength = @"X-Goog-Upload-Content-Length"; +static NSString *const kGTMSessionHeaderXGoogUploadContentType = @"X-Goog-Upload-Content-Type"; +static NSString *const kGTMSessionHeaderXGoogUploadOffset = @"X-Goog-Upload-Offset"; +static NSString *const kGTMSessionHeaderXGoogUploadProtocol = @"X-Goog-Upload-Protocol"; +static NSString *const kGTMSessionHeaderXGoogUploadSizeReceived = @"X-Goog-Upload-Size-Received"; +static NSString *const kGTMSessionHeaderXGoogUploadStatus = @"X-Goog-Upload-Status"; +static NSString *const kGTMSessionHeaderXGoogUploadURL = @"X-Goog-Upload-URL"; + +// Property of chunk fetchers identifying the parent upload fetcher. Non-retained NSValue. +static NSString *const kGTMSessionUploadFetcherChunkParentKey = @"_uploadFetcherChunkParent"; + +int64_t const kGTMSessionUploadFetcherStandardChunkSize = (int64_t)LLONG_MAX; + +#if TARGET_OS_IPHONE +int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = 10 * 1024 * 1024; // 10 MB for iOS, watchOS, tvOS +#else +int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = 100 * 1024 * 1024; // 100 MB for macOS +#endif + +typedef NS_ENUM(NSUInteger, GTMSessionUploadFetcherStatus) { + kStatusUnknown, + kStatusActive, + kStatusFinal, + kStatusCancelled, +}; + +NSString *const kGTMSessionFetcherUploadLocationObtainedNotification = + @"kGTMSessionFetcherUploadLocationObtainedNotification"; + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (ProtectedMethods) + +// Access to non-public method on the parent fetcher class. +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks; +- (void)createSessionIdentifierWithMetadata:(NSDictionary *)metadata; +- (GTMSessionFetcherCompletionHandler)completionHandlerWithTarget:(id)target + didFinishSelector:(SEL)finishedSelector; +- (void)invokeOnCallbackQueue:(dispatch_queue_t)callbackQueue + afterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block; +- (NSTimer *)retryTimer; + +@property(readwrite, strong) NSData *downloadedData; +- (void)releaseCallbacks; + +- (NSInteger)statusCodeUnsynchronized; + +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionUploadFetcher () + +// Changing readonly to readwrite. +@property(atomic, strong, readwrite) NSURLRequest *lastChunkRequest; +@property(atomic, readwrite, assign) int64_t currentOffset; + +// Internal properties. +@property(strong, atomic, GTM_NULLABLE) GTMSessionFetcher *fetcherInFlight; // Synchronized on self. + +@property(assign, atomic, getter=isSubdataGenerating) BOOL subdataGenerating; +@property(assign, atomic) BOOL shouldInitiateOffsetQuery; +@property(assign, atomic) int64_t uploadGranularity; + +@end + +@implementation GTMSessionUploadFetcher { + GTMSessionFetcher *_chunkFetcher; + + // We'll call through to the delegate's completion handler. + GTMSessionFetcherCompletionHandler _delegateCompletionHandler; + dispatch_queue_t _delegateCallbackQueue; + + // The initial fetch's body length and bytes actually sent are + // needed for calculating progress during subsequent chunk uploads + int64_t _initialBodyLength; + int64_t _initialBodySent; + + // The upload server address for the chunks of this upload session. + NSURL *_uploadLocationURL; + + // _uploadData, _uploadDataProvider, or _uploadFileHandle may be set, but only one. + NSData *_uploadData; + NSFileHandle *_uploadFileHandle; + GTMSessionUploadFetcherDataProvider _uploadDataProvider; + NSURL *_uploadFileURL; + int64_t _uploadFileLength; + NSString *_uploadMIMEType; + int64_t _chunkSize; + int64_t _uploadGranularity; + BOOL _isPaused; + BOOL _isRestartedUpload; + BOOL _shouldInitiateOffsetQuery; + + // Tied to useBackgroundSession property, since this property is applicable to chunk fetchers. + BOOL _useBackgroundSessionOnChunkFetchers; + + // We keep the latest offset into the upload data just for progress reporting. + int64_t _currentOffset; + + NSDictionary *_recentChunkReponseHeaders; + NSInteger _recentChunkStatusCode; + + // For waiting, we need to know the fetcher in flight, if any, and if subdata generation + // is in progress. + GTMSessionFetcher *_fetcherInFlight; + BOOL _isSubdataGenerating; +} + ++ (void)load { + [self uploadFetchersForBackgroundSessions]; +} + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTMSessionFetcherService *)fetcherService { + GTMSessionUploadFetcher *fetcher = [self uploadFetcherWithRequest:request + fetcherService:fetcherService]; + [fetcher setLocationURL:nil + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize]; + return fetcher; +} + ++ (instancetype)uploadFetcherWithLocation:(NSURL * GTM_NULLABLE_TYPE)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTMSessionFetcherService *)fetcherService { + GTMSessionUploadFetcher *fetcher = [self uploadFetcherWithRequest:nil + fetcherService:fetcherService]; + [fetcher setLocationURL:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize]; + return fetcher; +} + ++ (instancetype)uploadFetcherForSessionIdentifierMetadata:(NSDictionary *)metadata { + GTMSESSION_ASSERT_DEBUG( + [metadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] boolValue], + @"Session identifier metadata is not for an upload fetcher: %@", metadata); + + NSNumber *uploadFileLengthNum = metadata[kGTMSessionIdentifierUploadFileLengthMetadataKey]; + GTMSESSION_ASSERT_DEBUG(uploadFileLengthNum != nil, + @"Session metadata missing an UploadFileSize"); + if (uploadFileLengthNum == nil) return nil; + + int64_t uploadFileLength = [uploadFileLengthNum longLongValue]; + GTMSESSION_ASSERT_DEBUG(uploadFileLength >= 0, @"Session metadata UploadFileSize is unknown"); + + NSString *uploadFileURLString = metadata[kGTMSessionIdentifierUploadFileURLMetadataKey]; + GTMSESSION_ASSERT_DEBUG(uploadFileURLString, @"Session metadata missing an UploadFileURL"); + if (uploadFileURLString == nil) return nil; + + NSURL *uploadFileURL = [NSURL URLWithString:uploadFileURLString]; + // There used to be a call here to NSURL checkResourceIsReachableAndReturnError: to check for the + // existence of the file (also tried NSFileManager fileExistsAtPath:). We've determined + // empirically that the check can fail at startup even when the upload file does in fact exist. + // For now, we'll go ahead and restore the background upload fetcher. If the file doesn't exist, + // it will fail later. + + NSString *uploadLocationURLString = metadata[kGTMSessionIdentifierUploadLocationURLMetadataKey]; + NSURL *uploadLocationURL = + uploadLocationURLString ? [NSURL URLWithString:uploadLocationURLString] : nil; + + NSString *uploadMIMEType = + metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey]; + int64_t uploadChunkSize = + [metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] longLongValue]; + if (uploadChunkSize <= 0) { + uploadChunkSize = kGTMSessionUploadFetcherStandardChunkSize; + } + int64_t currentOffset = + [metadata[kGTMSessionIdentifierUploadCurrentOffsetMetadataKey] longLongValue]; + GTMSESSION_ASSERT_DEBUG(currentOffset <= uploadFileLength, + @"CurrentOffset (%lld) exceeds UploadFileSize (%lld)", + currentOffset, uploadFileLength); + if (currentOffset > uploadFileLength) return nil; + + GTMSessionUploadFetcher *uploadFetcher = [self uploadFetcherWithLocation:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:uploadChunkSize + fetcherService:nil]; + // Set the upload file length before setting the upload file URL tries to determine the length. + [uploadFetcher setUploadFileLength:uploadFileLength]; + + uploadFetcher.uploadFileURL = uploadFileURL; + uploadFetcher.sessionUserInfo = metadata; + uploadFetcher.useBackgroundSession = YES; + uploadFetcher.currentOffset = currentOffset; + uploadFetcher.allowedInsecureSchemes = @[ @"http" ]; // Allowed on restored upload fetcher. + return uploadFetcher; +} + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + fetcherService:(GTMSessionFetcherService *)fetcherService { + // Internal utility method for instantiating fetchers + GTMSessionUploadFetcher *fetcher; + if ([fetcherService isKindOfClass:[GTMSessionFetcherService class]]) { + fetcher = [fetcherService fetcherWithRequest:request + fetcherClass:self]; + } else { + fetcher = [self fetcherWithRequest:request]; + } + fetcher.useBackgroundSession = YES; + return fetcher; +} + ++ (NSPointerArray *)uploadFetcherPointerArrayForBackgroundSessions { + static NSPointerArray *gUploadFetcherPointerArrayForBackgroundSessions = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gUploadFetcherPointerArrayForBackgroundSessions = [NSPointerArray weakObjectsPointerArray]; + }); + return gUploadFetcherPointerArrayForBackgroundSessions; +} + ++ (instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + NSArray *uploadFetchersForBackgroundSessions = [self uploadFetchersForBackgroundSessions]; + for (GTMSessionUploadFetcher *uploadFetcher in uploadFetchersForBackgroundSessions) { + if ([uploadFetcher.chunkFetcher.sessionIdentifier isEqual:sessionIdentifier]) { + return uploadFetcher; + } + } + return nil; +} + ++ (NSArray *)uploadFetchersForBackgroundSessions { + // Collect the background session upload fetchers that are still in memory. + NSPointerArray *uploadFetcherPointerArray = [self uploadFetcherPointerArrayForBackgroundSessions]; + [uploadFetcherPointerArray compact]; + NSMutableSet *restoredSessionIdentifiers = [[NSMutableSet alloc] init]; + NSMutableArray *uploadFetchers = [[NSMutableArray alloc] init]; + for (GTMSessionUploadFetcher *uploadFetcher in uploadFetcherPointerArray) { + NSString *sessionIdentifier = uploadFetcher.chunkFetcher.sessionIdentifier; + if (sessionIdentifier) { + [restoredSessionIdentifiers addObject:sessionIdentifier]; + [uploadFetchers addObject:uploadFetcher]; + } + } + + // The system may have other ongoing background upload sessions. Restore upload fetchers for those + // too. + NSArray *fetchers = [GTMSessionFetcher fetchersForBackgroundSessions]; + for (GTMSessionFetcher *fetcher in fetchers) { + NSString *sessionIdentifier = fetcher.sessionIdentifier; + if (!sessionIdentifier || [restoredSessionIdentifiers containsObject:sessionIdentifier]) { + continue; + } + NSDictionary *sessionIdentifierMetadata = [fetcher sessionIdentifierMetadata]; + if (sessionIdentifierMetadata == nil) { + continue; + } + if (![sessionIdentifierMetadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] boolValue]) { + continue; + } + GTMSessionUploadFetcher *uploadFetcher = + [self uploadFetcherForSessionIdentifierMetadata:sessionIdentifierMetadata]; + if (uploadFetcher == nil) { + // Something went wrong with this upload fetcher, so kill the restored chunk fetcher. + [fetcher stopFetching]; + continue; + } + [uploadFetchers addObject:uploadFetcher]; + uploadFetcher->_chunkFetcher = fetcher; + uploadFetcher->_fetcherInFlight = fetcher; + [uploadFetcher attachSendProgressBlockToChunkFetcher:fetcher]; + fetcher.completionHandler = + [fetcher completionHandlerWithTarget:uploadFetcher + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; + + GTMSESSION_LOG_DEBUG(@"%@ restoring upload fetcher %@ for chunk fetcher %@", + [self class], uploadFetcher, fetcher); + } + return uploadFetchers; +} + +- (void)setUploadData:(NSData *)data { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadData != data) { + _uploadData = data; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSData *)uploadData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadData; + } +} + +- (void)setUploadFileHandle:(NSFileHandle *)fh { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileHandle != fh) { + _uploadFileHandle = fh; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSFileHandle *)uploadFileHandle { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadFileHandle; + } +} + +- (void)setUploadFileURL:(NSURL *)uploadURL { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileURL != uploadURL) { + _uploadFileURL = uploadURL; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSURL *)uploadFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadFileURL; + } +} + +- (void)setUploadFileLength:(int64_t)fullLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadFileLength = fullLength; + } +} + +- (void)setUploadDataLength:(int64_t)fullLength + provider:(GTMSessionUploadFetcherDataProvider)block { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadDataProvider = [block copy]; + _uploadFileLength = fullLength; + } + [self setupRequestHeaders]; +} + +- (GTMSessionUploadFetcherDataProvider)uploadDataProvider { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadDataProvider; + } +} + + +- (void)setUploadMIMEType:(NSString *)uploadMIMEType { + GTMSESSION_ASSERT_DEBUG(0, @"TODO: disallow setUploadMIMEType by making declaration readonly"); + // (and uploadMIMEType, chunksize, currentOffset) + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadMIMEType = uploadMIMEType; + } +} + +- (NSString *)uploadMIMEType { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadMIMEType; + } +} + +- (void)setChunkSize:(int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _chunkSize = chunkSize; + } +} + +- (int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _chunkSize; + } +} + +- (void)setupRequestHeaders { + GTMSessionCheckNotSynchronized(self); + +#if DEBUG + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + int hasData = (_uploadData != nil) ? 1 : 0; + int hasFileHandle = (_uploadFileHandle != nil) ? 1 : 0; + int hasFileURL = (_uploadFileURL != nil) ? 1 : 0; + int hasUploadDataProvider = (_uploadDataProvider != nil) ? 1 : 0; + int numberOfSources = hasData + hasFileHandle + hasFileURL + hasUploadDataProvider; + #pragma unused(numberOfSources) + GTMSESSION_ASSERT_DEBUG(numberOfSources == 1, + @"Need just one upload source (%d)", numberOfSources); + } // @synchronized(self) +#endif + + // Add our custom headers to the initial request indicating the data + // type and total size to be delivered later in the chunk requests. + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + + GTMSESSION_ASSERT_DEBUG((mutableRequest == nil) != (_uploadLocationURL == nil), + @"Request and location are mutually exclusive"); + if (!mutableRequest) return; + + NSNumber *lengthNum = @([self fullUploadLength]); + [mutableRequest setValue:@"resumable" + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadProtocol]; + [mutableRequest setValue:@"start" + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + [mutableRequest setValue:_uploadMIMEType + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentType]; + [mutableRequest setValue:lengthNum.stringValue + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentLength]; + + NSString *method = mutableRequest.HTTPMethod; + if (method == nil || [method caseInsensitiveCompare:@"GET"] == NSOrderedSame) { + [mutableRequest setHTTPMethod:@"POST"]; + } + + // Ensure the user agent header identifies this to the upload server as a + // GTMSessionUploadFetcher client. The /1 can be incremented in the unlikely circumstance + // we need to make a bug fix in the client that the server can recognize. + NSString *const kUserAgentStub = @"(GTMSUF/1)"; + NSString *userAgent = [mutableRequest valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent == nil + || [userAgent rangeOfString:kUserAgentStub].location == NSNotFound) { + if (userAgent.length == 0) { + userAgent = GTMFetcherStandardUserAgentString(nil); + } + userAgent = [userAgent stringByAppendingFormat:@" %@", kUserAgentStub]; + [mutableRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + [self setRequest:mutableRequest]; +} + +- (void)setLocationURL:(NSURL * GTM_NULLABLE_TYPE)location + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(chunkSize > 0, @"chunk size is zero"); + + // When resuming an upload, set the known upload target URL. + _uploadLocationURL = location; + + _uploadMIMEType = uploadMIMEType; + _chunkSize = chunkSize; + + // Indicate that we've not yet determined the file handle's length + _uploadFileLength = -1; + + // Indicate that we've not yet determined the upload fetcher status + _recentChunkStatusCode = -1; + + // If this is restarting an upload begun by another fetcher, + // the location is specified but the request is nil + _isRestartedUpload = (location != nil); + } // @synchronized(self) +} + +- (int64_t)fullUploadLength { + int64_t result; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadData) { + result = (int64_t)_uploadData.length; + } else { + if (_uploadFileLength == -1) { + if (_uploadFileHandle) { + // First time through, seek to end to determine file length + _uploadFileLength = (int64_t)[_uploadFileHandle seekToEndOfFile]; + } else if (_uploadDataProvider) { + // _uploadFileLength is set when the _uploadDataProvider is set. + GTMSESSION_ASSERT_DEBUG(_uploadFileLength >= 0, @"No uploadDataProvider length set"); + } else { + NSNumber *filesizeNum; + NSError *valueError; + if ([_uploadFileURL getResourceValue:&filesizeNum + forKey:NSURLFileSizeKey + error:&valueError]) { + _uploadFileLength = filesizeNum.longLongValue; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Cannot get file size: %@\n %@", + valueError, _uploadFileURL.path); + _uploadFileLength = 0; + } + } + } + result = _uploadFileLength; + } + } // @synchronized(self) + return result; +} + +// Make a subdata of the upload data. +- (void)generateChunkSubdataWithOffset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + GTMSessionUploadFetcherDataProvider uploadDataProvider = self.uploadDataProvider; + if (uploadDataProvider) { + uploadDataProvider(offset, length, response); + return; + } + + NSData *uploadData = self.uploadData; + if (uploadData) { + // NSData provided. + NSData *resultData; + if (offset == 0 && length == (int64_t)uploadData.length) { + resultData = uploadData; + } else { + int64_t dataLength = (int64_t)uploadData.length; + // Ensure our range is valid. b/18007814 + if (offset + length > dataLength) { + NSString *errorMessage = [NSString stringWithFormat: + @"Range invalid for upload data. offset: %lld\tlength: %lld\tdataLength: %lld", + offset, length, dataLength]; + GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage); + response(nil, [self uploadChunkUnavailableErrorWithDescription:errorMessage]); + return; + } + NSRange range = NSMakeRange((NSUInteger)offset, (NSUInteger)length); + resultData = [uploadData subdataWithRange:range]; + } + response(resultData, nil); + return; + } + NSURL *uploadFileURL = self.uploadFileURL; + if (uploadFileURL) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self generateChunkSubdataFromFileURL:uploadFileURL + offset:offset + length:length + response:response]; + }); + return; + } + GTMSESSION_ASSERT_DEBUG(_uploadFileHandle, @"Unexpectedly missing upload data package"); + NSFileHandle *uploadFileHandle = self.uploadFileHandle; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self generateChunkSubdataFromFileHandle:uploadFileHandle + offset:offset + length:length + response:response]; + }); +} + +- (void)generateChunkSubdataFromFileHandle:(NSFileHandle *)fileHandle + offset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + NSData *resultData; + NSError *error; + @try { + [fileHandle seekToFileOffset:(unsigned long long)offset]; + resultData = [fileHandle readDataOfLength:(NSUInteger)length]; + } + @catch (NSException *exception) { + GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileHandle failed to read, %@", exception); + error = [self uploadChunkUnavailableErrorWithDescription:exception.description]; + } + // The response always re-dispatches to the main thread, so we skip doing that here. + response(resultData, error); +} + +- (void)generateChunkSubdataFromFileURL:(NSURL *)fileURL + offset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + GTMSessionCheckNotSynchronized(self); + + NSData *resultData; + NSError *error; + int64_t fullUploadLength = [self fullUploadLength]; + NSData *mappedData = + [NSData dataWithContentsOfURL:fileURL + options:NSDataReadingMappedAlways + NSDataReadingUncached + error:&error]; + if (!mappedData) { + // We could not create an NSData by memory-mapping the file. +#if TARGET_IPHONE_SIMULATOR + // NSTemporaryDirectory() can differ in the simulator between app restarts, + // yet the contents for the new path remains unchanged, so try the latest temp path. + if ([error.domain isEqual:NSCocoaErrorDomain] && (error.code == NSFileReadNoSuchFileError)) { + NSString *filename = [fileURL lastPathComponent]; + NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + NSURL *newFileURL = [NSURL fileURLWithPath:filePath]; + if (![newFileURL isEqual:fileURL]) { + [self generateChunkSubdataFromFileURL:newFileURL + offset:offset + length:length + response:response]; + return; + } + } +#endif + + // If the file is just too large to create an NSData for, or if for some other reason we can't + // map it, create an NSFileHandle instead to read a subset into an NSData. +#if DEBUG + NSNumber *fileSizeNum; + BOOL hasFileSize = [fileURL getResourceValue:&fileSizeNum forKey:NSURLFileSizeKey error:NULL]; + GTMSESSION_LOG_DEBUG(@"Note: uploadFileURL is falling back to creating upload chunks by reading" + @" an NSFileHandle since uploadFileURL failed to map the upload file," + @" file size %@, %@", + hasFileSize ? fileSizeNum : @"unknown", error); +#endif + + NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:fileURL + error:&error]; + if (fileHandle != nil) { + [self generateChunkSubdataFromFileHandle:fileHandle + offset:offset + length:length + response:response]; + return; + } + GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileURL failed to read, %@", error); + // Fall through with the error. + } else { + // Successfully created an NSData by memory-mapping the file. + if (offset > 0 || length < fullUploadLength) { + NSRange range = NSMakeRange((NSUInteger)offset, (NSUInteger)length); + resultData = [mappedData subdataWithRange:range]; + } else { + resultData = mappedData; + } + } + // The response always re-dispatches to the main thread, so we skip re-dispatching here. + response(resultData, error); +} + +- (NSError *)uploadChunkUnavailableErrorWithDescription:(NSString *)description { + // The description in the userInfo is intended as a clue to programmers, not + // for client code to examine or rely on. + NSDictionary *userInfo = @{ @"description" : description }; + return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorUploadChunkUnavailable + userInfo:userInfo]; +} + +- (NSError *)prematureFailureErrorWithUserInfo:(NSDictionary *)userInfo { + // An error for if we get an unexpected status from the upload server or + // otherwise cannot continue. This is an issue beyond the upload protocol; + // there's no way the client can do anything useful except give up. + NSError *error = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:501 // Not implemented + userInfo:userInfo]; + return error; +} + ++ (GTMSessionUploadFetcherStatus)uploadStatusFromResponseHeaders:(NSDictionary *)responseHeaders { + NSString *statusString = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus]; + if ([statusString isEqual:@"active"]) { + return kStatusActive; + } + if ([statusString isEqual:@"final"]) { + return kStatusFinal; + } + if ([statusString isEqual:@"cancelled"]) { + return kStatusCancelled; + } + return kStatusUnknown; +} + +#pragma mark Method overrides affecting the initial fetch only + +- (void)setCompletionHandler:(GTMSessionFetcherCompletionHandler)handler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCompletionHandler = handler; + } +} + +- (void)setDelegateCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCallbackQueue = queue; + } +} + +- (dispatch_queue_t GTM_NULLABLE_TYPE)delegateCallbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateCallbackQueue; + } +} + +- (BOOL)isRestartedUpload { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isRestartedUpload; + } +} + +- (GTMSessionFetcher * GTM_NULLABLE_TYPE)chunkFetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _chunkFetcher; + } +} + +- (void)setChunkFetcher:(GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _chunkFetcher = fetcher; + } +} + +- (void)setFetcherInFlight:(GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _fetcherInFlight = fetcher; + } +} + +- (GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcherInFlight { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _fetcherInFlight; + } +} + +- (void)beginFetchWithCompletionHandler:(GTMSessionFetcherCompletionHandler)handler { + GTMSessionCheckNotSynchronized(self); + + [self setInitialBodyLength:[self bodyLength]]; + + // We'll hold onto the superclass's callback queue so we can invoke the handler + // even after the superclass has released the queue and its callback handler, as + // happens during auth failure. + [self setDelegateCallbackQueue:self.callbackQueue]; + self.completionHandler = handler; + + if ([self isRestartedUpload]) { + // When restarting an upload, we know the destination location for chunk fetches, + // but we need to query to find the initial offset. + if (![self isPaused]) { + [self sendQueryForUploadOffsetWithFetcherProperties:self.properties]; + } + return; + } + // We don't want to call into the client's completion block immediately + // after the finish of the initial connection (the delegate is called only + // when uploading finishes), so we substitute our own completion block to be + // called when the initial connection finishes + GTMSESSION_ASSERT_DEBUG(self.fetcherInFlight == nil, @"unexpected fetcher in flight: %@", + self.fetcherInFlight); + + self.fetcherInFlight = self; + [super beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + self.fetcherInFlight = nil; + // callback + + BOOL hasTestBlock = (self.testBlock != nil); + if (![self isRestartedUpload] && !hasTestBlock) { + if (error == nil) { + [self beginChunkFetches]; + } else { + if ([self retryTimer] == nil) { + [self invokeFinalCallbackWithData:nil + error:error + shouldInvalidateLocation:YES]; + } + } + } else { + // If there was no initial request, then this fetch is resuming some + // other uploadFetcher's initial request, and the superclass's connection + // is never used, so at this point we call the user's actual completion + // block. + if (!hasTestBlock) { + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + } else { + // There was a test block, so we won't do chunk fetches, but we simulate obtaining + // the data to be uploaded from the upload data provider block or the file handle, + // and then call back. + [self generateChunkSubdataWithOffset:0 + length:[self fullUploadLength] + response:^(NSData *generateData, NSError *generateError) { + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + }]; + } + } + }]; +} + +- (void)beginChunkFetches { + GTMSessionCheckNotSynchronized(self); + +#if DEBUG + // The initial response of the resumable upload protocol should have an + // empty body + // + // This assert typically happens because the upload create/edit link URL was + // not supplied with the request, and the server is thus expecting a non- + // resumable request/response. + if (self.downloadedData.length > 0) { + NSData *downloadedData = self.downloadedData; + NSString *str = [[NSString alloc] initWithData:downloadedData + encoding:NSUTF8StringEncoding]; + #pragma unused(str) + GTMSESSION_ASSERT_DEBUG(NO, @"unexpected response data (uploading to the wrong URL?)\n%@", str); + } +#endif + + // We need to get the upload URL from the location header to continue. + NSDictionary *responseHeaders = [self responseHeaders]; + + [self retrieveUploadChunkGranularityFromResponseHeaders:responseHeaders]; + + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown, + @"beginChunkFetches has unexpected upload status for headers %@", responseHeaders); + + BOOL isPrematureStop = (uploadStatus == kStatusFinal) || (uploadStatus == kStatusCancelled); + + NSString *uploadLocationURLStr = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadURL]; + BOOL hasUploadLocation = (uploadLocationURLStr.length > 0); + + if (isPrematureStop || !hasUploadLocation) { + GTMSESSION_ASSERT_DEBUG(NO, @"Premature failure: upload-status:\"%@\" location:%@", + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], uploadLocationURLStr); + // We cannot continue since we do not know the location to use + // as our upload destination. + NSDictionary *userInfo = nil; + NSData *downloadedData = self.downloadedData; + if (downloadedData.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : downloadedData }; + } + NSError *failureError = [self prematureFailureErrorWithUserInfo:userInfo]; + [self invokeFinalCallbackWithData:nil + error:failureError + shouldInvalidateLocation:YES]; + return; + } + + self.uploadLocationURL = [NSURL URLWithString:uploadLocationURLStr]; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherUploadLocationObtainedNotification + object:self]; + + // we've now sent all of the initial post body data, so we need to include + // its size in future progress indicator callbacks + [self setInitialBodySent:[self initialBodyLength]]; + + // just in case the user paused us during the initial fetch... + if (![self isPaused]) { + [self uploadNextChunkWithOffset:0]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + // Overrides the superclass. + [self invokeDelegateWithDidSendBytes:bytesSent + totalBytesSent:totalBytesSent + totalBytesExpectedToSend:totalBytesExpectedToSend + [self fullUploadLength]]; +} + +- (BOOL)shouldReleaseCallbacksUponCompletion { + // Overrides the superclass. + + // We don't want the superclass to release the delegate and callback + // blocks once the initial fetch has finished + // + // This is invoked for only successful completion of the connection; + // an error always will invoke and release the callbacks + return NO; +} + +- (void)invokeFinalCallbackWithData:(NSData *)data + error:(NSError *)error + shouldInvalidateLocation:(BOOL)shouldInvalidateLocation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (shouldInvalidateLocation) { + _uploadLocationURL = nil; + } + + dispatch_queue_t queue = _delegateCallbackQueue; + GTMSessionFetcherCompletionHandler handler = _delegateCompletionHandler; + if (queue && handler) { + [self invokeOnCallbackQueue:queue + afterUserStopped:NO + block:^{ + handler(data, error); + }]; + } + } // @synchronized(self) + + [self releaseUploadAndBaseCallbacks]; +} + +- (void)releaseUploadAndBaseCallbacks { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCallbackQueue = nil; + _delegateCompletionHandler = nil; + _uploadDataProvider = nil; + } + + // Release the base class's callbacks, too, if needed. + [self releaseCallbacks]; +} + +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks { + GTMSessionCheckNotSynchronized(self); + + // Clear _fetcherInFlight when stopped. Moved from stopFetching, since that's a public method, + // where this method does the work. Fixes issue clearing value when retryBlock included. + GTMSessionFetcher *fetcherInFlight = self.fetcherInFlight; + if (fetcherInFlight == self) { + self.fetcherInFlight = nil; + } + + [super stopFetchReleasingCallbacks:shouldReleaseCallbacks]; + + if (shouldReleaseCallbacks) { + [self releaseUploadAndBaseCallbacks]; + } +} + +#pragma mark Chunk fetching methods + +- (void)uploadNextChunkWithOffset:(int64_t)offset { + // use the properties in each chunk fetcher + NSDictionary *props = [self properties]; + + [self uploadNextChunkWithOffset:offset + fetcherProperties:props]; +} + +- (void)sendQueryForUploadOffsetWithFetcherProperties:(NSDictionary *)props { + GTMSessionFetcher *queryFetcher = [self uploadFetcherWithProperties:props + isQueryFetch:YES]; + queryFetcher.bodyData = [NSData data]; + + NSString *originalComment = self.comment; + [queryFetcher setCommentWithFormat:@"%@ (query offset)", + originalComment ? originalComment : @"upload"]; + + [queryFetcher setRequestValue:@"query" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + + self.fetcherInFlight = queryFetcher; + [queryFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(queryFetcher:finishedWithData:error:)]; +} + +- (void)queryFetcher:(GTMSessionFetcher *)queryFetcher + finishedWithData:(NSData *)data + error:(NSError *)error { + self.fetcherInFlight = nil; + + NSDictionary *responseHeaders = [queryFetcher responseHeaders]; + NSString *sizeReceivedHeader; + + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown || error != nil, + @"query fetcher completion has unexpected upload status for headers %@", responseHeaders); + + if (error == nil) { + sizeReceivedHeader = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadSizeReceived]; + + if (uploadStatus == kStatusCancelled || + (uploadStatus == kStatusActive && sizeReceivedHeader == nil)) { + NSDictionary *userInfo = nil; + if (data.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : data }; + } + error = [self prematureFailureErrorWithUserInfo:userInfo]; + } + } + + if (error == nil) { + int64_t offset = [sizeReceivedHeader longLongValue]; + int64_t fullUploadLength = [self fullUploadLength]; + if (offset >= fullUploadLength || uploadStatus == kStatusFinal) { + // Handle we're done + [self chunkFetcher:queryFetcher finishedWithData:data error:nil]; + } else { + [self retrieveUploadChunkGranularityFromResponseHeaders:responseHeaders]; + [self uploadNextChunkWithOffset:offset]; + } + } else { + // Handle query error + [self chunkFetcher:queryFetcher finishedWithData:data error:error]; + } +} + +- (void)sendCancelUploadWithFetcherProperties:(NSDictionary *)props { + GTMSessionFetcher *cancelFetcher = [self uploadFetcherWithProperties:props + isQueryFetch:YES]; + cancelFetcher.bodyData = [NSData data]; + + NSString *originalComment = self.comment; + [cancelFetcher setCommentWithFormat:@"%@ (cancel)", + originalComment ? originalComment : @"upload"]; + + [cancelFetcher setRequestValue:@"cancel" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + + self.fetcherInFlight = cancelFetcher; + [cancelFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + self.fetcherInFlight = nil; + if (error) { + GTMSESSION_LOG_DEBUG(@"cancelFetcher %@", error); + } + }]; +} + +- (void)uploadNextChunkWithOffset:(int64_t)offset + fetcherProperties:(NSDictionary *)props { + GTMSessionCheckNotSynchronized(self); + + // Example chunk headers: + // X-Goog-Upload-Command: upload, finalize + // X-Goog-Upload-Offset: 0 + // Content-Length: 2000000 + // Content-Type: image/jpeg + // + // {bytes 0-1999999} + + // The chunk upload URL requires no authentication header. + GTMSessionFetcher *chunkFetcher = [self uploadFetcherWithProperties:props + isQueryFetch:NO]; + [self attachSendProgressBlockToChunkFetcher:chunkFetcher]; + + BOOL isUploadingFileURL = (self.uploadFileURL != nil); + + // Upload another chunk, meeting server-required granularity. + int64_t chunkSize = self.chunkSize; + + int64_t fullUploadLength = [self fullUploadLength]; + + BOOL isUploadingFullFile = (offset == 0 && chunkSize >= fullUploadLength); + if (!isUploadingFileURL || !isUploadingFullFile) { + // We're not uploading the entire file and given the file URL. Since we'll be + // allocating a subdata block for a chunk, we need to bound it to something that + // won't blow the process's memory. + if (chunkSize > kGTMSessionUploadFetcherMaximumDemandBufferSize) { + chunkSize = kGTMSessionUploadFetcherMaximumDemandBufferSize; + } + } + + int64_t granularity = self.uploadGranularity; + if (granularity > 0) { + if (chunkSize < granularity) { + chunkSize = granularity; + } else { + chunkSize = chunkSize - (chunkSize % granularity); + } + } + + GTMSESSION_ASSERT_DEBUG(offset < fullUploadLength || fullUploadLength == 0, + @"offset %lld exceeds data length %lld", offset, fullUploadLength); + + if (granularity > 0) { + offset = offset - (offset % granularity); + } + + // If the chunk size is bigger than the remaining data, or else + // it's close enough in size to the remaining data that we'd rather + // avoid having a whole extra http fetch for the leftover bit, then make + // this chunk size exactly match the remaining data size + NSString *command; + int64_t thisChunkSize = chunkSize; + + BOOL isChunkTooBig = (thisChunkSize >= (fullUploadLength - offset)); + BOOL isChunkAlmostBigEnough = (fullUploadLength - offset - 2500 < thisChunkSize); + BOOL isFinalChunk = isChunkTooBig || isChunkAlmostBigEnough; + if (isFinalChunk) { + thisChunkSize = fullUploadLength - offset; + if (thisChunkSize > 0) { + command = @"upload, finalize"; + } else { + command = @"finalize"; + } + } else { + command = @"upload"; + } + NSString *lengthStr = @(thisChunkSize).stringValue; + NSString *offsetStr = @(offset).stringValue; + + [chunkFetcher setRequestValue:command forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + [chunkFetcher setRequestValue:lengthStr forHTTPHeaderField:@"Content-Length"]; + [chunkFetcher setRequestValue:offsetStr forHTTPHeaderField:kGTMSessionHeaderXGoogUploadOffset]; + + // Append the range of bytes in this chunk to the fetcher comment. + NSString *baseComment = self.comment; + [chunkFetcher setCommentWithFormat:@"%@ (%lld-%lld)", + baseComment ? baseComment : @"upload", offset, MAX(0, offset + thisChunkSize - 1)]; + + // The chunk size may have changed, so determine again if we're uploading the full file. + isUploadingFullFile = (offset == 0 && thisChunkSize >= fullUploadLength); + if (isUploadingFullFile && isUploadingFileURL) { + // The data is the full upload file URL. + chunkFetcher.bodyFileURL = self.uploadFileURL; + [self beginChunkFetcher:chunkFetcher + offset:offset]; + } else { + // Make an NSData for the subset for this upload chunk. + self.subdataGenerating = YES; + [self generateChunkSubdataWithOffset:offset + length:thisChunkSize + response:^(NSData *chunkData, NSError *chunkError) { + // The subdata methods may leave us on a background thread. + dispatch_async(dispatch_get_main_queue(), ^{ + self.subdataGenerating = NO; + if (chunkData == nil) { + NSError *responseError = chunkError; + if (!responseError) { + responseError = [self uploadChunkUnavailableErrorWithDescription:@"chunkData is nil"]; + } + [self invokeFinalCallbackWithData:nil + error:responseError + shouldInvalidateLocation:YES]; + return; + } + + BOOL didWriteFile = NO; + if (isUploadingFileURL) { + // Make a temporary file with the data subset. + NSString *tempName = + [NSString stringWithFormat:@"GTMUpload_temp_%@", [[NSUUID UUID] UUIDString]]; + NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:tempName]; + NSError *writeError; + didWriteFile = [chunkData writeToFile:tempPath + options:NSDataWritingAtomic + error:&writeError]; + if (didWriteFile) { + chunkFetcher.bodyFileURL = [NSURL fileURLWithPath:tempPath]; + } else { + GTMSESSION_LOG_DEBUG(@"writeToFile failed: %@\n%@", writeError, tempPath); + } + } + if (!didWriteFile) { + chunkFetcher.bodyData = [chunkData copy]; + } + [self beginChunkFetcher:chunkFetcher + offset:offset]; + }); + }]; + } +} + +- (void)beginChunkFetcher:(GTMSessionFetcher *)chunkFetcher + offset:(int64_t)offset { + + // Track the current offset for progress reporting + self.currentOffset = offset; + + // Hang on to the fetcher in case we need to cancel it. We set these before beginning the + // chunk fetch so the observers notified of chunk fetches can inspect the upload fetcher to + // match to the chunk. + self.chunkFetcher = chunkFetcher; + self.fetcherInFlight = chunkFetcher; + + // Update the last chunk request, including any request headers. + self.lastChunkRequest = chunkFetcher.request; + + [chunkFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; +} + +- (void)attachSendProgressBlockToChunkFetcher:(GTMSessionFetcher *)chunkFetcher { + chunkFetcher.sendProgressBlock = ^(int64_t bytesSent, int64_t totalBytesSent, + int64_t totalBytesExpectedToSend) { + // The total bytes expected include the initial body and the full chunked + // data, independent of how big this fetcher's chunk is. + int64_t initialBodySent = [self bodyLength]; // TODO(grobbins) use [self initialBodySent] + int64_t totalSent = initialBodySent + self.currentOffset + totalBytesSent; + int64_t totalExpected = initialBodySent + [self fullUploadLength]; + + [self invokeDelegateWithDidSendBytes:bytesSent + totalBytesSent:totalSent + totalBytesExpectedToSend:totalExpected]; + }; +} + +- (NSDictionary *)uploadSessionIdentifierMetadata { + NSMutableDictionary *metadata = [NSMutableDictionary dictionary]; + metadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] = @YES; + GTMSESSION_ASSERT_DEBUG(self.uploadFileURL, + @"Invalid upload fetcher to create session identifier for metadata"); + metadata[kGTMSessionIdentifierUploadFileURLMetadataKey] = [self.uploadFileURL absoluteString]; + metadata[kGTMSessionIdentifierUploadFileLengthMetadataKey] = @([self fullUploadLength]); + + if (self.uploadLocationURL) { + metadata[kGTMSessionIdentifierUploadLocationURLMetadataKey] = + [self.uploadLocationURL absoluteString]; + } + if (self.uploadMIMEType) { + metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey] = self.uploadMIMEType; + } + metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] = @(self.chunkSize); + metadata[kGTMSessionIdentifierUploadCurrentOffsetMetadataKey] = @(self.currentOffset); + return metadata; +} + +- (GTMSessionFetcher *)uploadFetcherWithProperties:(NSDictionary *)properties + isQueryFetch:(BOOL)isQueryFetch { + GTMSessionCheckNotSynchronized(self); + + // Common code to make a request for a query command or for a chunk upload. + NSURL *uploadLocationURL = self.uploadLocationURL; + NSMutableURLRequest *chunkRequest = [NSMutableURLRequest requestWithURL:uploadLocationURL]; + [chunkRequest setHTTPMethod:@"PUT"]; + + // copy the user-agent from the original connection + NSURLRequest *origRequest = self.request; + NSString *userAgent = [origRequest valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent.length > 0) { + [chunkRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + // To avoid timeouts when debugging, copy the timeout of the initial fetcher. + NSTimeInterval origTimeout = [origRequest timeoutInterval]; + [chunkRequest setTimeoutInterval:origTimeout]; + + // + // Make a new chunk fetcher. + // + GTMSessionFetcher *chunkFetcher = [GTMSessionFetcher fetcherWithRequest:chunkRequest]; + chunkFetcher.callbackQueue = self.callbackQueue; + chunkFetcher.sessionUserInfo = self.sessionUserInfo; + chunkFetcher.configurationBlock = self.configurationBlock; + chunkFetcher.allowedInsecureSchemes = self.allowedInsecureSchemes; + chunkFetcher.allowLocalhostRequest = self.allowLocalhostRequest; + chunkFetcher.allowInvalidServerCertificates = self.allowInvalidServerCertificates; + chunkFetcher.useUploadTask = !isQueryFetch; + + if (self.uploadFileURL && !isQueryFetch && self.useBackgroundSession) { + [chunkFetcher createSessionIdentifierWithMetadata:[self uploadSessionIdentifierMetadata]]; + } + + // Give the chunk fetcher the same properties as the previous chunk fetcher + chunkFetcher.properties = [properties mutableCopy]; + [chunkFetcher setProperty:[NSValue valueWithNonretainedObject:self] + forKey:kGTMSessionUploadFetcherChunkParentKey]; + + // copy other fetcher settings to the new fetcher + chunkFetcher.retryEnabled = self.retryEnabled; + chunkFetcher.maxRetryInterval = self.maxRetryInterval; + + if ([self isRetryEnabled]) { + // We interpose our own retry method both so we can change the request to ask the server to + // tell us where to resume the chunk. + chunkFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *chunkError, + GTMSessionFetcherRetryResponse response){ + void (^finish)(BOOL) = ^(BOOL shouldRetry){ + // We'll retry by sending an offset query. + if (shouldRetry) { + self.shouldInitiateOffsetQuery = !isQueryFetch; + + // We don't know what our actual offset is anymore, but the server will tell us. + self.currentOffset = 0; + } + // We don't actually want to retry this specific fetcher. + response(NO); + }; + + GTMSessionFetcherRetryBlock retryBlock = self.retryBlock; + if (retryBlock) { + // Ask the client, then call the finish block above. + retryBlock(suggestedWillRetry, chunkError, finish); + } else { + finish(suggestedWillRetry); + } + }; + } + + return chunkFetcher; +} + +- (void)chunkFetcher:(GTMSessionFetcher *)chunkFetcher + finishedWithData:(NSData *)data + error:(NSError *)error { + BOOL hasDestroyedOldChunkFetcher = NO; + self.fetcherInFlight = nil; + + NSDictionary *responseHeaders = [chunkFetcher responseHeaders]; + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown + || error != nil + || self.wasCreatedFromBackgroundSession, + @"chunk fetcher completion has kStatusUnknown upload status for headers %@ fetcher %@", + responseHeaders, self); + BOOL isUploadStatusStopped = (uploadStatus == kStatusFinal || uploadStatus == kStatusCancelled); + + // Check if the fetcher was actually querying. If it failed, do not retry, + // as it would enter an infinite retry loop. + NSString *uploadCommand = + chunkFetcher.request.allHTTPHeaderFields[kGTMSessionHeaderXGoogUploadCommand]; + BOOL isQueryFetch = [uploadCommand isEqual:@"query"]; + + int64_t previousContentLength = + [[chunkFetcher.request valueForHTTPHeaderField:@"Content-Length"] longLongValue]; + // The Content-Length header may not be present if the chunk fetcher was recreated from + // a background session. + BOOL hasKnownChunkSize = (previousContentLength > 0); + BOOL needsQuery = (!hasKnownChunkSize && !isUploadStatusStopped); + + if (error || (needsQuery && !isQueryFetch)) { + NSInteger status = error.code; + + // Status 4xx indicates a bad offset in the Google upload protocol. However, do not retry status + // 404 per spec, nor if the upload size appears to have been zero (since the server will just + // keep asking us to retry.) + if (self.shouldInitiateOffsetQuery || + (needsQuery && !isQueryFetch) || + ([error.domain isEqual:kGTMSessionFetcherStatusDomain] && + status >= 400 && status <= 499 && + status != 404 && + uploadStatus == kStatusActive && + previousContentLength > 0)) { + self.shouldInitiateOffsetQuery = NO; + [self destroyChunkFetcher]; + hasDestroyedOldChunkFetcher = YES; + [self sendQueryForUploadOffsetWithFetcherProperties:chunkFetcher.properties]; + } else { + // Some unexpected status has occurred; handle it as we would a regular + // object fetcher failure. + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:NO]; + } + } else { + // The chunk has uploaded successfully. + int64_t newOffset = self.currentOffset + previousContentLength; +#if DEBUG + // Verify that if we think all of the uploading data has been sent, the server responded with + // the "final" upload status. + BOOL hasUploadAllData = (newOffset == [self fullUploadLength]); + BOOL isFinalStatus = (uploadStatus == kStatusFinal); + #pragma unused(hasUploadAllData,isFinalStatus) + GTMSESSION_ASSERT_DEBUG(hasUploadAllData == isFinalStatus || !hasKnownChunkSize, + @"uploadStatus:%@ newOffset:%zd (%lld + %zd) fullUploadLength:%lld" + @" chunkFetcher:%@ requestHeaders:%@ responseHeaders:%@", + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], + newOffset, self.currentOffset, previousContentLength, + [self fullUploadLength], + chunkFetcher, chunkFetcher.request.allHTTPHeaderFields, + responseHeaders); +#endif + if (isUploadStatusStopped) { + // This was the last chunk. + if (error == nil && uploadStatus == kStatusCancelled) { + // Report cancelled status as an error. + NSDictionary *userInfo = nil; + if (data.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : data }; + } + data = nil; + error = [self prematureFailureErrorWithUserInfo:userInfo]; + } else { + // The upload is in final status. + // + // Take the chunk fetcher's data as the superclass data. + self.downloadedData = data; + self.statusCode = chunkFetcher.statusCode; + } + + // we're done + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + } else { + // Start the next chunk. + self.currentOffset = newOffset; + + // We want to destroy this chunk fetcher before creating the next one, but + // we want to pass on its properties + NSDictionary *props = [chunkFetcher properties]; + + // We no longer need to be able to cancel this chunkFetcher. Destroy it + // before we create a new chunk fetcher. + [self destroyChunkFetcher]; + hasDestroyedOldChunkFetcher = YES; + + [self uploadNextChunkWithOffset:newOffset + fetcherProperties:props]; + } + } + if (!hasDestroyedOldChunkFetcher) { + [self destroyChunkFetcher]; + } +} + +- (void)destroyChunkFetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_fetcherInFlight == _chunkFetcher) { + _fetcherInFlight = nil; + } + + [_chunkFetcher stopFetching]; + + NSURL *chunkFileURL = _chunkFetcher.bodyFileURL; + BOOL wasTemporaryUploadFile = ![chunkFileURL isEqual:_uploadFileURL]; + if (wasTemporaryUploadFile) { + NSError *error; + [[NSFileManager defaultManager] removeItemAtURL:chunkFileURL + error:&error]; + if (error) { + GTMSESSION_LOG_DEBUG(@"removingItemAtURL failed: %@\n%@", error, chunkFileURL); + } + } + + _recentChunkReponseHeaders = _chunkFetcher.responseHeaders; + + // To avoid retain cycles, remove all properties except the parent identifier. + _chunkFetcher.properties = + @{ kGTMSessionUploadFetcherChunkParentKey : [NSValue valueWithNonretainedObject:self] }; + + _chunkFetcher.retryBlock = nil; + _chunkFetcher.sendProgressBlock = nil; + _chunkFetcher = nil; + } // @synchronized(self) +} + +// This method calculates the proper values to pass to the client's send progress block. +// +// The actual total bytes sent include the initial body sent, plus the +// offset into the batched data prior to the current chunk fetcher + +- (void)invokeDelegateWithDidSendBytes:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpected { + GTMSessionCheckNotSynchronized(self); + + // Ensure the chunk fetcher survives the callback in case the user pauses the upload process. + __block GTMSessionFetcher *holdFetcher = self.chunkFetcher; + + [self invokeOnCallbackQueue:self.delegateCallbackQueue + afterUserStopped:NO + block:^{ + GTMSessionFetcherSendProgressBlock sendProgressBlock = self.sendProgressBlock; + if (sendProgressBlock) { + sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpected); + } + holdFetcher = nil; + }]; +} + +- (void)retrieveUploadChunkGranularityFromResponseHeaders:(NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + + // Standard granularity for Google uploads is 256K. + NSString *chunkGranularityHeader = + [responseHeaders objectForKey:@"X-Goog-Upload-Chunk-Granularity"]; + self.uploadGranularity = chunkGranularityHeader.longLongValue; +} + +#pragma mark - + +- (BOOL)isPaused { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isPaused; + } // @synchronized(self) +} + +- (void)pauseFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _isPaused = YES; + } // @synchronized(self) + + // Pausing just means stopping the current chunk from uploading; + // when we resume, we will send a query request to the server to + // figure out what bytes to resume sending. + // + // We won't try to cancel the initial data upload, but rather will check + // for being paused in beginChunkFetches. + [self destroyChunkFetcher]; +} + +- (void)resumeFetching { + BOOL wasPaused; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + wasPaused = _isPaused; + _isPaused = NO; + } // @synchronized(self) + + if (wasPaused) { + [self sendQueryForUploadOffsetWithFetcherProperties:self.properties]; + } +} + +- (void)stopFetching { + // Overrides the superclass + [self destroyChunkFetcher]; + + // If we think the server is waiting for more data, then tell it there won't be more. + if (self.uploadLocationURL) { + [self sendCancelUploadWithFetcherProperties:[self properties]]; + self.uploadLocationURL = nil; + } + + [super stopFetching]; +} + +#pragma mark - + +// Public properties. +@synthesize currentOffset = _currentOffset, + delegateCompletionHandler = _delegateCompletionHandler, + chunkFetcher = _chunkFetcher, + lastChunkRequest = _lastChunkRequest, + subdataGenerating = _subdataGenerating, + shouldInitiateOffsetQuery = _shouldInitiateOffsetQuery, + uploadGranularity = _uploadGranularity; + +// Internal properties. +@dynamic fetcherInFlight; +@dynamic activeFetcher; +@dynamic statusCode; +@dynamic delegateCallbackQueue; + ++ (void)removePointer:(void *)pointer fromPointerArray:(NSPointerArray *)pointerArray { + for (NSUInteger index = 0, count = pointerArray.count; index < count; ++index) { + void *pointerAtIndex = [pointerArray pointerAtIndex:index]; + if (pointerAtIndex == pointer) { + [pointerArray removePointerAtIndex:index]; + return; + } + } +} + +- (BOOL)useBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _useBackgroundSessionOnChunkFetchers; + } // @synchronized(self +} + +- (void)setUseBackgroundSession:(BOOL)useBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_useBackgroundSessionOnChunkFetchers != useBackgroundSession) { + _useBackgroundSessionOnChunkFetchers = useBackgroundSession; + NSPointerArray *uploadFetcherPointerArrayForBackgroundSessions = + [[self class] uploadFetcherPointerArrayForBackgroundSessions]; + if (_useBackgroundSessionOnChunkFetchers) { + [uploadFetcherPointerArrayForBackgroundSessions addPointer:(__bridge void *)self]; + } else { + [[self class] removePointer:(__bridge void *)self + fromPointerArray:uploadFetcherPointerArrayForBackgroundSessions]; + } + } + } // @synchronized(self +} + +- (BOOL)canFetchWithBackgroundSession { + // The initial upload fetcher is always a foreground session; the + // useBackgroundSession property will apply only to chunk fetchers, + // not to queries. + return NO; +} + +- (NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + // Overrides the superclass + + // If asked for the fetcher's response, use the most recent chunk fetcher's response, + // since the original request's response lacks useful information like the actual + // Content-Type. + NSDictionary *dict = self.chunkFetcher.responseHeaders; + if (dict) { + return dict; + } + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_recentChunkReponseHeaders) { + return _recentChunkReponseHeaders; + } + } // @synchronized(self + + // No chunk fetcher yet completed, so return whatever we have from the initial fetch. + return [super responseHeaders]; +} + +- (NSInteger)statusCodeUnsynchronized { + GTMSessionCheckSynchronized(self); + + if (_recentChunkStatusCode != -1) { + // Overrides the superclass to indicate status appropriate to the initial + // or latest chunk fetch + return _recentChunkStatusCode; + } else { + return [super statusCodeUnsynchronized]; + } +} + + +- (void)setStatusCode:(NSInteger)val { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _recentChunkStatusCode = val; + } +} + +- (int64_t)initialBodyLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _initialBodyLength; + } +} + +- (void)setInitialBodyLength:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _initialBodyLength = length; + } +} + +- (int64_t)initialBodySent { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _initialBodySent; + } +} + +- (void)setInitialBodySent:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _initialBodySent = length; + } +} + +- (NSURL *)uploadLocationURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadLocationURL; + } +} + +- (void)setUploadLocationURL:(NSURL *)locationURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadLocationURL = locationURL; + } +} + +- (GTMSessionFetcher *)activeFetcher { + GTMSessionFetcher *result = self.fetcherInFlight; + if (result) return result; + + return self; +} + +- (BOOL)isFetching { + // If there is an active chunk fetcher, then the upload fetcher is considered + // to still be fetching. + if (self.fetcherInFlight != nil) return YES; + + return [super isFetching]; +} + +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds { + NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + + while (self.fetcherInFlight || self.subdataGenerating) { + if ([timeoutDate timeIntervalSinceNow] < 0) return NO; + + if (self.subdataGenerating) { + // Allow time for subdata generation. + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:0.001]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + // Wait for any chunk or query fetchers that still have pending callbacks or + // notifications. + BOOL timedOut; + + if (self.fetcherInFlight == self) { + timedOut = ![super waitForCompletionWithTimeout:timeoutInSeconds]; + } else { + timedOut = ![self.fetcherInFlight waitForCompletionWithTimeout:timeoutInSeconds]; + } + if (timedOut) return NO; + } + } + return YES; +} + +@end + +@implementation GTMSessionFetcher (GTMSessionUploadFetcherMethods) + +- (GTMSessionUploadFetcher *)parentUploadFetcher { + NSValue *property = [self propertyForKey:kGTMSessionUploadFetcherChunkParentKey]; + if (!property) return nil; + + GTMSessionUploadFetcher *uploadFetcher = property.nonretainedObjectValue; + + GTMSESSION_ASSERT_DEBUG([uploadFetcher isKindOfClass:[GTMSessionUploadFetcher class]], + @"Unexpected parent upload fetcher class: %@", [uploadFetcher class]); + return uploadFetcher; +} + +@end diff --git a/Old Old Task Master/Pods/GoogleToolboxForMac/GTMDefines.h b/Old Old Task Master/Pods/GoogleToolboxForMac/GTMDefines.h new file mode 100644 index 0000000..8ec88cc --- /dev/null +++ b/Old Old Task Master/Pods/GoogleToolboxForMac/GTMDefines.h @@ -0,0 +1,392 @@ +// +// GTMDefines.h +// +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +// ============================================================================ + +#include +#include + +#ifdef __OBJC__ +#include +#endif // __OBJC__ + +#if TARGET_OS_IPHONE +#include +#endif // TARGET_OS_IPHONE + +// ---------------------------------------------------------------------------- +// CPP symbols that can be overridden in a prefix to control how the toolbox +// is compiled. +// ---------------------------------------------------------------------------- + + +// By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and +// GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens +// when a validation fails. If you implement your own validators, you may want +// to control their internals using the same macros for consistency. +#ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT + #define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0 +#endif + +// Ensure __has_feature and __has_extension are safe to use. +// See http://clang-analyzer.llvm.org/annotations.html +#ifndef __has_feature // Optional. + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef __has_extension + #define __has_extension __has_feature // Compatibility with pre-3.0 compilers. +#endif + +// Give ourselves a consistent way to do inlines. Apple's macros even use +// a few different actual definitions, so we're based off of the foundation +// one. +#if !defined(GTM_INLINE) + #if (defined (__GNUC__) && (__GNUC__ == 4)) || defined (__clang__) + #define GTM_INLINE static __inline__ __attribute__((always_inline)) + #else + #define GTM_INLINE static __inline__ + #endif +#endif + +// Give ourselves a consistent way of doing externs that links up nicely +// when mixing objc and objc++ +#if !defined (GTM_EXTERN) + #if defined __cplusplus + #define GTM_EXTERN extern "C" + #define GTM_EXTERN_C_BEGIN extern "C" { + #define GTM_EXTERN_C_END } + #else + #define GTM_EXTERN extern + #define GTM_EXTERN_C_BEGIN + #define GTM_EXTERN_C_END + #endif +#endif + +// Give ourselves a consistent way of exporting things if we have visibility +// set to hidden. +#if !defined (GTM_EXPORT) + #define GTM_EXPORT __attribute__((visibility("default"))) +#endif + +// Give ourselves a consistent way of declaring something as unused. This +// doesn't use __unused because that is only supported in gcc 4.2 and greater. +#if !defined (GTM_UNUSED) +#define GTM_UNUSED(x) ((void)(x)) +#endif + +// _GTMDevLog & _GTMDevAssert +// +// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for +// developer level errors. This implementation simply macros to NSLog/NSAssert. +// It is not intended to be a general logging/reporting system. +// +// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert +// for a little more background on the usage of these macros. +// +// _GTMDevLog log some error/problem in debug builds +// _GTMDevAssert assert if condition isn't met w/in a method/function +// in all builds. +// +// To replace this system, just provide different macro definitions in your +// prefix header. Remember, any implementation you provide *must* be thread +// safe since this could be called by anything in what ever situtation it has +// been placed in. +// + +// We only define the simple macros if nothing else has defined this. +#ifndef _GTMDevLog + +#ifdef DEBUG + #define _GTMDevLog(...) NSLog(__VA_ARGS__) +#else + #define _GTMDevLog(...) do { } while (0) +#endif + +#endif // _GTMDevLog + +#ifndef _GTMDevAssert +// we directly invoke the NSAssert handler so we can pass on the varargs +// (NSAssert doesn't have a macro we can use that takes varargs) +#if !defined(NS_BLOCK_ASSERTIONS) + #define _GTMDevAssert(condition, ...) \ + do { \ + if (!(condition)) { \ + [[NSAssertionHandler currentHandler] \ + handleFailureInFunction:(NSString *) \ + [NSString stringWithUTF8String:__PRETTY_FUNCTION__] \ + file:(NSString *)[NSString stringWithUTF8String:__FILE__] \ + lineNumber:__LINE__ \ + description:__VA_ARGS__]; \ + } \ + } while(0) +#else // !defined(NS_BLOCK_ASSERTIONS) + #define _GTMDevAssert(condition, ...) do { } while (0) +#endif // !defined(NS_BLOCK_ASSERTIONS) + +#endif // _GTMDevAssert + +// _GTMCompileAssert +// +// Note: Software for current compilers should just use _Static_assert directly +// instead of this macro. +// +// _GTMCompileAssert is an assert that is meant to fire at compile time if you +// want to check things at compile instead of runtime. For example if you +// want to check that a wchar is 4 bytes instead of 2 you would use +// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X) +// Note that the second "arg" is not in quotes, and must be a valid processor +// symbol in it's own right (no spaces, punctuation etc). + +// Wrapping this in an #ifndef allows external groups to define their own +// compile time assert scheme. +#ifndef _GTMCompileAssert + #if __has_feature(c_static_assert) || __has_extension(c_static_assert) + #define _GTMCompileAssert(test, msg) _Static_assert((test), #msg) + #else + // Pre-Xcode 7 support. + // + // We got this technique from here: + // http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html + #define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg + #define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg) + #define _GTMCompileAssert(test, msg) \ + typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ] + #endif // __has_feature(c_static_assert) || __has_extension(c_static_assert) +#endif // _GTMCompileAssert + +// ---------------------------------------------------------------------------- +// CPP symbols defined based on the project settings so the GTM code has +// simple things to test against w/o scattering the knowledge of project +// setting through all the code. +// ---------------------------------------------------------------------------- + +// Provide a single constant CPP symbol that all of GTM uses for ifdefing +// iPhone code. +#if TARGET_OS_IPHONE // iPhone SDK + // For iPhone specific stuff + #define GTM_IPHONE_SDK 1 + #if TARGET_IPHONE_SIMULATOR + #define GTM_IPHONE_DEVICE 0 + #define GTM_IPHONE_SIMULATOR 1 + #else + #define GTM_IPHONE_DEVICE 1 + #define GTM_IPHONE_SIMULATOR 0 + #endif // TARGET_IPHONE_SIMULATOR + // By default, GTM has provided it's own unittesting support, define this + // to use the support provided by Xcode, especially for the Xcode4 support + // for unittesting. + #ifndef GTM_USING_XCTEST + #define GTM_USING_XCTEST 0 + #endif + #define GTM_MACOS_SDK 0 +#else + // For MacOS specific stuff + #define GTM_MACOS_SDK 1 + #define GTM_IPHONE_SDK 0 + #define GTM_IPHONE_SIMULATOR 0 + #define GTM_IPHONE_DEVICE 0 + #ifndef GTM_USING_XCTEST + #define GTM_USING_XCTEST 0 + #endif +#endif + +// Some of our own availability macros +#if GTM_MACOS_SDK +#define GTM_AVAILABLE_ONLY_ON_IPHONE UNAVAILABLE_ATTRIBUTE +#define GTM_AVAILABLE_ONLY_ON_MACOS +#else +#define GTM_AVAILABLE_ONLY_ON_IPHONE +#define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE +#endif + +// GC was dropped by Apple, define the old constant incase anyone still keys +// off of it. +#ifndef GTM_SUPPORT_GC + #define GTM_SUPPORT_GC 0 +#endif + +// Some support for advanced clang static analysis functionality +#ifndef NS_RETURNS_RETAINED + #if __has_feature(attribute_ns_returns_retained) + #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) + #else + #define NS_RETURNS_RETAINED + #endif +#endif + +#ifndef NS_RETURNS_NOT_RETAINED + #if __has_feature(attribute_ns_returns_not_retained) + #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) + #else + #define NS_RETURNS_NOT_RETAINED + #endif +#endif + +#ifndef CF_RETURNS_RETAINED + #if __has_feature(attribute_cf_returns_retained) + #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) + #else + #define CF_RETURNS_RETAINED + #endif +#endif + +#ifndef CF_RETURNS_NOT_RETAINED + #if __has_feature(attribute_cf_returns_not_retained) + #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) + #else + #define CF_RETURNS_NOT_RETAINED + #endif +#endif + +#ifndef NS_CONSUMED + #if __has_feature(attribute_ns_consumed) + #define NS_CONSUMED __attribute__((ns_consumed)) + #else + #define NS_CONSUMED + #endif +#endif + +#ifndef CF_CONSUMED + #if __has_feature(attribute_cf_consumed) + #define CF_CONSUMED __attribute__((cf_consumed)) + #else + #define CF_CONSUMED + #endif +#endif + +#ifndef NS_CONSUMES_SELF + #if __has_feature(attribute_ns_consumes_self) + #define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) + #else + #define NS_CONSUMES_SELF + #endif +#endif + +#ifndef GTM_NONNULL + #if defined(__has_attribute) + #if __has_attribute(nonnull) + #define GTM_NONNULL(x) __attribute__((nonnull x)) + #else + #define GTM_NONNULL(x) + #endif + #else + #define GTM_NONNULL(x) + #endif +#endif + +// Invalidates the initializer from which it's called. +#ifndef GTMInvalidateInitializer + #if __has_feature(objc_arc) + #define GTMInvalidateInitializer() \ + do { \ + [self class]; /* Avoid warning of dead store to |self|. */ \ + _GTMDevAssert(NO, @"Invalid initializer."); \ + return nil; \ + } while (0) + #else + #define GTMInvalidateInitializer() \ + do { \ + [self release]; \ + _GTMDevAssert(NO, @"Invalid initializer."); \ + return nil; \ + } while (0) + #endif +#endif + +#ifndef GTMCFAutorelease + // GTMCFAutorelease returns an id. In contrast, Apple's CFAutorelease returns + // a CFTypeRef. + #if __has_feature(objc_arc) + #define GTMCFAutorelease(x) CFBridgingRelease(x) + #else + #define GTMCFAutorelease(x) ([(id)x autorelease]) + #endif +#endif + +#ifdef __OBJC__ + + +// Macro to allow you to create NSStrings out of other macros. +// #define FOO foo +// NSString *fooString = GTM_NSSTRINGIFY(FOO); +#if !defined (GTM_NSSTRINGIFY) + #define GTM_NSSTRINGIFY_INNER(x) @#x + #define GTM_NSSTRINGIFY(x) GTM_NSSTRINGIFY_INNER(x) +#endif + +// Macro to allow fast enumeration when building for 10.5 or later, and +// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration +// does keys, so pick the right thing, nothing is done on the FastEnumeration +// side to be sure you're getting what you wanted. +#ifndef GTM_FOREACH_OBJECT + #if TARGET_OS_IPHONE || !(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) + #define GTM_FOREACH_ENUMEREE(element, enumeration) \ + for (element in enumeration) + #define GTM_FOREACH_OBJECT(element, collection) \ + for (element in collection) + #define GTM_FOREACH_KEY(element, collection) \ + for (element in collection) + #else + #define GTM_FOREACH_ENUMEREE(element, enumeration) \ + for (NSEnumerator *_ ## element ## _enum = enumeration; \ + (element = [_ ## element ## _enum nextObject]) != nil; ) + #define GTM_FOREACH_OBJECT(element, collection) \ + GTM_FOREACH_ENUMEREE(element, [collection objectEnumerator]) + #define GTM_FOREACH_KEY(element, collection) \ + GTM_FOREACH_ENUMEREE(element, [collection keyEnumerator]) + #endif +#endif + +// ============================================================================ + +// GTM_SEL_STRING is for specifying selector (usually property) names to KVC +// or KVO methods. +// In debug it will generate warnings for undeclared selectors if +// -Wunknown-selector is turned on. +// In release it will have no runtime overhead. +#ifndef GTM_SEL_STRING + #ifdef DEBUG + #define GTM_SEL_STRING(selName) NSStringFromSelector(@selector(selName)) + #else + #define GTM_SEL_STRING(selName) @#selName + #endif // DEBUG +#endif // GTM_SEL_STRING + +#ifndef GTM_WEAK +#if __has_feature(objc_arc_weak) + // With ARC enabled, __weak means a reference that isn't implicitly + // retained. __weak objects are accessed through runtime functions, so + // they are zeroed out, but this requires OS X 10.7+. + // At clang r251041+, ARC-style zeroing weak references even work in + // non-ARC mode. + #define GTM_WEAK __weak + #elif __has_feature(objc_arc) + // ARC, but targeting 10.6 or older, where zeroing weak references don't + // exist. + #define GTM_WEAK __unsafe_unretained + #else + // With manual reference counting, __weak used to be silently ignored. + // clang r251041 gives it the ARC semantics instead. This means they + // now require a deployment target of 10.7, while some clients of GTM + // still target 10.6. In these cases, expand to __unsafe_unretained instead + #define GTM_WEAK + #endif +#endif + +#endif // __OBJC__ diff --git a/Old Old Task Master/Pods/GoogleToolboxForMac/LICENSE b/Old Old Task Master/Pods/GoogleToolboxForMac/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Old Old Task Master/Pods/GoogleToolboxForMac/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Old Old Task Master/Pods/Headers/Private/Firebase/Firebase.h b/Old Old Task Master/Pods/Headers/Private/Firebase/Firebase.h new file mode 120000 index 0000000..6d62033 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Private/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/Core/Sources/Firebase.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcher.h b/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcher.h new file mode 120000 index 0000000..7ed730f --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcher.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcher.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherLogging.h b/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherLogging.h new file mode 120000 index 0000000..ada41e3 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherLogging.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcherLogging.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherService.h b/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherService.h new file mode 120000 index 0000000..1ef9cbb --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherService.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcherService.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionUploadFetcher.h b/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionUploadFetcher.h new file mode 120000 index 0000000..cef7a0d --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionUploadFetcher.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionUploadFetcher.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDefines.h b/Old Old Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDefines.h new file mode 120000 index 0000000..5503110 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDefines.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/GTMDefines.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/Firebase/Firebase.h b/Old Old Task Master/Pods/Headers/Public/Firebase/Firebase.h new file mode 120000 index 0000000..6d62033 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/Core/Sources/Firebase.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics+AppDelegate.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics+AppDelegate.h new file mode 120000 index 0000000..1d9bd7e --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics+AppDelegate.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics.h new file mode 120000 index 0000000..f8fc4fb --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalyticsConfiguration.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalyticsConfiguration.h new file mode 120000 index 0000000..6773271 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalyticsConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalyticsConfiguration.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRApp.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRApp.h new file mode 120000 index 0000000..97c9b35 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRApp.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRApp.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRConfiguration.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRConfiguration.h new file mode 120000 index 0000000..c34ddb8 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRConfiguration.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIREventNames.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIREventNames.h new file mode 120000 index 0000000..8924cc0 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIREventNames.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIREventNames.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIROptions.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIROptions.h new file mode 120000 index 0000000..a40119b --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIROptions.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIROptions.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRParameterNames.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRParameterNames.h new file mode 120000 index 0000000..6e37a6e --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRParameterNames.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRParameterNames.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRUserPropertyNames.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRUserPropertyNames.h new file mode 120000 index 0000000..4459d6b --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRUserPropertyNames.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FirebaseAnalytics.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FirebaseAnalytics.h new file mode 120000 index 0000000..2d48a7d --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FirebaseAnalytics.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuth.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuth.h new file mode 120000 index 0000000..35e20c5 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuth.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuth.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthCredential.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthCredential.h new file mode 120000 index 0000000..ed32f36 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthCredential.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthCredential.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthErrors.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthErrors.h new file mode 120000 index 0000000..e21f64e --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthErrors.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthErrors.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIREmailPasswordAuthProvider.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIREmailPasswordAuthProvider.h new file mode 120000 index 0000000..2dbd016 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIREmailPasswordAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIREmailPasswordAuthProvider.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRFacebookAuthProvider.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRFacebookAuthProvider.h new file mode 120000 index 0000000..8fbecbe --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRFacebookAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRFacebookAuthProvider.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGitHubAuthProvider.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGitHubAuthProvider.h new file mode 120000 index 0000000..dbb098a --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGitHubAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGitHubAuthProvider.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGoogleAuthProvider.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGoogleAuthProvider.h new file mode 120000 index 0000000..ad7189e --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGoogleAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGoogleAuthProvider.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRTwitterAuthProvider.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRTwitterAuthProvider.h new file mode 120000 index 0000000..30a19f2 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRTwitterAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRTwitterAuthProvider.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUser.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUser.h new file mode 120000 index 0000000..ecac892 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUser.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUser.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUserInfo.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUserInfo.h new file mode 120000 index 0000000..ef1617c --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUserInfo.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUserInfo.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuth.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuth.h new file mode 120000 index 0000000..e3b2676 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuth.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuth.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuthVersion.h b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuthVersion.h new file mode 120000 index 0000000..ee9f380 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuthVersion.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuthVersion.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRAnalyticsConfiguration.h b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRAnalyticsConfiguration.h new file mode 120000 index 0000000..31d68c3 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRAnalyticsConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRAnalyticsConfiguration.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRApp.h b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRApp.h new file mode 120000 index 0000000..90c263a --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRApp.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRApp.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRConfiguration.h b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRConfiguration.h new file mode 120000 index 0000000..6a732c0 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRConfiguration.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRLoggerLevel.h b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRLoggerLevel.h new file mode 120000 index 0000000..a216706 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRLoggerLevel.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRLoggerLevel.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIROptions.h b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIROptions.h new file mode 120000 index 0000000..5bd77eb --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIROptions.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIROptions.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FirebaseCore.h b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FirebaseCore.h new file mode 120000 index 0000000..96e9330 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FirebaseCore.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FirebaseCore.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataEventType.h b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataEventType.h new file mode 120000 index 0000000..ba0eb10 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataEventType.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataEventType.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataSnapshot.h b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataSnapshot.h new file mode 120000 index 0000000..635d198 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataSnapshot.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataSnapshot.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabase.h b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabase.h new file mode 120000 index 0000000..72f9038 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabase.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabase.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseQuery.h b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseQuery.h new file mode 120000 index 0000000..9ad7555 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseQuery.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseQuery.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseReference.h b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseReference.h new file mode 120000 index 0000000..b935ca6 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseReference.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseReference.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRMutableData.h b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRMutableData.h new file mode 120000 index 0000000..4efb3f2 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRMutableData.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRMutableData.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRServerValue.h b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRServerValue.h new file mode 120000 index 0000000..8632fa0 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRServerValue.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRServerValue.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRTransactionResult.h b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRTransactionResult.h new file mode 120000 index 0000000..c56d5c8 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRTransactionResult.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRTransactionResult.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FirebaseDatabase.h b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FirebaseDatabase.h new file mode 120000 index 0000000..4eefb9c --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FirebaseDatabase.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FirebaseDatabase.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FIRInstanceID.h b/Old Old Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FIRInstanceID.h new file mode 120000 index 0000000..62c92b0 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FIRInstanceID.h @@ -0,0 +1 @@ +../../../../FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FIRInstanceID.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FirebaseInstanceID.h b/Old Old Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FirebaseInstanceID.h new file mode 120000 index 0000000..8925bdb --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FirebaseInstanceID.h @@ -0,0 +1 @@ +../../../../FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FirebaseInstanceID.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.h b/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.h new file mode 120000 index 0000000..7ed730f --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcher.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherLogging.h b/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherLogging.h new file mode 120000 index 0000000..ada41e3 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherLogging.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcherLogging.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherService.h b/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherService.h new file mode 120000 index 0000000..1ef9cbb --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherService.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcherService.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionUploadFetcher.h b/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionUploadFetcher.h new file mode 120000 index 0000000..cef7a0d --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionUploadFetcher.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionUploadFetcher.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDefines.h b/Old Old Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDefines.h new file mode 120000 index 0000000..5503110 --- /dev/null +++ b/Old Old Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDefines.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/GTMDefines.h \ No newline at end of file diff --git a/Old Old Task Master/Pods/Manifest.lock b/Old Old Task Master/Pods/Manifest.lock new file mode 100644 index 0000000..88a8631 --- /dev/null +++ b/Old Old Task Master/Pods/Manifest.lock @@ -0,0 +1,54 @@ +PODS: + - Firebase/Auth (3.16.0): + - Firebase/Core + - FirebaseAuth (= 3.1.1) + - Firebase/Core (3.16.0): + - FirebaseAnalytics (= 3.8.0) + - FirebaseCore (= 3.6.0) + - Firebase/Database (3.16.0): + - Firebase/Core + - FirebaseDatabase (= 3.1.2) + - FirebaseAnalytics (3.8.0): + - FirebaseCore (~> 3.6) + - FirebaseInstanceID (~> 1.0) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseAuth (3.1.1): + - FirebaseAnalytics (~> 3.7) + - GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1) + - GTMSessionFetcher/Core (~> 1.1) + - FirebaseCore (3.6.0): + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseDatabase (3.1.2): + - FirebaseAnalytics (~> 3.7) + - FirebaseInstanceID (1.0.10): + - FirebaseCore (~> 3.6) + - GoogleToolboxForMac/DebugUtils (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/Defines (2.1.1) + - GoogleToolboxForMac/NSData+zlib (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSDictionary+URLArguments (2.1.1): + - GoogleToolboxForMac/DebugUtils (= 2.1.1) + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (2.1.1) + - GTMSessionFetcher/Core (1.1.9) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Core + - Firebase/Database + +SPEC CHECKSUMS: + Firebase: 21bf4a89d3f01bfbe11adc3a5d934a4a3d3a5fd6 + FirebaseAnalytics: 920e46455f27b0a52a80907a6d9b73ee4bd1c635 + FirebaseAuth: cc8a1824170adbd351edb7f994490a3fb5c18be6 + FirebaseCore: 9691ee2ade70c098d7cf92440f4303f16d83ca75 + FirebaseDatabase: 05c96d7b43a7368dc91c07791adb49683e1738d1 + FirebaseInstanceID: b9eedd6846fb5e1f0f7279e1deaa7a7e4cf8392e + GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0 + GTMSessionFetcher: 5c046c76a1f859bc9c187e918f18e4fc7bb57b5e + +PODFILE CHECKSUM: 5dada07b8ffcd867f75f4115acd0e8c161a70c90 + +COCOAPODS: 1.2.1 diff --git a/Old Old Task Master/Pods/Pods.xcodeproj/project.pbxproj b/Old Old Task Master/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..3d5034a --- /dev/null +++ b/Old Old Task Master/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,649 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0E6F2758E5743B053E54C51B0D236AF0 /* GTMSessionUploadFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 73B2BC58D0FB9F9AFC72F7D4C8D02909 /* GTMSessionUploadFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1235AC549ED1B1EF40635602DCF8B4D5 /* GTMSessionFetcherLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FCB32B0455E0A379348B19AC860C5B9 /* GTMSessionFetcherLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1B8714DF33ABD898CF49FAA1314DCF34 /* GTMSessionFetcherService.m in Sources */ = {isa = PBXBuildFile; fileRef = C62240FD39CE838C79FD68FE7CB9FB5B /* GTMSessionFetcherService.m */; }; + 2089C7C2B78C35F067C3C93170D7F7B4 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C085E02FF89804F50ADDA04F5A586E94 /* Security.framework */; }; + 74368D11899CABE904801E788ADB2686 /* Pods-Task Master-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F3B24ED22504DFBA0A49537712904F6 /* Pods-Task Master-dummy.m */; }; + 9417B872ADCACCC4CFED22B51F5E05E0 /* GTMSessionFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 86CCB25D4A905E0DA0A0A73E63A840AC /* GTMSessionFetcher.m */; }; + 9931FBF0D5CD16A87511F3EBD2302A5B /* GTMSessionFetcher-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = CA5FF912989B8D3A95AB58C381DD72B6 /* GTMSessionFetcher-dummy.m */; }; + B4B084A9C602985BE7858EA801AD4382 /* GTMSessionFetcherService.h in Headers */ = {isa = PBXBuildFile; fileRef = C7A1137696A68341CF9C76E4D758EBCE /* GTMSessionFetcherService.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C7F8EA25E43B2F92523BB2A0112B8EA4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */; }; + C9F3C20808CA9AD5C931B60A1D0FA461 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */; }; + CF7E7B439D17C5FF57B2DBC7C03E10EF /* GTMSessionFetcherLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 35C3E32C69C9887413FA8F5BC4675FF4 /* GTMSessionFetcherLogging.m */; }; + E43766C39792FE24EFAF9291C5579176 /* GTMSessionUploadFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A1FC96FE4748B02292698C6FCB58032 /* GTMSessionUploadFetcher.m */; }; + E982A741CDD1A8CC804FC7F20E5C006F /* GTMSessionFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 45E41D504F62845ABE6D20C48310D460 /* GTMSessionFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + AACF8D625B28DCE6C32D0047BA13C200 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = DE868725B18AE240E550C5515AE66BC4; + remoteInfo = GTMSessionFetcher; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 006786176BE95D0D239972D1E7693E79 /* Pods-Task Master-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Task Master-acknowledgements.plist"; sourceTree = ""; }; + 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 2A1FC96FE4748B02292698C6FCB58032 /* GTMSessionUploadFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionUploadFetcher.m; path = Source/GTMSessionUploadFetcher.m; sourceTree = ""; }; + 2E2FD5B073A3A2E59B624F24A3DB94F9 /* FirebaseAuth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseAuth.framework; path = Frameworks/FirebaseAuth.framework; sourceTree = ""; }; + 355F4D2BE9E03FC8DC4E0B4707519CE5 /* libPods-Task Master.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libPods-Task Master.a"; path = "libPods-Task Master.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 35C3E32C69C9887413FA8F5BC4675FF4 /* GTMSessionFetcherLogging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherLogging.m; path = Source/GTMSessionFetcherLogging.m; sourceTree = ""; }; + 3966403013FC02BF79A90DCCA4900984 /* Pods-Task Master.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Task Master.release.xcconfig"; sourceTree = ""; }; + 3FCB32B0455E0A379348B19AC860C5B9 /* GTMSessionFetcherLogging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherLogging.h; path = Source/GTMSessionFetcherLogging.h; sourceTree = ""; }; + 45E41D504F62845ABE6D20C48310D460 /* GTMSessionFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcher.h; path = Source/GTMSessionFetcher.h; sourceTree = ""; }; + 5169C0CCC0500B13DE128F924FB61B45 /* GTMSessionFetcher-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GTMSessionFetcher-prefix.pch"; sourceTree = ""; }; + 6E11F1C16DAD2BBEA62777C73F438A26 /* GTMDefines.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = GTMDefines.h; sourceTree = ""; }; + 73B2BC58D0FB9F9AFC72F7D4C8D02909 /* GTMSessionUploadFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionUploadFetcher.h; path = Source/GTMSessionUploadFetcher.h; sourceTree = ""; }; + 762FA705FCCD2B31C691DF1BD0594F3F /* Pods-Task Master-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Task Master-resources.sh"; sourceTree = ""; }; + 7F3B24ED22504DFBA0A49537712904F6 /* Pods-Task Master-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Task Master-dummy.m"; sourceTree = ""; }; + 7FCC08EAF84E1D055CD13F3836E8DDE4 /* Pods-Task Master-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Task Master-frameworks.sh"; sourceTree = ""; }; + 86CCB25D4A905E0DA0A0A73E63A840AC /* GTMSessionFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcher.m; path = Source/GTMSessionFetcher.m; sourceTree = ""; }; + 871819037F996369FF7C04E2FC20DA0F /* Firebase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Firebase.h; path = Core/Sources/Firebase.h; sourceTree = ""; }; + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 99925E66D484AE426D73A32BBA9DAFF7 /* FirebaseAnalytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseAnalytics.framework; path = Frameworks/FirebaseAnalytics.framework; sourceTree = ""; }; + 9E0FEDCD4AB274B9139A253A6D518112 /* Pods-Task Master.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Task Master.debug.xcconfig"; sourceTree = ""; }; + AF1E895DC95D2F9E3B42A47DAA304339 /* libGTMSessionFetcher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libGTMSessionFetcher.a; path = libGTMSessionFetcher.a; sourceTree = BUILT_PRODUCTS_DIR; }; + B043F4A82543E9D3833DEA28A4D97593 /* GTMSessionFetcher.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GTMSessionFetcher.xcconfig; sourceTree = ""; }; + C085E02FF89804F50ADDA04F5A586E94 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + C45F0C220A49C6B68718B2F98DC71519 /* FirebaseDatabase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseDatabase.framework; path = Frameworks/FirebaseDatabase.framework; sourceTree = ""; }; + C62240FD39CE838C79FD68FE7CB9FB5B /* GTMSessionFetcherService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherService.m; path = Source/GTMSessionFetcherService.m; sourceTree = ""; }; + C7A1137696A68341CF9C76E4D758EBCE /* GTMSessionFetcherService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherService.h; path = Source/GTMSessionFetcherService.h; sourceTree = ""; }; + CA5FF912989B8D3A95AB58C381DD72B6 /* GTMSessionFetcher-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GTMSessionFetcher-dummy.m"; sourceTree = ""; }; + E5A6B9B9E39661030427C1A860F4B8BA /* FirebaseCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseCore.framework; path = Frameworks/FirebaseCore.framework; sourceTree = ""; }; + F1CC7706AD2036332313B762C21FC86A /* Pods-Task Master-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Task Master-acknowledgements.markdown"; sourceTree = ""; }; + F9D181B573A7200269D2E6CC23329475 /* FirebaseInstanceID.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseInstanceID.framework; path = Frameworks/FirebaseInstanceID.framework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D2BE8CE5663DF1EA1CF1CC5269C6067 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C9F3C20808CA9AD5C931B60A1D0FA461 /* Foundation.framework in Frameworks */, + 2089C7C2B78C35F067C3C93170D7F7B4 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BAD5D80D325AD33FFE969400D1AE73D2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C7F8EA25E43B2F92523BB2A0112B8EA4 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0CAF29B6C01D29AE80090D23000FFE6F /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2E2FD5B073A3A2E59B624F24A3DB94F9 /* FirebaseAuth.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 118671C53113E05870707CD81DA9E2F8 /* Core */ = { + isa = PBXGroup; + children = ( + 45E41D504F62845ABE6D20C48310D460 /* GTMSessionFetcher.h */, + 86CCB25D4A905E0DA0A0A73E63A840AC /* GTMSessionFetcher.m */, + 3FCB32B0455E0A379348B19AC860C5B9 /* GTMSessionFetcherLogging.h */, + 35C3E32C69C9887413FA8F5BC4675FF4 /* GTMSessionFetcherLogging.m */, + C7A1137696A68341CF9C76E4D758EBCE /* GTMSessionFetcherService.h */, + C62240FD39CE838C79FD68FE7CB9FB5B /* GTMSessionFetcherService.m */, + 73B2BC58D0FB9F9AFC72F7D4C8D02909 /* GTMSessionUploadFetcher.h */, + 2A1FC96FE4748B02292698C6FCB58032 /* GTMSessionUploadFetcher.m */, + ); + name = Core; + sourceTree = ""; + }; + 18E498ADE72B690B5806B0C06A6E25AD /* Core */ = { + isa = PBXGroup; + children = ( + 871819037F996369FF7C04E2FC20DA0F /* Firebase.h */, + ); + name = Core; + sourceTree = ""; + }; + 2767731D62B3613A00FF9DCB6E34FB2F /* FirebaseCore */ = { + isa = PBXGroup; + children = ( + AC0A959FEA4653CFA3F788E87FFD455A /* Frameworks */, + ); + name = FirebaseCore; + path = FirebaseCore; + sourceTree = ""; + }; + 32AA8B642B12043C482CBFD94A27E6C2 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 99925E66D484AE426D73A32BBA9DAFF7 /* FirebaseAnalytics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 32E8C7D44AC27CDB6A0953D8B2E6331F /* Pods */ = { + isa = PBXGroup; + children = ( + 6BD216CD4313AB56F94E297E1930276B /* Firebase */, + EEC60F996E59E8049B553AD1CCCAD1E6 /* FirebaseAnalytics */, + 71179DD4AEA677C05D558FA446406475 /* FirebaseAuth */, + 2767731D62B3613A00FF9DCB6E34FB2F /* FirebaseCore */, + C5B13693952565CA57BD93098A5E0F6B /* FirebaseDatabase */, + E16D16D8A7D1ADE08A8FAB25AF0BC666 /* FirebaseInstanceID */, + 5BB3079EE29A43BDFA96B73134706752 /* GoogleToolboxForMac */, + 62CAB90D8441DE61E1AFEF86C0D385A6 /* GTMSessionFetcher */, + ); + name = Pods; + sourceTree = ""; + }; + 433CD3331B6C3787F473C941B61FC68F /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4F990579C2E52276FD3C28227B49D60B /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + 4AAE49F71E8856578C4430191CC1ED3C /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + A111AF1E0E43326B0C6348C7298D6809 /* Pods-Task Master */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 4F990579C2E52276FD3C28227B49D60B /* iOS */ = { + isa = PBXGroup; + children = ( + 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */, + C085E02FF89804F50ADDA04F5A586E94 /* Security.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 5B18CC83D3C52A0677DC50E2FF968846 /* Defines */ = { + isa = PBXGroup; + children = ( + 6E11F1C16DAD2BBEA62777C73F438A26 /* GTMDefines.h */, + ); + name = Defines; + sourceTree = ""; + }; + 5BB3079EE29A43BDFA96B73134706752 /* GoogleToolboxForMac */ = { + isa = PBXGroup; + children = ( + 5B18CC83D3C52A0677DC50E2FF968846 /* Defines */, + ); + name = GoogleToolboxForMac; + path = GoogleToolboxForMac; + sourceTree = ""; + }; + 62CAB90D8441DE61E1AFEF86C0D385A6 /* GTMSessionFetcher */ = { + isa = PBXGroup; + children = ( + 118671C53113E05870707CD81DA9E2F8 /* Core */, + B7C5C2E24CAA2AD20AEF1DD5452D2E7A /* Support Files */, + ); + name = GTMSessionFetcher; + path = GTMSessionFetcher; + sourceTree = ""; + }; + 6BD216CD4313AB56F94E297E1930276B /* Firebase */ = { + isa = PBXGroup; + children = ( + 18E498ADE72B690B5806B0C06A6E25AD /* Core */, + ); + name = Firebase; + path = Firebase; + sourceTree = ""; + }; + 71179DD4AEA677C05D558FA446406475 /* FirebaseAuth */ = { + isa = PBXGroup; + children = ( + 0CAF29B6C01D29AE80090D23000FFE6F /* Frameworks */, + ); + name = FirebaseAuth; + path = FirebaseAuth; + sourceTree = ""; + }; + 7DB346D0F39D3F0E887471402A8071AB = { + isa = PBXGroup; + children = ( + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */, + 433CD3331B6C3787F473C941B61FC68F /* Frameworks */, + 32E8C7D44AC27CDB6A0953D8B2E6331F /* Pods */, + C15BD3A2E41BA262B64A227C582EC242 /* Products */, + 4AAE49F71E8856578C4430191CC1ED3C /* Targets Support Files */, + ); + sourceTree = ""; + }; + A111AF1E0E43326B0C6348C7298D6809 /* Pods-Task Master */ = { + isa = PBXGroup; + children = ( + F1CC7706AD2036332313B762C21FC86A /* Pods-Task Master-acknowledgements.markdown */, + 006786176BE95D0D239972D1E7693E79 /* Pods-Task Master-acknowledgements.plist */, + 7F3B24ED22504DFBA0A49537712904F6 /* Pods-Task Master-dummy.m */, + 7FCC08EAF84E1D055CD13F3836E8DDE4 /* Pods-Task Master-frameworks.sh */, + 762FA705FCCD2B31C691DF1BD0594F3F /* Pods-Task Master-resources.sh */, + 9E0FEDCD4AB274B9139A253A6D518112 /* Pods-Task Master.debug.xcconfig */, + 3966403013FC02BF79A90DCCA4900984 /* Pods-Task Master.release.xcconfig */, + ); + name = "Pods-Task Master"; + path = "Target Support Files/Pods-Task Master"; + sourceTree = ""; + }; + A119EA0063D6798B4BB6EA093B3BCFDB /* Frameworks */ = { + isa = PBXGroup; + children = ( + F9D181B573A7200269D2E6CC23329475 /* FirebaseInstanceID.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + AC0A959FEA4653CFA3F788E87FFD455A /* Frameworks */ = { + isa = PBXGroup; + children = ( + E5A6B9B9E39661030427C1A860F4B8BA /* FirebaseCore.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + B7C5C2E24CAA2AD20AEF1DD5452D2E7A /* Support Files */ = { + isa = PBXGroup; + children = ( + B043F4A82543E9D3833DEA28A4D97593 /* GTMSessionFetcher.xcconfig */, + CA5FF912989B8D3A95AB58C381DD72B6 /* GTMSessionFetcher-dummy.m */, + 5169C0CCC0500B13DE128F924FB61B45 /* GTMSessionFetcher-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/GTMSessionFetcher"; + sourceTree = ""; + }; + C15BD3A2E41BA262B64A227C582EC242 /* Products */ = { + isa = PBXGroup; + children = ( + AF1E895DC95D2F9E3B42A47DAA304339 /* libGTMSessionFetcher.a */, + 355F4D2BE9E03FC8DC4E0B4707519CE5 /* libPods-Task Master.a */, + ); + name = Products; + sourceTree = ""; + }; + C5B13693952565CA57BD93098A5E0F6B /* FirebaseDatabase */ = { + isa = PBXGroup; + children = ( + FFD8EDC4D40F5BD026D620C6DC86CB44 /* Frameworks */, + ); + name = FirebaseDatabase; + path = FirebaseDatabase; + sourceTree = ""; + }; + E16D16D8A7D1ADE08A8FAB25AF0BC666 /* FirebaseInstanceID */ = { + isa = PBXGroup; + children = ( + A119EA0063D6798B4BB6EA093B3BCFDB /* Frameworks */, + ); + name = FirebaseInstanceID; + path = FirebaseInstanceID; + sourceTree = ""; + }; + EEC60F996E59E8049B553AD1CCCAD1E6 /* FirebaseAnalytics */ = { + isa = PBXGroup; + children = ( + 32AA8B642B12043C482CBFD94A27E6C2 /* Frameworks */, + ); + name = FirebaseAnalytics; + path = FirebaseAnalytics; + sourceTree = ""; + }; + FFD8EDC4D40F5BD026D620C6DC86CB44 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C45F0C220A49C6B68718B2F98DC71519 /* FirebaseDatabase.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + A922FE66E6DEA4BD3090DCEB4580F34E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E982A741CDD1A8CC804FC7F20E5C006F /* GTMSessionFetcher.h in Headers */, + 1235AC549ED1B1EF40635602DCF8B4D5 /* GTMSessionFetcherLogging.h in Headers */, + B4B084A9C602985BE7858EA801AD4382 /* GTMSessionFetcherService.h in Headers */, + 0E6F2758E5743B053E54C51B0D236AF0 /* GTMSessionUploadFetcher.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 8319E0E7280E6BAA117F6552B77F2DE2 /* Pods-Task Master */ = { + isa = PBXNativeTarget; + buildConfigurationList = 111DD01AA2BB87FC737BE4F0C9D3E7CB /* Build configuration list for PBXNativeTarget "Pods-Task Master" */; + buildPhases = ( + F74A3933C43FB0EF1EE2E6D7C2BB5614 /* Sources */, + BAD5D80D325AD33FFE969400D1AE73D2 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 9265A0FDF51013E8A79DCF2B2ECD9684 /* PBXTargetDependency */, + ); + name = "Pods-Task Master"; + productName = "Pods-Task Master"; + productReference = 355F4D2BE9E03FC8DC4E0B4707519CE5 /* libPods-Task Master.a */; + productType = "com.apple.product-type.library.static"; + }; + DE868725B18AE240E550C5515AE66BC4 /* GTMSessionFetcher */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4693C211CA1C7318A8B388F1C2D24725 /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */; + buildPhases = ( + 34191111C8E6A7E0C8B7499BA636A66A /* Sources */, + 8D2BE8CE5663DF1EA1CF1CC5269C6067 /* Frameworks */, + A922FE66E6DEA4BD3090DCEB4580F34E /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GTMSessionFetcher; + productName = GTMSessionFetcher; + productReference = AF1E895DC95D2F9E3B42A47DAA304339 /* libGTMSessionFetcher.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 0700; + }; + buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 7DB346D0F39D3F0E887471402A8071AB; + productRefGroup = C15BD3A2E41BA262B64A227C582EC242 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + DE868725B18AE240E550C5515AE66BC4 /* GTMSessionFetcher */, + 8319E0E7280E6BAA117F6552B77F2DE2 /* Pods-Task Master */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 34191111C8E6A7E0C8B7499BA636A66A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9931FBF0D5CD16A87511F3EBD2302A5B /* GTMSessionFetcher-dummy.m in Sources */, + 9417B872ADCACCC4CFED22B51F5E05E0 /* GTMSessionFetcher.m in Sources */, + CF7E7B439D17C5FF57B2DBC7C03E10EF /* GTMSessionFetcherLogging.m in Sources */, + 1B8714DF33ABD898CF49FAA1314DCF34 /* GTMSessionFetcherService.m in Sources */, + E43766C39792FE24EFAF9291C5579176 /* GTMSessionUploadFetcher.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F74A3933C43FB0EF1EE2E6D7C2BB5614 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74368D11899CABE904801E788ADB2686 /* Pods-Task Master-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 9265A0FDF51013E8A79DCF2B2ECD9684 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GTMSessionFetcher; + target = DE868725B18AE240E550C5515AE66BC4 /* GTMSessionFetcher */; + targetProxy = AACF8D625B28DCE6C32D0047BA13C200 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 163D87BE96A63549B0EACF1CC31A2E90 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + 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_OBJC_ROOT_CLASS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_REQUIRED = NO; + COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + ONLY_ACTIVE_ARCH = YES; + PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 37105017826B7567B44FC825080562F5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3966403013FC02BF79A90DCCA4900984 /* Pods-Task Master.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MACH_O_TYPE = staticlib; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 6089EF5AAE5528CF09E8655B284A438E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B043F4A82543E9D3833DEA28A4D97593 /* GTMSessionFetcher.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 707B86CFB21B645E37109F39754D4051 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + 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_OBJC_ROOT_CLASS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_REQUIRED = NO; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 7433D24BDAA62C86AF339F0830CB362A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9E0FEDCD4AB274B9139A253A6D518112 /* Pods-Task Master.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MACH_O_TYPE = staticlib; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 85750C6A2D9EFD780B5CD014850783CA /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B043F4A82543E9D3833DEA28A4D97593 /* GTMSessionFetcher.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 111DD01AA2BB87FC737BE4F0C9D3E7CB /* Build configuration list for PBXNativeTarget "Pods-Task Master" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7433D24BDAA62C86AF339F0830CB362A /* Debug */, + 37105017826B7567B44FC825080562F5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 163D87BE96A63549B0EACF1CC31A2E90 /* Debug */, + 707B86CFB21B645E37109F39754D4051 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4693C211CA1C7318A8B388F1C2D24725 /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 85750C6A2D9EFD780B5CD014850783CA /* Debug */, + 6089EF5AAE5528CF09E8655B284A438E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; +} diff --git a/Old Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme b/Old Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme new file mode 100644 index 0000000..8aa99fc --- /dev/null +++ b/Old Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Old Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Master.xcscheme b/Old Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Master.xcscheme new file mode 100644 index 0000000..26afb1f --- /dev/null +++ b/Old Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Master.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Old Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist b/Old Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..bd176cd --- /dev/null +++ b/Old Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,32 @@ + + + + + SchemeUserState + + GTMSessionFetcher.xcscheme + + isShown + + + Pods-Task Master.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + 8319E0E7280E6BAA117F6552B77F2DE2 + + primary + + + DE868725B18AE240E550C5515AE66BC4 + + primary + + + + + diff --git a/Old Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m b/Old Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m new file mode 100644 index 0000000..13d68b3 --- /dev/null +++ b/Old Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GTMSessionFetcher : NSObject +@end +@implementation PodsDummy_GTMSessionFetcher +@end diff --git a/Old Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch b/Old Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Old Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-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/Old Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig b/Old Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig new file mode 100644 index 0000000..88fb1dd --- /dev/null +++ b/Old Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = -framework "Security" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GTMSessionFetcher +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES diff --git a/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.markdown b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.markdown new file mode 100644 index 0000000..59d725a --- /dev/null +++ b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.markdown @@ -0,0 +1,439 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## Firebase + +Copyright 2017 Google + +## FirebaseAnalytics + +Copyright 2017 Google + +## FirebaseAuth + +Copyright 2017 Google + +## FirebaseCore + +Copyright 2017 Google + +## FirebaseDatabase + +Copyright 2017 Google + +## FirebaseInstanceID + +Copyright 2017 Google + +## GTMSessionFetcher + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## GoogleToolboxForMac + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Generated by CocoaPods - https://cocoapods.org diff --git a/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.plist b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.plist new file mode 100644 index 0000000..3a210a5 --- /dev/null +++ b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.plist @@ -0,0 +1,513 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + Firebase + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseAnalytics + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseAuth + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseCore + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseDatabase + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseInstanceID + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + GTMSessionFetcher + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + GoogleToolboxForMac + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-dummy.m b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-dummy.m new file mode 100644 index 0000000..d8a8d9b --- /dev/null +++ b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_Task_Master : NSObject +@end +@implementation PodsDummy_Pods_Task_Master +@end diff --git a/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh new file mode 100755 index 0000000..0f29f13 --- /dev/null +++ b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh @@ -0,0 +1,92 @@ +#!/bin/sh +set -e + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +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 dont' throw errors + echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync -av --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}" + 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 && exit ${PIPESTATUS[0]}) + 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 +} + +# 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_identitiy + 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 file + archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" + stripped="" + for arch in $archs; do + if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" || exit 1 + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi +} + +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh new file mode 100755 index 0000000..aed060f --- /dev/null +++ b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh @@ -0,0 +1,102 @@ +#!/bin/sh +set -e + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +case "${TARGETED_DEVICE_FAMILY}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + 3) + TARGET_DEVICE_ARGS="--target-device tv" + ;; + 4) + TARGET_DEVICE_ARGS="--target-device watch" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; +esac + +install_resource() +{ + if [[ "$1" = /* ]] ; then + RESOURCE_PATH="$1" + else + RESOURCE_PATH="${PODS_ROOT}/$1" + fi + if [[ ! -e "$RESOURCE_PATH" ]] ; then + cat << EOM +error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. +EOM + exit 1 + fi + case $RESOURCE_PATH in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.framework) + echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" + xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + *) + echo "$RESOURCE_PATH" + echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" + ;; + esac +} + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] +then + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "${PODS_ROOT}*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi diff --git a/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig new file mode 100644 index 0000000..55a90e2 --- /dev/null +++ b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig @@ -0,0 +1,10 @@ +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/FirebaseAuth/Frameworks" "${PODS_ROOT}/FirebaseCore/Frameworks" "${PODS_ROOT}/FirebaseDatabase/Frameworks" "${PODS_ROOT}/FirebaseInstanceID/Frameworks" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) ${PODS_ROOT}/Firebase/Core/Sources $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Firebase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAuth" -isystem "${PODS_ROOT}/Headers/Public/FirebaseCore" -isystem "${PODS_ROOT}/Headers/Public/FirebaseDatabase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" -isystem "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" -isystem "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = $(inherited) -ObjC -l"GTMSessionFetcher" -l"c++" -l"icucore" -l"sqlite3" -l"z" -framework "CFNetwork" -framework "FirebaseAnalytics" -framework "FirebaseAuth" -framework "FirebaseCore" -framework "FirebaseDatabase" -framework "FirebaseInstanceID" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" +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 diff --git a/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig new file mode 100644 index 0000000..55a90e2 --- /dev/null +++ b/Old Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig @@ -0,0 +1,10 @@ +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/FirebaseAuth/Frameworks" "${PODS_ROOT}/FirebaseCore/Frameworks" "${PODS_ROOT}/FirebaseDatabase/Frameworks" "${PODS_ROOT}/FirebaseInstanceID/Frameworks" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) ${PODS_ROOT}/Firebase/Core/Sources $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Firebase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAuth" -isystem "${PODS_ROOT}/Headers/Public/FirebaseCore" -isystem "${PODS_ROOT}/Headers/Public/FirebaseDatabase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" -isystem "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" -isystem "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = $(inherited) -ObjC -l"GTMSessionFetcher" -l"c++" -l"icucore" -l"sqlite3" -l"z" -framework "CFNetwork" -framework "FirebaseAnalytics" -framework "FirebaseAuth" -framework "FirebaseCore" -framework "FirebaseDatabase" -framework "FirebaseInstanceID" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" +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 diff --git a/Old Old Task Master/Task Master.xcodeproj/project.pbxproj b/Old Old Task Master/Task Master.xcodeproj/project.pbxproj new file mode 100644 index 0000000..77d112c --- /dev/null +++ b/Old Old Task Master/Task Master.xcodeproj/project.pbxproj @@ -0,0 +1,680 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5F7E30901EA162F5004ADFB6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E308F1EA162F5004ADFB6 /* AppDelegate.swift */; }; + 5F7E30921EA162F5004ADFB6 /* ViewControllers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30911EA162F5004ADFB6 /* ViewControllers.swift */; }; + 5F7E30951EA162F5004ADFB6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F7E30931EA162F5004ADFB6 /* Main.storyboard */; }; + 5F7E30971EA162F5004ADFB6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5F7E30961EA162F5004ADFB6 /* Assets.xcassets */; }; + 5F7E309A1EA162F5004ADFB6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F7E30981EA162F5004ADFB6 /* LaunchScreen.storyboard */; }; + 5F7E30A51EA162F5004ADFB6 /* Task_MasterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30A41EA162F5004ADFB6 /* Task_MasterTests.swift */; }; + 5F7E30B01EA162F5004ADFB6 /* Task_MasterUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30AF1EA162F5004ADFB6 /* Task_MasterUITests.swift */; }; + 5F7E30BE1EA1671A004ADFB6 /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30BD1EA1671A004ADFB6 /* Task.swift */; }; + 5F7E30C01EA16739004ADFB6 /* Alerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30BF1EA16739004ADFB6 /* Alerts.swift */; }; + 5F7E30C21EA16752004ADFB6 /* TasksTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30C11EA16752004ADFB6 /* TasksTable.swift */; }; + 5F7E30C41EA16769004ADFB6 /* TasksCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30C31EA16769004ADFB6 /* TasksCell.swift */; }; + 5F7E30C61EA1677A004ADFB6 /* TaskView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30C51EA1677A004ADFB6 /* TaskView.swift */; }; + 5F7E30CA1EA1685B004ADFB6 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5F7E30C91EA1685B004ADFB6 /* GoogleService-Info.plist */; }; + 5F7E30CC1EA16B85004ADFB6 /* UserViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30CB1EA16B85004ADFB6 /* UserViews.swift */; }; + 5F7E30D21EA16DD6004ADFB6 /* OnBoardingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30CE1EA16DD6004ADFB6 /* OnBoardingController.swift */; }; + 5F7E30D31EA16DD6004ADFB6 /* WelcomeScreenOne.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30CF1EA16DD6004ADFB6 /* WelcomeScreenOne.swift */; }; + 5F7E30D41EA16DD6004ADFB6 /* WelcomeScreenThree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30D01EA16DD6004ADFB6 /* WelcomeScreenThree.swift */; }; + 5F7E30D51EA16DD6004ADFB6 /* WelcomeScreenTwo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7E30D11EA16DD6004ADFB6 /* WelcomeScreenTwo.swift */; }; + D9197C917CB1407F6E7C9129 /* libPods-Task Master.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD32888E11B697B72541ED7B /* libPods-Task Master.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 5F7E30A11EA162F5004ADFB6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5F7E30841EA162F5004ADFB6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5F7E308B1EA162F5004ADFB6; + remoteInfo = "Task Master"; + }; + 5F7E30AC1EA162F5004ADFB6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5F7E30841EA162F5004ADFB6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5F7E308B1EA162F5004ADFB6; + remoteInfo = "Task Master"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0961200CB6738617741F7882 /* Pods-Task Master.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Task Master.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig"; sourceTree = ""; }; + 5F7E308C1EA162F5004ADFB6 /* Task Master.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Task Master.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F7E308F1EA162F5004ADFB6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 5F7E30911EA162F5004ADFB6 /* ViewControllers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllers.swift; sourceTree = ""; }; + 5F7E30941EA162F5004ADFB6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5F7E30961EA162F5004ADFB6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5F7E30991EA162F5004ADFB6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5F7E309B1EA162F5004ADFB6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5F7E30A01EA162F5004ADFB6 /* Task MasterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Task MasterTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F7E30A41EA162F5004ADFB6 /* Task_MasterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Task_MasterTests.swift; sourceTree = ""; }; + 5F7E30A61EA162F5004ADFB6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5F7E30AB1EA162F5004ADFB6 /* Task MasterUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Task MasterUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F7E30AF1EA162F5004ADFB6 /* Task_MasterUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Task_MasterUITests.swift; sourceTree = ""; }; + 5F7E30B11EA162F5004ADFB6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5F7E30BD1EA1671A004ADFB6 /* Task.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Task.swift; sourceTree = ""; }; + 5F7E30BF1EA16739004ADFB6 /* Alerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Alerts.swift; sourceTree = ""; }; + 5F7E30C11EA16752004ADFB6 /* TasksTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TasksTable.swift; sourceTree = ""; }; + 5F7E30C31EA16769004ADFB6 /* TasksCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TasksCell.swift; sourceTree = ""; }; + 5F7E30C51EA1677A004ADFB6 /* TaskView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TaskView.swift; sourceTree = ""; }; + 5F7E30C71EA16792004ADFB6 /* BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = ""; }; + 5F7E30C81EA167B9004ADFB6 /* Task Master.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Task Master.entitlements"; sourceTree = ""; }; + 5F7E30C91EA1685B004ADFB6 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 5F7E30CB1EA16B85004ADFB6 /* UserViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserViews.swift; sourceTree = ""; }; + 5F7E30CE1EA16DD6004ADFB6 /* OnBoardingController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnBoardingController.swift; sourceTree = ""; }; + 5F7E30CF1EA16DD6004ADFB6 /* WelcomeScreenOne.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeScreenOne.swift; sourceTree = ""; }; + 5F7E30D01EA16DD6004ADFB6 /* WelcomeScreenThree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeScreenThree.swift; sourceTree = ""; }; + 5F7E30D11EA16DD6004ADFB6 /* WelcomeScreenTwo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeScreenTwo.swift; sourceTree = ""; }; + 8D8EE9F6B30C691A08BD87C9 /* Pods-Task Master.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Task Master.release.xcconfig"; path = "Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig"; sourceTree = ""; }; + FD32888E11B697B72541ED7B /* libPods-Task Master.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Task Master.a"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5F7E30891EA162F5004ADFB6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D9197C917CB1407F6E7C9129 /* libPods-Task Master.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F7E309D1EA162F5004ADFB6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F7E30A81EA162F5004ADFB6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1ED2F8BA8E0F47E9D47F6C4D /* Frameworks */ = { + isa = PBXGroup; + children = ( + FD32888E11B697B72541ED7B /* libPods-Task Master.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 2599CDDDC888C87B917B603D /* Pods */ = { + isa = PBXGroup; + children = ( + 0961200CB6738617741F7882 /* Pods-Task Master.debug.xcconfig */, + 8D8EE9F6B30C691A08BD87C9 /* Pods-Task Master.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 5F7E30831EA162F5004ADFB6 = { + isa = PBXGroup; + children = ( + 5F7E308E1EA162F5004ADFB6 /* Task Master */, + 5F7E30A31EA162F5004ADFB6 /* Task MasterTests */, + 5F7E30AE1EA162F5004ADFB6 /* Task MasterUITests */, + 5F7E308D1EA162F5004ADFB6 /* Products */, + 2599CDDDC888C87B917B603D /* Pods */, + 1ED2F8BA8E0F47E9D47F6C4D /* Frameworks */, + ); + sourceTree = ""; + }; + 5F7E308D1EA162F5004ADFB6 /* Products */ = { + isa = PBXGroup; + children = ( + 5F7E308C1EA162F5004ADFB6 /* Task Master.app */, + 5F7E30A01EA162F5004ADFB6 /* Task MasterTests.xctest */, + 5F7E30AB1EA162F5004ADFB6 /* Task MasterUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 5F7E308E1EA162F5004ADFB6 /* Task Master */ = { + isa = PBXGroup; + children = ( + 5F7E30CB1EA16B85004ADFB6 /* UserViews.swift */, + 5F7E30C81EA167B9004ADFB6 /* Task Master.entitlements */, + 5F7E308F1EA162F5004ADFB6 /* AppDelegate.swift */, + 5F7E30911EA162F5004ADFB6 /* ViewControllers.swift */, + 5F7E30931EA162F5004ADFB6 /* Main.storyboard */, + 5F7E30BD1EA1671A004ADFB6 /* Task.swift */, + 5F7E30BF1EA16739004ADFB6 /* Alerts.swift */, + 5F7E30C11EA16752004ADFB6 /* TasksTable.swift */, + 5F7E30CD1EA16DC7004ADFB6 /* OnBoard */, + 5F7E30C91EA1685B004ADFB6 /* GoogleService-Info.plist */, + 5F7E30C31EA16769004ADFB6 /* TasksCell.swift */, + 5F7E30C51EA1677A004ADFB6 /* TaskView.swift */, + 5F7E30C71EA16792004ADFB6 /* BridgingHeader.h */, + 5F7E30961EA162F5004ADFB6 /* Assets.xcassets */, + 5F7E30981EA162F5004ADFB6 /* LaunchScreen.storyboard */, + 5F7E309B1EA162F5004ADFB6 /* Info.plist */, + ); + path = "Task Master"; + sourceTree = ""; + }; + 5F7E30A31EA162F5004ADFB6 /* Task MasterTests */ = { + isa = PBXGroup; + children = ( + 5F7E30A41EA162F5004ADFB6 /* Task_MasterTests.swift */, + 5F7E30A61EA162F5004ADFB6 /* Info.plist */, + ); + path = "Task MasterTests"; + sourceTree = ""; + }; + 5F7E30AE1EA162F5004ADFB6 /* Task MasterUITests */ = { + isa = PBXGroup; + children = ( + 5F7E30AF1EA162F5004ADFB6 /* Task_MasterUITests.swift */, + 5F7E30B11EA162F5004ADFB6 /* Info.plist */, + ); + path = "Task MasterUITests"; + sourceTree = ""; + }; + 5F7E30CD1EA16DC7004ADFB6 /* OnBoard */ = { + isa = PBXGroup; + children = ( + 5F7E30CE1EA16DD6004ADFB6 /* OnBoardingController.swift */, + 5F7E30CF1EA16DD6004ADFB6 /* WelcomeScreenOne.swift */, + 5F7E30D01EA16DD6004ADFB6 /* WelcomeScreenThree.swift */, + 5F7E30D11EA16DD6004ADFB6 /* WelcomeScreenTwo.swift */, + ); + name = OnBoard; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5F7E308B1EA162F5004ADFB6 /* Task Master */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F7E30B41EA162F5004ADFB6 /* Build configuration list for PBXNativeTarget "Task Master" */; + buildPhases = ( + D23EC013BD35D41B020D2A3E /* [CP] Check Pods Manifest.lock */, + 5F7E30881EA162F5004ADFB6 /* Sources */, + 5F7E30891EA162F5004ADFB6 /* Frameworks */, + 5F7E308A1EA162F5004ADFB6 /* Resources */, + 2D6F8D45323E6559043798F5 /* [CP] Embed Pods Frameworks */, + D43A0511E33DD6C59D0409E1 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Task Master"; + productName = "Task Master"; + productReference = 5F7E308C1EA162F5004ADFB6 /* Task Master.app */; + productType = "com.apple.product-type.application"; + }; + 5F7E309F1EA162F5004ADFB6 /* Task MasterTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F7E30B71EA162F5004ADFB6 /* Build configuration list for PBXNativeTarget "Task MasterTests" */; + buildPhases = ( + 5F7E309C1EA162F5004ADFB6 /* Sources */, + 5F7E309D1EA162F5004ADFB6 /* Frameworks */, + 5F7E309E1EA162F5004ADFB6 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5F7E30A21EA162F5004ADFB6 /* PBXTargetDependency */, + ); + name = "Task MasterTests"; + productName = "Task MasterTests"; + productReference = 5F7E30A01EA162F5004ADFB6 /* Task MasterTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 5F7E30AA1EA162F5004ADFB6 /* Task MasterUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F7E30BA1EA162F5004ADFB6 /* Build configuration list for PBXNativeTarget "Task MasterUITests" */; + buildPhases = ( + 5F7E30A71EA162F5004ADFB6 /* Sources */, + 5F7E30A81EA162F5004ADFB6 /* Frameworks */, + 5F7E30A91EA162F5004ADFB6 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5F7E30AD1EA162F5004ADFB6 /* PBXTargetDependency */, + ); + name = "Task MasterUITests"; + productName = "Task MasterUITests"; + productReference = 5F7E30AB1EA162F5004ADFB6 /* Task MasterUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5F7E30841EA162F5004ADFB6 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 0830; + ORGANIZATIONNAME = "Alexander Davis"; + TargetAttributes = { + 5F7E308B1EA162F5004ADFB6 = { + CreatedOnToolsVersion = 8.3.1; + DevelopmentTeam = 28CC8SCVUN; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Keychain = { + enabled = 1; + }; + }; + }; + 5F7E309F1EA162F5004ADFB6 = { + CreatedOnToolsVersion = 8.3.1; + DevelopmentTeam = 28CC8SCVUN; + ProvisioningStyle = Automatic; + TestTargetID = 5F7E308B1EA162F5004ADFB6; + }; + 5F7E30AA1EA162F5004ADFB6 = { + CreatedOnToolsVersion = 8.3.1; + DevelopmentTeam = 28CC8SCVUN; + ProvisioningStyle = Automatic; + TestTargetID = 5F7E308B1EA162F5004ADFB6; + }; + }; + }; + buildConfigurationList = 5F7E30871EA162F5004ADFB6 /* Build configuration list for PBXProject "Task Master" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5F7E30831EA162F5004ADFB6; + productRefGroup = 5F7E308D1EA162F5004ADFB6 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5F7E308B1EA162F5004ADFB6 /* Task Master */, + 5F7E309F1EA162F5004ADFB6 /* Task MasterTests */, + 5F7E30AA1EA162F5004ADFB6 /* Task MasterUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5F7E308A1EA162F5004ADFB6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F7E309A1EA162F5004ADFB6 /* LaunchScreen.storyboard in Resources */, + 5F7E30CA1EA1685B004ADFB6 /* GoogleService-Info.plist in Resources */, + 5F7E30971EA162F5004ADFB6 /* Assets.xcassets in Resources */, + 5F7E30951EA162F5004ADFB6 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F7E309E1EA162F5004ADFB6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F7E30A91EA162F5004ADFB6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2D6F8D45323E6559043798F5 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + D23EC013BD35D41B020D2A3E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + D43A0511E33DD6C59D0409E1 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5F7E30881EA162F5004ADFB6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F7E30D21EA16DD6004ADFB6 /* OnBoardingController.swift in Sources */, + 5F7E30D31EA16DD6004ADFB6 /* WelcomeScreenOne.swift in Sources */, + 5F7E30921EA162F5004ADFB6 /* ViewControllers.swift in Sources */, + 5F7E30C61EA1677A004ADFB6 /* TaskView.swift in Sources */, + 5F7E30BE1EA1671A004ADFB6 /* Task.swift in Sources */, + 5F7E30D41EA16DD6004ADFB6 /* WelcomeScreenThree.swift in Sources */, + 5F7E30C41EA16769004ADFB6 /* TasksCell.swift in Sources */, + 5F7E30C01EA16739004ADFB6 /* Alerts.swift in Sources */, + 5F7E30901EA162F5004ADFB6 /* AppDelegate.swift in Sources */, + 5F7E30C21EA16752004ADFB6 /* TasksTable.swift in Sources */, + 5F7E30CC1EA16B85004ADFB6 /* UserViews.swift in Sources */, + 5F7E30D51EA16DD6004ADFB6 /* WelcomeScreenTwo.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F7E309C1EA162F5004ADFB6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F7E30A51EA162F5004ADFB6 /* Task_MasterTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F7E30A71EA162F5004ADFB6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F7E30B01EA162F5004ADFB6 /* Task_MasterUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 5F7E30A21EA162F5004ADFB6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5F7E308B1EA162F5004ADFB6 /* Task Master */; + targetProxy = 5F7E30A11EA162F5004ADFB6 /* PBXContainerItemProxy */; + }; + 5F7E30AD1EA162F5004ADFB6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5F7E308B1EA162F5004ADFB6 /* Task Master */; + targetProxy = 5F7E30AC1EA162F5004ADFB6 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 5F7E30931EA162F5004ADFB6 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5F7E30941EA162F5004ADFB6 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5F7E30981EA162F5004ADFB6 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5F7E30991EA162F5004ADFB6 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5F7E30B21EA162F5004ADFB6 /* 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++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "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.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 5F7E30B31EA162F5004ADFB6 /* 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++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + 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.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5F7E30B51EA162F5004ADFB6 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0961200CB6738617741F7882 /* Pods-Task Master.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = "Task Master/Task Master.entitlements"; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task Master/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-Master"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 5F7E30B61EA162F5004ADFB6 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8D8EE9F6B30C691A08BD87C9 /* Pods-Task Master.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = "Task Master/Task Master.entitlements"; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task Master/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-Master"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 5F7E30B81EA162F5004ADFB6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task MasterTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-MasterTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Task Master.app/Task Master"; + }; + name = Debug; + }; + 5F7E30B91EA162F5004ADFB6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task MasterTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-MasterTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Task Master.app/Task Master"; + }; + name = Release; + }; + 5F7E30BB1EA162F5004ADFB6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task MasterUITests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-MasterUITests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_TARGET_NAME = "Task Master"; + }; + name = Debug; + }; + 5F7E30BC1EA162F5004ADFB6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task MasterUITests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-MasterUITests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_TARGET_NAME = "Task Master"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5F7E30871EA162F5004ADFB6 /* Build configuration list for PBXProject "Task Master" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F7E30B21EA162F5004ADFB6 /* Debug */, + 5F7E30B31EA162F5004ADFB6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F7E30B41EA162F5004ADFB6 /* Build configuration list for PBXNativeTarget "Task Master" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F7E30B51EA162F5004ADFB6 /* Debug */, + 5F7E30B61EA162F5004ADFB6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F7E30B71EA162F5004ADFB6 /* Build configuration list for PBXNativeTarget "Task MasterTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F7E30B81EA162F5004ADFB6 /* Debug */, + 5F7E30B91EA162F5004ADFB6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F7E30BA1EA162F5004ADFB6 /* Build configuration list for PBXNativeTarget "Task MasterUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F7E30BB1EA162F5004ADFB6 /* Debug */, + 5F7E30BC1EA162F5004ADFB6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5F7E30841EA162F5004ADFB6 /* Project object */; +} diff --git a/Task Master.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Old Old Task Master/Task Master.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from Task Master.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to Old Old Task Master/Task Master.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/Old Old Task Master/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate b/Old Old Task Master/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..43cdd04 Binary files /dev/null and b/Old Old Task Master/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Old Old Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Task Master.xcscheme b/Old Old Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Task Master.xcscheme new file mode 100644 index 0000000..2e7958a --- /dev/null +++ b/Old Old Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Task Master.xcscheme @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Old Old Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist b/Old Old Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..8084321 --- /dev/null +++ b/Old Old Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,32 @@ + + + + + SchemeUserState + + Task Master.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 5F7E308B1EA162F5004ADFB6 + + primary + + + 5F7E309F1EA162F5004ADFB6 + + primary + + + 5F7E30AA1EA162F5004ADFB6 + + primary + + + + + diff --git a/Old Old Task Master/Task Master.xcworkspace/contents.xcworkspacedata b/Old Old Task Master/Task Master.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..07cc9b5 --- /dev/null +++ b/Old Old Task Master/Task Master.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Old Old Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate b/Old Old Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..03d5c7f Binary files /dev/null and b/Old Old Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Old Old Task Master/Task Master/Alerts.swift b/Old Old Task Master/Task Master/Alerts.swift new file mode 100644 index 0000000..31505b6 --- /dev/null +++ b/Old Old Task Master/Task Master/Alerts.swift @@ -0,0 +1,24 @@ +// +// Alerts.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +extension UIAlertController { + + static func withError(error: NSError) -> UIAlertController { + let alert = UIAlertController(title: "Error", + message: error.localizedDescription, + preferredStyle: .alert) + + let cancelAction = UIAlertAction(title: "Ok", + style: .default) + alert.addAction(cancelAction) + return alert + } +} diff --git a/Old Old Task Master/Task Master/AppDelegate.swift b/Old Old Task Master/Task Master/AppDelegate.swift new file mode 100644 index 0000000..a1d4953 --- /dev/null +++ b/Old Old Task Master/Task Master/AppDelegate.swift @@ -0,0 +1,66 @@ +// +// AppDelegate.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import UIKit +import Firebase +import UserNotifications +import NotificationCenter +import FirebaseDatabase + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + // Use Firebase library to configure APIs + FIRApp.configure() + FIRDatabase.database().persistenceEnabled = true + + //If User Is Signed In Direct to Main App Section + let currentUser = FIRAuth.auth()?.currentUser + let mainStoryboard = UIStoryboard(name: "Main", bundle: nil) + if currentUser != nil + { + self.window?.rootViewController = mainStoryboard.instantiateViewController(withIdentifier: "MainView") + } + else + { + self.window?.rootViewController = mainStoryboard.instantiateViewController(withIdentifier: "OnBoard") + } + + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 0000000..d98c3c4 --- /dev/null +++ b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,152 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-App-57x57@1x.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-App-57x57@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50x50@1x.png", + "scale" : "1x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50x50@2x.png", + "scale" : "2x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-App-72x72@1x.png", + "scale" : "1x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-App-72x72@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..cb8c8dd Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..31a69a7 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..50bb01a Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..bdd7215 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..0f63d35 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..3ffb1d1 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..31a69a7 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..5f25168 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..5ccf3e8 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..8bf9ff2 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..290e064 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..5ccf3e8 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..2bd6152 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..f994c63 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..abe476f Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..ce5c7a6 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..49def24 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..e88b914 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png new file mode 100644 index 0000000..ce98871 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png new file mode 100644 index 0000000..0833776 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/Contents.json b/Old Old Task Master/Task Master/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Old Old Task Master/Task Master/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Task Master/Assets.xcassets/create_new-50.imageset/Contents.json b/Old Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/Contents.json similarity index 100% rename from Task Master/Assets.xcassets/create_new-50.imageset/Contents.json rename to Old Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/Contents.json diff --git a/Task Master/Assets.xcassets/create_new-50.imageset/create_new-25.png b/Old Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-25.png similarity index 100% rename from Task Master/Assets.xcassets/create_new-50.imageset/create_new-25.png rename to Old Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-25.png diff --git a/Task Master/Assets.xcassets/create_new-50.imageset/create_new-32.png b/Old Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-32.png similarity index 100% rename from Task Master/Assets.xcassets/create_new-50.imageset/create_new-32.png rename to Old Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-32.png diff --git a/Task Master/Assets.xcassets/create_new-50.imageset/create_new-50.png b/Old Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-50.png similarity index 100% rename from Task Master/Assets.xcassets/create_new-50.imageset/create_new-50.png rename to Old Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-50.png diff --git a/Task Master/Assets.xcassets/first.imageset/Contents.json b/Old Old Task Master/Task Master/Assets.xcassets/first.imageset/Contents.json similarity index 100% rename from Task Master/Assets.xcassets/first.imageset/Contents.json rename to Old Old Task Master/Task Master/Assets.xcassets/first.imageset/Contents.json diff --git a/Task Master/Assets.xcassets/first.imageset/first.pdf b/Old Old Task Master/Task Master/Assets.xcassets/first.imageset/first.pdf similarity index 100% rename from Task Master/Assets.xcassets/first.imageset/first.pdf rename to Old Old Task Master/Task Master/Assets.xcassets/first.imageset/first.pdf diff --git a/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/Contents.json b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/Contents.json new file mode 100644 index 0000000..43003d0 --- /dev/null +++ b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "iTunesArtwork@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "iTunesArtwork@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "iTunesArtwork@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@1x.png b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@1x.png new file mode 100644 index 0000000..5bb8a72 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@1x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@2x.png new file mode 100644 index 0000000..17c0cb6 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@3x.png b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@3x.png new file mode 100644 index 0000000..510b9df Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@3x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork@1x.png b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork@1x.png new file mode 100644 index 0000000..5bb8a72 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork@1x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork@2x.png b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork@2x.png new file mode 100644 index 0000000..17c0cb6 Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork@2x.png differ diff --git a/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork@3x.png b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork@3x.png new file mode 100644 index 0000000..510b9df Binary files /dev/null and b/Old Old Task Master/Task Master/Assets.xcassets/iTunesArtwork@3x.png differ diff --git a/Task Master/Assets.xcassets/report_card-50.imageset/Contents.json b/Old Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/Contents.json similarity index 100% rename from Task Master/Assets.xcassets/report_card-50.imageset/Contents.json rename to Old Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/Contents.json diff --git a/Task Master/Assets.xcassets/report_card-50.imageset/report_card-25.png b/Old Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-25.png similarity index 100% rename from Task Master/Assets.xcassets/report_card-50.imageset/report_card-25.png rename to Old Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-25.png diff --git a/Task Master/Assets.xcassets/report_card-50.imageset/report_card-32.png b/Old Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-32.png similarity index 100% rename from Task Master/Assets.xcassets/report_card-50.imageset/report_card-32.png rename to Old Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-32.png diff --git a/Task Master/Assets.xcassets/report_card-50.imageset/report_card-50.png b/Old Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-50.png similarity index 100% rename from Task Master/Assets.xcassets/report_card-50.imageset/report_card-50.png rename to Old Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-50.png diff --git a/Task Master/Assets.xcassets/second.imageset/Contents.json b/Old Old Task Master/Task Master/Assets.xcassets/second.imageset/Contents.json similarity index 100% rename from Task Master/Assets.xcassets/second.imageset/Contents.json rename to Old Old Task Master/Task Master/Assets.xcassets/second.imageset/Contents.json diff --git a/Task Master/Assets.xcassets/second.imageset/second.pdf b/Old Old Task Master/Task Master/Assets.xcassets/second.imageset/second.pdf similarity index 100% rename from Task Master/Assets.xcassets/second.imageset/second.pdf rename to Old Old Task Master/Task Master/Assets.xcassets/second.imageset/second.pdf diff --git a/Old Old Task Master/Task Master/Base.lproj/LaunchScreen.storyboard b/Old Old Task Master/Task Master/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..d19da7e --- /dev/null +++ b/Old Old Task Master/Task Master/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Old Old Task Master/Task Master/Base.lproj/Main.storyboard b/Old Old Task Master/Task Master/Base.lproj/Main.storyboard new file mode 100644 index 0000000..cbc71cd --- /dev/null +++ b/Old Old Task Master/Task Master/Base.lproj/Main.storyboard @@ -0,0 +1,736 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Old Old Task Master/Task Master/BridgingHeader.h b/Old Old Task Master/Task Master/BridgingHeader.h new file mode 100644 index 0000000..fe8e802 --- /dev/null +++ b/Old Old Task Master/Task Master/BridgingHeader.h @@ -0,0 +1,15 @@ +// +// BridgingHeader.h +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +#ifndef BridgingHeader_h +#define BridgingHeader_h + + +#endif /* BridgingHeader_h */ + +#import diff --git a/Old Old Task Master/Task Master/GoogleService-Info.plist b/Old Old Task Master/Task Master/GoogleService-Info.plist new file mode 100644 index 0000000..9a46224 --- /dev/null +++ b/Old Old Task Master/Task Master/GoogleService-Info.plist @@ -0,0 +1,40 @@ + + + + + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 + CLIENT_ID + 423696983750-k57prfa7vk5bebm4nuvv4cfa78qthbfr.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.423696983750-k57prfa7vk5bebm4nuvv4cfa78qthbfr + API_KEY + AIzaSyDhHM39kcgnk5eVFOKq4pvCbiSSEGGQ0iQ + GCM_SENDER_ID + 423696983750 + PLIST_VERSION + 1 + BUNDLE_ID + ADCMNetworks.Task-Master + PROJECT_ID + taskmaster-20716 + STORAGE_BUCKET + taskmaster-20716.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:423696983750:ios:ee84cdaa017a58a7 + DATABASE_URL + https://taskmaster-20716.firebaseio.com + + \ No newline at end of file diff --git a/Old Old Task Master/Task Master/Info.plist b/Old Old Task Master/Task Master/Info.plist new file mode 100644 index 0000000..68dc9cd --- /dev/null +++ b/Old Old Task Master/Task Master/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarStyle + UIStatusBarStyleLightContent + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + + + diff --git a/Old Old Task Master/Task Master/OnBoardingController.swift b/Old Old Task Master/Task Master/OnBoardingController.swift new file mode 100644 index 0000000..14a7430 --- /dev/null +++ b/Old Old Task Master/Task Master/OnBoardingController.swift @@ -0,0 +1,83 @@ +// +// OnBoardingController.swift +// My Mind +// +// Created by Alexander Davis on 30/03/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class OnBoardingController : UIPageViewController { + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + + override func viewDidLoad() { + // Set the dataSource and delegate in code. + // I can't figure out how to do this in the Storyboard! + dataSource = self + delegate = self + // This is the starting point. Start with step zero. + setViewControllers([getPageOne()], direction: .forward, animated: false, completion: nil) + } + + func getPageOne() -> PageOne { + return storyboard!.instantiateViewController(withIdentifier: "WelcomeScreenOne") as! PageOne + } + + func getPageTwo() -> PageTwo { + return storyboard!.instantiateViewController(withIdentifier: "WelcomeScreenTwo") as! PageTwo + } + + func getPageThree() -> PageThree { + return storyboard!.instantiateViewController(withIdentifier: "WelcomeScreenThree") as! PageThree + } + +} + +// MARK: - UIPageViewControllerDataSource methods + +extension OnBoardingController : UIPageViewControllerDataSource { + + func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { + if viewController.isKind(of: PageTwo.self) { + // 2 -> 1 + return getPageTwo() + } else if viewController.isKind(of: PageTwo.self) { + // 1 -> 0 + return getPageOne() + } else { + // 0 -> end of the road + return nil + } + } + + func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { + if viewController.isKind(of: PageOne.self) { + // 0 -> 1 + return getPageTwo() + } else if viewController.isKind(of: PageTwo.self) { + // 1 -> 2 + return getPageThree() + } else { + // 2 -> end of the road + return nil + } + } + + + // This only gets called once, when setViewControllers is called + func presentationIndex(for pageViewController: UIPageViewController) -> Int { + return 0 + } + +} + +// MARK: - UIPageViewControllerDelegate methods + +extension OnBoardingController : UIPageViewControllerDelegate { + +} diff --git a/Old Old Task Master/Task Master/Task Master.entitlements b/Old Old Task Master/Task Master/Task Master.entitlements new file mode 100644 index 0000000..4299252 --- /dev/null +++ b/Old Old Task Master/Task Master/Task Master.entitlements @@ -0,0 +1,10 @@ + + + + + keychain-access-groups + + $(AppIdentifierPrefix)ADCMNetworks.Task-Master + + + diff --git a/Old Old Task Master/Task Master/Task.swift b/Old Old Task Master/Task Master/Task.swift new file mode 100644 index 0000000..f388f9e --- /dev/null +++ b/Old Old Task Master/Task Master/Task.swift @@ -0,0 +1,55 @@ +// +// Task.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import Firebase + +/* Have keys as constants to prevent spelling errors + * and avoid confusion. eg. "title" can be found in + * ViewControllers too, so places can exist where the + * particular string is used for something else. + */ +let kTaskTitleKey = "title" +let kTaskCompletedKey = "completed" +let kTaskUserKey = "user" + +struct Task { + let title: String + let user: String + let firebaseReference: FIRDatabaseReference? + var completed: Bool + + /* Constructor for instantiating a new object in code. + */ + init(title: String, user: String, completed: Bool, id: String = "") { + self.title = title + self.user = user + self.completed = completed + self.firebaseReference = nil + } + + /* Constructor for instantiating an object received from Firebase. + */ + init(snapshot: FIRDataSnapshot) { + let snapshotValue = snapshot.value as! [String: Any] + self.title = snapshotValue[kTaskTitleKey] as! String + self.user = snapshotValue[kTaskUserKey] as! String + self.completed = snapshotValue[kTaskCompletedKey] as! Bool + self.firebaseReference = snapshot.ref + } + + /* Member to help updating values of an existing object. + */ + func toDictionary() -> Any { + return [ + kTaskTitleKey: self.title, + kTaskUserKey: self.user, + kTaskCompletedKey: self.completed + ] + } +} diff --git a/Old Old Task Master/Task Master/TaskView.swift b/Old Old Task Master/Task Master/TaskView.swift new file mode 100644 index 0000000..de44198 --- /dev/null +++ b/Old Old Task Master/Task Master/TaskView.swift @@ -0,0 +1,31 @@ +// +// TaskView.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class TaskViewController: UIViewController { + + var taskTitle: String? + var taskCompleted: Bool? + + @IBOutlet weak var titleField: UITextField! + @IBOutlet weak var completedSwitch: UISwitch! + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + self.titleField.text = self.taskTitle ?? "" + self.completedSwitch.setOn(taskCompleted ?? false, animated:false) + } + + func updateValues() { + self.taskTitle = self.titleField.text + self.taskCompleted = self.completedSwitch.isOn + } +} diff --git a/Old Old Task Master/Task Master/TasksCell.swift b/Old Old Task Master/Task Master/TasksCell.swift new file mode 100644 index 0000000..e19d03e --- /dev/null +++ b/Old Old Task Master/Task Master/TasksCell.swift @@ -0,0 +1,16 @@ +// +// TasksCell.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class TasksTableViewCell: UITableViewCell { + + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var completedSwitch: UISwitch! +} diff --git a/Old Old Task Master/Task Master/TasksTable.swift b/Old Old Task Master/Task Master/TasksTable.swift new file mode 100644 index 0000000..1950a97 --- /dev/null +++ b/Old Old Task Master/Task Master/TasksTable.swift @@ -0,0 +1,155 @@ +// +// TasksTable.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import Firebase + +let kTasksListPath = "tasks-list" +let kTaskViewControllerSegueIdentifier = "TaskViewController" + +class TasksTableViewController: UITableViewController { + + let tasksReference = FIRDatabase.database().reference(withPath: kTasksListPath) + var tasks = [Task]() + var selectedTask: Task? = nil + weak var currentUser = FIRAuth.auth()?.currentUser + + override func viewDidLoad() { + super.viewDidLoad() + + /* Query tasks from firebase when this view controller is instantiated + */ + self.tasksReference.queryOrdered(byChild: kTaskCompletedKey).observe(.value, with: { snapshot in + + /* The callback block will be executed each and every time the value changes. + */ + var items: [Task] = [] + + for item in snapshot.children { + let task = Task(snapshot: item as! FIRDataSnapshot) + items.append(task) + } + + self.tasks = items + self.tableView.reloadData() + }) + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == kTaskViewControllerSegueIdentifier { + /* Pass along the selected task to the particular task view controller. + */ + if let taskViewController = segue.destination as? TaskViewController { + taskViewController.taskTitle = self.selectedTask?.title + taskViewController.taskCompleted = self.selectedTask?.completed + } + } + } + + @IBAction func prepareForUnwind(segue: UIStoryboardSegue) { + if let taskViewController = segue.source as? TaskViewController { + taskViewController.updateValues() + + if taskViewController.titleField.text == "" { + let alertController = UIAlertController(title: "Error", message: "Please enter a task name.", preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + }else{ + if let task = self.selectedTask { + /* This particular task was an existing one + it should be updated in Firebase. + */ + if let title = taskViewController.taskTitle, + let completed = taskViewController.taskCompleted, + let email = self.currentUser?.email { + + let taskFirebasePath = task.firebaseReference + taskFirebasePath?.updateChildValues([ + kTaskTitleKey: title, + kTaskUserKey: email, + kTaskCompletedKey: completed + ]) + } + } else { + /* This task is new, + it should be created in Firebase + */ + if let title = taskViewController.taskTitle, + let completed = taskViewController.taskCompleted, + let email = self.currentUser?.email { + + let task = Task(title: title, user: email, completed: completed) + let taskFirebasePath = self.tasksReference.ref.child(title.lowercased()) + taskFirebasePath.setValue(task.toDictionary()) + } + } + } + } + self.selectedTask = nil + } + + @IBAction func addTask() { + self.performSegue(withIdentifier: kTaskViewControllerSegueIdentifier, sender: self) + } + + // MARK: - Table view data source + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return self.tasks.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell", for: indexPath) + + if let c = cell as? TasksTableViewCell { + let task = self.tasks[indexPath.row] + c.titleLabel.text = task.title + c.completedSwitch.setOn(task.completed, animated: true) + } + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let task = self.tasks[indexPath.row] + + /* Keep a reference to the task that is currently edited. + */ + self.selectedTask = task + self.performSegue(withIdentifier: kTaskViewControllerSegueIdentifier, sender: self) + } + + override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + return true + } + + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + let task = self.tasks[indexPath.row] + /* Delete this task. + No tableview updates should be done here because a callback notification + will be provided. + */ + task.firebaseReference?.removeValue() + } + } + @IBAction func SignOut(_ sender: UIBarButtonItem) { + if FIRAuth.auth()?.currentUser != nil { + do { + try FIRAuth.auth()?.signOut() + let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "OnBooard") + present(vc, animated: true, completion: nil) + + } catch let error as NSError { + print(error.localizedDescription) + } + } + } +} diff --git a/Old Old Task Master/Task Master/UserViews.swift b/Old Old Task Master/Task Master/UserViews.swift new file mode 100644 index 0000000..a9220d0 --- /dev/null +++ b/Old Old Task Master/Task Master/UserViews.swift @@ -0,0 +1,168 @@ +// +// LoginView.swift +// My Mind +// +// Created by Alexander Davis on 31/03/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit +import Firebase +import FirebaseAuth + +class LoginView: UIViewController { + + @IBOutlet weak var Emailtbx: UITextField! + @IBOutlet weak var Passwordtbx: UITextField! + @IBAction func Loginbtn(_ sender: UIButton) { + if self.Emailtbx.text == "" || self.Passwordtbx.text == "" { + + //Alert to tell the user that there was an error because they didn't fill anything in the textfields because they didn't fill anything in + + let alertController = UIAlertController(title: "Error", message: "Please enter an email and password.", preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + + } else { + + FIRAuth.auth()?.signIn(withEmail: self.Emailtbx.text!, password: self.Passwordtbx.text!) { (user, error) in + + if error == nil { + + //Print into the console if successfully logged in + print("You have successfully logged in") + + //Go to the MainController if the login is sucessful + let alertController = UIAlertController(title: "Welcome", message: "You have successfully logged in", preferredStyle: .alert) + let vc = self.storyboard?.instantiateViewController(withIdentifier: "MainView") + let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in self.present(vc!, animated: true, completion: nil);}) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + + } else { + + //Tells the user that there is an error and then gets firebase to tell them the error + let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + } + } + } + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + } + +class SignUp : UIViewController { + + @IBOutlet weak var Emailtbx: UITextField! + @IBOutlet weak var Passwordtbx: UITextField! + @IBAction func createAccountbtn(_ sender: UIButton) { + if Emailtbx.text == "" { + let alertController = UIAlertController(title: "Error", message: "Please enter your email and password", preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) + alertController.addAction(defaultAction) + + present(alertController, animated: true, completion: nil) + + } else { + FIRAuth.auth()?.createUser(withEmail: Emailtbx.text!, password: Passwordtbx.text!) { (user, error) in + + if error == nil { + let alertController = UIAlertController(title: "Sign Up Complete", message: "You have Successfully Signed Up", preferredStyle: .alert) + let vc = self.storyboard?.instantiateViewController(withIdentifier: "Login") + let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in self.present(vc!, animated: true, completion: nil);}) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + + } else { + let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + } + } + } + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } +} + +class ForgotPass : UIViewController { + + @IBOutlet weak var Emailtbx: UITextField! + @IBAction func Resetbtn(_ sender: UIButton) { + if self.Emailtbx.text == "" { + let alertController = UIAlertController(title: "Oops!", message: "Please enter an email.", preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) + alertController.addAction(defaultAction) + + present(alertController, animated: true, completion: nil) + + } else { + FIRAuth.auth()?.sendPasswordReset(withEmail: self.Emailtbx.text!, completion: { (error) in + + var title = "" + var message = "" + + if error != nil { + title = "Error!" + message = (error?.localizedDescription)! + } else { + title = "Success!" + message = "Password reset email sent." + self.Emailtbx.text = "" + } + + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + + let vc = self.storyboard?.instantiateViewController(withIdentifier: "Login") + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: { action in self.present(vc!, animated: true, completion: nil);}) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + }) + } + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } +} + +class Logout : UIViewController { + + @IBAction func Logoutbtn(_ sender: UIButton) { + if FIRAuth.auth()?.currentUser != nil { + do { + try FIRAuth.auth()?.signOut() + let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "OnBoard") + present(vc, animated: true, completion: nil) + + } catch let error as NSError { + print(error.localizedDescription) + } + } + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } +} diff --git a/Old Old Task Master/Task Master/ViewControllers.swift b/Old Old Task Master/Task Master/ViewControllers.swift new file mode 100644 index 0000000..c3127dc --- /dev/null +++ b/Old Old Task Master/Task Master/ViewControllers.swift @@ -0,0 +1,88 @@ +// +// ViewController.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import UIKit + +import UIKit +import Firebase + +let kUserLoggedInSegueIdentifier = "userLoggedIn" + +class MainViewController: UIViewController { + + /* @IBOutlets create references so strings can be read from + the UITextFields + */ + @IBOutlet weak var emailField: UITextField! + @IBOutlet weak var passwordField: UITextField! + + /* Have a reference to the last signed in user to compare + changes + */ + weak var currentUser: FIRUser? + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + if let auth = FIRAuth.auth() { + + /* Add a state change listener to firebase + to get a notification if the user signed in. + */ + auth.addStateDidChangeListener({ (auth, user) in + if user != nil && user != self.currentUser { + self.currentUser = user + self.performSegue(withIdentifier: kUserLoggedInSegueIdentifier, + sender: self) + } + }) + } + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + if let auth = FIRAuth.auth() { + /* Following the balance principle in iOS, + Stop listening to user state changes while not on screen. + */ + auth.removeStateDidChangeListener(self) + } + } + + @IBAction func login() { + if let email = self.emailField.text, + let password = self.passwordField.text, + let auth = FIRAuth.auth() { + + /* If both email and password fields are not empty, + call firebase signin + */ + auth.signIn(withEmail: email, + password: password) + } + } + + @IBAction func register() { + if let email = self.emailField.text, + let password = self.passwordField.text, + let auth = FIRAuth.auth() { + /* Note: creating a user automatically signs in. + */ + auth.createUser(withEmail: email, + password: password) { user, error in + if error != nil { + self.present(UIAlertController.withError(error: error! as NSError), + animated: true, + completion: nil) + } + } + } + } + + +} diff --git a/Old Old Task Master/Task Master/WelcomeScreenOne.swift b/Old Old Task Master/Task Master/WelcomeScreenOne.swift new file mode 100644 index 0000000..ae853e4 --- /dev/null +++ b/Old Old Task Master/Task Master/WelcomeScreenOne.swift @@ -0,0 +1,18 @@ +// +// WelcomeScreenOne.swift +// My Mind +// +// Created by Alexander Davis on 30/03/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class PageOne : UIViewController { + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + +} diff --git a/Old Old Task Master/Task Master/WelcomeScreenThree.swift b/Old Old Task Master/Task Master/WelcomeScreenThree.swift new file mode 100644 index 0000000..502dbfb --- /dev/null +++ b/Old Old Task Master/Task Master/WelcomeScreenThree.swift @@ -0,0 +1,18 @@ +// +// WelcomeScreenThree.swift +// My Mind +// +// Created by Alexander Davis on 30/03/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class PageThree : UIViewController { + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + +} diff --git a/Old Old Task Master/Task Master/WelcomeScreenTwo.swift b/Old Old Task Master/Task Master/WelcomeScreenTwo.swift new file mode 100644 index 0000000..29edc23 --- /dev/null +++ b/Old Old Task Master/Task Master/WelcomeScreenTwo.swift @@ -0,0 +1,18 @@ +// +// WelcomeScreenTwo.swift +// My Mind +// +// Created by Alexander Davis on 30/03/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class PageTwo : UIViewController { + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + +} diff --git a/Task MasterTests/Info.plist b/Old Old Task Master/Task MasterTests/Info.plist similarity index 100% rename from Task MasterTests/Info.plist rename to Old Old Task Master/Task MasterTests/Info.plist diff --git a/Old Old Task Master/Task MasterTests/Task_MasterTests.swift b/Old Old Task Master/Task MasterTests/Task_MasterTests.swift new file mode 100644 index 0000000..3edc153 --- /dev/null +++ b/Old Old Task Master/Task MasterTests/Task_MasterTests.swift @@ -0,0 +1,36 @@ +// +// Task_MasterTests.swift +// Task MasterTests +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import XCTest +@testable import Task_Master + +class Task_MasterTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/Old Old Task Master/Task MasterUITests/Info.plist b/Old Old Task Master/Task MasterUITests/Info.plist new file mode 100644 index 0000000..6c6c23c --- /dev/null +++ b/Old Old Task Master/Task MasterUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Old Old Task Master/Task MasterUITests/Task_MasterUITests.swift b/Old Old Task Master/Task MasterUITests/Task_MasterUITests.swift new file mode 100644 index 0000000..cb48168 --- /dev/null +++ b/Old Old Task Master/Task MasterUITests/Task_MasterUITests.swift @@ -0,0 +1,36 @@ +// +// Task_MasterUITests.swift +// Task MasterUITests +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import XCTest + +class Task_MasterUITests: XCTestCase { + + override func setUp() { + super.setUp() + + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. + XCUIApplication().launch() + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + +} diff --git a/Old Task Master/Podfile b/Old Task Master/Podfile new file mode 100644 index 0000000..e057de3 --- /dev/null +++ b/Old Task Master/Podfile @@ -0,0 +1,21 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' + +target 'Task Master' do + # Comment the next line if you're not using Swift and don't want to use dynamic frameworks + use_frameworks! + + # Pods for Task Master + + target 'Task MasterTests' do + inherit! :search_paths + # Pods for testing + end + + pod 'Firebase/Core' + pod 'Firebase/Auth' + pod 'Firebase/Messaging' + pod 'Firebase/Database' + pod 'Firebase/Storage' + +end diff --git a/Old Task Master/Podfile.lock b/Old Task Master/Podfile.lock new file mode 100644 index 0000000..30f67a1 --- /dev/null +++ b/Old Task Master/Podfile.lock @@ -0,0 +1,75 @@ +PODS: + - Firebase/Auth (3.15.0): + - Firebase/Core + - FirebaseAuth (= 3.1.1) + - Firebase/Core (3.15.0): + - FirebaseAnalytics (= 3.7.0) + - FirebaseCore (= 3.5.2) + - Firebase/Database (3.15.0): + - Firebase/Core + - FirebaseDatabase (= 3.1.2) + - Firebase/Messaging (3.15.0): + - Firebase/Core + - FirebaseMessaging (= 1.2.2) + - Firebase/Storage (3.15.0): + - Firebase/Core + - FirebaseStorage (= 1.1.0) + - FirebaseAnalytics (3.7.0): + - FirebaseCore (~> 3.5) + - FirebaseInstanceID (~> 1.0) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseAuth (3.1.1): + - FirebaseAnalytics (~> 3.7) + - GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1) + - GTMSessionFetcher/Core (~> 1.1) + - FirebaseCore (3.5.2): + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseDatabase (3.1.2): + - FirebaseAnalytics (~> 3.7) + - FirebaseInstanceID (1.0.9) + - FirebaseMessaging (1.2.2): + - FirebaseAnalytics (~> 3.7) + - FirebaseInstanceID (~> 1.0) + - GoogleToolboxForMac/Logger (~> 2.1) + - Protobuf (~> 3.1) + - FirebaseStorage (1.1.0): + - FirebaseAnalytics (~> 3.7) + - GTMSessionFetcher/Core (~> 1.1) + - GoogleToolboxForMac/DebugUtils (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/Defines (2.1.1) + - GoogleToolboxForMac/Logger (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSData+zlib (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSDictionary+URLArguments (2.1.1): + - GoogleToolboxForMac/DebugUtils (= 2.1.1) + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (2.1.1) + - GTMSessionFetcher/Core (1.1.9) + - Protobuf (3.2.0) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Core + - Firebase/Database + - Firebase/Messaging + - Firebase/Storage + +SPEC CHECKSUMS: + Firebase: 2b1cdfba1cda8589f32904a697cc753322bff9d8 + FirebaseAnalytics: 0d1b7d81d5021155be37702a94ba1ec16d45365d + FirebaseAuth: cc8a1824170adbd351edb7f994490a3fb5c18be6 + FirebaseCore: a024587e43778508700af8c6b1209f7c4516ba02 + FirebaseDatabase: 05c96d7b43a7368dc91c07791adb49683e1738d1 + FirebaseInstanceID: 2d0518b1378fe9d685ef40cbdd63d2fdc1125339 + FirebaseMessaging: df8267f378580a24174ce7861233aa11d5c90109 + FirebaseStorage: a5c55b23741a49a72af8f30f95b3bb5ddbeda12d + GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0 + GTMSessionFetcher: 5c046c76a1f859bc9c187e918f18e4fc7bb57b5e + Protobuf: 745f59e122e5de98d4d7ef291e264a0eef80f58e + +PODFILE CHECKSUM: 8f1ab855a2ae7198fb47b1fa1f13c62dd6eaac8c + +COCOAPODS: 1.2.0 diff --git a/Old Task Master/Pods/Headers/Private/Firebase/Firebase.h b/Old Task Master/Pods/Headers/Private/Firebase/Firebase.h new file mode 120000 index 0000000..6d62033 --- /dev/null +++ b/Old Task Master/Pods/Headers/Private/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/Core/Sources/Firebase.h \ No newline at end of file diff --git a/Old Task Master/Pods/Headers/Public/Firebase/Firebase.h b/Old Task Master/Pods/Headers/Public/Firebase/Firebase.h new file mode 120000 index 0000000..6d62033 --- /dev/null +++ b/Old Task Master/Pods/Headers/Public/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/Core/Sources/Firebase.h \ No newline at end of file diff --git a/Old Task Master/Pods/Pods.xcodeproj/project.pbxproj b/Old Task Master/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..b71386c --- /dev/null +++ b/Old Task Master/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,1569 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 03D9A9338B4C4A547D0EDB778622FE5F /* GPBUnknownField.h in Headers */ = {isa = PBXBuildFile; fileRef = B4C6ED157DDBEB555E8BDE5770898609 /* GPBUnknownField.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 07340F15BACBA601736DBB2ABF1ABC35 /* GTMSessionFetcherLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C6D27FDFD73A966993B7225705A11C4 /* GTMSessionFetcherLogging.m */; }; + 0C297FFE87536C58E1BD9F84762AD35F /* GPBWellKnownTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 790800F3E75624020FA272F85A1E4CE0 /* GPBWellKnownTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0FD95C77F4D26FDEF060B165B38E38E1 /* GPBProtocolBuffers_RuntimeSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = CB76A82B21FE383C21246A7F14E0E5ED /* GPBProtocolBuffers_RuntimeSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 162F73650877177FAB96CC08BE515C97 /* GTMNSDictionary+URLArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A10BA821BB9F1F8A17651B4EE85C880 /* GTMNSDictionary+URLArguments.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1AC07C876FA170C637713815AD65AE94 /* Duration.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = FFEB46E9093597B723323030167F5DC9 /* Duration.pbobjc.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 1AE244B9B7A24028FC231AB5244B5AFE /* Type.pbobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = 51487F35473DCF3C86F3A38B71F9B4CE /* Type.pbobjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1B314C427956D7BB6420A01FF8FC1224 /* GPBWellKnownTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD5A737B97DA9C6DCA7C1022540C17D /* GPBWellKnownTypes.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 1D0D20DBA47FD65B2A5A5DE2BD6BC887 /* Pods-Task Master-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 438BE34209D01569817ED84CB82EE0A5 /* Pods-Task Master-dummy.m */; }; + 1D8AB37710CA2025CB4529995AB4149C /* GPBUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = AC9C017D361D072E574FA20FF426DCE3 /* GPBUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ED67707C258751E7888DAC2AB3D8501 /* GTMSessionFetcherLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 983AE580D3D68286E61B5C8B5F334D87 /* GTMSessionFetcherLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 20950941DA29EE48DFA15BCA9A0210AF /* GPBUnknownFieldSet_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A615A3055E6CED8A78B90AABDF8C87F6 /* GPBUnknownFieldSet_PackagePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 25CEBB7D05A007691375434587AA4FCF /* Protobuf-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 9E22C7F51E1D8856BFAB037815B57BE2 /* Protobuf-dummy.m */; }; + 261913C4C9A09C4FC5BDCD7CA00BCD81 /* Any.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A2ED75D43C15B570B134A7546D782B6 /* Any.pbobjc.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 2C655997A136E46BF307B7538B3C7C36 /* GPBCodedInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 40C91D60EE2B2D053DCFBB7E4ABD3726 /* GPBCodedInputStream.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 2CE91CC9D788EE4C74CAC9624B705236 /* GPBDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 17A1815AD5EAF7E32F66559D9E4BD75B /* GPBDescriptor.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 2F1AF78224FE4B37727002FF33B1DE39 /* Timestamp.pbobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F142FD49ED067F8913338CE22072164 /* Timestamp.pbobjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2F8E36740CA1536BAD2A8BA06E6939AC /* GPBDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FBBD81F52EADA7B6E8ED529693596F2 /* GPBDictionary.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 327AD50BD57D92C49F4A842D131EA079 /* GPBUnknownField.m in Sources */ = {isa = PBXBuildFile; fileRef = 7826B17530A7BC70C57FB8F1BCE7D2E5 /* GPBUnknownField.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 33C6BB2680C6E10B1FA0B5832C5C412B /* GPBDescriptor_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D39EC1E759D1098A332A2FCE9CE8218 /* GPBDescriptor_PackagePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 370112294682E448737B4C0C2F44C179 /* Any.pbobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = AFA3C02BFF3168A892F8BE7331F8D072 /* Any.pbobjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3A0F1C2E934F06DCE1D9B45C8176FF57 /* GPBMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D7058F232FC7286C84B762006AD5F6C /* GPBMessage.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 3F314C7B45CA75B9075CE6BF1D8A34E5 /* GPBDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 20AB0481AA1720C66C6F703A8EAE6C62 /* GPBDescriptor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43EB5608A304AAA6D221B2E5CC0ED6B0 /* GTMNSString+URLArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = C5F51F1FA7D655A89E57367E5D9C6E5C /* GTMNSString+URLArguments.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 450E5A090328E7D1BD167496E80DFA1F /* GTMNSDictionary+URLArguments.m in Sources */ = {isa = PBXBuildFile; fileRef = 7826C75FF1FFC7BDB0A233132A409822 /* GTMNSDictionary+URLArguments.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 45AACE7ED64B60DB9023976C928131A2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */; }; + 4639D2530BE0EFEC170D2A37DECEEC4D /* Api.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 44A37F647C4BDE9787DAE77B219B1CD1 /* Api.pbobjc.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 4802E1AC6C1603B62890488D8F69A796 /* Protobuf-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = AFCC9BE81DB073D04B6AF48A91264FBB /* Protobuf-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 48DCA9DC8163025967B0EC7BF5233017 /* Api.pbobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = 9013A40E6583E08D3B0015706746B4ED /* Api.pbobjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 56D0F0D420B767BD2D701AE5F2BAC312 /* SourceContext.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = AF5B4A9F3F9C2602860D1ABD933BC989 /* SourceContext.pbobjc.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 57FFAAC0D91DCBE356711A96E4E25563 /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C19AF3A610AD7D087493F0FC21989DD /* Type.pbobjc.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 5C476A7D90DB3F32B0FF571D2492717B /* Wrappers.pbobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = A6108FAFBE7B468A4F29AB6401541A23 /* Wrappers.pbobjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 63F4579804EEF3DECBD27D579D4FA196 /* GTMMethodCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 2C0832DAF6AE03C6AC3FA92CF622C512 /* GTMMethodCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 64F31B70A6E5E6963518A01C285B435F /* GTMSessionFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = BCD0C2439C3D36EB1CCD2534F78F0A87 /* GTMSessionFetcher.m */; }; + 69C80E9455E5B4DE476295A8E01D960A /* GPBWireFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 8089F26D73C3D8EA03D7987B1010D206 /* GPBWireFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6B4F19D8BD01EAF45CA1FE09294B7E12 /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A28BC8E8AB21377CA886B7436FFC0CB /* GTMNSData+zlib.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 6C1EE2D83500E16530B87113624619F5 /* GPBArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 1652B3EBB328D6F3AD33CD5D4D3C5D97 /* GPBArray.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6E606AC80340A6C0D2DB4F51A59B0E8B /* Pods-Task MasterTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F0541D224D8027080311EF1A8CDCC79C /* Pods-Task MasterTests-dummy.m */; }; + 6EA6DFC4473A9B2DB6B8A42EA986BA5B /* GTMSessionFetcher-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = CB0E8EBC040DEF0CDDDA89B1CF842E84 /* GTMSessionFetcher-dummy.m */; }; + 6F908A2494CBC5A78C1C9CFBDA2D6E95 /* Pods-Task Master-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 39FD3B458C249F75F405179FC1FF3697 /* Pods-Task Master-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 72B9A19E429C92B8866B50F9C03ADB5B /* GPBArray_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C53C765B432E3A93918B509A5F4EDD /* GPBArray_PackagePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7693C97371B72954902E05582DE0B4A5 /* GPBExtensionInternals.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A72D556A557A87F5E255EF5B3F93F3A /* GPBExtensionInternals.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7F2A025DA61C0108C7DDDC69A2BE7F35 /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C2F73AA619F0197684E0F854BD25387F /* GPBRootObject.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 84160C31A93C4C53AC915C3E8EE1C960 /* GPBCodedOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = FD8B4B49C13E6DD590DF4F9AD6FB3531 /* GPBCodedOutputStream.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 8852FD9AFC242520924D98BE9C4E2477 /* GTMSessionFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEDDE72DF6E6E4F5FC416CAB00AEB9D /* GTMSessionFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 88B8C5E102BDDD1F9C8B454A80CFCF9A /* GPBCodedInputStream_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DC2843670BF217B5E2E434805881433C /* GPBCodedInputStream_PackagePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8B9241E640FE9CF729F2198266F28213 /* GTMLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = F5888B78723685140BE3DBD98AE2A2D2 /* GTMLogger.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 8D1E9814E93E1D22607F52D4FEDA30F8 /* GPBDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = B09C42309F6DA214D63BCECF912FD095 /* GPBDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8E52B99DBE2D51455C8A0A77313E5A3E /* Pods-Task MasterTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 45F421DC69FB4EA99B0FC3DE9A991061 /* Pods-Task MasterTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9024F4774BD8DDE03700B223CF7F8164 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */; }; + 9414790418F4D609D0C013C333CD997E /* GPBArray.h in Headers */ = {isa = PBXBuildFile; fileRef = F39971C663288B1BB328B890576AEAB3 /* GPBArray.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 95C69447F517DB81437EDE0003486963 /* GTMSessionFetcherService.m in Sources */ = {isa = PBXBuildFile; fileRef = 21B57505496D8B6FD3C53DAF4BF4F85D /* GTMSessionFetcherService.m */; }; + 9A0765016AAF1DE8D415F5C7077B08E3 /* SourceContext.pbobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C2B28134C4600D751831044BF350C78 /* SourceContext.pbobjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C9430F5A6A582FDEC475F0F87845990 /* GPBCodedOutputStream_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 6445DA24F37284CCD7D60F42AEDB328E /* GPBCodedOutputStream_PackagePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9DA28C3544749A7DB9AB129BEC773550 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C085E02FF89804F50ADDA04F5A586E94 /* Security.framework */; }; + 9EFDC382EA8046BD94BE4F6583BC2800 /* GPBMessage_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 183DB240A46971803A28CB9FE34F36F7 /* GPBMessage_PackagePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A1C1013347C39AD49E4E27D2078BD080 /* Empty.pbobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CAF7291732371309D361C70D69ADB13 /* Empty.pbobjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AC2675E8A2D6BABC9FDD6C582992A2BE /* GPBRootObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5AF114D6270A4C46880D7426E9513D12 /* GPBRootObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AE65CFF60F2B6AFFE6BBD123832A466A /* GPBMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 012B8F7A597A78C4DC407EB21266F1FD /* GPBMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B63B9795D2866789089F8DB65B7A23FE /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A272AD8371E28EB1582401951BB2145 /* Wrappers.pbobjc.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + BBC4FE778C649CF03B8655DE21181103 /* GTMLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 98EE81E4A4B16AF8FBC4EDCCF60A6ED9 /* GTMLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BD41E55F7E05E5AAD8E177BB3B78A74D /* GTMDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = ED55067FB15F176C5520ACE63453EFB7 /* GTMDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BD422CF8DE48A6806CA885FA3F737600 /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 5478F306DD4CFE69F2191586C1134CFE /* Struct.pbobjc.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + BD9A28EB9B94DAB1DCAE2A5FBD1ECE45 /* GPBExtensionInternals.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C78E4E1E09D7B3EE68E2C0371DB16E /* GPBExtensionInternals.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C0AD5637AFC2EE013EFD8FA8B2FA5448 /* GPBUnknownField_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 40645DD995F3756914E088A2C7A376EE /* GPBUnknownField_PackagePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C0C8DBA23FC57BBA2A14D0B2D8777BCE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */; }; + C20E4F80CF42F565B246B4D7D3538166 /* GPBUnknownFieldSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 96AB867DF2498D9F4BFD385FF309D3B9 /* GPBUnknownFieldSet.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C501E17E9E8501752B99011E17E41412 /* GTMNSData+zlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B83949EABAB968C5EB2EB1645287F75 /* GTMNSData+zlib.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C6E6A71DF80F6383D0E5730B3127A712 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */; }; + D0204CCB31003F4F2FE7C94932213C6B /* GoogleToolboxForMac-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BABE3ACB1E5C89A0DD8852DBCCE7350 /* GoogleToolboxForMac-dummy.m */; }; + D102CA6D7DBBFFB059EBCFC17251CEFA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */; }; + D3F381B45ADFDDE51CA31F1E141236CA /* GTMSessionFetcher-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = F52B2F8ADE485FB8B736318B625BEEB3 /* GTMSessionFetcher-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D54FEC0940B3BEBBCF522C5DCDE4FEAC /* GPBWireFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = B4FB8ECB30A4645801605A66D0352E93 /* GPBWireFormat.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + D5BA2D2DDF82EBBA1469B16B92F63F08 /* FieldMask.pbobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = BA1D3365619803CC79F3D9029371A4B9 /* FieldMask.pbobjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D8F796CB869D288897675BFA976EB502 /* GPBUnknownFieldSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 4343BCC511F1B2E716924FCC914AEAEF /* GPBUnknownFieldSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DB4E3CE4E90F6DF0FFAC700CECE17C0D /* GPBBootstrap.h in Headers */ = {isa = PBXBuildFile; fileRef = F078A18E0183CAAAE12EF3DA46497041 /* GPBBootstrap.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DCA645D3121B7B6F914A6F55DD20A2E8 /* GPBExtensionRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 206DB77ADDB86ADE766DAA2B6D4D9EB8 /* GPBExtensionRegistry.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + DF9559C3822E3C6119BE43E4EDFD7EEE /* GTMSessionFetcherService.h in Headers */ = {isa = PBXBuildFile; fileRef = 87A361B65A55B0CC4D1032AC961E83E4 /* GTMSessionFetcherService.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E5DC45292C2DBCC38C722CA79D72341E /* Empty.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = E7F6FA5DD1D752E01CE83A59F370B060 /* Empty.pbobjc.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + E8C1EC8D3DBC968518E575FE52BCC8F8 /* FieldMask.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 63AA4541517F2BC8F131C7FF4AFF8791 /* FieldMask.pbobjc.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + EB8CE90003139D73977562D1129F077D /* GoogleToolboxForMac-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 63418CDFFEF03330C72BCB0E6BCE8326 /* GoogleToolboxForMac-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC1707751A2DBCB466E29764EC7ECB86 /* GTMDebugThreadValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = 38A20C930F4C3794CA06FCCB5E0EC3E0 /* GTMDebugThreadValidation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ECC361F16DD9AEDCB90A194369E2A44A /* GPBRuntimeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = A12C2AAACD327D4C77B174328EF69FF0 /* GPBRuntimeTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EE3D7A9094F92C691B7CBA93868152B5 /* GTMNSString+URLArguments.m in Sources */ = {isa = PBXBuildFile; fileRef = 05A76B20AAB10FCDAD8E5B5761EE8699 /* GTMNSString+URLArguments.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + EE45FA1DFEB2298F29DEC2CB16B0F27F /* GPBRootObject_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = CBE7F93249373B50AB7CE38A6754F4C6 /* GPBRootObject_PackagePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F09EDD53B94234F5F8DAC4DCD5CD969E /* GTMSessionUploadFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 07F03CB27E18344D93011E691D1D0A90 /* GTMSessionUploadFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F48CF3B9FE8C456125D9BE1882F7B73D /* GTMDebugSelectorValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = 333CD81708A67E757714E071F8A11EC7 /* GTMDebugSelectorValidation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F4E294C07EE32FFCDCF7FF4D71D850BD /* GTMSessionUploadFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = BFF3AF00032D6C72B401A57619A28B1D /* GTMSessionUploadFetcher.m */; }; + F60739AA237DA6BEABDD597768BED1C0 /* GPBCodedOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC11CE0FB9F14202CA375B041AD146A /* GPBCodedOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F73D234B2C9ECDF1EC1F47A1AE31D2FD /* Duration.pbobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C645DC6CCFABF04EDEC517521DDE5E /* Duration.pbobjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F7B139F36890542E92C170487C927AE5 /* GPBProtocolBuffers.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A2A570111CB9024D326F42B784D98B3 /* GPBProtocolBuffers.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F90E13187B1579EF72C2777CAB6166C9 /* GPBUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7861A5A6B9DE9321864DA5D890704730 /* GPBUtilities.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + F99BA2DF2E0AF6477D89BC497CED41B8 /* GPBUtilities_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 10A80EE767123ED08B56E7897D94CF3E /* GPBUtilities_PackagePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FB62FC1E37F6C18BA8ACC2454C9C9202 /* Struct.pbobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = D22FA5505BE5CB79E15F6F8E38F3220A /* Struct.pbobjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FC2DEEF82EFC0A684165713AE6D490B6 /* GPBCodedInputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ECB11AFB48B7345C1EC841FAAB74AFD /* GPBCodedInputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FE0EA6C2B83923E04D16C7A413587439 /* GPBDictionary_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 97E1086524747FB1670E51E9F21371EA /* GPBDictionary_PackagePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FEEB26218DDAEC5C664129DF57B3F0F8 /* GPBExtensionRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4572E8C5075336BED5332E87B9B07489 /* GPBExtensionRegistry.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FFBB264338AEE6FBCA6E93BB67B8E928 /* Timestamp.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 67F36AA81E40884A5895D415D9836B3C /* Timestamp.pbobjc.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 4A2C4D4552A04DFB5B243DDB6C6A6CB4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = C052BEBFBD0AB5218CC64BA3450F6547; + remoteInfo = GTMSessionFetcher; + }; + 5FF127B497D58F8325C4346DBEAE7607 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = DF4C6C83F4304FC2867DC11122FF8CFB; + remoteInfo = Protobuf; + }; + A84D0B5F21361A2E2243ED88C9308EE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6D5CEDECD3D8DC52EA507E0431BDA8A0; + remoteInfo = GoogleToolboxForMac; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 012B8F7A597A78C4DC407EB21266F1FD /* GPBMessage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBMessage.h; path = objectivec/GPBMessage.h; sourceTree = ""; }; + 05A76B20AAB10FCDAD8E5B5761EE8699 /* GTMNSString+URLArguments.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GTMNSString+URLArguments.m"; path = "Foundation/GTMNSString+URLArguments.m"; sourceTree = ""; }; + 0673E0ABB5DC30AFE7ED3596B2C7D316 /* Pods-Task Master-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Task Master-acknowledgements.markdown"; sourceTree = ""; }; + 07F03CB27E18344D93011E691D1D0A90 /* GTMSessionUploadFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionUploadFetcher.h; path = Source/GTMSessionUploadFetcher.h; sourceTree = ""; }; + 0C04BCEFEC71CD4C28C481DF41DE8169 /* GoogleToolboxForMac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = GoogleToolboxForMac.framework; path = GoogleToolboxForMac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0D977C5C4514D54B0A539FB5C1E04D6E /* Pods_Task_MasterTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_Task_MasterTests.framework; path = "Pods-Task MasterTests.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 10A80EE767123ED08B56E7897D94CF3E /* GPBUtilities_PackagePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBUtilities_PackagePrivate.h; path = objectivec/GPBUtilities_PackagePrivate.h; sourceTree = ""; }; + 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 1652B3EBB328D6F3AD33CD5D4D3C5D97 /* GPBArray.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBArray.m; path = objectivec/GPBArray.m; sourceTree = ""; }; + 17A1815AD5EAF7E32F66559D9E4BD75B /* GPBDescriptor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBDescriptor.m; path = objectivec/GPBDescriptor.m; sourceTree = ""; }; + 183DB240A46971803A28CB9FE34F36F7 /* GPBMessage_PackagePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBMessage_PackagePrivate.h; path = objectivec/GPBMessage_PackagePrivate.h; sourceTree = ""; }; + 1B83949EABAB968C5EB2EB1645287F75 /* GTMNSData+zlib.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GTMNSData+zlib.h"; path = "Foundation/GTMNSData+zlib.h"; sourceTree = ""; }; + 1D7058F232FC7286C84B762006AD5F6C /* GPBMessage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBMessage.m; path = objectivec/GPBMessage.m; sourceTree = ""; }; + 1ECB11AFB48B7345C1EC841FAAB74AFD /* GPBCodedInputStream.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBCodedInputStream.h; path = objectivec/GPBCodedInputStream.h; sourceTree = ""; }; + 1F142FD49ED067F8913338CE22072164 /* Timestamp.pbobjc.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Timestamp.pbobjc.h; path = objectivec/google/protobuf/Timestamp.pbobjc.h; sourceTree = ""; }; + 206DB77ADDB86ADE766DAA2B6D4D9EB8 /* GPBExtensionRegistry.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBExtensionRegistry.m; path = objectivec/GPBExtensionRegistry.m; sourceTree = ""; }; + 20AB0481AA1720C66C6F703A8EAE6C62 /* GPBDescriptor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBDescriptor.h; path = objectivec/GPBDescriptor.h; sourceTree = ""; }; + 20E6F0FE55D241CC752A7084ADB2D274 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 21B57505496D8B6FD3C53DAF4BF4F85D /* GTMSessionFetcherService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherService.m; path = Source/GTMSessionFetcherService.m; sourceTree = ""; }; + 2A24785673E34F0B688399C305485173 /* GoogleToolboxForMac.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleToolboxForMac.xcconfig; sourceTree = ""; }; + 2C0832DAF6AE03C6AC3FA92CF622C512 /* GTMMethodCheck.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMMethodCheck.h; path = DebugUtils/GTMMethodCheck.h; sourceTree = ""; }; + 2C8EB2F139D2F44C974FC089552243ED /* Pods-Task MasterTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Task MasterTests.release.xcconfig"; sourceTree = ""; }; + 2FBBD81F52EADA7B6E8ED529693596F2 /* GPBDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBDictionary.m; path = objectivec/GPBDictionary.m; sourceTree = ""; }; + 314D949A5B496ACFD68FBCB2D8FB9CF0 /* Pods-Task Master.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Task Master.release.xcconfig"; sourceTree = ""; }; + 333CD81708A67E757714E071F8A11EC7 /* GTMDebugSelectorValidation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMDebugSelectorValidation.h; path = DebugUtils/GTMDebugSelectorValidation.h; sourceTree = ""; }; + 38A20C930F4C3794CA06FCCB5E0EC3E0 /* GTMDebugThreadValidation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMDebugThreadValidation.h; path = DebugUtils/GTMDebugThreadValidation.h; sourceTree = ""; }; + 39FD3B458C249F75F405179FC1FF3697 /* Pods-Task Master-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Task Master-umbrella.h"; sourceTree = ""; }; + 3A28BC8E8AB21377CA886B7436FFC0CB /* GTMNSData+zlib.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GTMNSData+zlib.m"; path = "Foundation/GTMNSData+zlib.m"; sourceTree = ""; }; + 3B3F9B789834EEAAF725CA6EC15E9A9C /* FirebaseDatabase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseDatabase.framework; path = Frameworks/FirebaseDatabase.framework; sourceTree = ""; }; + 3BB030E51CD1AC57D9890C75BD19B2E8 /* Pods-Task MasterTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Task MasterTests-acknowledgements.markdown"; sourceTree = ""; }; + 3BE0AF7C64769BADF1FD163493E52EA4 /* GoogleToolboxForMac.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = GoogleToolboxForMac.modulemap; sourceTree = ""; }; + 3C6D27FDFD73A966993B7225705A11C4 /* GTMSessionFetcherLogging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherLogging.m; path = Source/GTMSessionFetcherLogging.m; sourceTree = ""; }; + 40645DD995F3756914E088A2C7A376EE /* GPBUnknownField_PackagePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBUnknownField_PackagePrivate.h; path = objectivec/GPBUnknownField_PackagePrivate.h; sourceTree = ""; }; + 40C91D60EE2B2D053DCFBB7E4ABD3726 /* GPBCodedInputStream.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBCodedInputStream.m; path = objectivec/GPBCodedInputStream.m; sourceTree = ""; }; + 4343BCC511F1B2E716924FCC914AEAEF /* GPBUnknownFieldSet.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBUnknownFieldSet.h; path = objectivec/GPBUnknownFieldSet.h; sourceTree = ""; }; + 438BE34209D01569817ED84CB82EE0A5 /* Pods-Task Master-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Task Master-dummy.m"; sourceTree = ""; }; + 44A37F647C4BDE9787DAE77B219B1CD1 /* Api.pbobjc.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Api.pbobjc.m; path = objectivec/google/protobuf/Api.pbobjc.m; sourceTree = ""; }; + 4572E8C5075336BED5332E87B9B07489 /* GPBExtensionRegistry.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBExtensionRegistry.h; path = objectivec/GPBExtensionRegistry.h; sourceTree = ""; }; + 45F421DC69FB4EA99B0FC3DE9A991061 /* Pods-Task MasterTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Task MasterTests-umbrella.h"; sourceTree = ""; }; + 4A2ED75D43C15B570B134A7546D782B6 /* Any.pbobjc.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Any.pbobjc.m; path = objectivec/google/protobuf/Any.pbobjc.m; sourceTree = ""; }; + 4BC11CE0FB9F14202CA375B041AD146A /* GPBCodedOutputStream.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBCodedOutputStream.h; path = objectivec/GPBCodedOutputStream.h; sourceTree = ""; }; + 4D39EC1E759D1098A332A2FCE9CE8218 /* GPBDescriptor_PackagePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBDescriptor_PackagePrivate.h; path = objectivec/GPBDescriptor_PackagePrivate.h; sourceTree = ""; }; + 51487F35473DCF3C86F3A38B71F9B4CE /* Type.pbobjc.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Type.pbobjc.h; path = objectivec/google/protobuf/Type.pbobjc.h; sourceTree = ""; }; + 5478F306DD4CFE69F2191586C1134CFE /* Struct.pbobjc.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Struct.pbobjc.m; path = objectivec/google/protobuf/Struct.pbobjc.m; sourceTree = ""; }; + 54B8E400CABEC24BF68FDC2D2EB251DF /* Pods-Task MasterTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = "Pods-Task MasterTests.modulemap"; sourceTree = ""; }; + 5A2A570111CB9024D326F42B784D98B3 /* GPBProtocolBuffers.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBProtocolBuffers.h; path = objectivec/GPBProtocolBuffers.h; sourceTree = ""; }; + 5AF114D6270A4C46880D7426E9513D12 /* GPBRootObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBRootObject.h; path = objectivec/GPBRootObject.h; sourceTree = ""; }; + 63418CDFFEF03330C72BCB0E6BCE8326 /* GoogleToolboxForMac-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GoogleToolboxForMac-umbrella.h"; sourceTree = ""; }; + 63AA4541517F2BC8F131C7FF4AFF8791 /* FieldMask.pbobjc.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FieldMask.pbobjc.m; path = objectivec/google/protobuf/FieldMask.pbobjc.m; sourceTree = ""; }; + 6445DA24F37284CCD7D60F42AEDB328E /* GPBCodedOutputStream_PackagePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBCodedOutputStream_PackagePrivate.h; path = objectivec/GPBCodedOutputStream_PackagePrivate.h; sourceTree = ""; }; + 64E8DC81178A87D2BB4062A3905E58AA /* FirebaseCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseCore.framework; path = Frameworks/FirebaseCore.framework; sourceTree = ""; }; + 67F36AA81E40884A5895D415D9836B3C /* Timestamp.pbobjc.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Timestamp.pbobjc.m; path = objectivec/google/protobuf/Timestamp.pbobjc.m; sourceTree = ""; }; + 6862E12C741F0762A7BF3B5DF6E1A975 /* GTMSessionFetcher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = GTMSessionFetcher.framework; path = GTMSessionFetcher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 69F0F1833FF76AE83EED5BCA7CD86E37 /* Firebase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Firebase.h; path = Core/Sources/Firebase.h; sourceTree = ""; }; + 6A5ED3F0B31F5341EF8EB9EF61ABE73F /* Pods-Task MasterTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Task MasterTests-acknowledgements.plist"; sourceTree = ""; }; + 6ADE482EEB5C315E1A17B36A1E26455F /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 7826B17530A7BC70C57FB8F1BCE7D2E5 /* GPBUnknownField.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBUnknownField.m; path = objectivec/GPBUnknownField.m; sourceTree = ""; }; + 7826C75FF1FFC7BDB0A233132A409822 /* GTMNSDictionary+URLArguments.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GTMNSDictionary+URLArguments.m"; path = "Foundation/GTMNSDictionary+URLArguments.m"; sourceTree = ""; }; + 7861A5A6B9DE9321864DA5D890704730 /* GPBUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBUtilities.m; path = objectivec/GPBUtilities.m; sourceTree = ""; }; + 790800F3E75624020FA272F85A1E4CE0 /* GPBWellKnownTypes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBWellKnownTypes.h; path = objectivec/GPBWellKnownTypes.h; sourceTree = ""; }; + 7A10BA821BB9F1F8A17651B4EE85C880 /* GTMNSDictionary+URLArguments.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GTMNSDictionary+URLArguments.h"; path = "Foundation/GTMNSDictionary+URLArguments.h"; sourceTree = ""; }; + 7BABE3ACB1E5C89A0DD8852DBCCE7350 /* GoogleToolboxForMac-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GoogleToolboxForMac-dummy.m"; sourceTree = ""; }; + 8089F26D73C3D8EA03D7987B1010D206 /* GPBWireFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBWireFormat.h; path = objectivec/GPBWireFormat.h; sourceTree = ""; }; + 818777C0CF56245F60C4F081E31D329F /* Pods-Task MasterTests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Task MasterTests-frameworks.sh"; sourceTree = ""; }; + 86BA7390D6875FB6D221449B4FB4050D /* FirebaseStorage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseStorage.framework; path = Frameworks/FirebaseStorage.framework; sourceTree = ""; }; + 87A361B65A55B0CC4D1032AC961E83E4 /* GTMSessionFetcherService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherService.h; path = Source/GTMSessionFetcherService.h; sourceTree = ""; }; + 8A7D6DBD30C825FA1364219272BA2A31 /* Protobuf-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Protobuf-prefix.pch"; sourceTree = ""; }; + 8BD5A737B97DA9C6DCA7C1022540C17D /* GPBWellKnownTypes.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBWellKnownTypes.m; path = objectivec/GPBWellKnownTypes.m; sourceTree = ""; }; + 8C19AF3A610AD7D087493F0FC21989DD /* Type.pbobjc.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Type.pbobjc.m; path = objectivec/google/protobuf/Type.pbobjc.m; sourceTree = ""; }; + 8CAF7291732371309D361C70D69ADB13 /* Empty.pbobjc.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Empty.pbobjc.h; path = objectivec/google/protobuf/Empty.pbobjc.h; sourceTree = ""; }; + 8E64E0368ABDD45084A0CD5232C2AF8D /* Pods-Task Master-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Task Master-frameworks.sh"; sourceTree = ""; }; + 8E86D4F41D053E0F37A5BB27A24AB668 /* GTMSessionFetcher.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GTMSessionFetcher.xcconfig; sourceTree = ""; }; + 9013A40E6583E08D3B0015706746B4ED /* Api.pbobjc.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Api.pbobjc.h; path = objectivec/google/protobuf/Api.pbobjc.h; sourceTree = ""; }; + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 96AB867DF2498D9F4BFD385FF309D3B9 /* GPBUnknownFieldSet.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBUnknownFieldSet.m; path = objectivec/GPBUnknownFieldSet.m; sourceTree = ""; }; + 97E1086524747FB1670E51E9F21371EA /* GPBDictionary_PackagePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBDictionary_PackagePrivate.h; path = objectivec/GPBDictionary_PackagePrivate.h; sourceTree = ""; }; + 983AE580D3D68286E61B5C8B5F334D87 /* GTMSessionFetcherLogging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherLogging.h; path = Source/GTMSessionFetcherLogging.h; sourceTree = ""; }; + 98EE81E4A4B16AF8FBC4EDCCF60A6ED9 /* GTMLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMLogger.h; path = Foundation/GTMLogger.h; sourceTree = ""; }; + 993D20BECAED5BA2B5F6D02B450D6E1F /* Pods-Task MasterTests-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Task MasterTests-resources.sh"; sourceTree = ""; }; + 9A272AD8371E28EB1582401951BB2145 /* Wrappers.pbobjc.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Wrappers.pbobjc.m; path = objectivec/google/protobuf/Wrappers.pbobjc.m; sourceTree = ""; }; + 9A72D556A557A87F5E255EF5B3F93F3A /* GPBExtensionInternals.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBExtensionInternals.h; path = objectivec/GPBExtensionInternals.h; sourceTree = ""; }; + 9C2B28134C4600D751831044BF350C78 /* SourceContext.pbobjc.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SourceContext.pbobjc.h; path = objectivec/google/protobuf/SourceContext.pbobjc.h; sourceTree = ""; }; + 9CF1E2CF379D403A07A30CC6090DB133 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9E22C7F51E1D8856BFAB037815B57BE2 /* Protobuf-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Protobuf-dummy.m"; sourceTree = ""; }; + A12C2AAACD327D4C77B174328EF69FF0 /* GPBRuntimeTypes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBRuntimeTypes.h; path = objectivec/GPBRuntimeTypes.h; sourceTree = ""; }; + A4F687C5A12DC348F0A041B02AF44F2A /* GoogleToolboxForMac-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GoogleToolboxForMac-prefix.pch"; sourceTree = ""; }; + A6108FAFBE7B468A4F29AB6401541A23 /* Wrappers.pbobjc.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Wrappers.pbobjc.h; path = objectivec/google/protobuf/Wrappers.pbobjc.h; sourceTree = ""; }; + A615A3055E6CED8A78B90AABDF8C87F6 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBUnknownFieldSet_PackagePrivate.h; path = objectivec/GPBUnknownFieldSet_PackagePrivate.h; sourceTree = ""; }; + A7E6C3D103A84D537228DC0C4AD87AC8 /* GTMSessionFetcher-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GTMSessionFetcher-prefix.pch"; sourceTree = ""; }; + A8706D465B0C2F36EF95D5135302CD03 /* FirebaseAnalytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseAnalytics.framework; path = Frameworks/FirebaseAnalytics.framework; sourceTree = ""; }; + A9577970E4246EBBE74FB1A1C04C980C /* Pods-Task Master.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = "Pods-Task Master.modulemap"; sourceTree = ""; }; + AC9C017D361D072E574FA20FF426DCE3 /* GPBUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBUtilities.h; path = objectivec/GPBUtilities.h; sourceTree = ""; }; + AD313E9353A050828C6EF78F72A3AB9E /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AF5B4A9F3F9C2602860D1ABD933BC989 /* SourceContext.pbobjc.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SourceContext.pbobjc.m; path = objectivec/google/protobuf/SourceContext.pbobjc.m; sourceTree = ""; }; + AFA3C02BFF3168A892F8BE7331F8D072 /* Any.pbobjc.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Any.pbobjc.h; path = objectivec/google/protobuf/Any.pbobjc.h; sourceTree = ""; }; + AFCC9BE81DB073D04B6AF48A91264FBB /* Protobuf-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Protobuf-umbrella.h"; sourceTree = ""; }; + B09C42309F6DA214D63BCECF912FD095 /* GPBDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBDictionary.h; path = objectivec/GPBDictionary.h; sourceTree = ""; }; + B4C6ED157DDBEB555E8BDE5770898609 /* GPBUnknownField.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBUnknownField.h; path = objectivec/GPBUnknownField.h; sourceTree = ""; }; + B4FB8ECB30A4645801605A66D0352E93 /* GPBWireFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBWireFormat.m; path = objectivec/GPBWireFormat.m; sourceTree = ""; }; + BA1D3365619803CC79F3D9029371A4B9 /* FieldMask.pbobjc.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FieldMask.pbobjc.h; path = objectivec/google/protobuf/FieldMask.pbobjc.h; sourceTree = ""; }; + BAF99425AC2F6920481D9BFB3163B08D /* Protobuf.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = Protobuf.modulemap; sourceTree = ""; }; + BCBF497B6B7672570A8BF3A61B138FCE /* FirebaseMessaging.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseMessaging.framework; path = Frameworks/FirebaseMessaging.framework; sourceTree = ""; }; + BCD0C2439C3D36EB1CCD2534F78F0A87 /* GTMSessionFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcher.m; path = Source/GTMSessionFetcher.m; sourceTree = ""; }; + BE0839E6D36674FEC567B979A5A5B548 /* Protobuf.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Protobuf.framework; path = Protobuf.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BF8ED924E9F4BCF5356BB829D4C9EDB7 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + BFF3AF00032D6C72B401A57619A28B1D /* GTMSessionUploadFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionUploadFetcher.m; path = Source/GTMSessionUploadFetcher.m; sourceTree = ""; }; + C085E02FF89804F50ADDA04F5A586E94 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + C2C645DC6CCFABF04EDEC517521DDE5E /* Duration.pbobjc.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Duration.pbobjc.h; path = objectivec/google/protobuf/Duration.pbobjc.h; sourceTree = ""; }; + C2F73AA619F0197684E0F854BD25387F /* GPBRootObject.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBRootObject.m; path = objectivec/GPBRootObject.m; sourceTree = ""; }; + C5F51F1FA7D655A89E57367E5D9C6E5C /* GTMNSString+URLArguments.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GTMNSString+URLArguments.h"; path = "Foundation/GTMNSString+URLArguments.h"; sourceTree = ""; }; + C93E47F76B9A0D1420B5D3DEC675EC24 /* FirebaseInstanceID.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseInstanceID.framework; path = Frameworks/FirebaseInstanceID.framework; sourceTree = ""; }; + CA329348A553C12780A49F4F4EDDFD08 /* Pods-Task Master-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Task Master-acknowledgements.plist"; sourceTree = ""; }; + CB0E8EBC040DEF0CDDDA89B1CF842E84 /* GTMSessionFetcher-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GTMSessionFetcher-dummy.m"; sourceTree = ""; }; + CB76A82B21FE383C21246A7F14E0E5ED /* GPBProtocolBuffers_RuntimeSupport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBProtocolBuffers_RuntimeSupport.h; path = objectivec/GPBProtocolBuffers_RuntimeSupport.h; sourceTree = ""; }; + CBE7F93249373B50AB7CE38A6754F4C6 /* GPBRootObject_PackagePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBRootObject_PackagePrivate.h; path = objectivec/GPBRootObject_PackagePrivate.h; sourceTree = ""; }; + D22FA5505BE5CB79E15F6F8E38F3220A /* Struct.pbobjc.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Struct.pbobjc.h; path = objectivec/google/protobuf/Struct.pbobjc.h; sourceTree = ""; }; + D75142FB9ECD866AEF874E634CB3A44F /* GTMSessionFetcher.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = GTMSessionFetcher.modulemap; sourceTree = ""; }; + D789E88CFAE8C4A0A6E479F323C836BD /* Pods_Task_Master.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_Task_Master.framework; path = "Pods-Task Master.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + DC2843670BF217B5E2E434805881433C /* GPBCodedInputStream_PackagePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBCodedInputStream_PackagePrivate.h; path = objectivec/GPBCodedInputStream_PackagePrivate.h; sourceTree = ""; }; + DCB60864AD42C3F5A999BBAE53018EC3 /* Pods-Task Master.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Task Master.debug.xcconfig"; sourceTree = ""; }; + DFC89E01D7E59B31CDDE58689A074092 /* Protobuf.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Protobuf.xcconfig; sourceTree = ""; }; + E7F6FA5DD1D752E01CE83A59F370B060 /* Empty.pbobjc.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Empty.pbobjc.m; path = objectivec/google/protobuf/Empty.pbobjc.m; sourceTree = ""; }; + E9D7DA31B18D3025D7B9FDA5B72C5F25 /* Pods-Task MasterTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Task MasterTests.debug.xcconfig"; sourceTree = ""; }; + EBEDDE72DF6E6E4F5FC416CAB00AEB9D /* GTMSessionFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcher.h; path = Source/GTMSessionFetcher.h; sourceTree = ""; }; + ED55067FB15F176C5520ACE63453EFB7 /* GTMDefines.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = GTMDefines.h; sourceTree = ""; }; + EE27CFE3721D792C114170EBE6CBF234 /* FirebaseAuth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseAuth.framework; path = Frameworks/FirebaseAuth.framework; sourceTree = ""; }; + F0541D224D8027080311EF1A8CDCC79C /* Pods-Task MasterTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Task MasterTests-dummy.m"; sourceTree = ""; }; + F078A18E0183CAAAE12EF3DA46497041 /* GPBBootstrap.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBBootstrap.h; path = objectivec/GPBBootstrap.h; sourceTree = ""; }; + F39971C663288B1BB328B890576AEAB3 /* GPBArray.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBArray.h; path = objectivec/GPBArray.h; sourceTree = ""; }; + F52B2F8ADE485FB8B736318B625BEEB3 /* GTMSessionFetcher-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GTMSessionFetcher-umbrella.h"; sourceTree = ""; }; + F5888B78723685140BE3DBD98AE2A2D2 /* GTMLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMLogger.m; path = Foundation/GTMLogger.m; sourceTree = ""; }; + F8C53C765B432E3A93918B509A5F4EDD /* GPBArray_PackagePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GPBArray_PackagePrivate.h; path = objectivec/GPBArray_PackagePrivate.h; sourceTree = ""; }; + F9C78E4E1E09D7B3EE68E2C0371DB16E /* GPBExtensionInternals.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBExtensionInternals.m; path = objectivec/GPBExtensionInternals.m; sourceTree = ""; }; + FD8B4B49C13E6DD590DF4F9AD6FB3531 /* GPBCodedOutputStream.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GPBCodedOutputStream.m; path = objectivec/GPBCodedOutputStream.m; sourceTree = ""; }; + FE4B883319839651967EF230592E8861 /* Pods-Task Master-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Task Master-resources.sh"; sourceTree = ""; }; + FFEB46E9093597B723323030167F5DC9 /* Duration.pbobjc.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Duration.pbobjc.m; path = objectivec/google/protobuf/Duration.pbobjc.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 056EBB96213E97E100463CD18FF9683F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C0C8DBA23FC57BBA2A14D0B2D8777BCE /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6AE88E96161DE195EAAF0A3B6375EA50 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9024F4774BD8DDE03700B223CF7F8164 /* Foundation.framework in Frameworks */, + 9DA28C3544749A7DB9AB129BEC773550 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6C3C5ED5DDA6AB7517EE6B02783EBE22 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 45AACE7ED64B60DB9023976C928131A2 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 861601680AF8A5E23DFF9F54684E4250 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C6E6A71DF80F6383D0E5730B3127A712 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D4427013B659CCB6CC14F595124589DD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D102CA6D7DBBFFB059EBCFC17251CEFA /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1288EFF7A4CCA6C6189A063A9CF049D6 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 86BA7390D6875FB6D221449B4FB4050D /* FirebaseStorage.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 1409BEAE3CAF976A9B81AA26C9B9061B /* Frameworks */ = { + isa = PBXGroup; + children = ( + BCBF497B6B7672570A8BF3A61B138FCE /* FirebaseMessaging.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 15D65D2A00030C8FC36A3F942CAACBD4 /* NSData+zlib */ = { + isa = PBXGroup; + children = ( + 1B83949EABAB968C5EB2EB1645287F75 /* GTMNSData+zlib.h */, + 3A28BC8E8AB21377CA886B7436FFC0CB /* GTMNSData+zlib.m */, + ); + name = "NSData+zlib"; + sourceTree = ""; + }; + 2EBFCD6B86B202A07C3CDCC92F99D5E6 /* Logger */ = { + isa = PBXGroup; + children = ( + 98EE81E4A4B16AF8FBC4EDCCF60A6ED9 /* GTMLogger.h */, + F5888B78723685140BE3DBD98AE2A2D2 /* GTMLogger.m */, + ); + name = Logger; + sourceTree = ""; + }; + 372B81792C7D4DEC03491B75D208841C /* Frameworks */ = { + isa = PBXGroup; + children = ( + EE27CFE3721D792C114170EBE6CBF234 /* FirebaseAuth.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 433CD3331B6C3787F473C941B61FC68F /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4F990579C2E52276FD3C28227B49D60B /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + 453032B09801C2B512B2C8B65B55342C /* NSDictionary+URLArguments */ = { + isa = PBXGroup; + children = ( + 7A10BA821BB9F1F8A17651B4EE85C880 /* GTMNSDictionary+URLArguments.h */, + 7826C75FF1FFC7BDB0A233132A409822 /* GTMNSDictionary+URLArguments.m */, + ); + name = "NSDictionary+URLArguments"; + sourceTree = ""; + }; + 47E81C3D3B0BFA945941BFC3E2F674E8 /* FirebaseMessaging */ = { + isa = PBXGroup; + children = ( + 1409BEAE3CAF976A9B81AA26C9B9061B /* Frameworks */, + ); + name = FirebaseMessaging; + path = FirebaseMessaging; + sourceTree = ""; + }; + 4BA0E3D45D7D6F35A5EDD38E17AAA63D /* Core */ = { + isa = PBXGroup; + children = ( + 69F0F1833FF76AE83EED5BCA7CD86E37 /* Firebase.h */, + ); + name = Core; + sourceTree = ""; + }; + 4CB0AF65AFC3997809B572FC211B5E6C /* FirebaseInstanceID */ = { + isa = PBXGroup; + children = ( + C7DD5D4EF36DE3CA836708FA8AAB451A /* Frameworks */, + ); + name = FirebaseInstanceID; + path = FirebaseInstanceID; + sourceTree = ""; + }; + 4F990579C2E52276FD3C28227B49D60B /* iOS */ = { + isa = PBXGroup; + children = ( + 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */, + C085E02FF89804F50ADDA04F5A586E94 /* Security.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 5840F8AD0C716816501D8F3DCFFBE660 /* Protobuf */ = { + isa = PBXGroup; + children = ( + AFA3C02BFF3168A892F8BE7331F8D072 /* Any.pbobjc.h */, + 4A2ED75D43C15B570B134A7546D782B6 /* Any.pbobjc.m */, + 9013A40E6583E08D3B0015706746B4ED /* Api.pbobjc.h */, + 44A37F647C4BDE9787DAE77B219B1CD1 /* Api.pbobjc.m */, + C2C645DC6CCFABF04EDEC517521DDE5E /* Duration.pbobjc.h */, + FFEB46E9093597B723323030167F5DC9 /* Duration.pbobjc.m */, + 8CAF7291732371309D361C70D69ADB13 /* Empty.pbobjc.h */, + E7F6FA5DD1D752E01CE83A59F370B060 /* Empty.pbobjc.m */, + BA1D3365619803CC79F3D9029371A4B9 /* FieldMask.pbobjc.h */, + 63AA4541517F2BC8F131C7FF4AFF8791 /* FieldMask.pbobjc.m */, + F39971C663288B1BB328B890576AEAB3 /* GPBArray.h */, + 1652B3EBB328D6F3AD33CD5D4D3C5D97 /* GPBArray.m */, + F8C53C765B432E3A93918B509A5F4EDD /* GPBArray_PackagePrivate.h */, + F078A18E0183CAAAE12EF3DA46497041 /* GPBBootstrap.h */, + 1ECB11AFB48B7345C1EC841FAAB74AFD /* GPBCodedInputStream.h */, + 40C91D60EE2B2D053DCFBB7E4ABD3726 /* GPBCodedInputStream.m */, + DC2843670BF217B5E2E434805881433C /* GPBCodedInputStream_PackagePrivate.h */, + 4BC11CE0FB9F14202CA375B041AD146A /* GPBCodedOutputStream.h */, + FD8B4B49C13E6DD590DF4F9AD6FB3531 /* GPBCodedOutputStream.m */, + 6445DA24F37284CCD7D60F42AEDB328E /* GPBCodedOutputStream_PackagePrivate.h */, + 20AB0481AA1720C66C6F703A8EAE6C62 /* GPBDescriptor.h */, + 17A1815AD5EAF7E32F66559D9E4BD75B /* GPBDescriptor.m */, + 4D39EC1E759D1098A332A2FCE9CE8218 /* GPBDescriptor_PackagePrivate.h */, + B09C42309F6DA214D63BCECF912FD095 /* GPBDictionary.h */, + 2FBBD81F52EADA7B6E8ED529693596F2 /* GPBDictionary.m */, + 97E1086524747FB1670E51E9F21371EA /* GPBDictionary_PackagePrivate.h */, + 9A72D556A557A87F5E255EF5B3F93F3A /* GPBExtensionInternals.h */, + F9C78E4E1E09D7B3EE68E2C0371DB16E /* GPBExtensionInternals.m */, + 4572E8C5075336BED5332E87B9B07489 /* GPBExtensionRegistry.h */, + 206DB77ADDB86ADE766DAA2B6D4D9EB8 /* GPBExtensionRegistry.m */, + 012B8F7A597A78C4DC407EB21266F1FD /* GPBMessage.h */, + 1D7058F232FC7286C84B762006AD5F6C /* GPBMessage.m */, + 183DB240A46971803A28CB9FE34F36F7 /* GPBMessage_PackagePrivate.h */, + 5A2A570111CB9024D326F42B784D98B3 /* GPBProtocolBuffers.h */, + CB76A82B21FE383C21246A7F14E0E5ED /* GPBProtocolBuffers_RuntimeSupport.h */, + 5AF114D6270A4C46880D7426E9513D12 /* GPBRootObject.h */, + C2F73AA619F0197684E0F854BD25387F /* GPBRootObject.m */, + CBE7F93249373B50AB7CE38A6754F4C6 /* GPBRootObject_PackagePrivate.h */, + A12C2AAACD327D4C77B174328EF69FF0 /* GPBRuntimeTypes.h */, + B4C6ED157DDBEB555E8BDE5770898609 /* GPBUnknownField.h */, + 7826B17530A7BC70C57FB8F1BCE7D2E5 /* GPBUnknownField.m */, + 40645DD995F3756914E088A2C7A376EE /* GPBUnknownField_PackagePrivate.h */, + 4343BCC511F1B2E716924FCC914AEAEF /* GPBUnknownFieldSet.h */, + 96AB867DF2498D9F4BFD385FF309D3B9 /* GPBUnknownFieldSet.m */, + A615A3055E6CED8A78B90AABDF8C87F6 /* GPBUnknownFieldSet_PackagePrivate.h */, + AC9C017D361D072E574FA20FF426DCE3 /* GPBUtilities.h */, + 7861A5A6B9DE9321864DA5D890704730 /* GPBUtilities.m */, + 10A80EE767123ED08B56E7897D94CF3E /* GPBUtilities_PackagePrivate.h */, + 790800F3E75624020FA272F85A1E4CE0 /* GPBWellKnownTypes.h */, + 8BD5A737B97DA9C6DCA7C1022540C17D /* GPBWellKnownTypes.m */, + 8089F26D73C3D8EA03D7987B1010D206 /* GPBWireFormat.h */, + B4FB8ECB30A4645801605A66D0352E93 /* GPBWireFormat.m */, + 9C2B28134C4600D751831044BF350C78 /* SourceContext.pbobjc.h */, + AF5B4A9F3F9C2602860D1ABD933BC989 /* SourceContext.pbobjc.m */, + D22FA5505BE5CB79E15F6F8E38F3220A /* Struct.pbobjc.h */, + 5478F306DD4CFE69F2191586C1134CFE /* Struct.pbobjc.m */, + 1F142FD49ED067F8913338CE22072164 /* Timestamp.pbobjc.h */, + 67F36AA81E40884A5895D415D9836B3C /* Timestamp.pbobjc.m */, + 51487F35473DCF3C86F3A38B71F9B4CE /* Type.pbobjc.h */, + 8C19AF3A610AD7D087493F0FC21989DD /* Type.pbobjc.m */, + A6108FAFBE7B468A4F29AB6401541A23 /* Wrappers.pbobjc.h */, + 9A272AD8371E28EB1582401951BB2145 /* Wrappers.pbobjc.m */, + 690C2C68A7857BC1C1A4003A88CE132B /* Support Files */, + ); + name = Protobuf; + path = Protobuf; + sourceTree = ""; + }; + 5CBD517F7AF77A10E402710B444781D1 /* Pods-Task MasterTests */ = { + isa = PBXGroup; + children = ( + AD313E9353A050828C6EF78F72A3AB9E /* Info.plist */, + 54B8E400CABEC24BF68FDC2D2EB251DF /* Pods-Task MasterTests.modulemap */, + 3BB030E51CD1AC57D9890C75BD19B2E8 /* Pods-Task MasterTests-acknowledgements.markdown */, + 6A5ED3F0B31F5341EF8EB9EF61ABE73F /* Pods-Task MasterTests-acknowledgements.plist */, + F0541D224D8027080311EF1A8CDCC79C /* Pods-Task MasterTests-dummy.m */, + 818777C0CF56245F60C4F081E31D329F /* Pods-Task MasterTests-frameworks.sh */, + 993D20BECAED5BA2B5F6D02B450D6E1F /* Pods-Task MasterTests-resources.sh */, + 45F421DC69FB4EA99B0FC3DE9A991061 /* Pods-Task MasterTests-umbrella.h */, + E9D7DA31B18D3025D7B9FDA5B72C5F25 /* Pods-Task MasterTests.debug.xcconfig */, + 2C8EB2F139D2F44C974FC089552243ED /* Pods-Task MasterTests.release.xcconfig */, + ); + name = "Pods-Task MasterTests"; + path = "Target Support Files/Pods-Task MasterTests"; + sourceTree = ""; + }; + 63247A155CCE559982E3BAF52BB98473 /* FirebaseAnalytics */ = { + isa = PBXGroup; + children = ( + 729CEF21D4B0D56422A9790F9C7BD3DC /* Frameworks */, + ); + name = FirebaseAnalytics; + path = FirebaseAnalytics; + sourceTree = ""; + }; + 690C2C68A7857BC1C1A4003A88CE132B /* Support Files */ = { + isa = PBXGroup; + children = ( + 20E6F0FE55D241CC752A7084ADB2D274 /* Info.plist */, + BAF99425AC2F6920481D9BFB3163B08D /* Protobuf.modulemap */, + DFC89E01D7E59B31CDDE58689A074092 /* Protobuf.xcconfig */, + 9E22C7F51E1D8856BFAB037815B57BE2 /* Protobuf-dummy.m */, + 8A7D6DBD30C825FA1364219272BA2A31 /* Protobuf-prefix.pch */, + AFCC9BE81DB073D04B6AF48A91264FBB /* Protobuf-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/Protobuf"; + sourceTree = ""; + }; + 6C22876A563DE8C5FFED5D47EEBB35A5 /* GTMSessionFetcher */ = { + isa = PBXGroup; + children = ( + C01F13067919BF3D2ABC6000848730E5 /* Core */, + 982FDC69613A48CD6470044A8C3392AB /* Support Files */, + ); + name = GTMSessionFetcher; + path = GTMSessionFetcher; + sourceTree = ""; + }; + 729CEF21D4B0D56422A9790F9C7BD3DC /* Frameworks */ = { + isa = PBXGroup; + children = ( + A8706D465B0C2F36EF95D5135302CD03 /* FirebaseAnalytics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 73201DB50A7A97BA70190DF889F1E9A7 /* FirebaseStorage */ = { + isa = PBXGroup; + children = ( + 1288EFF7A4CCA6C6189A063A9CF049D6 /* Frameworks */, + ); + name = FirebaseStorage; + path = FirebaseStorage; + sourceTree = ""; + }; + 798436A5DDB14849DAF407B34CCCE65B /* Pods */ = { + isa = PBXGroup; + children = ( + EEEB3D45FCCD17538CFCBE77DC19B5DC /* Firebase */, + 63247A155CCE559982E3BAF52BB98473 /* FirebaseAnalytics */, + 9FD99E8FD2E2BE619BDF06D43BBFD755 /* FirebaseAuth */, + 81F2B95AA963314997E554C379565FB3 /* FirebaseCore */, + C091577A87536C7057E6B19EEAFD7407 /* FirebaseDatabase */, + 4CB0AF65AFC3997809B572FC211B5E6C /* FirebaseInstanceID */, + 47E81C3D3B0BFA945941BFC3E2F674E8 /* FirebaseMessaging */, + 73201DB50A7A97BA70190DF889F1E9A7 /* FirebaseStorage */, + 8935A8D6E4DEE1EA321A330710477A02 /* GoogleToolboxForMac */, + 6C22876A563DE8C5FFED5D47EEBB35A5 /* GTMSessionFetcher */, + 5840F8AD0C716816501D8F3DCFFBE660 /* Protobuf */, + ); + name = Pods; + sourceTree = ""; + }; + 7A9A479B0D7EAA69B68B8B2CA5E634E8 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 9CEDEDBE003C24F2A24C2FC9D579113D /* Pods-Task Master */, + 5CBD517F7AF77A10E402710B444781D1 /* Pods-Task MasterTests */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 7DB346D0F39D3F0E887471402A8071AB = { + isa = PBXGroup; + children = ( + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */, + 433CD3331B6C3787F473C941B61FC68F /* Frameworks */, + 798436A5DDB14849DAF407B34CCCE65B /* Pods */, + CBDC87CCEDF63ABF0C599D511B5F9791 /* Products */, + 7A9A479B0D7EAA69B68B8B2CA5E634E8 /* Targets Support Files */, + ); + sourceTree = ""; + }; + 81F2B95AA963314997E554C379565FB3 /* FirebaseCore */ = { + isa = PBXGroup; + children = ( + D0E3EFFFBC81BC169A4E915652FA825C /* Frameworks */, + ); + name = FirebaseCore; + path = FirebaseCore; + sourceTree = ""; + }; + 84B0D1CE817BA7E76DF1CB278F19C9AB /* Support Files */ = { + isa = PBXGroup; + children = ( + 3BE0AF7C64769BADF1FD163493E52EA4 /* GoogleToolboxForMac.modulemap */, + 2A24785673E34F0B688399C305485173 /* GoogleToolboxForMac.xcconfig */, + 7BABE3ACB1E5C89A0DD8852DBCCE7350 /* GoogleToolboxForMac-dummy.m */, + A4F687C5A12DC348F0A041B02AF44F2A /* GoogleToolboxForMac-prefix.pch */, + 63418CDFFEF03330C72BCB0E6BCE8326 /* GoogleToolboxForMac-umbrella.h */, + 9CF1E2CF379D403A07A30CC6090DB133 /* Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/GoogleToolboxForMac"; + sourceTree = ""; + }; + 8935A8D6E4DEE1EA321A330710477A02 /* GoogleToolboxForMac */ = { + isa = PBXGroup; + children = ( + E3E235B0DA730C8A0DF65B3F7ACC2CB9 /* DebugUtils */, + A85F675F43ADCD0083BBBF380A317E32 /* Defines */, + 2EBFCD6B86B202A07C3CDCC92F99D5E6 /* Logger */, + 15D65D2A00030C8FC36A3F942CAACBD4 /* NSData+zlib */, + 453032B09801C2B512B2C8B65B55342C /* NSDictionary+URLArguments */, + A371FB3CDAC42098EF969B747AEBAC52 /* NSString+URLArguments */, + 84B0D1CE817BA7E76DF1CB278F19C9AB /* Support Files */, + ); + name = GoogleToolboxForMac; + path = GoogleToolboxForMac; + sourceTree = ""; + }; + 982FDC69613A48CD6470044A8C3392AB /* Support Files */ = { + isa = PBXGroup; + children = ( + D75142FB9ECD866AEF874E634CB3A44F /* GTMSessionFetcher.modulemap */, + 8E86D4F41D053E0F37A5BB27A24AB668 /* GTMSessionFetcher.xcconfig */, + CB0E8EBC040DEF0CDDDA89B1CF842E84 /* GTMSessionFetcher-dummy.m */, + A7E6C3D103A84D537228DC0C4AD87AC8 /* GTMSessionFetcher-prefix.pch */, + F52B2F8ADE485FB8B736318B625BEEB3 /* GTMSessionFetcher-umbrella.h */, + BF8ED924E9F4BCF5356BB829D4C9EDB7 /* Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/GTMSessionFetcher"; + sourceTree = ""; + }; + 9CEDEDBE003C24F2A24C2FC9D579113D /* Pods-Task Master */ = { + isa = PBXGroup; + children = ( + 6ADE482EEB5C315E1A17B36A1E26455F /* Info.plist */, + A9577970E4246EBBE74FB1A1C04C980C /* Pods-Task Master.modulemap */, + 0673E0ABB5DC30AFE7ED3596B2C7D316 /* Pods-Task Master-acknowledgements.markdown */, + CA329348A553C12780A49F4F4EDDFD08 /* Pods-Task Master-acknowledgements.plist */, + 438BE34209D01569817ED84CB82EE0A5 /* Pods-Task Master-dummy.m */, + 8E64E0368ABDD45084A0CD5232C2AF8D /* Pods-Task Master-frameworks.sh */, + FE4B883319839651967EF230592E8861 /* Pods-Task Master-resources.sh */, + 39FD3B458C249F75F405179FC1FF3697 /* Pods-Task Master-umbrella.h */, + DCB60864AD42C3F5A999BBAE53018EC3 /* Pods-Task Master.debug.xcconfig */, + 314D949A5B496ACFD68FBCB2D8FB9CF0 /* Pods-Task Master.release.xcconfig */, + ); + name = "Pods-Task Master"; + path = "Target Support Files/Pods-Task Master"; + sourceTree = ""; + }; + 9FD99E8FD2E2BE619BDF06D43BBFD755 /* FirebaseAuth */ = { + isa = PBXGroup; + children = ( + 372B81792C7D4DEC03491B75D208841C /* Frameworks */, + ); + name = FirebaseAuth; + path = FirebaseAuth; + sourceTree = ""; + }; + A371FB3CDAC42098EF969B747AEBAC52 /* NSString+URLArguments */ = { + isa = PBXGroup; + children = ( + C5F51F1FA7D655A89E57367E5D9C6E5C /* GTMNSString+URLArguments.h */, + 05A76B20AAB10FCDAD8E5B5761EE8699 /* GTMNSString+URLArguments.m */, + ); + name = "NSString+URLArguments"; + sourceTree = ""; + }; + A85F675F43ADCD0083BBBF380A317E32 /* Defines */ = { + isa = PBXGroup; + children = ( + ED55067FB15F176C5520ACE63453EFB7 /* GTMDefines.h */, + ); + name = Defines; + sourceTree = ""; + }; + C01F13067919BF3D2ABC6000848730E5 /* Core */ = { + isa = PBXGroup; + children = ( + EBEDDE72DF6E6E4F5FC416CAB00AEB9D /* GTMSessionFetcher.h */, + BCD0C2439C3D36EB1CCD2534F78F0A87 /* GTMSessionFetcher.m */, + 983AE580D3D68286E61B5C8B5F334D87 /* GTMSessionFetcherLogging.h */, + 3C6D27FDFD73A966993B7225705A11C4 /* GTMSessionFetcherLogging.m */, + 87A361B65A55B0CC4D1032AC961E83E4 /* GTMSessionFetcherService.h */, + 21B57505496D8B6FD3C53DAF4BF4F85D /* GTMSessionFetcherService.m */, + 07F03CB27E18344D93011E691D1D0A90 /* GTMSessionUploadFetcher.h */, + BFF3AF00032D6C72B401A57619A28B1D /* GTMSessionUploadFetcher.m */, + ); + name = Core; + sourceTree = ""; + }; + C091577A87536C7057E6B19EEAFD7407 /* FirebaseDatabase */ = { + isa = PBXGroup; + children = ( + E46C800AB1D3F3015025D51944BAE76B /* Frameworks */, + ); + name = FirebaseDatabase; + path = FirebaseDatabase; + sourceTree = ""; + }; + C7DD5D4EF36DE3CA836708FA8AAB451A /* Frameworks */ = { + isa = PBXGroup; + children = ( + C93E47F76B9A0D1420B5D3DEC675EC24 /* FirebaseInstanceID.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + CBDC87CCEDF63ABF0C599D511B5F9791 /* Products */ = { + isa = PBXGroup; + children = ( + 0C04BCEFEC71CD4C28C481DF41DE8169 /* GoogleToolboxForMac.framework */, + 6862E12C741F0762A7BF3B5DF6E1A975 /* GTMSessionFetcher.framework */, + D789E88CFAE8C4A0A6E479F323C836BD /* Pods_Task_Master.framework */, + 0D977C5C4514D54B0A539FB5C1E04D6E /* Pods_Task_MasterTests.framework */, + BE0839E6D36674FEC567B979A5A5B548 /* Protobuf.framework */, + ); + name = Products; + sourceTree = ""; + }; + D0E3EFFFBC81BC169A4E915652FA825C /* Frameworks */ = { + isa = PBXGroup; + children = ( + 64E8DC81178A87D2BB4062A3905E58AA /* FirebaseCore.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + E3E235B0DA730C8A0DF65B3F7ACC2CB9 /* DebugUtils */ = { + isa = PBXGroup; + children = ( + 333CD81708A67E757714E071F8A11EC7 /* GTMDebugSelectorValidation.h */, + 38A20C930F4C3794CA06FCCB5E0EC3E0 /* GTMDebugThreadValidation.h */, + 2C0832DAF6AE03C6AC3FA92CF622C512 /* GTMMethodCheck.h */, + ); + name = DebugUtils; + sourceTree = ""; + }; + E46C800AB1D3F3015025D51944BAE76B /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3B3F9B789834EEAAF725CA6EC15E9A9C /* FirebaseDatabase.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + EEEB3D45FCCD17538CFCBE77DC19B5DC /* Firebase */ = { + isa = PBXGroup; + children = ( + 4BA0E3D45D7D6F35A5EDD38E17AAA63D /* Core */, + ); + name = Firebase; + path = Firebase; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 1536C625BDA9A53679F06773C6652B6E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 370112294682E448737B4C0C2F44C179 /* Any.pbobjc.h in Headers */, + 48DCA9DC8163025967B0EC7BF5233017 /* Api.pbobjc.h in Headers */, + F73D234B2C9ECDF1EC1F47A1AE31D2FD /* Duration.pbobjc.h in Headers */, + A1C1013347C39AD49E4E27D2078BD080 /* Empty.pbobjc.h in Headers */, + D5BA2D2DDF82EBBA1469B16B92F63F08 /* FieldMask.pbobjc.h in Headers */, + 9414790418F4D609D0C013C333CD997E /* GPBArray.h in Headers */, + 72B9A19E429C92B8866B50F9C03ADB5B /* GPBArray_PackagePrivate.h in Headers */, + DB4E3CE4E90F6DF0FFAC700CECE17C0D /* GPBBootstrap.h in Headers */, + FC2DEEF82EFC0A684165713AE6D490B6 /* GPBCodedInputStream.h in Headers */, + 88B8C5E102BDDD1F9C8B454A80CFCF9A /* GPBCodedInputStream_PackagePrivate.h in Headers */, + F60739AA237DA6BEABDD597768BED1C0 /* GPBCodedOutputStream.h in Headers */, + 9C9430F5A6A582FDEC475F0F87845990 /* GPBCodedOutputStream_PackagePrivate.h in Headers */, + 3F314C7B45CA75B9075CE6BF1D8A34E5 /* GPBDescriptor.h in Headers */, + 33C6BB2680C6E10B1FA0B5832C5C412B /* GPBDescriptor_PackagePrivate.h in Headers */, + 8D1E9814E93E1D22607F52D4FEDA30F8 /* GPBDictionary.h in Headers */, + FE0EA6C2B83923E04D16C7A413587439 /* GPBDictionary_PackagePrivate.h in Headers */, + 7693C97371B72954902E05582DE0B4A5 /* GPBExtensionInternals.h in Headers */, + FEEB26218DDAEC5C664129DF57B3F0F8 /* GPBExtensionRegistry.h in Headers */, + AE65CFF60F2B6AFFE6BBD123832A466A /* GPBMessage.h in Headers */, + 9EFDC382EA8046BD94BE4F6583BC2800 /* GPBMessage_PackagePrivate.h in Headers */, + F7B139F36890542E92C170487C927AE5 /* GPBProtocolBuffers.h in Headers */, + 0FD95C77F4D26FDEF060B165B38E38E1 /* GPBProtocolBuffers_RuntimeSupport.h in Headers */, + AC2675E8A2D6BABC9FDD6C582992A2BE /* GPBRootObject.h in Headers */, + EE45FA1DFEB2298F29DEC2CB16B0F27F /* GPBRootObject_PackagePrivate.h in Headers */, + ECC361F16DD9AEDCB90A194369E2A44A /* GPBRuntimeTypes.h in Headers */, + 03D9A9338B4C4A547D0EDB778622FE5F /* GPBUnknownField.h in Headers */, + C0AD5637AFC2EE013EFD8FA8B2FA5448 /* GPBUnknownField_PackagePrivate.h in Headers */, + D8F796CB869D288897675BFA976EB502 /* GPBUnknownFieldSet.h in Headers */, + 20950941DA29EE48DFA15BCA9A0210AF /* GPBUnknownFieldSet_PackagePrivate.h in Headers */, + 1D8AB37710CA2025CB4529995AB4149C /* GPBUtilities.h in Headers */, + F99BA2DF2E0AF6477D89BC497CED41B8 /* GPBUtilities_PackagePrivate.h in Headers */, + 0C297FFE87536C58E1BD9F84762AD35F /* GPBWellKnownTypes.h in Headers */, + 69C80E9455E5B4DE476295A8E01D960A /* GPBWireFormat.h in Headers */, + 4802E1AC6C1603B62890488D8F69A796 /* Protobuf-umbrella.h in Headers */, + 9A0765016AAF1DE8D415F5C7077B08E3 /* SourceContext.pbobjc.h in Headers */, + FB62FC1E37F6C18BA8ACC2454C9C9202 /* Struct.pbobjc.h in Headers */, + 2F1AF78224FE4B37727002FF33B1DE39 /* Timestamp.pbobjc.h in Headers */, + 1AE244B9B7A24028FC231AB5244B5AFE /* Type.pbobjc.h in Headers */, + 5C476A7D90DB3F32B0FF571D2492717B /* Wrappers.pbobjc.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3254B8DF404753DF71BAABA7CDB8CF9E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8E52B99DBE2D51455C8A0A77313E5A3E /* Pods-Task MasterTests-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 79DB98FE30B6EC1D8C72FCFAC5031C8E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 6F908A2494CBC5A78C1C9CFBDA2D6E95 /* Pods-Task Master-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7C9A2748345D25082BA10BC98B8D5807 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + EB8CE90003139D73977562D1129F077D /* GoogleToolboxForMac-umbrella.h in Headers */, + F48CF3B9FE8C456125D9BE1882F7B73D /* GTMDebugSelectorValidation.h in Headers */, + EC1707751A2DBCB466E29764EC7ECB86 /* GTMDebugThreadValidation.h in Headers */, + BD41E55F7E05E5AAD8E177BB3B78A74D /* GTMDefines.h in Headers */, + BBC4FE778C649CF03B8655DE21181103 /* GTMLogger.h in Headers */, + 63F4579804EEF3DECBD27D579D4FA196 /* GTMMethodCheck.h in Headers */, + C501E17E9E8501752B99011E17E41412 /* GTMNSData+zlib.h in Headers */, + 162F73650877177FAB96CC08BE515C97 /* GTMNSDictionary+URLArguments.h in Headers */, + 43EB5608A304AAA6D221B2E5CC0ED6B0 /* GTMNSString+URLArguments.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 82D993B88C10479096F17ADDEAB85D94 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D3F381B45ADFDDE51CA31F1E141236CA /* GTMSessionFetcher-umbrella.h in Headers */, + 8852FD9AFC242520924D98BE9C4E2477 /* GTMSessionFetcher.h in Headers */, + 1ED67707C258751E7888DAC2AB3D8501 /* GTMSessionFetcherLogging.h in Headers */, + DF9559C3822E3C6119BE43E4EDFD7EEE /* GTMSessionFetcherService.h in Headers */, + F09EDD53B94234F5F8DAC4DCD5CD969E /* GTMSessionUploadFetcher.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 6D5CEDECD3D8DC52EA507E0431BDA8A0 /* GoogleToolboxForMac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6CA44BD43AA2613869A5BA2839D015BC /* Build configuration list for PBXNativeTarget "GoogleToolboxForMac" */; + buildPhases = ( + 71B2CD65CBC5F51408BC5B1C1889A5F9 /* Sources */, + 056EBB96213E97E100463CD18FF9683F /* Frameworks */, + 7C9A2748345D25082BA10BC98B8D5807 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GoogleToolboxForMac; + productName = GoogleToolboxForMac; + productReference = 0C04BCEFEC71CD4C28C481DF41DE8169 /* GoogleToolboxForMac.framework */; + productType = "com.apple.product-type.framework"; + }; + C052BEBFBD0AB5218CC64BA3450F6547 /* GTMSessionFetcher */ = { + isa = PBXNativeTarget; + buildConfigurationList = D7CC8559AB6F51830204F1A9CE54BF3E /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */; + buildPhases = ( + C5A309EC5A80A27DBD420C5176E2122A /* Sources */, + 6AE88E96161DE195EAAF0A3B6375EA50 /* Frameworks */, + 82D993B88C10479096F17ADDEAB85D94 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GTMSessionFetcher; + productName = GTMSessionFetcher; + productReference = 6862E12C741F0762A7BF3B5DF6E1A975 /* GTMSessionFetcher.framework */; + productType = "com.apple.product-type.framework"; + }; + CA009515194EBB975DFF5106DB7702CA /* Pods-Task MasterTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5A87F05986F4D5E992B0CD6385B3EB4E /* Build configuration list for PBXNativeTarget "Pods-Task MasterTests" */; + buildPhases = ( + FFCF22BD1FA00DAF0A01D58587118D24 /* Sources */, + 861601680AF8A5E23DFF9F54684E4250 /* Frameworks */, + 3254B8DF404753DF71BAABA7CDB8CF9E /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Pods-Task MasterTests"; + productName = "Pods-Task MasterTests"; + productReference = 0D977C5C4514D54B0A539FB5C1E04D6E /* Pods_Task_MasterTests.framework */; + productType = "com.apple.product-type.framework"; + }; + D7C7853AD970C331A6D62BDD0FA9E801 /* Pods-Task Master */ = { + isa = PBXNativeTarget; + buildConfigurationList = 362B7B105DFECB29B3484D5B0E99774E /* Build configuration list for PBXNativeTarget "Pods-Task Master" */; + buildPhases = ( + 6D1C03030AF8D5C573AFEA11C1C761BE /* Sources */, + D4427013B659CCB6CC14F595124589DD /* Frameworks */, + 79DB98FE30B6EC1D8C72FCFAC5031C8E /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + E9E5B6664F0A0DBB8B46AE72A87C8E29 /* PBXTargetDependency */, + 6839A9CBEF95F6DF49DC6DEE1FFB288B /* PBXTargetDependency */, + 64BC9DF6B1BF5A36DECD1FF702218E43 /* PBXTargetDependency */, + ); + name = "Pods-Task Master"; + productName = "Pods-Task Master"; + productReference = D789E88CFAE8C4A0A6E479F323C836BD /* Pods_Task_Master.framework */; + productType = "com.apple.product-type.framework"; + }; + DF4C6C83F4304FC2867DC11122FF8CFB /* Protobuf */ = { + isa = PBXNativeTarget; + buildConfigurationList = 83EA6B83029A9435E85CCAE0BFA5104E /* Build configuration list for PBXNativeTarget "Protobuf" */; + buildPhases = ( + 42ECD0EF6DFC65B823D9D24BFED5338A /* Sources */, + 6C3C5ED5DDA6AB7517EE6B02783EBE22 /* Frameworks */, + 1536C625BDA9A53679F06773C6652B6E /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Protobuf; + productName = Protobuf; + productReference = BE0839E6D36674FEC567B979A5A5B548 /* Protobuf.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 0700; + }; + buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 7DB346D0F39D3F0E887471402A8071AB; + productRefGroup = CBDC87CCEDF63ABF0C599D511B5F9791 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 6D5CEDECD3D8DC52EA507E0431BDA8A0 /* GoogleToolboxForMac */, + C052BEBFBD0AB5218CC64BA3450F6547 /* GTMSessionFetcher */, + D7C7853AD970C331A6D62BDD0FA9E801 /* Pods-Task Master */, + CA009515194EBB975DFF5106DB7702CA /* Pods-Task MasterTests */, + DF4C6C83F4304FC2867DC11122FF8CFB /* Protobuf */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 42ECD0EF6DFC65B823D9D24BFED5338A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 261913C4C9A09C4FC5BDCD7CA00BCD81 /* Any.pbobjc.m in Sources */, + 4639D2530BE0EFEC170D2A37DECEEC4D /* Api.pbobjc.m in Sources */, + 1AC07C876FA170C637713815AD65AE94 /* Duration.pbobjc.m in Sources */, + E5DC45292C2DBCC38C722CA79D72341E /* Empty.pbobjc.m in Sources */, + E8C1EC8D3DBC968518E575FE52BCC8F8 /* FieldMask.pbobjc.m in Sources */, + 6C1EE2D83500E16530B87113624619F5 /* GPBArray.m in Sources */, + 2C655997A136E46BF307B7538B3C7C36 /* GPBCodedInputStream.m in Sources */, + 84160C31A93C4C53AC915C3E8EE1C960 /* GPBCodedOutputStream.m in Sources */, + 2CE91CC9D788EE4C74CAC9624B705236 /* GPBDescriptor.m in Sources */, + 2F8E36740CA1536BAD2A8BA06E6939AC /* GPBDictionary.m in Sources */, + BD9A28EB9B94DAB1DCAE2A5FBD1ECE45 /* GPBExtensionInternals.m in Sources */, + DCA645D3121B7B6F914A6F55DD20A2E8 /* GPBExtensionRegistry.m in Sources */, + 3A0F1C2E934F06DCE1D9B45C8176FF57 /* GPBMessage.m in Sources */, + 7F2A025DA61C0108C7DDDC69A2BE7F35 /* GPBRootObject.m in Sources */, + 327AD50BD57D92C49F4A842D131EA079 /* GPBUnknownField.m in Sources */, + C20E4F80CF42F565B246B4D7D3538166 /* GPBUnknownFieldSet.m in Sources */, + F90E13187B1579EF72C2777CAB6166C9 /* GPBUtilities.m in Sources */, + 1B314C427956D7BB6420A01FF8FC1224 /* GPBWellKnownTypes.m in Sources */, + D54FEC0940B3BEBBCF522C5DCDE4FEAC /* GPBWireFormat.m in Sources */, + 25CEBB7D05A007691375434587AA4FCF /* Protobuf-dummy.m in Sources */, + 56D0F0D420B767BD2D701AE5F2BAC312 /* SourceContext.pbobjc.m in Sources */, + BD422CF8DE48A6806CA885FA3F737600 /* Struct.pbobjc.m in Sources */, + FFBB264338AEE6FBCA6E93BB67B8E928 /* Timestamp.pbobjc.m in Sources */, + 57FFAAC0D91DCBE356711A96E4E25563 /* Type.pbobjc.m in Sources */, + B63B9795D2866789089F8DB65B7A23FE /* Wrappers.pbobjc.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6D1C03030AF8D5C573AFEA11C1C761BE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D0D20DBA47FD65B2A5A5DE2BD6BC887 /* Pods-Task Master-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 71B2CD65CBC5F51408BC5B1C1889A5F9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0204CCB31003F4F2FE7C94932213C6B /* GoogleToolboxForMac-dummy.m in Sources */, + 8B9241E640FE9CF729F2198266F28213 /* GTMLogger.m in Sources */, + 6B4F19D8BD01EAF45CA1FE09294B7E12 /* GTMNSData+zlib.m in Sources */, + 450E5A090328E7D1BD167496E80DFA1F /* GTMNSDictionary+URLArguments.m in Sources */, + EE3D7A9094F92C691B7CBA93868152B5 /* GTMNSString+URLArguments.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C5A309EC5A80A27DBD420C5176E2122A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6EA6DFC4473A9B2DB6B8A42EA986BA5B /* GTMSessionFetcher-dummy.m in Sources */, + 64F31B70A6E5E6963518A01C285B435F /* GTMSessionFetcher.m in Sources */, + 07340F15BACBA601736DBB2ABF1ABC35 /* GTMSessionFetcherLogging.m in Sources */, + 95C69447F517DB81437EDE0003486963 /* GTMSessionFetcherService.m in Sources */, + F4E294C07EE32FFCDCF7FF4D71D850BD /* GTMSessionUploadFetcher.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FFCF22BD1FA00DAF0A01D58587118D24 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6E606AC80340A6C0D2DB4F51A59B0E8B /* Pods-Task MasterTests-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 64BC9DF6B1BF5A36DECD1FF702218E43 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Protobuf; + target = DF4C6C83F4304FC2867DC11122FF8CFB /* Protobuf */; + targetProxy = 5FF127B497D58F8325C4346DBEAE7607 /* PBXContainerItemProxy */; + }; + 6839A9CBEF95F6DF49DC6DEE1FFB288B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleToolboxForMac; + target = 6D5CEDECD3D8DC52EA507E0431BDA8A0 /* GoogleToolboxForMac */; + targetProxy = A84D0B5F21361A2E2243ED88C9308EE5 /* PBXContainerItemProxy */; + }; + E9E5B6664F0A0DBB8B46AE72A87C8E29 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GTMSessionFetcher; + target = C052BEBFBD0AB5218CC64BA3450F6547 /* GTMSessionFetcher */; + targetProxy = 4A2C4D4552A04DFB5B243DDB6C6A6CB4 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 103066F7A1BFD8DF169624F71C79AC96 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E9D7DA31B18D3025D7B9FDA5B72C5F25 /* Pods-Task MasterTests.debug.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "Target Support Files/Pods-Task MasterTests/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = Pods_Task_MasterTests; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 173EB991F4189BD0521FB9FF314C1A99 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8E86D4F41D053E0F37A5BB27A24AB668 /* GTMSessionFetcher.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/GTMSessionFetcher/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/GTMSessionFetcher/GTMSessionFetcher.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = GTMSessionFetcher; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 1AF71ADD48CF1018949D1682AD92322C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 314D949A5B496ACFD68FBCB2D8FB9CF0 /* Pods-Task Master.release.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "Target Support Files/Pods-Task Master/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Task Master/Pods-Task Master.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = Pods_Task_Master; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 599D6C0671BDC29AE3D47E58A2A0B116 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2A24785673E34F0B688399C305485173 /* GoogleToolboxForMac.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/GoogleToolboxForMac/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/GoogleToolboxForMac/GoogleToolboxForMac.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = GoogleToolboxForMac; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 5EC9DDC590E000FC3BF93D2E1B5E2AFB /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8E86D4F41D053E0F37A5BB27A24AB668 /* GTMSessionFetcher.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/GTMSessionFetcher/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/GTMSessionFetcher/GTMSessionFetcher.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = GTMSessionFetcher; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 803DFA8931A6ABBCF4F1E55665A8BD37 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2A24785673E34F0B688399C305485173 /* GoogleToolboxForMac.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/GoogleToolboxForMac/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/GoogleToolboxForMac/GoogleToolboxForMac.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = GoogleToolboxForMac; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + B797C43ADC9C3AC6A6B9F86FA10520AF /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2C8EB2F139D2F44C974FC089552243ED /* Pods-Task MasterTests.release.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "Target Support Files/Pods-Task MasterTests/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = Pods_Task_MasterTests; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + C9AB81BFD05E6D67605417F865AD0797 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + 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_OBJC_ROOT_CLASS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_REQUIRED = NO; + COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + ONLY_ACTIVE_ARCH = YES; + PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + CDC1EAA54BFCF14D22EA589B44B802B2 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DFC89E01D7E59B31CDDE58689A074092 /* Protobuf.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/Protobuf/Protobuf-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Protobuf/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/Protobuf/Protobuf.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = Protobuf; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + E4B41E3879F96F184FA2E66797C2E7AC /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DFC89E01D7E59B31CDDE58689A074092 /* Protobuf.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/Protobuf/Protobuf-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Protobuf/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/Protobuf/Protobuf.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = Protobuf; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + EDC2AA7A769C7EC8985877948E1A0E59 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + 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_OBJC_ROOT_CLASS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_REQUIRED = NO; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + F38F9CD196DD7E34D56EA4C00FBC3BC4 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DCB60864AD42C3F5A999BBAE53018EC3 /* Pods-Task Master.debug.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "Target Support Files/Pods-Task Master/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Task Master/Pods-Task Master.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = Pods_Task_Master; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C9AB81BFD05E6D67605417F865AD0797 /* Debug */, + EDC2AA7A769C7EC8985877948E1A0E59 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 362B7B105DFECB29B3484D5B0E99774E /* Build configuration list for PBXNativeTarget "Pods-Task Master" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F38F9CD196DD7E34D56EA4C00FBC3BC4 /* Debug */, + 1AF71ADD48CF1018949D1682AD92322C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5A87F05986F4D5E992B0CD6385B3EB4E /* Build configuration list for PBXNativeTarget "Pods-Task MasterTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 103066F7A1BFD8DF169624F71C79AC96 /* Debug */, + B797C43ADC9C3AC6A6B9F86FA10520AF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6CA44BD43AA2613869A5BA2839D015BC /* Build configuration list for PBXNativeTarget "GoogleToolboxForMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 803DFA8931A6ABBCF4F1E55665A8BD37 /* Debug */, + 599D6C0671BDC29AE3D47E58A2A0B116 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83EA6B83029A9435E85CCAE0BFA5104E /* Build configuration list for PBXNativeTarget "Protobuf" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CDC1EAA54BFCF14D22EA589B44B802B2 /* Debug */, + E4B41E3879F96F184FA2E66797C2E7AC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D7CC8559AB6F51830204F1A9CE54BF3E /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 173EB991F4189BD0521FB9FF314C1A99 /* Debug */, + 5EC9DDC590E000FC3BF93D2E1B5E2AFB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; +} diff --git a/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme new file mode 100644 index 0000000..87b5a38 --- /dev/null +++ b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme new file mode 100644 index 0000000..e0be996 --- /dev/null +++ b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Master.xcscheme b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Master.xcscheme new file mode 100644 index 0000000..1b4b0d7 --- /dev/null +++ b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Master.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task MasterTests.xcscheme b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task MasterTests.xcscheme new file mode 100644 index 0000000..580788f --- /dev/null +++ b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task MasterTests.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Protobuf.xcscheme b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Protobuf.xcscheme new file mode 100644 index 0000000..18006dd --- /dev/null +++ b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Protobuf.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..7aaa042 --- /dev/null +++ b/Old Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,62 @@ + + + + + SchemeUserState + + GTMSessionFetcher.xcscheme + + isShown + + + GoogleToolboxForMac.xcscheme + + isShown + + + Pods-Task Master.xcscheme + + isShown + + + Pods-Task MasterTests.xcscheme + + isShown + + + Protobuf.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + 6D5CEDECD3D8DC52EA507E0431BDA8A0 + + primary + + + C052BEBFBD0AB5218CC64BA3450F6547 + + primary + + + CA009515194EBB975DFF5106DB7702CA + + primary + + + D7C7853AD970C331A6D62BDD0FA9E801 + + primary + + + DF4C6C83F4304FC2867DC11122FF8CFB + + primary + + + + + diff --git a/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m new file mode 100644 index 0000000..13d68b3 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GTMSessionFetcher : NSObject +@end +@implementation PodsDummy_GTMSessionFetcher +@end diff --git a/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-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/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-umbrella.h b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-umbrella.h new file mode 100644 index 0000000..1c0b7b8 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-umbrella.h @@ -0,0 +1,20 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "GTMSessionFetcher.h" +#import "GTMSessionFetcherLogging.h" +#import "GTMSessionFetcherService.h" +#import "GTMSessionUploadFetcher.h" + +FOUNDATION_EXPORT double GTMSessionFetcherVersionNumber; +FOUNDATION_EXPORT const unsigned char GTMSessionFetcherVersionString[]; + diff --git a/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap new file mode 100644 index 0000000..5121a4d --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap @@ -0,0 +1,6 @@ +framework module GTMSessionFetcher { + umbrella header "GTMSessionFetcher-umbrella.h" + + export * + module * { export * } +} diff --git a/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig new file mode 100644 index 0000000..4e36256 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/FirebaseMessaging" "${PODS_ROOT}/Headers/Public/FirebaseStorage" +OTHER_LDFLAGS = -framework "Security" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GTMSessionFetcher +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES diff --git a/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/Info.plist b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/Info.plist new file mode 100644 index 0000000..05bf6cb --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GTMSessionFetcher/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.9 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-dummy.m b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-dummy.m new file mode 100644 index 0000000..9e35ec0 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GoogleToolboxForMac : NSObject +@end +@implementation PodsDummy_GoogleToolboxForMac +@end diff --git a/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-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/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-umbrella.h b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-umbrella.h new file mode 100644 index 0000000..dc2e232 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "GTMDebugSelectorValidation.h" +#import "GTMDebugThreadValidation.h" +#import "GTMMethodCheck.h" +#import "GTMDefines.h" +#import "GTMLogger.h" +#import "GTMNSData+zlib.h" +#import "GTMNSDictionary+URLArguments.h" +#import "GTMNSString+URLArguments.h" + +FOUNDATION_EXPORT double GoogleToolboxForMacVersionNumber; +FOUNDATION_EXPORT const unsigned char GoogleToolboxForMacVersionString[]; + diff --git a/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.modulemap b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.modulemap new file mode 100644 index 0000000..3245b6d --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.modulemap @@ -0,0 +1,6 @@ +framework module GoogleToolboxForMac { + umbrella header "GoogleToolboxForMac-umbrella.h" + + export * + module * { export * } +} diff --git a/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.xcconfig b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.xcconfig new file mode 100644 index 0000000..ef944b7 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/FirebaseMessaging" "${PODS_ROOT}/Headers/Public/FirebaseStorage" +OTHER_LDFLAGS = -l"z" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleToolboxForMac +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES diff --git a/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/Info.plist b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/Info.plist new file mode 100644 index 0000000..92aaf05 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/GoogleToolboxForMac/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.1.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task Master/Info.plist b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task Master/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/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.markdown b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.markdown new file mode 100644 index 0000000..e8bc777 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.markdown @@ -0,0 +1,493 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## Firebase + +Copyright 2017 Google + +## FirebaseAnalytics + +Copyright 2017 Google + +## FirebaseAuth + +Copyright 2017 Google + +## FirebaseCore + +Copyright 2017 Google + +## FirebaseDatabase + +Copyright 2017 Google + +## FirebaseInstanceID + +Copyright 2017 Google + +## FirebaseMessaging + +Copyright 2017 Google + +## FirebaseStorage + +Copyright 2017 Google + +## GTMSessionFetcher + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## GoogleToolboxForMac + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## Protobuf + +This license applies to all parts of Protocol Buffers except the following: + + - Atomicops support for generic gcc, located in + src/google/protobuf/stubs/atomicops_internals_generic_gcc.h. + This file is copyrighted by Red Hat Inc. + + - Atomicops support for AIX/POWER, located in + src/google/protobuf/stubs/atomicops_internals_power.h. + This file is copyrighted by Bloomberg Finance LP. + +Copyright 2014, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + +Generated by CocoaPods - https://cocoapods.org diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.plist b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.plist new file mode 100644 index 0000000..79323a0 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.plist @@ -0,0 +1,585 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + Firebase + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseAnalytics + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseAuth + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseCore + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseDatabase + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseInstanceID + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseMessaging + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseStorage + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + GTMSessionFetcher + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + GoogleToolboxForMac + Type + PSGroupSpecifier + + + FooterText + This license applies to all parts of Protocol Buffers except the following: + + - Atomicops support for generic gcc, located in + src/google/protobuf/stubs/atomicops_internals_generic_gcc.h. + This file is copyrighted by Red Hat Inc. + + - Atomicops support for AIX/POWER, located in + src/google/protobuf/stubs/atomicops_internals_power.h. + This file is copyrighted by Bloomberg Finance LP. + +Copyright 2014, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + + License + New BSD + Title + Protobuf + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-dummy.m b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-dummy.m new file mode 100644 index 0000000..d8a8d9b --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_Task_Master : NSObject +@end +@implementation PodsDummy_Pods_Task_Master +@end diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh new file mode 100755 index 0000000..9f71c69 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh @@ -0,0 +1,103 @@ +#!/bin/sh +set -e + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +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 dont' throw errors + echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync -av --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}" + 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 && exit ${PIPESTATUS[0]}) + 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 +} + +# 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_identitiy + 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 file + archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" + stripped="" + for arch in $archs; do + if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" || exit 1 + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi +} + + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "$BUILT_PRODUCTS_DIR/GTMSessionFetcher/GTMSessionFetcher.framework" + install_framework "$BUILT_PRODUCTS_DIR/GoogleToolboxForMac/GoogleToolboxForMac.framework" + install_framework "$BUILT_PRODUCTS_DIR/Protobuf/Protobuf.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "$BUILT_PRODUCTS_DIR/GTMSessionFetcher/GTMSessionFetcher.framework" + install_framework "$BUILT_PRODUCTS_DIR/GoogleToolboxForMac/GoogleToolboxForMac.framework" + install_framework "$BUILT_PRODUCTS_DIR/Protobuf/Protobuf.framework" +fi +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh new file mode 100755 index 0000000..4602c68 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh @@ -0,0 +1,99 @@ +#!/bin/sh +set -e + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +case "${TARGETED_DEVICE_FAMILY}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + 3) + TARGET_DEVICE_ARGS="--target-device tv" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; +esac + +install_resource() +{ + if [[ "$1" = /* ]] ; then + RESOURCE_PATH="$1" + else + RESOURCE_PATH="${PODS_ROOT}/$1" + fi + if [[ ! -e "$RESOURCE_PATH" ]] ; then + cat << EOM +error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. +EOM + exit 1 + fi + case $RESOURCE_PATH in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.framework) + echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" + xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + *) + echo "$RESOURCE_PATH" + echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" + ;; + esac +} + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] +then + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "${PODS_ROOT}*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-umbrella.h b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-umbrella.h new file mode 100644 index 0000000..efa9234 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-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_Task_MasterVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_Task_MasterVersionString[]; + diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig new file mode 100644 index 0000000..d187dcc --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig @@ -0,0 +1,9 @@ +FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher" "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac" "$PODS_CONFIGURATION_BUILD_DIR/Protobuf" "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/FirebaseAuth/Frameworks" "${PODS_ROOT}/FirebaseCore/Frameworks" "${PODS_ROOT}/FirebaseDatabase/Frameworks" "${PODS_ROOT}/FirebaseInstanceID/Frameworks" "${PODS_ROOT}/FirebaseMessaging/Frameworks" "${PODS_ROOT}/FirebaseStorage/Frameworks" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 +HEADER_SEARCH_PATHS = $(inherited) ${PODS_ROOT}/Firebase/Core/Sources $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/FirebaseMessaging" "${PODS_ROOT}/Headers/Public/FirebaseStorage" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher/GTMSessionFetcher.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac/GoogleToolboxForMac.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/Protobuf/Protobuf.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Firebase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAuth" -isystem "${PODS_ROOT}/Headers/Public/FirebaseCore" -isystem "${PODS_ROOT}/Headers/Public/FirebaseDatabase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" -isystem "${PODS_ROOT}/Headers/Public/FirebaseMessaging" -isystem "${PODS_ROOT}/Headers/Public/FirebaseStorage" +OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"icucore" -l"sqlite3" -l"z" -framework "AddressBook" -framework "CFNetwork" -framework "FirebaseAnalytics" -framework "FirebaseAuth" -framework "FirebaseCore" -framework "FirebaseDatabase" -framework "FirebaseInstanceID" -framework "FirebaseMessaging" -framework "FirebaseStorage" -framework "GTMSessionFetcher" -framework "GoogleToolboxForMac" -framework "MobileCoreServices" -framework "Protobuf" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT}/Pods diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.modulemap b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.modulemap new file mode 100644 index 0000000..508ae7a --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.modulemap @@ -0,0 +1,6 @@ +framework module Pods_Task_Master { + umbrella header "Pods-Task Master-umbrella.h" + + export * + module * { export * } +} diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig new file mode 100644 index 0000000..d187dcc --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig @@ -0,0 +1,9 @@ +FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher" "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac" "$PODS_CONFIGURATION_BUILD_DIR/Protobuf" "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/FirebaseAuth/Frameworks" "${PODS_ROOT}/FirebaseCore/Frameworks" "${PODS_ROOT}/FirebaseDatabase/Frameworks" "${PODS_ROOT}/FirebaseInstanceID/Frameworks" "${PODS_ROOT}/FirebaseMessaging/Frameworks" "${PODS_ROOT}/FirebaseStorage/Frameworks" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 +HEADER_SEARCH_PATHS = $(inherited) ${PODS_ROOT}/Firebase/Core/Sources $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/FirebaseMessaging" "${PODS_ROOT}/Headers/Public/FirebaseStorage" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher/GTMSessionFetcher.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac/GoogleToolboxForMac.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/Protobuf/Protobuf.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Firebase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAuth" -isystem "${PODS_ROOT}/Headers/Public/FirebaseCore" -isystem "${PODS_ROOT}/Headers/Public/FirebaseDatabase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" -isystem "${PODS_ROOT}/Headers/Public/FirebaseMessaging" -isystem "${PODS_ROOT}/Headers/Public/FirebaseStorage" +OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"icucore" -l"sqlite3" -l"z" -framework "AddressBook" -framework "CFNetwork" -framework "FirebaseAnalytics" -framework "FirebaseAuth" -framework "FirebaseCore" -framework "FirebaseDatabase" -framework "FirebaseInstanceID" -framework "FirebaseMessaging" -framework "FirebaseStorage" -framework "GTMSessionFetcher" -framework "GoogleToolboxForMac" -framework "MobileCoreServices" -framework "Protobuf" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT}/Pods diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Info.plist b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/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/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-acknowledgements.markdown b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-acknowledgements.markdown new file mode 100644 index 0000000..102af75 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-acknowledgements.markdown @@ -0,0 +1,3 @@ +# Acknowledgements +This application makes use of the following third party libraries: +Generated by CocoaPods - https://cocoapods.org diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-acknowledgements.plist b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-acknowledgements.plist new file mode 100644 index 0000000..7acbad1 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-acknowledgements.plist @@ -0,0 +1,29 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-dummy.m b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-dummy.m new file mode 100644 index 0000000..c85d227 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_Task_MasterTests : NSObject +@end +@implementation PodsDummy_Pods_Task_MasterTests +@end diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-frameworks.sh b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-frameworks.sh new file mode 100755 index 0000000..0f29f13 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-frameworks.sh @@ -0,0 +1,92 @@ +#!/bin/sh +set -e + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +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 dont' throw errors + echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync -av --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}" + 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 && exit ${PIPESTATUS[0]}) + 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 +} + +# 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_identitiy + 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 file + archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" + stripped="" + for arch in $archs; do + if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" || exit 1 + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi +} + +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-umbrella.h b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-umbrella.h new file mode 100644 index 0000000..481d1b7 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-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_Task_MasterTestsVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_Task_MasterTestsVersionString[]; + diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.debug.xcconfig b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.debug.xcconfig new file mode 100644 index 0000000..eb4de6e --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.debug.xcconfig @@ -0,0 +1,9 @@ +FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher" "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac" "$PODS_CONFIGURATION_BUILD_DIR/Protobuf" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/FirebaseMessaging" "${PODS_ROOT}/Headers/Public/FirebaseStorage" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher/GTMSessionFetcher.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac/GoogleToolboxForMac.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/Protobuf/Protobuf.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Firebase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAuth" -isystem "${PODS_ROOT}/Headers/Public/FirebaseCore" -isystem "${PODS_ROOT}/Headers/Public/FirebaseDatabase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" -isystem "${PODS_ROOT}/Headers/Public/FirebaseMessaging" -isystem "${PODS_ROOT}/Headers/Public/FirebaseStorage" +OTHER_LDFLAGS = $(inherited) -l"c++" -l"icucore" -l"sqlite3" -l"z" -framework "AddressBook" -framework "CFNetwork" -framework "MobileCoreServices" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT}/Pods diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.modulemap b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.modulemap new file mode 100644 index 0000000..b134080 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.modulemap @@ -0,0 +1,6 @@ +framework module Pods_Task_MasterTests { + umbrella header "Pods-Task MasterTests-umbrella.h" + + export * + module * { export * } +} diff --git a/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.release.xcconfig b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.release.xcconfig new file mode 100644 index 0000000..eb4de6e --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.release.xcconfig @@ -0,0 +1,9 @@ +FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher" "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac" "$PODS_CONFIGURATION_BUILD_DIR/Protobuf" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/FirebaseMessaging" "${PODS_ROOT}/Headers/Public/FirebaseStorage" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher/GTMSessionFetcher.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac/GoogleToolboxForMac.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/Protobuf/Protobuf.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Firebase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAuth" -isystem "${PODS_ROOT}/Headers/Public/FirebaseCore" -isystem "${PODS_ROOT}/Headers/Public/FirebaseDatabase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" -isystem "${PODS_ROOT}/Headers/Public/FirebaseMessaging" -isystem "${PODS_ROOT}/Headers/Public/FirebaseStorage" +OTHER_LDFLAGS = $(inherited) -l"c++" -l"icucore" -l"sqlite3" -l"z" -framework "AddressBook" -framework "CFNetwork" -framework "MobileCoreServices" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT}/Pods diff --git a/Old Task Master/Pods/Target Support Files/Protobuf/Info.plist b/Old Task Master/Pods/Target Support Files/Protobuf/Info.plist new file mode 100644 index 0000000..9ae03a0 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Protobuf/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.2.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf-dummy.m b/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf-dummy.m new file mode 100644 index 0000000..e0f0a33 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Protobuf : NSObject +@end +@implementation PodsDummy_Protobuf +@end diff --git a/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf-prefix.pch b/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf-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/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf-umbrella.h b/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf-umbrella.h new file mode 100644 index 0000000..9242d72 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf-umbrella.h @@ -0,0 +1,54 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "GPBArray.h" +#import "GPBArray_PackagePrivate.h" +#import "GPBBootstrap.h" +#import "GPBCodedInputStream.h" +#import "GPBCodedInputStream_PackagePrivate.h" +#import "GPBCodedOutputStream.h" +#import "GPBCodedOutputStream_PackagePrivate.h" +#import "GPBDescriptor.h" +#import "GPBDescriptor_PackagePrivate.h" +#import "GPBDictionary.h" +#import "GPBDictionary_PackagePrivate.h" +#import "GPBExtensionInternals.h" +#import "GPBExtensionRegistry.h" +#import "GPBMessage.h" +#import "GPBMessage_PackagePrivate.h" +#import "GPBProtocolBuffers.h" +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "GPBRootObject.h" +#import "GPBRootObject_PackagePrivate.h" +#import "GPBRuntimeTypes.h" +#import "GPBUnknownField.h" +#import "GPBUnknownFieldSet.h" +#import "GPBUnknownFieldSet_PackagePrivate.h" +#import "GPBUnknownField_PackagePrivate.h" +#import "GPBUtilities.h" +#import "GPBUtilities_PackagePrivate.h" +#import "GPBWellKnownTypes.h" +#import "GPBWireFormat.h" +#import "Any.pbobjc.h" +#import "Api.pbobjc.h" +#import "Duration.pbobjc.h" +#import "Empty.pbobjc.h" +#import "FieldMask.pbobjc.h" +#import "SourceContext.pbobjc.h" +#import "Struct.pbobjc.h" +#import "Timestamp.pbobjc.h" +#import "Type.pbobjc.h" +#import "Wrappers.pbobjc.h" + +FOUNDATION_EXPORT double ProtobufVersionNumber; +FOUNDATION_EXPORT const unsigned char ProtobufVersionString[]; + diff --git a/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf.modulemap b/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf.modulemap new file mode 100644 index 0000000..57d3b39 --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf.modulemap @@ -0,0 +1,6 @@ +framework module Protobuf { + umbrella header "Protobuf-umbrella.h" + + export * + module * { export * } +} diff --git a/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf.xcconfig b/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf.xcconfig new file mode 100644 index 0000000..7c5865b --- /dev/null +++ b/Old Task Master/Pods/Target Support Files/Protobuf/Protobuf.xcconfig @@ -0,0 +1,9 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/Protobuf +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/FirebaseMessaging" "${PODS_ROOT}/Headers/Public/FirebaseStorage" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Protobuf +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES diff --git a/Task Master.xcodeproj/project.pbxproj b/Old Task Master/Task Master.xcodeproj/project.pbxproj similarity index 69% rename from Task Master.xcodeproj/project.pbxproj rename to Old Task Master/Task Master.xcodeproj/project.pbxproj index e4bfb88..78e49c6 100644 --- a/Task Master.xcodeproj/project.pbxproj +++ b/Old Task Master/Task Master.xcodeproj/project.pbxproj @@ -7,16 +7,20 @@ objects = { /* Begin PBXBuildFile section */ + 009BD8C190CEAC330A77019D /* Pods_Task_Master.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6BAFFA5C9426B4DE421453D /* Pods_Task_Master.framework */; }; 5F05B7221DFE210A0095C03B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F05B7211DFE210A0095C03B /* AppDelegate.swift */; }; - 5F05B7261DFE210A0095C03B /* SecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F05B7251DFE210A0095C03B /* SecondViewController.swift */; }; + 5F05B7261DFE210A0095C03B /* NewTaskController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F05B7251DFE210A0095C03B /* NewTaskController.swift */; }; 5F05B7291DFE210A0095C03B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F05B7271DFE210A0095C03B /* Main.storyboard */; }; 5F05B72B1DFE210A0095C03B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5F05B72A1DFE210A0095C03B /* Assets.xcassets */; }; 5F05B7391DFE210A0095C03B /* Task_MasterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F05B7381DFE210A0095C03B /* Task_MasterTests.swift */; }; 5F05B7441DFE21290095C03B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F05B7431DFE21290095C03B /* LaunchScreen.storyboard */; }; + 5F3D2DE61E9B17DC002C59A3 /* ToDo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F3D2DE51E9B17DC002C59A3 /* ToDo.swift */; }; 5F7AECE81E94B8D900CB5A9F /* ToDoListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F7AECE71E94B8D900CB5A9F /* ToDoListTableViewController.swift */; }; 5F8812851DFE25F60041BEAB /* TaskMaster.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F8812841DFE25F60041BEAB /* TaskMaster.swift */; }; 5F8812871DFE26520041BEAB /* FirstViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F8812861DFE26520041BEAB /* FirstViewController.swift */; }; 5F88128B1DFE27BA0041BEAB /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F88128A1DFE27BA0041BEAB /* MapKit.framework */; }; + 5FA18BFB1E9B154200E149DC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5FA18BFA1E9B154200E149DC /* GoogleService-Info.plist */; }; + F73594BDEB2EFCE16689FD31 /* Pods_Task_MasterTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 46B8670A869D5F7E950D4428 /* Pods_Task_MasterTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -30,9 +34,11 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 30958D7EA5B464BCFFA6A1B8 /* Pods-Task MasterTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Task MasterTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.debug.xcconfig"; sourceTree = ""; }; + 46B8670A869D5F7E950D4428 /* Pods_Task_MasterTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Task_MasterTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5F05B71E1DFE210A0095C03B /* Task Master.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Task Master.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 5F05B7211DFE210A0095C03B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 5F05B7251DFE210A0095C03B /* SecondViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondViewController.swift; sourceTree = ""; }; + 5F05B7251DFE210A0095C03B /* NewTaskController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTaskController.swift; sourceTree = ""; }; 5F05B7281DFE210A0095C03B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 5F05B72A1DFE210A0095C03B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 5F05B72F1DFE210A0095C03B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -40,12 +46,18 @@ 5F05B7381DFE210A0095C03B /* Task_MasterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Task_MasterTests.swift; sourceTree = ""; }; 5F05B73A1DFE210A0095C03B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5F05B7431DFE21290095C03B /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 5F3D2DE51E9B17DC002C59A3 /* ToDo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToDo.swift; sourceTree = ""; }; 5F7AECE61E94B87000CB5A9F /* ToDoListTableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ToDoListTableViewController.h; sourceTree = ""; }; 5F7AECE71E94B8D900CB5A9F /* ToDoListTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToDoListTableViewController.swift; sourceTree = ""; }; 5F8812841DFE25F60041BEAB /* TaskMaster.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TaskMaster.swift; sourceTree = ""; }; 5F8812861DFE26520041BEAB /* FirstViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstViewController.swift; sourceTree = ""; }; 5F8812881DFE27970041BEAB /* Task Master.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Task Master.entitlements"; sourceTree = ""; }; 5F88128A1DFE27BA0041BEAB /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; + 5FA18BFA1E9B154200E149DC /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + B300B6DA8A0FB3B30B83859C /* Pods-Task Master.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Task Master.release.xcconfig"; path = "Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig"; sourceTree = ""; }; + CA2D4ED6C257CB480D7F4D0D /* Pods-Task MasterTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Task MasterTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests.release.xcconfig"; sourceTree = ""; }; + F03E56475678366C68484290 /* Pods-Task Master.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Task Master.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig"; sourceTree = ""; }; + F6BAFFA5C9426B4DE421453D /* Pods_Task_Master.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Task_Master.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -54,6 +66,7 @@ buildActionMask = 2147483647; files = ( 5F88128B1DFE27BA0041BEAB /* MapKit.framework in Frameworks */, + 009BD8C190CEAC330A77019D /* Pods_Task_Master.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -61,6 +74,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F73594BDEB2EFCE16689FD31 /* Pods_Task_MasterTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -74,6 +88,7 @@ 5F05B7371DFE210A0095C03B /* Task MasterTests */, 5F05B71F1DFE210A0095C03B /* Products */, 5F8812891DFE27BA0041BEAB /* Frameworks */, + D88D851C8E955AEBB1EC7ABA /* Pods */, ); sourceTree = ""; }; @@ -90,16 +105,18 @@ isa = PBXGroup; children = ( 5F8812881DFE27970041BEAB /* Task Master.entitlements */, + 5FA18BFA1E9B154200E149DC /* GoogleService-Info.plist */, 5F8812861DFE26520041BEAB /* FirstViewController.swift */, 5F8812841DFE25F60041BEAB /* TaskMaster.swift */, 5F05B7211DFE210A0095C03B /* AppDelegate.swift */, - 5F05B7251DFE210A0095C03B /* SecondViewController.swift */, + 5F05B7251DFE210A0095C03B /* NewTaskController.swift */, 5F05B7271DFE210A0095C03B /* Main.storyboard */, 5F7AECE61E94B87000CB5A9F /* ToDoListTableViewController.h */, 5F7AECE71E94B8D900CB5A9F /* ToDoListTableViewController.swift */, 5F05B7431DFE21290095C03B /* LaunchScreen.storyboard */, 5F05B72A1DFE210A0095C03B /* Assets.xcassets */, 5F05B72F1DFE210A0095C03B /* Info.plist */, + 5F3D2DE51E9B17DC002C59A3 /* ToDo.swift */, ); path = "Task Master"; sourceTree = ""; @@ -117,10 +134,23 @@ isa = PBXGroup; children = ( 5F88128A1DFE27BA0041BEAB /* MapKit.framework */, + F6BAFFA5C9426B4DE421453D /* Pods_Task_Master.framework */, + 46B8670A869D5F7E950D4428 /* Pods_Task_MasterTests.framework */, ); name = Frameworks; sourceTree = ""; }; + D88D851C8E955AEBB1EC7ABA /* Pods */ = { + isa = PBXGroup; + children = ( + F03E56475678366C68484290 /* Pods-Task Master.debug.xcconfig */, + B300B6DA8A0FB3B30B83859C /* Pods-Task Master.release.xcconfig */, + 30958D7EA5B464BCFFA6A1B8 /* Pods-Task MasterTests.debug.xcconfig */, + CA2D4ED6C257CB480D7F4D0D /* Pods-Task MasterTests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -128,9 +158,12 @@ isa = PBXNativeTarget; buildConfigurationList = 5F05B73D1DFE210A0095C03B /* Build configuration list for PBXNativeTarget "Task Master" */; buildPhases = ( + 597CBC409A40AA7FBEA5FA27 /* [CP] Check Pods Manifest.lock */, 5F05B71A1DFE210A0095C03B /* Sources */, 5F05B71B1DFE210A0095C03B /* Frameworks */, 5F05B71C1DFE210A0095C03B /* Resources */, + FCAE0D008257C633FD48B75B /* [CP] Embed Pods Frameworks */, + 004ABD4EC195A3A300C33F02 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -145,9 +178,12 @@ isa = PBXNativeTarget; buildConfigurationList = 5F05B7401DFE210A0095C03B /* Build configuration list for PBXNativeTarget "Task MasterTests" */; buildPhases = ( + 5024236ABF54285B0FD893F3 /* [CP] Check Pods Manifest.lock */, 5F05B7301DFE210A0095C03B /* Sources */, 5F05B7311DFE210A0095C03B /* Frameworks */, 5F05B7321DFE210A0095C03B /* Resources */, + FEDFF483C35C1F47B445383D /* [CP] Embed Pods Frameworks */, + 2E3E792344EA7CDBB696FC20 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -166,7 +202,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0830; ORGANIZATIONNAME = "Alexander Davis Computing and Media"; TargetAttributes = { 5F05B71D1DFE210A0095C03B = { @@ -226,6 +262,7 @@ 5F05B7441DFE21290095C03B /* LaunchScreen.storyboard in Resources */, 5F05B72B1DFE210A0095C03B /* Assets.xcassets in Resources */, 5F05B7291DFE210A0095C03B /* Main.storyboard in Resources */, + 5FA18BFB1E9B154200E149DC /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -238,14 +275,108 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 004ABD4EC195A3A300C33F02 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 2E3E792344EA7CDBB696FC20 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 5024236ABF54285B0FD893F3 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 597CBC409A40AA7FBEA5FA27 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + FCAE0D008257C633FD48B75B /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + FEDFF483C35C1F47B445383D /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Task MasterTests/Pods-Task MasterTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 5F05B71A1DFE210A0095C03B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5F05B7261DFE210A0095C03B /* SecondViewController.swift in Sources */, + 5F05B7261DFE210A0095C03B /* NewTaskController.swift in Sources */, 5F7AECE81E94B8D900CB5A9F /* ToDoListTableViewController.swift in Sources */, 5F05B7221DFE210A0095C03B /* AppDelegate.swift in Sources */, + 5F3D2DE61E9B17DC002C59A3 /* ToDo.swift in Sources */, 5F8812851DFE25F60041BEAB /* TaskMaster.swift in Sources */, 5F8812871DFE26520041BEAB /* FirstViewController.swift in Sources */, ); @@ -299,6 +430,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -348,6 +480,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -374,6 +507,7 @@ }; 5F05B73E1DFE210A0095C03B /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F03E56475678366C68484290 /* Pods-Task Master.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "Task Master/Task Master.entitlements"; @@ -388,6 +522,7 @@ }; 5F05B73F1DFE210A0095C03B /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B300B6DA8A0FB3B30B83859C /* Pods-Task Master.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "Task Master/Task Master.entitlements"; @@ -402,6 +537,7 @@ }; 5F05B7411DFE210A0095C03B /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 30958D7EA5B464BCFFA6A1B8 /* Pods-Task MasterTests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -417,6 +553,7 @@ }; 5F05B7421DFE210A0095C03B /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = CA2D4ED6C257CB480D7F4D0D /* Pods-Task MasterTests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; diff --git a/Old Task Master/Task Master.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Old Task Master/Task Master.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..d44d66f --- /dev/null +++ b/Old Task Master/Task Master.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Old Task Master/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate b/Old Task Master/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..9b35436 Binary files /dev/null and b/Old Task Master/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Old Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist similarity index 75% rename from Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist rename to Old Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 9fecf37..30ae3fd 100644 --- a/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/Old Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -3,22 +3,6 @@ type = "1" version = "2.0"> - - - - + + + + + + diff --git a/Old Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate b/Old Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..9e559fd Binary files /dev/null and b/Old Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Old Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Old Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..ed9a9b4 --- /dev/null +++ b/Old Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/Task Master/AppDelegate.swift b/Old Task Master/Task Master/AppDelegate.swift similarity index 98% rename from Task Master/AppDelegate.swift rename to Old Task Master/Task Master/AppDelegate.swift index 1803b80..8b60ace 100644 --- a/Task Master/AppDelegate.swift +++ b/Old Task Master/Task Master/AppDelegate.swift @@ -7,6 +7,7 @@ // import UIKit +import Firebase @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -16,6 +17,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. + FIRApp.configure() return true } diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d98c3c4 --- /dev/null +++ b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,152 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-App-57x57@1x.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-App-57x57@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50x50@1x.png", + "scale" : "1x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50x50@2x.png", + "scale" : "2x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-App-72x72@1x.png", + "scale" : "1x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-App-72x72@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..cb8c8dd Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..31a69a7 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..50bb01a Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..bdd7215 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..0f63d35 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..3ffb1d1 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..31a69a7 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..5f25168 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..5ccf3e8 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..8bf9ff2 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..290e064 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..5ccf3e8 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..2bd6152 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..f994c63 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..abe476f Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..ce5c7a6 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..49def24 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..e88b914 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png new file mode 100644 index 0000000..ce98871 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png new file mode 100644 index 0000000..0833776 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/Contents.json b/Old Task Master/Task Master/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Old Task Master/Task Master/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/Contents.json b/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/Contents.json new file mode 100755 index 0000000..c084b4d --- /dev/null +++ b/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "create_new-25.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "create_new-32.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "create_new-50.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-25.png b/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-25.png new file mode 100755 index 0000000..a5a31cc Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-25.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-32.png b/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-32.png new file mode 100755 index 0000000..ceb4e8c Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-32.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-50.png b/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-50.png new file mode 100755 index 0000000..01be1c0 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-50.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/first.imageset/Contents.json b/Old Task Master/Task Master/Assets.xcassets/first.imageset/Contents.json new file mode 100755 index 0000000..33a7451 --- /dev/null +++ b/Old Task Master/Task Master/Assets.xcassets/first.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "first.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Old Task Master/Task Master/Assets.xcassets/first.imageset/first.pdf b/Old Task Master/Task Master/Assets.xcassets/first.imageset/first.pdf new file mode 100755 index 0000000..47d911d Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/first.imageset/first.pdf differ diff --git a/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/Contents.json b/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/Contents.json new file mode 100644 index 0000000..43003d0 --- /dev/null +++ b/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "iTunesArtwork@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "iTunesArtwork@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "iTunesArtwork@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@1x.png b/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@1x.png new file mode 100644 index 0000000..5bb8a72 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@1x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@2x.png b/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@2x.png new file mode 100644 index 0000000..17c0cb6 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@2x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@3x.png b/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@3x.png new file mode 100644 index 0000000..510b9df Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@3x.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/Contents.json b/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/Contents.json new file mode 100755 index 0000000..58b2369 --- /dev/null +++ b/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "report_card-25.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "report_card-32.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "report_card-50.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-25.png b/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-25.png new file mode 100755 index 0000000..f18566e Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-25.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-32.png b/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-32.png new file mode 100755 index 0000000..fdf21c7 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-32.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-50.png b/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-50.png new file mode 100755 index 0000000..fe73ac5 Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-50.png differ diff --git a/Old Task Master/Task Master/Assets.xcassets/second.imageset/Contents.json b/Old Task Master/Task Master/Assets.xcassets/second.imageset/Contents.json new file mode 100755 index 0000000..03bd9c9 --- /dev/null +++ b/Old Task Master/Task Master/Assets.xcassets/second.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "second.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Old Task Master/Task Master/Assets.xcassets/second.imageset/second.pdf b/Old Task Master/Task Master/Assets.xcassets/second.imageset/second.pdf new file mode 100755 index 0000000..401614e Binary files /dev/null and b/Old Task Master/Task Master/Assets.xcassets/second.imageset/second.pdf differ diff --git a/Task Master/Base.lproj/Main.storyboard b/Old Task Master/Task Master/Base.lproj/Main.storyboard similarity index 76% rename from Task Master/Base.lproj/Main.storyboard rename to Old Task Master/Task Master/Base.lproj/Main.storyboard index 4bb20d8..0ce55b1 100644 --- a/Task Master/Base.lproj/Main.storyboard +++ b/Old Task Master/Task Master/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -38,6 +38,16 @@ + + + + + + + + + + @@ -60,6 +70,8 @@ + + @@ -71,7 +83,7 @@ - + @@ -86,6 +98,11 @@ + + + + + @@ -95,9 +112,6 @@ - - - @@ -105,9 +119,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Old Task Master/Task Master/FirstViewController.swift b/Old Task Master/Task Master/FirstViewController.swift new file mode 100644 index 0000000..c465066 --- /dev/null +++ b/Old Task Master/Task Master/FirstViewController.swift @@ -0,0 +1,83 @@ +// +// FirstViewController.swift +// Task Master +// +// Created by Alexander Davis on 12/12/2016. +// Copyright © 2016 Alexander Davis Computing and Media. All rights reserved. +// + +import UIKit +import Firebase +import FirebaseDatabase + +class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource + +{ + @IBOutlet var tblTasks : UITableView! + + + override func viewDidLoad() { + super.viewDidLoad() + tblTasks.reloadData() + } + + var todoList = [Todo]() + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + loadData() + } + + func loadData() { + self.todoList.removeAll() + let ref = FIRDatabase.database().reference() + ref.child("todoList").observeSingleEvent(of: .value, with: { (snapshot) in + if let todoDict = snapshot.value as? [String:AnyObject] { + for (_,todoElement) in todoDict { + print(todoElement); + let todo = Todo() + todo.name = todoElement["name"] as? String + todo.desc = todoElement["message"] as? String + todo.reminderDate = todoElement["date"] as? String + self.todoList.append(todo) + } + } + // self.tableView.reloadData() + + }) { (error) in + print(error.localizedDescription) + } + + } + + //MARK: TableView datasource + + func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return self.todoList.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoCell") + cell!.textLabel?.text = todoList[indexPath.row].name + return cell! + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ + return taskMgr.tasks.count + } + + func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){ + + if (editingStyle == UITableViewCellEditingStyle.delete){ + + taskMgr.tasks.remove(at: indexPath.row) + tblTasks.reloadData() + } + } + +} diff --git a/Old Task Master/Task Master/GoogleService-Info.plist b/Old Task Master/Task Master/GoogleService-Info.plist new file mode 100644 index 0000000..9a46224 --- /dev/null +++ b/Old Task Master/Task Master/GoogleService-Info.plist @@ -0,0 +1,40 @@ + + + + + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 + CLIENT_ID + 423696983750-k57prfa7vk5bebm4nuvv4cfa78qthbfr.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.423696983750-k57prfa7vk5bebm4nuvv4cfa78qthbfr + API_KEY + AIzaSyDhHM39kcgnk5eVFOKq4pvCbiSSEGGQ0iQ + GCM_SENDER_ID + 423696983750 + PLIST_VERSION + 1 + BUNDLE_ID + ADCMNetworks.Task-Master + PROJECT_ID + taskmaster-20716 + STORAGE_BUCKET + taskmaster-20716.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:423696983750:ios:ee84cdaa017a58a7 + DATABASE_URL + https://taskmaster-20716.firebaseio.com + + \ No newline at end of file diff --git a/Task Master/Info.plist b/Old Task Master/Task Master/Info.plist similarity index 100% rename from Task Master/Info.plist rename to Old Task Master/Task Master/Info.plist diff --git a/Task Master/LaunchScreen.storyboard b/Old Task Master/Task Master/LaunchScreen.storyboard similarity index 77% rename from Task Master/LaunchScreen.storyboard rename to Old Task Master/Task Master/LaunchScreen.storyboard index e98734a..7eaf1fc 100644 --- a/Task Master/LaunchScreen.storyboard +++ b/Old Task Master/Task Master/LaunchScreen.storyboard @@ -22,18 +22,22 @@ - @@ -45,10 +49,15 @@ + + - + + + + diff --git a/Task Master/SecondViewController.swift b/Old Task Master/Task Master/NewTaskController.swift similarity index 50% rename from Task Master/SecondViewController.swift rename to Old Task Master/Task Master/NewTaskController.swift index 8596a37..e8ced88 100644 --- a/Task Master/SecondViewController.swift +++ b/Old Task Master/Task Master/NewTaskController.swift @@ -7,11 +7,44 @@ // import UIKit +import Firebase +import FirebaseDatabase -class SecondViewController: UIViewController, UITextFieldDelegate { +class NewTask: UIViewController, UITextFieldDelegate { + + var todo:Todo? + + @IBOutlet weak var nametbx: UITextField! + @IBOutlet weak var descriptiontbx: UITextField! + @IBOutlet weak var deadlinedpr: UIDatePicker! + + @IBAction func donebtn(_ sender: UIBarButtonItem) { + if todo == nil { + todo = Todo() + } + + // first section + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "dd/MM/yyyy hh:mm a" + + todo?.name = self.nametbx.text + todo?.desc = self.descriptiontbx.text + todo?.reminderDate = dateFormatter.string(from: self.deadlinedpr.date) + + //second section + let ref = FIRDatabase.database().reference() + let key = ref.child("todoList").childByAutoId().key + + let dictionaryTodo = [ "name" : todo!.name! , + "description" : todo!.desc!, + "date" : todo!.reminderDate!] + + let childUpdates = ["/todoList/\(key)": dictionaryTodo] + ref.updateChildValues(childUpdates, withCompletionBlock: { (error, ref) -> Void in + self.navigationController?.popViewController(animated: true) + }) + } - @IBOutlet var txtTask: UITextField! - @IBOutlet var txtDesc: UITextField! override func viewDidLoad() { super.viewDidLoad() @@ -23,24 +56,6 @@ class SecondViewController: UIViewController, UITextFieldDelegate { // Dispose of any resources that can be recreated. } - @IBAction func btnAddTask(_ sender : UIButton){ - if (txtTask.text == ""){ - //App won't add task if textbox is empty - } else { - //If above case is 'false', Task Master will create a task - let name: String = txtTask.text! - let description: String = txtDesc.text! - taskMgr.addTask(name, desc: description) - - //Once Task is added, keyboard will be dismissed and form will reset - - self.view.endEditing(true) - txtTask.text = nil - txtDesc.text = nil - - } - } - override func touchesBegan(_ touches: Set, with event: UIEvent?) { self.view.endEditing(true) } diff --git a/Task Master/Task Master.entitlements b/Old Task Master/Task Master/Task Master.entitlements similarity index 100% rename from Task Master/Task Master.entitlements rename to Old Task Master/Task Master/Task Master.entitlements diff --git a/Task Master/TaskMaster.swift b/Old Task Master/Task Master/TaskMaster.swift similarity index 100% rename from Task Master/TaskMaster.swift rename to Old Task Master/Task Master/TaskMaster.swift diff --git a/Old Task Master/Task Master/ToDo.swift b/Old Task Master/Task Master/ToDo.swift new file mode 100644 index 0000000..ed555ee --- /dev/null +++ b/Old Task Master/Task Master/ToDo.swift @@ -0,0 +1,18 @@ +// +// ToDo.swift +// Task Master +// +// Created by Alexander Davis on 10/04/2017. +// Copyright © 2017 Alexander Davis Computing and Media. All rights reserved. +// + +import Foundation +import UIKit + +class Todo: NSObject { + var name :String? + var desc: String? + var reminderDate: String? + // id which is set from firebase to uniquely identify it + var uniqueId:String? +} diff --git a/Task Master/ToDoListTableViewController.h b/Old Task Master/Task Master/ToDoListTableViewController.h similarity index 100% rename from Task Master/ToDoListTableViewController.h rename to Old Task Master/Task Master/ToDoListTableViewController.h diff --git a/Task Master/ToDoListTableViewController.swift b/Old Task Master/Task Master/ToDoListTableViewController.swift similarity index 100% rename from Task Master/ToDoListTableViewController.swift rename to Old Task Master/Task Master/ToDoListTableViewController.swift diff --git a/Old Task Master/Task MasterTests/Info.plist b/Old Task Master/Task MasterTests/Info.plist new file mode 100644 index 0000000..6c6c23c --- /dev/null +++ b/Old Task Master/Task MasterTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Task MasterTests/Task_MasterTests.swift b/Old Task Master/Task MasterTests/Task_MasterTests.swift similarity index 100% rename from Task MasterTests/Task_MasterTests.swift rename to Old Task Master/Task MasterTests/Task_MasterTests.swift diff --git a/S14110259 Task Master Final.zip b/S14110259 Task Master Final.zip new file mode 100644 index 0000000..2c7421b Binary files /dev/null and b/S14110259 Task Master Final.zip differ diff --git a/Task Master Logo.png b/Task Master Logo.png new file mode 100644 index 0000000..9ff9eaf Binary files /dev/null and b/Task Master Logo.png differ diff --git a/Task Master Logo.psd b/Task Master Logo.psd new file mode 100644 index 0000000..8507429 Binary files /dev/null and b/Task Master Logo.psd differ diff --git a/Task Master Logo.zip b/Task Master Logo.zip new file mode 100644 index 0000000..68c2aa9 Binary files /dev/null and b/Task Master Logo.zip differ diff --git a/Task Master Logo/android/mipmap-hdpi/ic_launcher.png b/Task Master Logo/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..f994c63 Binary files /dev/null and b/Task Master Logo/android/mipmap-hdpi/ic_launcher.png differ diff --git a/Task Master Logo/android/mipmap-ldpi/ic_launcher.png b/Task Master Logo/android/mipmap-ldpi/ic_launcher.png new file mode 100644 index 0000000..1e59c8c Binary files /dev/null and b/Task Master Logo/android/mipmap-ldpi/ic_launcher.png differ diff --git a/Task Master Logo/android/mipmap-mdpi/ic_launcher.png b/Task Master Logo/android/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..4110066 Binary files /dev/null and b/Task Master Logo/android/mipmap-mdpi/ic_launcher.png differ diff --git a/Task Master Logo/android/mipmap-xhdpi/ic_launcher.png b/Task Master Logo/android/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..b0a1a0c Binary files /dev/null and b/Task Master Logo/android/mipmap-xhdpi/ic_launcher.png differ diff --git a/Task Master Logo/android/mipmap-xxhdpi/ic_launcher.png b/Task Master Logo/android/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..abe476f Binary files /dev/null and b/Task Master Logo/android/mipmap-xxhdpi/ic_launcher.png differ diff --git a/Task Master Logo/android/mipmap-xxxhdpi/ic_launcher.png b/Task Master Logo/android/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..6499ab5 Binary files /dev/null and b/Task Master Logo/android/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/Task Master Logo/android/playstore-icon.png b/Task Master Logo/android/playstore-icon.png new file mode 100644 index 0000000..ac6a6e0 Binary files /dev/null and b/Task Master Logo/android/playstore-icon.png differ diff --git a/Task Master Logo/imessenger/icon-messages-app-27x20@1x.png b/Task Master Logo/imessenger/icon-messages-app-27x20@1x.png new file mode 100644 index 0000000..afbc40f Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-app-27x20@1x.png differ diff --git a/Task Master Logo/imessenger/icon-messages-app-27x20@2x.png b/Task Master Logo/imessenger/icon-messages-app-27x20@2x.png new file mode 100644 index 0000000..3d9029c Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-app-27x20@2x.png differ diff --git a/Task Master Logo/imessenger/icon-messages-app-27x20@3x.png b/Task Master Logo/imessenger/icon-messages-app-27x20@3x.png new file mode 100644 index 0000000..ed6a5b8 Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-app-27x20@3x.png differ diff --git a/Task Master Logo/imessenger/icon-messages-app-iPadAir-67x50@2x.png b/Task Master Logo/imessenger/icon-messages-app-iPadAir-67x50@2x.png new file mode 100644 index 0000000..5f5c6fb Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-app-iPadAir-67x50@2x.png differ diff --git a/Task Master Logo/imessenger/icon-messages-app-iPadAir-74x55@2x.png b/Task Master Logo/imessenger/icon-messages-app-iPadAir-74x55@2x.png new file mode 100644 index 0000000..c6eff1f Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-app-iPadAir-74x55@2x.png differ diff --git a/Task Master Logo/imessenger/icon-messages-app-iPhone-60x45@1x.png b/Task Master Logo/imessenger/icon-messages-app-iPhone-60x45@1x.png new file mode 100644 index 0000000..6eeaf3e Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-app-iPhone-60x45@1x.png differ diff --git a/Task Master Logo/imessenger/icon-messages-app-iPhone-60x45@2x.png b/Task Master Logo/imessenger/icon-messages-app-iPhone-60x45@2x.png new file mode 100644 index 0000000..939bd81 Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-app-iPhone-60x45@2x.png differ diff --git a/Task Master Logo/imessenger/icon-messages-app-iPhone-60x45@3x.png b/Task Master Logo/imessenger/icon-messages-app-iPhone-60x45@3x.png new file mode 100644 index 0000000..4dbdcd1 Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-app-iPhone-60x45@3x.png differ diff --git a/Task Master Logo/imessenger/icon-messages-app-store-1024x768.png b/Task Master Logo/imessenger/icon-messages-app-store-1024x768.png new file mode 100644 index 0000000..3c75a65 Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-app-store-1024x768.png differ diff --git a/Task Master Logo/imessenger/icon-messages-transcript-32x24@1x.png b/Task Master Logo/imessenger/icon-messages-transcript-32x24@1x.png new file mode 100644 index 0000000..24e0770 Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-transcript-32x24@1x.png differ diff --git a/Task Master Logo/imessenger/icon-messages-transcript-32x24@2x.png b/Task Master Logo/imessenger/icon-messages-transcript-32x24@2x.png new file mode 100644 index 0000000..da54229 Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-transcript-32x24@2x.png differ diff --git a/Task Master Logo/imessenger/icon-messages-transcript-32x24@3x.png b/Task Master Logo/imessenger/icon-messages-transcript-32x24@3x.png new file mode 100644 index 0000000..55b9d63 Binary files /dev/null and b/Task Master Logo/imessenger/icon-messages-transcript-32x24@3x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Contents.json b/Task Master Logo/ios/AppIcon.appiconset/Contents.json new file mode 100755 index 0000000..4a631f4 --- /dev/null +++ b/Task Master Logo/ios/AppIcon.appiconset/Contents.json @@ -0,0 +1,176 @@ +{ + "images":[ + { + "idiom":"iphone", + "size":"20x20", + "scale":"2x", + "filename":"Icon-App-20x20@2x.png" + }, + { + "idiom":"iphone", + "size":"20x20", + "scale":"3x", + "filename":"Icon-App-20x20@3x.png" + }, + { + "idiom":"iphone", + "size":"29x29", + "scale":"1x", + "filename":"Icon-App-29x29@1x.png" + }, + { + "idiom":"iphone", + "size":"29x29", + "scale":"2x", + "filename":"Icon-App-29x29@2x.png" + }, + { + "idiom":"iphone", + "size":"29x29", + "scale":"3x", + "filename":"Icon-App-29x29@3x.png" + }, + { + "idiom":"iphone", + "size":"40x40", + "scale":"1x", + "filename":"Icon-App-40x40@1x.png" + }, + { + "idiom":"iphone", + "size":"40x40", + "scale":"2x", + "filename":"Icon-App-40x40@2x.png" + }, + { + "idiom":"iphone", + "size":"40x40", + "scale":"3x", + "filename":"Icon-App-40x40@3x.png" + }, + { + "idiom":"iphone", + "size":"57x57", + "scale":"1x", + "filename":"Icon-App-57x57@1x.png" + }, + { + "idiom":"iphone", + "size":"57x57", + "scale":"2x", + "filename":"Icon-App-57x57@2x.png" + }, + { + "idiom":"iphone", + "size":"60x60", + "scale":"1x", + "filename":"Icon-App-60x60@1x.png" + }, + { + "idiom":"iphone", + "size":"60x60", + "scale":"2x", + "filename":"Icon-App-60x60@2x.png" + }, + { + "idiom":"iphone", + "size":"60x60", + "scale":"3x", + "filename":"Icon-App-60x60@3x.png" + }, + { + "idiom":"iphone", + "size":"76x76", + "scale":"1x", + "filename":"Icon-App-76x76@1x.png" + }, + { + "idiom":"ipad", + "size":"20x20", + "scale":"1x", + "filename":"Icon-App-20x20@1x.png" + }, + { + "idiom":"ipad", + "size":"20x20", + "scale":"2x", + "filename":"Icon-App-20x20@2x.png" + }, + { + "idiom":"ipad", + "size":"29x29", + "scale":"1x", + "filename":"Icon-App-29x29@1x.png" + }, + { + "idiom":"ipad", + "size":"29x29", + "scale":"2x", + "filename":"Icon-App-29x29@2x.png" + }, + { + "idiom":"ipad", + "size":"40x40", + "scale":"1x", + "filename":"Icon-App-40x40@1x.png" + }, + { + "idiom":"ipad", + "size":"40x40", + "scale":"2x", + "filename":"Icon-App-40x40@2x.png" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50x50@1x.png", + "scale" : "1x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50x50@2x.png", + "scale" : "2x" + }, + { + "idiom":"ipad", + "size":"72x72", + "scale":"1x", + "filename":"Icon-App-72x72@1x.png" + }, + { + "idiom":"ipad", + "size":"72x72", + "scale":"2x", + "filename":"Icon-App-72x72@2x.png" + }, + { + "idiom":"ipad", + "size":"76x76", + "scale":"1x", + "filename":"Icon-App-76x76@1x.png" + }, + { + "idiom":"ipad", + "size":"76x76", + "scale":"2x", + "filename":"Icon-App-76x76@2x.png" + }, + { + "idiom":"ipad", + "size":"76x76", + "scale":"3x", + "filename":"Icon-App-76x76@3x.png" + }, + { + "idiom":"ipad", + "size":"83.5x83.5", + "scale":"2x", + "filename":"Icon-App-83.5x83.5@2x.png" + } + ], + "info":{ + "version":1, + "author":"makeappicon" + } +} diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-20x20@1x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..cb8c8dd Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-20x20@2x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..31a69a7 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-20x20@3x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..50bb01a Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-29x29@1x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..bdd7215 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-29x29@2x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..0f63d35 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-29x29@3x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..3ffb1d1 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-40x40@1x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..31a69a7 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-40x40@2x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..5f25168 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-40x40@3x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..5ccf3e8 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-57x57@1x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..8bf9ff2 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-57x57@2x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..290e064 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-60x60@1x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-60x60@1x.png new file mode 100644 index 0000000..50bb01a Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-60x60@1x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-60x60@2x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..5ccf3e8 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-60x60@3x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..2bd6152 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-72x72@1x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..f994c63 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-72x72@2x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..abe476f Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-76x76@1x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..ce5c7a6 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-76x76@2x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..49def24 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-76x76@3x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-76x76@3x.png new file mode 100644 index 0000000..be9f986 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-76x76@3x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..e88b914 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-Small-50x50@1x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-Small-50x50@1x.png new file mode 100644 index 0000000..ce98871 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-Small-50x50@1x.png differ diff --git a/Task Master Logo/ios/AppIcon.appiconset/Icon-Small-50x50@2x.png b/Task Master Logo/ios/AppIcon.appiconset/Icon-Small-50x50@2x.png new file mode 100644 index 0000000..0833776 Binary files /dev/null and b/Task Master Logo/ios/AppIcon.appiconset/Icon-Small-50x50@2x.png differ diff --git a/Task Master Logo/ios/README.md b/Task Master Logo/ios/README.md new file mode 100644 index 0000000..6b3251a --- /dev/null +++ b/Task Master Logo/ios/README.md @@ -0,0 +1,24 @@ +## iTunesArtwork & iTunesArtwork@2x (App Icon) file extension: + +PNG extension is prepended to these two files - + +While Apple suggested to omit the extension for these files, +the '.png' extension is actually required for iTunesConnect submission. + +This is done for you so you don't have to. + +However, for Ad_hoc or Enterprise distirbution, the extension should be removed +from the files before adding to XCode to avoid error. + +refs: https://developer.apple.com/library/ios/qa/qa1686/_index.html + +## iTunesArtwork & iTunesArtwork@2x (App Icon) transparency handling: + +As images with alpha channels or transparencies cannot be set as an application's icon on +iTunesConnect, all transparent pixels in your images will be converted into +solid blacks. + +To achieve the best result, you're advised to adjust the transparency settings +in your source files before converting them with makeAppIcon. + +refs: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/AppIcons.html diff --git a/Task Master Logo/ios/iTunesArtwork@1x.png b/Task Master Logo/ios/iTunesArtwork@1x.png new file mode 100644 index 0000000..5bb8a72 Binary files /dev/null and b/Task Master Logo/ios/iTunesArtwork@1x.png differ diff --git a/Task Master Logo/ios/iTunesArtwork@2x.png b/Task Master Logo/ios/iTunesArtwork@2x.png new file mode 100644 index 0000000..17c0cb6 Binary files /dev/null and b/Task Master Logo/ios/iTunesArtwork@2x.png differ diff --git a/Task Master Logo/ios/iTunesArtwork@3x.png b/Task Master Logo/ios/iTunesArtwork@3x.png new file mode 100644 index 0000000..510b9df Binary files /dev/null and b/Task Master Logo/ios/iTunesArtwork@3x.png differ diff --git a/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate b/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 9885b25..0000000 Binary files a/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json b/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100755 index b8236c6..0000000 --- a/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Task Master/FirstViewController.swift b/Task Master/FirstViewController.swift deleted file mode 100644 index 8f29dc3..0000000 --- a/Task Master/FirstViewController.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// FirstViewController.swift -// Task Master -// -// Created by Alexander Davis on 12/12/2016. -// Copyright © 2016 Alexander Davis Computing and Media. All rights reserved. -// - -import UIKit - -class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource - -{ - @IBOutlet var tblTasks : UITableView! - - - override func viewDidLoad() { - super.viewDidLoad() - tblTasks.reloadData() - } - - override func viewWillAppear(_ animated: Bool) { - self.tblTasks.reloadData() - } - - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ - return taskMgr.tasks.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{ - - let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "Default Tasks") - - //Assign the contents of var "items" to the textLabel of each cell - cell.textLabel!.text = taskMgr.tasks[indexPath.row].name - cell.detailTextLabel!.text = taskMgr.tasks[indexPath.row].desc - - return cell - - } - - func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){ - - if (editingStyle == UITableViewCellEditingStyle.delete){ - - taskMgr.tasks.remove(at: indexPath.row) - tblTasks.reloadData() - } - } - -} diff --git a/Task Master/Podfile b/Task Master/Podfile new file mode 100644 index 0000000..5b1eb15 --- /dev/null +++ b/Task Master/Podfile @@ -0,0 +1,8 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '10.3' + +target 'Task Master' do + pod 'Firebase/Core' + pod 'Firebase/Database' + pod 'Firebase/Auth' + end diff --git a/Task Master/Podfile.lock b/Task Master/Podfile.lock new file mode 100644 index 0000000..88a8631 --- /dev/null +++ b/Task Master/Podfile.lock @@ -0,0 +1,54 @@ +PODS: + - Firebase/Auth (3.16.0): + - Firebase/Core + - FirebaseAuth (= 3.1.1) + - Firebase/Core (3.16.0): + - FirebaseAnalytics (= 3.8.0) + - FirebaseCore (= 3.6.0) + - Firebase/Database (3.16.0): + - Firebase/Core + - FirebaseDatabase (= 3.1.2) + - FirebaseAnalytics (3.8.0): + - FirebaseCore (~> 3.6) + - FirebaseInstanceID (~> 1.0) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseAuth (3.1.1): + - FirebaseAnalytics (~> 3.7) + - GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1) + - GTMSessionFetcher/Core (~> 1.1) + - FirebaseCore (3.6.0): + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseDatabase (3.1.2): + - FirebaseAnalytics (~> 3.7) + - FirebaseInstanceID (1.0.10): + - FirebaseCore (~> 3.6) + - GoogleToolboxForMac/DebugUtils (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/Defines (2.1.1) + - GoogleToolboxForMac/NSData+zlib (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSDictionary+URLArguments (2.1.1): + - GoogleToolboxForMac/DebugUtils (= 2.1.1) + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (2.1.1) + - GTMSessionFetcher/Core (1.1.9) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Core + - Firebase/Database + +SPEC CHECKSUMS: + Firebase: 21bf4a89d3f01bfbe11adc3a5d934a4a3d3a5fd6 + FirebaseAnalytics: 920e46455f27b0a52a80907a6d9b73ee4bd1c635 + FirebaseAuth: cc8a1824170adbd351edb7f994490a3fb5c18be6 + FirebaseCore: 9691ee2ade70c098d7cf92440f4303f16d83ca75 + FirebaseDatabase: 05c96d7b43a7368dc91c07791adb49683e1738d1 + FirebaseInstanceID: b9eedd6846fb5e1f0f7279e1deaa7a7e4cf8392e + GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0 + GTMSessionFetcher: 5c046c76a1f859bc9c187e918f18e4fc7bb57b5e + +PODFILE CHECKSUM: 5dada07b8ffcd867f75f4115acd0e8c161a70c90 + +COCOAPODS: 1.2.1 diff --git a/Task Master/Pods/Firebase/Core/Sources/Firebase.h b/Task Master/Pods/Firebase/Core/Sources/Firebase.h new file mode 100755 index 0000000..90798a6 --- /dev/null +++ b/Task Master/Pods/Firebase/Core/Sources/Firebase.h @@ -0,0 +1,52 @@ +#import +#import + +#if !defined(__has_include) + #error "Firebase.h won't import anything if your compiler doesn't support __has_include. Please \ + import the headers individually." +#else + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + +#endif // defined(__has_include) diff --git a/Task Master/Pods/Firebase/Core/Sources/module.modulemap b/Task Master/Pods/Firebase/Core/Sources/module.modulemap new file mode 100755 index 0000000..3685b54 --- /dev/null +++ b/Task Master/Pods/Firebase/Core/Sources/module.modulemap @@ -0,0 +1,4 @@ +module Firebase { + export * + header "Firebase.h" +} \ No newline at end of file diff --git a/Task Master/Pods/Firebase/README.md b/Task Master/Pods/Firebase/README.md new file mode 100755 index 0000000..bfc5419 --- /dev/null +++ b/Task Master/Pods/Firebase/README.md @@ -0,0 +1,76 @@ +# Firebase APIs for iOS + +Simplify your iOS development, grow your user base, and monetize more +effectively with Firebase services. + +Much more information can be found at [https://firebase.google.com](https://firebase.google.com). + +## Install a Firebase SDK using CocoaPods + +Firebase distributes several iOS specific APIs and SDKs via CocoaPods. +You can install the CocoaPods tool on OS X by running the following command from +the terminal. Detailed information is available in the [Getting Started +guide](https://guides.cocoapods.org/using/getting-started.html#getting-started). + +``` +$ sudo gem install cocoapods +``` + +## Try out an SDK + +You can try any of the SDKs with `pod try`. Run the following command and select +the SDK you are interested in when prompted: + +``` +$ pod try Firebase +``` + +Note that some SDKs may require credentials. More information is available in +the SDK-specific documentation at [https://firebase.google.com/docs/](https://firebase.google.com/docs/). + +## Add a Firebase SDK to your iOS app + +CocoaPods is used to install and manage dependencies in existing Xcode projects. + +1. Create an Xcode project, and save it to your local machine. +2. Create a file named `Podfile` in your project directory. This file defines + your project's dependencies, and is commonly referred to as a Podspec. +3. Open `Podfile`, and add your dependencies. A simple Podspec is shown here: + + ``` + platform :ios, '7.0' + pod 'Firebase' + ``` + +4. Save the file. +5. Open a terminal and `cd` to the directory containing the Podfile. + + ``` + $ cd /project/ + ``` + +6. Run the `pod install` command. This will install the SDKs specified in the + Podspec, along with any dependencies they may have. + + ``` + $ pod install + ``` + +7. Open your app's `.xcworkspace` file to launch Xcode. + Use this file for all development on your app. +8. You can also install other Firebase SDKs by adding the subspecs in the + Podfile. + + ``` + pod 'Firebase/AdMob' + pod 'Firebase/Analytics' + pod 'Firebase/AppIndexing' + pod 'Firebase/Auth' + pod 'Firebase/Crash' + pod 'Firebase/Database' + pod 'Firebase/DynamicLinks' + pod 'Firebase/Invites' + pod 'Firebase/Messaging' + pod 'Firebase/RemoteConfig' + pod 'Firebase/Storage' + ``` diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100755 index 0000000..35dc4be Binary files /dev/null and b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100755 index 0000000..e3ff4c1 --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,57 @@ +#import + +#import "FIRAnalytics.h" + +/** + * Provides App Delegate handlers to be used in your App Delegate. + * + * To save time integrating Firebase Analytics in an application, Firebase Analytics does not + * require delegation implementation from the AppDelegate. Instead this is automatically done by + * Firebase Analytics. Should you choose instead to delegate manually, you can turn off the App + * Delegate Proxy by adding FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting + * it to NO, and adding the methods in this category to corresponding delegation handlers. + * + * To handle Universal Links, you must return YES in + * [UIApplicationDelegate application:didFinishLaunchingWithOptions:]. + */ +@interface FIRAnalytics (AppDelegate) + +/** + * Handles events related to a URL session that are waiting to be processed. + * + * For optimal use of Firebase Analytics, call this method from the + * [UIApplicationDelegate application:handleEventsForBackgroundURLSession:completionHandler] + * method of the app delegate in your app. + * + * @param identifier The identifier of the URL session requiring attention. + * @param completionHandler The completion handler to call when you finish processing the events. + * Calling this completion handler lets the system know that your app's user interface is + * updated and a new snapshot can be taken. + */ ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(void (^)(void))completionHandler; + +/** + * Handles the event when the app is launched by a URL. + * + * Call this method from [UIApplicationDelegate application:openURL:options:] (on iOS 9.0 and + * above), or [UIApplicationDelegate application:openURL:sourceApplication:annotation:] (on iOS 8.x + * and below) in your app. + * + * @param url The URL resource to open. This resource can be a network resource or a file. + */ ++ (void)handleOpenURL:(NSURL *)url; + +/** + * Handles the event when the app receives data associated with user activity that includes a + * Universal Link (on iOS 9.0 and above). + * + * Call this method from [UIApplication continueUserActivity:restorationHandler:] in your app + * delegate (on iOS 9.0 and above). + * + * @param userActivity The activity object containing the data associated with the task the user + * was performing. + */ ++ (void)handleUserActivity:(id)userActivity; + +@end diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100755 index 0000000..f5023f5 --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,102 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///

    +///
  • app_clear_data
  • +///
  • app_remove
  • +///
  • app_update
  • +///
  • error
  • +///
  • first_open
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_" prefix +/// is reserved and should not be used. Note that event names are case-sensitive and that +/// logging two events whose names differ only in case will result in two distinct events. +/// @param parameters The dictionary of event parameters. Passing nil indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only NSString +/// and NSNumber (signed 64-bit integer and 64-bit floating-point number) parameter types are +/// supported. NSString parameter values can be up to 100 characters long. The "firebase_" +/// prefix is reserved and should not be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters; + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to nil removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_" prefix is +/// reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name; + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 36 characters long. Setting userID to nil removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets the current screen name, which specifies the current visual context in your app. This helps +/// identify the areas in your app where users spend their time and how they interact with your app. +/// +/// Note that screen reporting is enabled automatically and records the class name of the current +/// UIViewController for you without requiring you to call this method. If you implement +/// viewDidAppear in your UIViewController but do not call [super viewDidAppear:], that screen class +/// will not be automatically tracked. The class name can optionally be overridden by calling this +/// method in the viewDidAppear callback of your UIViewController and specifying the +/// screenClassOverride parameter. +/// +/// If your app does not use a distinct UIViewController for each screen, you should call this +/// method and specify a distinct screenName each time a new screen is presented to the user. +/// +/// The screen name and screen class remain in effect until the current UIViewController changes or +/// a new call to setScreenName:screenClass: is made. +/// +/// @param screenName The name of the current screen. Should contain 1 to 100 characters. Set to nil +/// to clear the current screen name. +/// @param screenClassOverride The name of the screen class. Should contain 1 to 100 characters. By +/// default this is the class name of the current UIViewController. Set to nil to revert to the +/// default class name. ++ (void)setScreenName:(nullable NSString *)screenName + screenClass:(nullable NSString *)screenClassOverride; + +/// The unique ID for this instance of the application. ++ (NSString *)appInstanceID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalyticsConfiguration.h b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalyticsConfiguration.h new file mode 100755 index 0000000..dc227a4 --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalyticsConfiguration.h @@ -0,0 +1 @@ +#import diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRApp.h b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRApp.h new file mode 100755 index 0000000..de24da1 --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRApp.h @@ -0,0 +1 @@ +#import diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRConfiguration.h b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRConfiguration.h new file mode 100755 index 0000000..be2ff7b --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRConfiguration.h @@ -0,0 +1 @@ +#import diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100755 index 0000000..3b40eec --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,336 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_" +/// prefix is reserved and should not be used. + +/// Add Payment Info event. This event signifies that a user has submitted their payment information +/// to your app. +static NSString *const kFIREventAddPaymentInfo = @"add_payment_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item was added to a cart for +/// purchase. Add this event to a funnel with kFIREventEcommercePurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c kFIRParameterValue parameter, you must +/// also supply the @c kFIRParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c kFIRParameterQuantity (signed 64-bit integer as NSNumber)
  • +///
  • @c kFIRParameterItemID (NSString)
  • +///
  • @c kFIRParameterItemName (NSString)
  • +///
  • @c kFIRParameterItemCategory (NSString)
  • +///
  • @c kFIRParameterItemLocationID (NSString) (optional)
  • +///
  • @c kFIRParameterPrice (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterOrigin (NSString) (optional)
  • +///
  • @c kFIRParameterDestination (NSString) (optional)
  • +///
  • @c kFIRParameterStartDate (NSString) (optional)
  • +///
  • @c kFIRParameterEndDate (NSString) (optional)
  • +///
+static NSString *const kFIREventAddToCart = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. +/// Use this event to identify popular gift items in your app. Note: If you supply the +/// @c kFIRParameterValue parameter, you must also supply the @c kFIRParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c kFIRParameterQuantity (signed 64-bit integer as NSNumber)
  • +///
  • @c kFIRParameterItemID (NSString)
  • +///
  • @c kFIRParameterItemName (NSString)
  • +///
  • @c kFIRParameterItemCategory (NSString)
  • +///
  • @c kFIRParameterItemLocationID (NSString) (optional)
  • +///
  • @c kFIRParameterPrice (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist = @"add_to_wishlist"; + +/// App Open event. By logging this event when an App is moved to the foreground, developers can +/// understand how often users leave and return during the course of a Session. Although Sessions +/// are automatically reported, this event can provide further clarification around the continuous +/// engagement of app-users. +static NSString *const kFIREventAppOpen = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your kFIREventEcommercePurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c kFIRParameterValue +/// parameter, you must also supply the @c kFIRParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterTransactionID (NSString) (optional)
  • +///
  • @c kFIRParameterStartDate (NSString) (optional)
  • +///
  • @c kFIRParameterEndDate (NSString) (optional)
  • +///
  • @c kFIRParameterNumberOfNights (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfRooms (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfPassengers (signed 64-bit integer as NSNumber) (optional) +/// for travel bookings
  • +///
  • @c kFIRParameterOrigin (NSString) (optional)
  • +///
  • @c kFIRParameterDestination (NSString) (optional)
  • +///
  • @c kFIRParameterTravelClass (NSString) (optional) for travel bookings
  • +///
+static NSString *const kFIREventBeginCheckout = @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters kFIRParameterSource, +/// kFIRParameterMedium or kFIRParameterCampaign. Params: +/// +///
    +///
  • @c kFIRParameterSource (NSString)
  • +///
  • @c kFIRParameterMedium (NSString)
  • +///
  • @c kFIRParameterCampaign (NSString)
  • +///
  • @c kFIRParameterTerm (NSString) (optional)
  • +///
  • @c kFIRParameterContent (NSString) (optional)
  • +///
  • @c kFIRParameterAdNetworkClickID (NSString) (optional)
  • +///
  • @c kFIRParameterCP1 (NSString) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails = @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c kFIREventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c kFIRParameterVirtualCurrencyName (NSString)
  • +///
  • @c kFIRParameterValue (signed 64-bit integer or double as NSNumber)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency = @"earn_virtual_currency"; + +/// E-Commerce Purchase event. This event signifies that an item was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c kFIRParameterValue parameter, you must also +/// supply the @c kFIRParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterTransactionID (NSString) (optional)
  • +///
  • @c kFIRParameterTax (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterShipping (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterCoupon (NSString) (optional)
  • +///
  • @c kFIRParameterLocation (NSString) (optional)
  • +///
  • @c kFIRParameterStartDate (NSString) (optional)
  • +///
  • @c kFIRParameterEndDate (NSString) (optional)
  • +///
  • @c kFIRParameterNumberOfNights (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfRooms (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfPassengers (signed 64-bit integer as NSNumber) (optional) +/// for travel bookings
  • +///
  • @c kFIRParameterOrigin (NSString) (optional)
  • +///
  • @c kFIRParameterDestination (NSString) (optional)
  • +///
  • @c kFIRParameterTravelClass (NSString) (optional) for travel bookings
  • +///
+static NSString *const kFIREventEcommercePurchase = @"ecommerce_purchase"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c kFIRParameterValue parameter, you must also supply the @c kFIRParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
+static NSString *const kFIREventGenerateLead = @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c kFIRParameterGroupID (NSString)
  • +///
+static NSString *const kFIREventJoinGroup = @"join_group"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c kFIRParameterLevel (signed 64-bit integer as NSNumber)
  • +///
  • @c kFIRParameterCharacter (NSString) (optional)
  • +///
+static NSString *const kFIREventLevelUp = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c kFIRParameterScore (signed 64-bit integer as NSNumber)
  • +///
  • @c kFIRParameterLevel (signed 64-bit integer as NSNumber) (optional)
  • +///
  • @c kFIRParameterCharacter (NSString) (optional)
  • +///
+static NSString *const kFIREventPostScore = @"post_score"; + +/// Present Offer event. This event signifies that the app has presented a purchase offer to a user. +/// Add this event to a funnel with the kFIREventAddToCart and kFIREventEcommercePurchase to gauge +/// your conversion process. Note: If you supply the @c kFIRParameterValue parameter, you must +/// also supply the @c kFIRParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c kFIRParameterQuantity (signed 64-bit integer as NSNumber)
  • +///
  • @c kFIRParameterItemID (NSString)
  • +///
  • @c kFIRParameterItemName (NSString)
  • +///
  • @c kFIRParameterItemCategory (NSString)
  • +///
  • @c kFIRParameterItemLocationID (NSString) (optional)
  • +///
  • @c kFIRParameterPrice (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
+static NSString *const kFIREventPresentOffer = @"present_offer"; + +/// E-Commerce Purchase Refund event. This event signifies that an item purchase was refunded. +/// Note: If you supply the @c kFIRParameterValue parameter, you must also supply the +/// @c kFIRParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterTransactionID (NSString) (optional)
  • +///
+static NSString *const kFIREventPurchaseRefund = @"purchase_refund"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c kFIRParameterSearchTerm (NSString)
  • +///
  • @c kFIRParameterStartDate (NSString) (optional)
  • +///
  • @c kFIRParameterEndDate (NSString) (optional)
  • +///
  • @c kFIRParameterNumberOfNights (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfRooms (signed 64-bit integer as NSNumber) (optional) for +/// hotel bookings
  • +///
  • @c kFIRParameterNumberOfPassengers (signed 64-bit integer as NSNumber) (optional) +/// for travel bookings
  • +///
  • @c kFIRParameterOrigin (NSString) (optional)
  • +///
  • @c kFIRParameterDestination (NSString) (optional)
  • +///
  • @c kFIRParameterTravelClass (NSString) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c kFIRParameterContentType (NSString)
  • +///
  • @c kFIRParameterItemID (NSString)
  • +///
+static NSString *const kFIREventSelectContent = @"select_content"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c kFIRParameterContentType (NSString)
  • +///
  • @c kFIRParameterItemID (NSString)
  • +///
+static NSString *const kFIREventShare = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c kFIRParameterSignUpMethod (NSString)
  • +///
+static NSString *const kFIREventSignUp = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c kFIRParameterItemName (NSString)
  • +///
  • @c kFIRParameterVirtualCurrencyName (NSString)
  • +///
  • @c kFIRParameterValue (signed 64-bit integer or double as NSNumber)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with kFIREventTutorialComplete to understand how many users complete this +/// process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin = @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with kFIREventTutorialBegin to gauge the completion rate of your +/// on-boarding process. +static NSString *const kFIREventTutorialComplete = @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c kFIRParameterAchievementID (NSString)
  • +///
+static NSString *const kFIREventUnlockAchievement = @"unlock_achievement"; + +/// View Item event. This event signifies that some content was shown to the user. This content may +/// be a product, a webpage or just a simple image or text. Use the appropriate parameters to +/// contextualize the event. Use this event to discover the most popular items viewed in your app. +/// Note: If you supply the @c kFIRParameterValue parameter, you must also supply the +/// @c kFIRParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c kFIRParameterItemID (NSString)
  • +///
  • @c kFIRParameterItemName (NSString)
  • +///
  • @c kFIRParameterItemCategory (NSString)
  • +///
  • @c kFIRParameterItemLocationID (NSString) (optional)
  • +///
  • @c kFIRParameterPrice (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterQuantity (signed 64-bit integer as NSNumber) (optional)
  • +///
  • @c kFIRParameterCurrency (NSString) (optional)
  • +///
  • @c kFIRParameterValue (double as NSNumber) (optional)
  • +///
  • @c kFIRParameterStartDate (NSString) (optional)
  • +///
  • @c kFIRParameterEndDate (NSString) (optional)
  • +///
  • @c kFIRParameterFlightNumber (NSString) (optional) for travel bookings
  • +///
  • @c kFIRParameterNumberOfPassengers (signed 64-bit integer as NSNumber) (optional) +/// for travel bookings
  • +///
  • @c kFIRParameterNumberOfNights (signed 64-bit integer as NSNumber) (optional) for +/// travel bookings
  • +///
  • @c kFIRParameterNumberOfRooms (signed 64-bit integer as NSNumber) (optional) for +/// travel bookings
  • +///
  • @c kFIRParameterOrigin (NSString) (optional)
  • +///
  • @c kFIRParameterDestination (NSString) (optional)
  • +///
  • @c kFIRParameterSearchTerm (NSString) (optional) for travel bookings
  • +///
  • @c kFIRParameterTravelClass (NSString) (optional) for travel bookings
  • +///
+static NSString *const kFIREventViewItem = @"view_item"; + +/// View Item List event. Log this event when the user has been presented with a list of items of a +/// certain category. Params: +/// +///
    +///
  • @c kFIRParameterItemCategory (NSString)
  • +///
+static NSString *const kFIREventViewItemList = @"view_item_list"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c kFIRParameterSearchTerm (NSString)
  • +///
+static NSString *const kFIREventViewSearchResults = @"view_search_results"; diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIROptions.h b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIROptions.h new file mode 100755 index 0000000..126824b --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIROptions.h @@ -0,0 +1 @@ +#import diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100755 index 0000000..a43e347 --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,369 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long. The "firebase_" prefix is reserved and should not be used. + +/// Game achievement ID (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterAchievementID : @"10_matches_won",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterAchievementID = @"achievement_id"; + +/// Ad Network Click ID (NSString). Used for network-specific click IDs which vary in format. +///
+///     NSDictionary *params = @{
+///       kFIRParameterAdNetworkClickID : @"1234567",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterAdNetworkClickID = @"aclid"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterCampaign : @"winter_promotion",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterCampaign = @"campaign"; + +/// Character used in game (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterCharacter : @"beat_boss",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterCharacter = @"character"; + +/// Campaign content (NSString). +static NSString *const kFIRParameterContent = @"content"; + +/// Type of content selected (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterContentType : @"news article",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterContentType = @"content_type"; + +/// Coupon code for a purchasable item (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterCoupon : @"zz123",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterCoupon = @"coupon"; + +/// Campaign custom parameter (NSString). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     NSDictionary *params = @{
+///       kFIRParameterCP1 : @"custom_data",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterCP1 = @"cp1"; + +/// Purchase currency in 3-letter +/// ISO_4217 format (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterCurrency : @"USD",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterCurrency = @"currency"; + +/// Flight or Travel destination (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterDestination : @"Mountain View, CA",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterDestination = @"destination"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterEndDate : @"2015-09-14",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterEndDate = @"end_date"; + +/// Flight number for travel events (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterFlightNumber : @"ZZ800",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterFlightNumber = @"flight_number"; + +/// Group/clan/guild ID (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterGroupID : @"g1",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterGroupID = @"group_id"; + +/// Item category (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterItemCategory : @"t-shirts",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterItemCategory = @"item_category"; + +/// Item ID (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterItemID : @"p7654",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterItemID = @"item_id"; + +/// The Google Place ID (NSString) that +/// corresponds to the associated item. Alternatively, you can supply your own custom Location ID. +///
+///     NSDictionary *params = @{
+///       kFIRParameterItemLocationID : @"ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterItemLocationID = @"item_location_id"; + +/// Item name (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterItemName : @"abc",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterItemName = @"item_name"; + +/// Level in game (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterLevel : @(42),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterLevel = @"level"; + +/// Location (NSString). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     NSDictionary *params = @{
+///       kFIRParameterLocation : @"ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterLocation = @"location"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterMedium : @"email",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterMedium = @"medium"; + +/// Number of nights staying at hotel (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterNumberOfNights : @(3),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterNumberOfNights = @"number_of_nights"; + +/// Number of passengers traveling (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterNumberOfPassengers : @(11),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterNumberOfPassengers = @"number_of_passengers"; + +/// Number of rooms for travel events (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterNumberOfRooms : @(2),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterNumberOfRooms = @"number_of_rooms"; + +/// Flight or Travel origin (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterOrigin : @"Mountain View, CA",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterOrigin = @"origin"; + +/// Purchase price (double as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterPrice : @(1.0),
+///       kFIRParameterCurrency : @"USD",  // e.g. $1.00 USD
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterPrice = @"price"; + +/// Purchase quantity (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterQuantity : @(1),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterQuantity = @"quantity"; + +/// Score in game (signed 64-bit integer as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterScore : @(4200),
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterScore = @"score"; + +/// The search string/keywords used (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterSearchTerm : @"periodic table",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterSearchTerm = @"search_term"; + +/// Shipping cost (double as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterShipping : @(9.50),
+///       kFIRParameterCurrency : @"USD",  // e.g. $9.50 USD
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterShipping = @"shipping"; + +/// Sign up method (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterSignUpMethod : @"google",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterSignUpMethod = @"sign_up_method"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterSource : @"InMobi",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterSource = @"source"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterStartDate : @"2015-09-14",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterStartDate = @"start_date"; + +/// Tax amount (double as NSNumber). +///
+///     NSDictionary *params = @{
+///       kFIRParameterTax : @(1.0),
+///       kFIRParameterCurrency : @"USD",  // e.g. $1.00 USD
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterTax = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterTerm : @"game",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterTerm = @"term"; + +/// A single ID for a ecommerce group transaction (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterTransactionID : @"ab7236dd9823",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterTransactionID = @"transaction_id"; + +/// Travel class (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterTravelClass : @"business",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterTravelClass = @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as signed +/// 64-bit integer or double as NSNumber. Notes: Values for pre-defined currency-related events +/// (such as @c kFIREventAddToCart) should be supplied using double as NSNumber and must be +/// accompanied by a @c kFIRParameterCurrency parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. +///
+///     NSDictionary *params = @{
+///       kFIRParameterValue : @(3.99),
+///       kFIRParameterCurrency : @"USD",  // e.g. $3.99 USD
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterValue = @"value"; + +/// Name of virtual currency type (NSString). +///
+///     NSDictionary *params = @{
+///       kFIRParameterVirtualCurrencyName : @"virtual_currency_name",
+///       // ...
+///     };
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName = @"virtual_currency_name"; diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100755 index 0000000..54cf1c2 --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,13 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_" prefix is reserved and should not be used. + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod = @"sign_up_method"; diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100755 index 0000000..3142c97 --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,9 @@ +#import "FIRAnalyticsConfiguration.h" +#import "FIRApp.h" +#import "FIRConfiguration.h" +#import "FIROptions.h" +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Modules/module.modulemap b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100755 index 0000000..6394d59 --- /dev/null +++ b/Task Master/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,8 @@ +framework module FirebaseAnalytics { + umbrella header "FirebaseAnalytics.h" + export * + module * { export *} + link "sqlite3" + link "z" + link framework "UIKit" +} \ No newline at end of file diff --git a/Task Master/Pods/FirebaseAuth/CHANGELOG.md b/Task Master/Pods/FirebaseAuth/CHANGELOG.md new file mode 100755 index 0000000..a42f7d1 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/CHANGELOG.md @@ -0,0 +1,38 @@ +# 2017-02-06 -- v3.1.1 +- Allows handling of additional errors when sending OOB action emails. The + server can respond with the following new error messages: + INVALID_MESSAGE_PAYLOAD,INVALID_SENDER and INVALID_RECIPIENT_EMAIL. +- Removes incorrect reference to FIRAuthErrorCodeCredentialTooOld in FIRUser.h. +- Provides additional error information from server if available. + +# 2016-12-13 -- v3.1.0 +- Adds FIRAuth methods that enable the app to follow up with user actions + delivered by email, such as verifying email address or reset password. +- No longer applies the keychain workaround introduced in v3.0.5 on iOS 10.2 + simulator or above since the issue has been fixed. +- Fixes nullability compilation warnings when used in Swift. +- Better reports missing password error. + +# 2016-10-24 -- v3.0.6 +- Switches to depend on open sourced GoogleToolboxForMac and GTMSessionFetcher. +- Improves logging of keychain error when initializing. + +# 2016-09-14 -- v3.0.5 +- Works around a keychain issue in iOS 10 simulator. +- Reports the correct error for invalid email when signing in with email and + password. + +# 2016-07-18 -- v3.0.4 +- Fixes a race condition bug that could crash the app with an exception from + NSURLSession on iOS 9. + +# 2016-06-20 -- v3.0.3 +- Adds documentation for all possible errors returned by each method. +- Improves error handling and messages for a variety of error conditions. +- Whether or not an user is considered anonymous is now consistent with other + platforms. +- A saved signed in user is now siloed between different Firebase projects + within the same app. + +# 2016-05-18 -- v3.0.2 +- Initial public release. diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/FirebaseAuth b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/FirebaseAuth new file mode 100755 index 0000000..18675e6 Binary files /dev/null and b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/FirebaseAuth differ diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuth.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuth.h new file mode 100755 index 0000000..1f2be01 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuth.h @@ -0,0 +1,488 @@ +/** @file FIRAuth.h + @brief Firebase Auth SDK + @copyright Copyright 2015 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +#import "FIRAuthErrors.h" + +@class FIRApp; +@class FIRAuth; +@class FIRAuthCredential; +@class FIRUser; +@protocol FIRAuthStateListener; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthStateDidChangeListenerHandle + @brief The type of handle returned by @c FIRAuth.addAuthStateDidChangeListener:. + */ +typedef id FIRAuthStateDidChangeListenerHandle; + +/** @typedef FIRAuthStateDidChangeListenerBlock + @brief The type of block which can be registered as a listener for auth state did change events. + + @param auth The FIRAuth object on which state changes occurred. + @param user Optionally; the current signed in user, if any. + */ +typedef void(^FIRAuthStateDidChangeListenerBlock)(FIRAuth *auth, FIRUser *_Nullable user); + +/** + @brief The name of the @c NSNotificationCenter notification which is posted when the auth state + changes (for example, a new token has been produced, a user signs in or signs out). The + object parameter of the notification is the sender @c FIRAuth instance. + */ +extern NSString *const FIRAuthStateDidChangeNotification; + +/** @typedef FIRAuthResultCallback + @brief The type of block invoked when sign-in related events complete. + + @param user Optionally; the signed in user, if any. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRAuthResultCallback)(FIRUser *_Nullable user, NSError *_Nullable error); + +/** @typedef FIRProviderQueryCallback + @brief The type of block invoked when a list of identity providers for a given email address is + requested. + + @param providers Optionally; a list of provider identifiers, if any. + @see FIRGoogleAuthProviderID etc. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRProviderQueryCallback)(NSArray *_Nullable providers, + NSError *_Nullable error); + +/** @typedef FIRSendPasswordResetCallback + @brief The type of block invoked when sending a password reset email. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRSendPasswordResetCallback)(NSError *_Nullable error); + +/** @typedef FIRConfirmPasswordResetCallback + @brief The type of block invoked when performing a password reset. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRConfirmPasswordResetCallback)(NSError *_Nullable error); + +/** @typedef FIRVerifyPasswordResetCodeCallback + @brief The type of block invoked when verifying that an out of band code should be used to + perform password reset. + + @param email Optionally; the email address of the user for which the out of band code applies. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRVerifyPasswordResetCodeCallback)(NSString *_Nullable email, + NSError *_Nullable error); + +/** @typedef FIRApplyActionCodeCallback + @brief The type of block invoked when applying an action code. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRApplyActionCodeCallback)(NSError *_Nullable error); + +/** + @brief Keys used to retrieve operation data from a @c FIRActionCodeInfo object by the @c + dataForKey method. + */ +typedef NS_ENUM(NSInteger, FIRActionDataKey) { + /** + * The email address to which the code was sent. + * For FIRActionCodeOperationRecoverEmail, the new email address for the account. + */ + FIRActionCodeEmailKey = 0, + + /** For FIRActionCodeOperationRecoverEmail, the current email address for the account. */ + FIRActionCodeFromEmailKey = 1 +}; + +/** @class FIRActionCodeInfo + @brief Manages information regarding action codes. + */ +@interface FIRActionCodeInfo : NSObject + +/** + @brief Operations which can be performed with action codes. + */ +typedef NS_ENUM(NSInteger, FIRActionCodeOperation) { + /** Action code for unknown operation. */ + FIRActionCodeOperationUnknown = 0, + + /** Action code for password reset operation. */ + FIRActionCodeOperationPasswordReset = 1, + + /** Action code for verify email operation. */ + FIRActionCodeOperationVerifyEmail = 2 +}; + +/** + @brief The operation being performed. + */ +@property(nonatomic, readonly) FIRActionCodeOperation operation; + +/** @fn dataForKey: + @brief The operation being performed. + + @param key The FIRActionDataKey value used to retrieve the operation data. + + @return The operation data pertaining to the provided action code key. + */ +- (NSString *)dataForKey:(FIRActionDataKey)key; + +/** @fn init + @brief please use initWithOperation: instead. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +/** @typedef FIRCheckActionCodeCallBack + @brief The type of block invoked when performing a check action code operation. + + @param info Metadata corresponding to the action code. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRCheckActionCodeCallBack)(FIRActionCodeInfo *_Nullable info, + NSError *_Nullable error); + +/** @class FIRAuth + @brief Manages authentication for Firebase apps. + @remarks This class is thread-safe. + */ +@interface FIRAuth : NSObject + +/** @fn auth + @brief Gets the auth object for the default Firebase app. + @remarks Thread safe. + */ ++ (nullable FIRAuth *)auth NS_SWIFT_NAME(auth()); + +/** @fn authWithApp: + @brief Gets the auth object for a @c FIRApp. + + @param app The FIRApp for which to retrieve the associated FIRAuth instance. + @return The FIRAuth instance associated with the given FIRApp. + */ ++ (nullable FIRAuth *)authWithApp:(FIRApp *)app; + +/** @property app + @brief Gets the @c FIRApp object that this auth object is connected to. + */ +@property(nonatomic, weak, readonly, nullable) FIRApp *app; + +/** @property currentUser + @brief Synchronously gets the cached current user, or null if there is none. + */ +@property(nonatomic, strong, readonly, nullable) FIRUser *currentUser; + +/** @fn init + @brief Please access auth instances using @c FIRAuth.auth and @c FIRAuth.authForApp:. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn fetchProvidersForEmail:completion: + @brief Fetches the list of IdPs that can be used for signing in with the provided email address. + Useful for an "identifier-first" sign-in flow. + + @param email The email address for which to obtain a list of identity providers. + @param completion Optionally; a block which is invoked when the list of providers for the + specified email address is ready or an error was encountered. Invoked asynchronously on the + main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed.
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)fetchProvidersForEmail:(NSString *)email + completion:(nullable FIRProviderQueryCallback)completion; + +/** @fn signInWithEmail:password:completion: + @brief Signs in using an email address and password. + + @param email The user's email address. + @param password The user's password. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + +
    +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that email and password + accounts are not enabled. Enable them in the Auth section of the + Firebase console. +
  • +
  • @c FIRAuthErrorCodeUserDisabled - Indicates the user's account is disabled. +
  • +
  • @c FIRAuthErrorCodeWrongPassword - Indicates the user attempted + sign in with an incorrect password. +
  • +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)signInWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn signInWithCredential:completion: + @brief Asynchronously signs in to Firebase with the given 3rd-party credentials (e.g. a Facebook + login Access Token, a Google ID Token/Access Token pair, etc.) + + @param credential The credential supplied by the IdP. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidCredential - Indicates the supplied credential is invalid. + This could happen if it has expired or it is malformed. +
  • +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that accounts + with the identity provider represented by the credential are not enabled. + Enable them in the Auth section of the Firebase console. +
  • +
  • @c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email asserted by the credential + (e.g. the email in a Facebook access token) is already in use by an existing account, + that cannot be authenticated with this sign-in method. Call fetchProvidersForEmail for + this user’s email and then prompt them to sign in with any of the sign-in providers + returned. This error will only be thrown if the "One account per email address" + setting is enabled in the Firebase console, under Auth settings. Please note that the + error code raised in this specific situation may not be the same on + Web and Android. +
  • +
  • @c FIRAuthErrorCodeUserDisabled - Indicates the user's account is disabled. +
  • +
  • @c FIRAuthErrorCodeWrongPassword - Indicates the user attempted sign in with an + incorrect password, if credential is of the type EmailPasswordAuthCredential. +
  • +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)signInWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn signInAnonymouslyWithCompletion: + @brief Asynchronously creates and becomes an anonymous user. + @param completion Optionally; a block which is invoked when the sign in finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks If there is already an anonymous user signed in, that user will be returned instead. + If there is any other existing user signed in, that user will be signed out. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that anonymous accounts are + not enabled. Enable them in the Auth section of the Firebase console. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)signInAnonymouslyWithCompletion:(nullable FIRAuthResultCallback)completion; + +/** @fn signInWithCustomToken:completion: + @brief Asynchronously signs in to Firebase with the given Auth token. + + @param token A self-signed custom auth token. + @param completion Optionally; a block which is invoked when the sign in finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidCustomToken - Indicates a validation error with + the custom token. +
  • +
  • @c FIRAuthErrorCodeCustomTokenMismatch - Indicates the service account and the API key + belong to different projects. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)signInWithCustomToken:(NSString *)token + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn createUserWithEmail:password:completion: + @brief Creates and, on success, signs in a user with the given email address and password. + + @param email The user's email address. + @param password The user's desired password. + @param completion Optionally; a block which is invoked when the sign up flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed. +
  • +
  • @c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email used to attempt sign up + already exists. Call fetchProvidersForEmail to check which sign-in mechanisms the user + used, and prompt the user to sign in with one of those. +
  • +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that email and password accounts + are not enabled. Enable them in the Auth section of the Firebase console. +
  • +
  • @c FIRAuthErrorCodeWeakPassword - Indicates an attempt to set a password that is + considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo + dictionary object will contain more detailed explanation that can be shown to the user. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)createUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn confirmPasswordResetWithCode:newPassword:completion: + @brief Resets the password given a code sent to the user outside of the app and a new password + for the user. + + @param newPassword The new password. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeWeakPassword - Indicates an attempt to set a password that is + considered too weak. +
  • +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates the administrator disabled sign + in with the specified identity provider. +
  • +
  • @c FIRAuthErrorCodeExpiredActionCode - Indicates the OOB code is expired. +
  • +
  • @c FIRAuthErrorCodeInvalidActionCode - Indicates the OOB code is invalid. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)confirmPasswordResetWithCode:(NSString *)code + newPassword:(NSString *)newPassword + completion:(FIRConfirmPasswordResetCallback)completion; + +/** @fn checkActionCode:completion: + @brief Checks the validity of an out of band code. + + @param code The out of band code to check validity. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)checkActionCode:(NSString *)code completion:(FIRCheckActionCodeCallBack)completion; + +/** @fn verifyPasswordResetCode:completion: + @brief Checks the validity of a verify password reset code. + + @param code The password reset code to be verified. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)verifyPasswordResetCode:(NSString *)code + completion:(FIRVerifyPasswordResetCodeCallback)completion; + +/** @fn applyActionCode:completion: + @brief Applies out of band code. + + @param code The out of band code to be applied. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks This method will not work for out of band codes which require an additional parameter, + such as password reset code. + */ +- (void)applyActionCode:(NSString *)code + completion:(FIRApplyActionCodeCallback)completion; + +/** @fn sendPasswordResetWithEmail:completion: + @brief Initiates a password reset for the given email address. + + @param email The email address of the user. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidRecipientEmail - Indicates an invalid recipient email was + sent in the request. +
  • +
  • @c FIRAuthErrorCodeInvalidSender - Indicates an invalid sender email is set in + the console for this action. +
  • +
  • @c FIRAuthErrorCodeInvalidMessagePayload - Indicates an invalid email template for + sending update email. +
  • +
+ */ +- (void)sendPasswordResetWithEmail:(NSString *)email + completion:(nullable FIRSendPasswordResetCallback)completion; + +/** @fn signOut: + @brief Signs out the current user. + + @param error Optionally; if an error occurs, upon return contains an NSError object that + describes the problem; is nil otherwise. + @return @YES when the sign out request was successful. @NO otherwise. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeKeychainError - Indicates an error occurred when accessing the + keychain. The @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo + dictionary will contain more information about the error encountered. +
  • +
+ + */ +- (BOOL)signOut:(NSError *_Nullable *_Nullable)error; + +/** @fn addAuthStateDidChangeListener: + @brief Registers a block as an "auth state did change" listener. To be invoked when: + + + The block is registered as a listener, + + The current user changes, or, + + The current user's access token changes. + + @param listener The block to be invoked. The block is always invoked asynchronously on the main + thread, even for it's initial invocation after having been added as a listener. + + @remarks The block is invoked immediately after adding it according to it's standard invocation + semantics, asynchronously on the main thread. Users should pay special attention to + making sure the block does not inadvertently retain objects which should not be retained by + the long-lived block. The block itself will be retained by @c FIRAuth until it is + unregistered or until the @c FIRAuth instance is otherwise deallocated. + + @return A handle useful for manually unregistering the block as a listener. + */ +- (FIRAuthStateDidChangeListenerHandle)addAuthStateDidChangeListener: + (FIRAuthStateDidChangeListenerBlock)listener; + +/** @fn removeAuthStateDidChangeListener: + @brief Unregisters a block as an "auth state did change" listener. + + @param listenerHandle The handle for the listener. + */ +- (void)removeAuthStateDidChangeListener:(FIRAuthStateDidChangeListenerHandle)listenerHandle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthCredential.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthCredential.h new file mode 100755 index 0000000..f960143 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthCredential.h @@ -0,0 +1,31 @@ +/** @file FIRAuthCredential.h + @brief Firebase Auth SDK + @copyright Copyright 2015 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthCredential + @brief Represents a credential. + */ +@interface FIRAuthCredential : NSObject + +/** @property provider + @brief Gets the name of the identity provider for the credential. + */ +@property(nonatomic, copy, readonly) NSString *provider; + +/** @fn init + @brief This is an abstract base class. Concrete instances should be created via factory + methods available in the various authentication provider libraries (like the Facebook + provider or the Google provider libraries.) + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthErrors.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthErrors.h new file mode 100755 index 0000000..3940347 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthErrors.h @@ -0,0 +1,176 @@ +/** @file FIRAuthErrors.h + @brief Firebase Auth SDK + @copyright Copyright 2015 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +/** @class FIRAuthErrors + @remarks Error Codes common to all API Methods: +
    +
  • @c FIRAuthErrorCodeNetworkError
  • +
  • @c FIRAuthErrorCodeUserNotFound
  • +
  • @c FIRAuthErrorCodeUserTokenExpired
  • +
  • @c FIRAuthErrorCodeTooManyRequests
  • +
  • @c FIRAuthErrorCodeInvalidAPIKey
  • +
  • @c FIRAuthErrorCodeAppNotAuthorized
  • +
  • @c FIRAuthErrorCodeKeychainError
  • +
  • @c FIRAuthErrorCodeInternalError
  • +
+ @remarks Common error codes for @c FIRUser operations: +
    +
  • @c FIRAuthErrorCodeInvalidUserToken
  • +
  • @c FIRAuthErrorCodeUserDisabled
  • +
+ */ +@interface FIRAuthErrors + +/** + @brief The Firebase Auth error domain. + */ +extern NSString *const FIRAuthErrorDomain; + +/** + @brief The name of the key for the "error_name" string in the NSError userinfo dictionary. + */ +extern NSString *const FIRAuthErrorNameKey; + +/** + @brief Error codes used by Firebase Auth. + */ +typedef NS_ENUM(NSInteger, FIRAuthErrorCode) { + /** Indicates a validation error with the custom token. + */ + FIRAuthErrorCodeInvalidCustomToken = 17000, + + /** Indicates the service account and the API key belong to different projects. + */ + FIRAuthErrorCodeCustomTokenMismatch = 17002, + + /** Indicates the IDP token or requestUri is invalid. + */ + FIRAuthErrorCodeInvalidCredential = 17004, + + /** Indicates the user's account is disabled on the server. + */ + FIRAuthErrorCodeUserDisabled = 17005, + + /** Indicates the administrator disabled sign in with the specified identity provider. + */ + FIRAuthErrorCodeOperationNotAllowed = 17006, + + /** Indicates the email used to attempt a sign up is already in use. + */ + FIRAuthErrorCodeEmailAlreadyInUse = 17007, + + /** Indicates the email is invalid. + */ + FIRAuthErrorCodeInvalidEmail = 17008, + + /** Indicates the user attempted sign in with a wrong password. + */ + FIRAuthErrorCodeWrongPassword = 17009, + + /** Indicates that too many requests were made to a server method. + */ + FIRAuthErrorCodeTooManyRequests = 17010, + + /** Indicates the user account was not found. + */ + FIRAuthErrorCodeUserNotFound = 17011, + + /** Indicates account linking is required. + */ + FIRAuthErrorCodeAccountExistsWithDifferentCredential = 17012, + + /** Same enum as @c FIRAuthErrorCodeAccountExistsWithDifferentCredential , + but with incorrect spelling. Only exists for backwards compatiblity. + */ + FIRAuthErrrorCodeAccountExistsWithDifferentCredential = 17012, + + /** Indicates the user has attemped to change email or password more than 5 minutes after + signing in. + */ + FIRAuthErrorCodeRequiresRecentLogin = 17014, + + /** Indicates an attempt to link a provider to which the account is already linked. + */ + FIRAuthErrorCodeProviderAlreadyLinked = 17015, + + /** Indicates an attempt to unlink a provider that is not linked. + */ + FIRAuthErrorCodeNoSuchProvider = 17016, + + /** Indicates user's saved auth credential is invalid, the user needs to sign in again. + */ + FIRAuthErrorCodeInvalidUserToken = 17017, + + /** Indicates a network error occurred (such as a timeout, interrupted connection, or + unreachable host). These types of errors are often recoverable with a retry. The @c + NSUnderlyingError field in the @c NSError.userInfo dictionary will contain the error + encountered. + */ + FIRAuthErrorCodeNetworkError = 17020, + + /** Indicates the saved token has expired, for example, the user may have changed account + password on another device. The user needs to sign in again on the device that made this + request. + */ + FIRAuthErrorCodeUserTokenExpired = 17021, + + /** Indicates an invalid API key was supplied in the request. + */ + FIRAuthErrorCodeInvalidAPIKey = 17023, + + /** Indicates that an attempt was made to reauthenticate with a user which is not the current + user. + */ + FIRAuthErrorCodeUserMismatch = 17024, + + /** Indicates an attempt to link with a credential that has already been linked with a + different Firebase account + */ + FIRAuthErrorCodeCredentialAlreadyInUse = 17025, + + /** Indicates an attempt to set a password that is considered too weak. + */ + FIRAuthErrorCodeWeakPassword = 17026, + + /** Indicates the App is not authorized to use Firebase Authentication with the + provided API Key. + */ + FIRAuthErrorCodeAppNotAuthorized = 17028, + + /** Indicates the OOB code is expired. + */ + FIRAuthErrorCodeExpiredActionCode = 17029, + + /** Indicates the OOB code is invalid. + */ + FIRAuthErrorCodeInvalidActionCode = 17030, + + /** Indicates that there are invalid parameters in the payload during a "send password reset + * email" attempt. + */ + FIRAuthErrorCodeInvalidMessagePayload = 17031, + + /** Indicates that the sender email is invalid during a "send password reset email" attempt. + */ + FIRAuthErrorCodeInvalidSender = 17032, + + /** Indicates that the recipient email is invalid. + */ + FIRAuthErrorCodeInvalidRecipientEmail = 17033, + + /** Indicates an error occurred while attempting to access the keychain. + */ + FIRAuthErrorCodeKeychainError = 17995, + + /** Indicates an internal error occurred. + */ + FIRAuthErrorCodeInternalError = 17999, +}; + +@end diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIREmailPasswordAuthProvider.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIREmailPasswordAuthProvider.h new file mode 100755 index 0000000..a18d5b4 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIREmailPasswordAuthProvider.h @@ -0,0 +1,40 @@ +/** @file FIREmailPasswordAuthProvider.h + @brief Firebase Auth SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the email & password identity provider. + */ +extern NSString *const FIREmailPasswordAuthProviderID; + +/** @class FIREmailPasswordAuthProvider + @brief A concrete implementation of @c FIRAuthProvider for Email & Password Sign In. + */ +@interface FIREmailPasswordAuthProvider : NSObject + +/** @fn credentialWithEmail:password: + @brief Creates an @c FIRAuthCredential for an email & password sign in. + + @param email The user's email address. + @param password The user's password. + @return A FIRAuthCredential containing the email & password credential. + */ ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRFacebookAuthProvider.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRFacebookAuthProvider.h new file mode 100755 index 0000000..ce968d2 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRFacebookAuthProvider.h @@ -0,0 +1,39 @@ +/** @file FIRFacebookAuthProvider.h + @brief Firebase Auth SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Facebook identity provider. + */ +extern NSString *const FIRFacebookAuthProviderID; + +/** @class FIRFacebookAuthProvider + @brief Utility class for constructing Facebook credentials. + */ +@interface FIRFacebookAuthProvider : NSObject + +/** @fn credentialWithAccessToken: + @brief Creates an @c FIRAuthCredential for a Facebook sign in. + + @param accessToken The Access Token from Facebook. + @return A FIRAuthCredential containing the Facebook credentials. + */ ++ (FIRAuthCredential *)credentialWithAccessToken:(NSString *)accessToken; + +/** @fn init + @brief This class should not be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGitHubAuthProvider.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGitHubAuthProvider.h new file mode 100755 index 0000000..fcc1491 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGitHubAuthProvider.h @@ -0,0 +1,39 @@ +/** @file FIRGitHubAuthProvider.h + @brief Firebase Auth SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the GitHub identity provider. + */ +extern NSString *const FIRGitHubAuthProviderID; + +/** @class FIRGitHubAuthProvider + @brief Utility class for constructing GitHub credentials. + */ +@interface FIRGitHubAuthProvider : NSObject + +/** @fn credentialWithToken: + @brief Creates an @c FIRAuthCredential for a GitHub sign in. + + @param token The GitHub OAuth access token. + @return A FIRAuthCredential containing the GitHub credential. + */ ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGoogleAuthProvider.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGoogleAuthProvider.h new file mode 100755 index 0000000..cdd574b --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGoogleAuthProvider.h @@ -0,0 +1,41 @@ +/** @file FIRGoogleAuthProvider.h + @brief Firebase Auth SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Google identity provider. + */ +extern NSString *const FIRGoogleAuthProviderID; + +/** @class FIRGoogleAuthProvider + @brief Utility class for constructing Google Sign In credentials. + */ +@interface FIRGoogleAuthProvider : NSObject + +/** @fn credentialWithIDToken:accessToken: + @brief Creates an @c FIRAuthCredential for a Google sign in. + + @param IDToken The ID Token from Google. + @param accessToken The Access Token from Google. + @return A FIRAuthCredential containing the Google credentials. + */ ++ (FIRAuthCredential *)credentialWithIDToken:(NSString *)IDToken + accessToken:(NSString *)accessToken; + +/** @fn init + @brief This class should not be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRTwitterAuthProvider.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRTwitterAuthProvider.h new file mode 100755 index 0000000..6d1e993 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRTwitterAuthProvider.h @@ -0,0 +1,40 @@ +/** @file FIRTwitterAuthProvider.h + @brief Firebase Auth SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Twitter identity provider. + */ +extern NSString *const FIRTwitterAuthProviderID; + +/** @class FIRTwitterAuthProvider + @brief Utility class for constructing Twitter credentials. + */ +@interface FIRTwitterAuthProvider : NSObject + +/** @fn credentialWithToken:secret: + @brief Creates an @c FIRAuthCredential for a Twitter sign in. + + @param token The Twitter OAuth token. + @param secret The Twitter OAuth secret. + @return A FIRAuthCredential containing the Twitter credential. + */ ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token secret:(NSString *)secret; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUser.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUser.h new file mode 100755 index 0000000..a137701 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUser.h @@ -0,0 +1,376 @@ +/** @file FIRUser.h + @brief Firebase Auth SDK + @copyright Copyright 2015 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +#import "FIRAuth.h" +#import "FIRUserInfo.h" + +@class FIRUserProfileChangeRequest; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthTokenCallback + @brief The type of block called when a token is ready for use. + @see FIRUser.getTokenWithCompletion: + @see FIRUser.getTokenForcingRefresh:withCompletion: + + @param token Optionally; an access token if the request was successful. + @param error Optionally; the error which occurred - or nil if the request was successful. + + @remarks One of: @c token or @c error will always be non-nil. + */ +typedef void (^FIRAuthTokenCallback)(NSString *_Nullable token, NSError *_Nullable error); + +/** @typedef FIRUserProfileChangeCallback + @brief The type of block called when a user profile change has finished. + + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRUserProfileChangeCallback)(NSError *_Nullable error); + +/** @typedef FIRSendEmailVerificationCallback + @brief The type of block called when a request to send an email verification has finished. + + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRSendEmailVerificationCallback)(NSError *_Nullable error); + +/** @class FIRUser + @brief Represents a user. + @remarks This class is thread-safe. + */ +@interface FIRUser : NSObject + +/** @property anonymous + @brief Indicates the user represents an anonymous user. + */ +@property(nonatomic, readonly, getter=isAnonymous) BOOL anonymous; + +/** @property emailVerified + @brief Indicates the email address associated with this user has been verified. + */ +@property(nonatomic, readonly, getter=isEmailVerified) BOOL emailVerified; + +/** @property refreshToken + @brief A refresh token; useful for obtaining new access tokens independently. + @remarks This property should only be used for advanced scenarios, and is not typically needed. + */ +@property(nonatomic, readonly, nullable) NSString *refreshToken; + +/** @property providerData + @brief Profile data for each identity provider, if any. + @remarks This data is cached on sign-in and updated when linking or unlinking. + */ +@property(nonatomic, readonly, nonnull) NSArray> *providerData; + +/** @fn init + @brief This class should not be instantiated. + @remarks To retrieve the current user, use @c FIRAuth.currentUser. To sign a user + in or out, use the methods on @c FIRAuth. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn updateEmail:completion: + @brief Updates the email address for the user. On success, the cached user profile data is + updated. + @remarks May fail if there is already an account with this email address that was created using + email and password authentication. + + @param email The email address for the user. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidRecipientEmail - Indicates an invalid recipient email was + sent in the request. +
  • +
  • @c FIRAuthErrorCodeInvalidSender - Indicates an invalid sender email is set in + the console for this action. +
  • +
  • @c FIRAuthErrorCodeInvalidMessagePayload - Indicates an invalid email template for + sending update email. +
  • +
  • @c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email is already in use by another + account. +
  • +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed. +
  • +
  • @c FIRAuthErrorCodeRequiresRecentLogin - Updating a user’s email is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + invoking reauthenticateWithCredential:completion: on FIRUser. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + */ +- (void)updateEmail:(NSString *)email completion:(nullable FIRUserProfileChangeCallback)completion; + +/** @fn updatePassword:completion: + @brief Updates the password for the user. On success, the cached user profile data is updated. + + @param password The new password for the user. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates the administrator disabled + sign in with the specified identity provider. +
  • +
  • @c FIRAuthErrorCodeRequiresRecentLogin - Updating a user’s password is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + invoking reauthenticateWithCredential:completion: on FIRUser. +
  • +
  • @c FIRAuthErrorCodeWeakPassword - Indicates an attempt to set a password that is + considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo + dictionary object will contain more detailed explanation that can be shown to the user. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + */ +- (void)updatePassword:(NSString *)password + completion:(nullable FIRUserProfileChangeCallback)completion; + +/** @fn profileChangeRequest + @brief Creates an object which may be used to change the user's profile data. + + @remarks Set the properties of the returned object, then call + @c FIRUserProfileChangeRequest.commitChangesWithCallback: to perform the updates atomically. + + @return An object which may be used to change the user's profile data atomically. + */ +- (FIRUserProfileChangeRequest *)profileChangeRequest; + +/** @fn reloadWithCompletion: + @brief Reloads the user's profile data from the server. + + @param completion Optionally; the block invoked when the reload has finished. Invoked + asynchronously on the main thread in the future. + + @remarks May fail with a @c FIRAuthErrorCodeRequiresRecentLogin error code. In this case + you should call @c FIRUser.reauthenticateWithCredential:completion: before re-invoking + @c FIRUser.updateEmail:completion:. + + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)reloadWithCompletion:(nullable FIRUserProfileChangeCallback)completion; + +/** @fn reauthenticateWithCredential:completion: + @brief Renews the user's authentication tokens by validating a fresh set of credentials supplied + by the user. + + @param credential A user-supplied credential, which will be validated by the server. This can be + a successful third-party identity provider sign-in, or an email address and password. + @param completion Optionally; the block invoked when the re-authentication operation has + finished. Invoked asynchronously on the main thread in the future. + + @remarks If the user associated with the supplied credential is different from the current user, + or if the validation of the supplied credentials fails; an error is returned and the current + user remains signed in. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidCredential - Indicates the supplied credential is invalid. + This could happen if it has expired or it is malformed. +
  • +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that accounts with the + identity provider represented by the credential are not enabled. Enable them in the + Auth section of the Firebase console. +
  • +
  • @c FIRAuthErrorCodeEmailAlreadyInUse - Indicates the email asserted by the credential + (e.g. the email in a Facebook access token) is already in use by an existing account, + that cannot be authenticated with this method. Call fetchProvidersForEmail for + this user’s email and then prompt them to sign in with any of the sign-in providers + returned. This error will only be thrown if the "One account per email address" + setting is enabled in the Firebase console, under Auth settings. Please note that the + error code raised in this specific situation may not be the same on Web and Android. +
  • +
  • @c FIRAuthErrorCodeUserDisabled - Indicates the user's account is disabled. +
  • +
  • @c FIRAuthErrorCodeWrongPassword - Indicates the user attempted reauthentication with + an incorrect password, if credential is of the type EmailPasswordAuthCredential. +
  • +
  • @c FIRAuthErrorCodeUserMismatch - Indicates that an attempt was made to + reauthenticate with a user which is not the current user. +
  • +
  • @c FIRAuthErrorCodeInvalidEmail - Indicates the email address is malformed.
  • +
+ @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)reauthenticateWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRUserProfileChangeCallback)completion; + +/** @fn getTokenWithCompletion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)getTokenWithCompletion:(nullable FIRAuthTokenCallback)completion; + +/** @fn getTokenForcingRefresh:completion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason + other than an expiration. + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks The authentication token will be refreshed (by making a network request) if it has + expired, or if @c forceRefresh is YES. + + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)getTokenForcingRefresh:(BOOL)forceRefresh + completion:(nullable FIRAuthTokenCallback)completion; + +/** @fn linkWithCredential:completion: + @brief Associates a user account from a third-party identity provider with this user. + + @param credential The credential for the identity provider. + @param completion Optionally; the block invoked when the unlinking is complete, or fails. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeProviderAlreadyLinked - Indicates an attempt to link a provider of a + type already linked to this account. +
  • +
  • @c FIRAuthErrorCodeCredentialAlreadyInUse - Indicates an attempt to link with a + credential + that has already been linked with a different Firebase account. +
  • +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that accounts with the identity + provider represented by the credential are not enabled. Enable them in the Auth section + of the Firebase console. +
  • +
+ + @remarks This method may also return error codes associated with updateEmail:completion: and + updatePassword:completion: on FIRUser. + + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + */ +- (void)linkWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn unlinkFromProvider:completion: + @brief Disassociates a user account from a third-party identity provider with this user. + + @param provider The provider ID of the provider to unlink. + @param completion Optionally; the block invoked when the unlinking is complete, or fails. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeNoSuchProvider - Indicates an attempt to unlink a provider + that is not linked to the account. +
  • +
  • @c FIRAuthErrorCodeRequiresRecentLogin - Updating email is a security sensitive + operation that requires a recent login from the user. This error indicates the user + has not signed in recently enough. To resolve, reauthenticate the user by invoking + reauthenticateWithCredential:completion: on FIRUser. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + */ +- (void)unlinkFromProvider:(NSString *)provider + completion:(nullable FIRAuthResultCallback)completion; + +/** @fn sendEmailVerificationWithCompletion: + @brief Initiates email verification for the user. + + @param completion Optionally; the block invoked when the request to send an email verification + is complete, or fails. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeInvalidRecipientEmail - Indicates an invalid recipient email was + sent in the request. +
  • +
  • @c FIRAuthErrorCodeInvalidSender - Indicates an invalid sender email is set in + the console for this action. +
  • +
  • @c FIRAuthErrorCodeInvalidMessagePayload - Indicates an invalid email template for + sending update email. +
  • +
  • @c FIRAuthErrorCodeUserNotFound - Indicates the user account was not found.
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + */ +- (void)sendEmailVerificationWithCompletion:(nullable FIRSendEmailVerificationCallback)completion; + +/** @fn deleteWithCompletion: + @brief Deletes the user account (also signs out the user, if this was the current user). + + @param completion Optionally; the block invoked when the request to delete the account is + complete, or fails. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeRequiresRecentLogin - Updating email is a security sensitive + operation that requires a recent login from the user. This error indicates the user + has not signed in recently enough. To resolve, reauthenticate the user by invoking + reauthenticateWithCredential:completion: on FIRUser. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all FIRUser methods. + + */ +- (void)deleteWithCompletion:(nullable FIRUserProfileChangeCallback)completion; + +@end + +/** @class FIRUserProfileChangeRequest + @brief Represents an object capable of updating a user's profile data. + @remarks Properties are marked as being part of a profile update when they are set. Setting a + property value to nil is not the same as leaving the property unassigned. + */ +@interface FIRUserProfileChangeRequest : NSObject + +/** @fn init + @brief Please use @c FIRUser.profileChangeRequest + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @property displayName + @brief The user's display name. + @remarks It is an error to set this property after calling + @c FIRUserProfileChangeRequest.commitChangesWithCallback: + */ +@property(nonatomic, copy, nullable) NSString *displayName; + +/** @property photoURL + @brief The user's photo URL. + @remarks It is an error to set this property after calling + @c FIRUserProfileChangeRequest.commitChangesWithCallback: + */ +@property(nonatomic, copy, nullable) NSURL *photoURL; + +/** @fn commitChangesWithCompletion: + @brief Commits any pending changes. + @remarks This method should only be called once. Once called, property values should not be + changed. + + @param completion Optionally; the block invoked when the user profile change has been applied. + Invoked asynchronously on the main thread in the future. + */ +- (void)commitChangesWithCompletion:(nullable FIRUserProfileChangeCallback)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUserInfo.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUserInfo.h new file mode 100755 index 0000000..3dfac18 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUserInfo.h @@ -0,0 +1,44 @@ +/** @file FIRUserInfo.h + @brief Firebase Auth SDK + @copyright Copyright 2015 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief Represents user data returned from an identity provider. + */ +@protocol FIRUserInfo + +/** @property providerID + @brief The provider identifier. + */ +@property(nonatomic, copy, readonly) NSString *providerID; + +/** @property uid + @brief The provider's user ID for the user. + */ +@property(nonatomic, copy, readonly) NSString *uid; + +/** @property displayName + @brief The name of the user. + */ +@property(nonatomic, copy, readonly, nullable) NSString *displayName; + +/** @property photoURL + @brief The URL of the user's profile photo. + */ +@property(nonatomic, copy, readonly, nullable) NSURL *photoURL; + +/** @property email + @brief The user's email address. + */ +@property(nonatomic, copy, readonly, nullable) NSString *email; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuth.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuth.h new file mode 100755 index 0000000..2e0a35c --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuth.h @@ -0,0 +1,11 @@ +#import "FIREmailPasswordAuthProvider.h" +#import "FIRFacebookAuthProvider.h" +#import "FIRGitHubAuthProvider.h" +#import "FIRGoogleAuthProvider.h" +#import "FIRTwitterAuthProvider.h" +#import "FIRAuth.h" +#import "FIRAuthCredential.h" +#import "FIRAuthErrors.h" +#import "FIRUser.h" +#import "FIRUserInfo.h" +#import "FirebaseAuthVersion.h" diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuthVersion.h b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuthVersion.h new file mode 100755 index 0000000..3f29d7b --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuthVersion.h @@ -0,0 +1,18 @@ +/*! @file FirebaseAuthVersion.h + @brief Firebase SDK + @copyright Copyright 2016 Google Inc. + @remarks Use of this SDK is subject to the Google APIs Terms of Service: + https://developers.google.com/terms/ + */ + +#import + +/** + Version number for FirebaseAuth. + */ +extern const double FirebaseAuthVersionNumber; + +/** + Version string for FirebaseAuth. + */ +extern const unsigned char *const FirebaseAuthVersionString; diff --git a/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Modules/module.modulemap b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Modules/module.modulemap new file mode 100755 index 0000000..c58f30e --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/Frameworks/FirebaseAuth.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module FirebaseAuth { + umbrella header "FirebaseAuth.h" + export * + module * { export *} + link "z" + link framework "CoreGraphics" + link framework "Foundation" + link framework "Security" + link framework "UIKit" +} \ No newline at end of file diff --git a/Task Master/Pods/FirebaseAuth/README.md b/Task Master/Pods/FirebaseAuth/README.md new file mode 100755 index 0000000..e766949 --- /dev/null +++ b/Task Master/Pods/FirebaseAuth/README.md @@ -0,0 +1,8 @@ +# Firebase Auth for iOS + +Firebase Auth enables apps to easily support multiple authentication options +for their end users. + +Please visit [our developer site](https://developers.google.com/) for +integration instructions, documentation, support information, and terms of +service. diff --git a/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/FirebaseCore b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/FirebaseCore new file mode 100755 index 0000000..18fad71 Binary files /dev/null and b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/FirebaseCore differ diff --git a/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRAnalyticsConfiguration.h b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRAnalyticsConfiguration.h new file mode 100755 index 0000000..667d5a4 --- /dev/null +++ b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRAnalyticsConfiguration.h @@ -0,0 +1,38 @@ +#import + +/** + * This class provides configuration fields for Firebase Analytics. + */ +@interface FIRAnalyticsConfiguration : NSObject + +/** + * Returns the shared instance of FIRAnalyticsConfiguration. + */ ++ (FIRAnalyticsConfiguration *)sharedInstance; + +/** + * Sets the minimum engagement time in seconds required to start a new session. The default value + * is 10 seconds. + */ +- (void)setMinimumSessionInterval:(NSTimeInterval)minimumSessionInterval; + +/** + * Sets the interval of inactivity in seconds that terminates the current session. The default + * value is 1800 seconds (30 minutes). + */ +- (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/** + * Sets whether analytics collection is enabled for this app on this device. This setting is + * persisted across app sessions. By default it is enabled. + */ +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/** + * Deprecated. Sets whether measurement and reporting are enabled for this app on this device. By + * default they are enabled. + */ +- (void)setIsEnabled:(BOOL)isEnabled + DEPRECATED_MSG_ATTRIBUTE("Use setAnalyticsCollectionEnabled: instead."); + +@end diff --git a/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRApp.h b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRApp.h new file mode 100755 index 0000000..263c4be --- /dev/null +++ b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRApp.h @@ -0,0 +1,98 @@ +#import +#import + +@class FIROptions; + +NS_ASSUME_NONNULL_BEGIN + +/** A block that takes a BOOL and has no return value. */ +typedef void (^FIRAppVoidBoolCallback)(BOOL success); + +/** + * The entry point of Firebase SDKs. + * + * Initialize and configure FIRApp using +[FIRApp configure] + * or other customized ways as shown below. + * + * The logging system has two modes: default mode and debug mode. In default mode, only logs with + * log level Notice, Warning and Error will be sent to device. In debug mode, all logs will be sent + * to device. The log levels that Firebase uses are consistent with the ASL log levels. + * + * Enable debug mode by passing the -FIRDebugEnabled argument to the application. You can add this + * argument in the application's Xcode scheme. When debug mode is enabled via -FIRDebugEnabled, + * further executions of the application will also be in debug mode. In order to return to default + * mode, you must explicitly disable the debug mode with the application argument -FIRDebugDisabled. + * + * It is also possible to change the default logging level in code by calling setLoggerLevel: on + * the FIRConfiguration interface. + */ +@interface FIRApp : NSObject + +/** + * Configures a default Firebase app. Raises an exception if any configuration step fails. The + * default app is named "__FIRAPP_DEFAULT". This method should be called after the app is launched + * and before using Firebase services. This method is thread safe. + */ ++ (void)configure; + +/** + * Configures the default Firebase app with the provided options. The default app is named + * "__FIRAPP_DEFAULT". Raises an exception if any configuration step fails. This method is thread + * safe. + * + * @param options The Firebase application options used to configure the service. + */ ++ (void)configureWithOptions:(FIROptions *)options; + +/** + * Configures a Firebase app with the given name and options. Raises an exception if any + * configuration step fails. This method is thread safe. + * + * @param name The application's name given by the developer. The name should should only contain + Letters, Numbers and Underscore. + * @param options The Firebase application options used to configure the services. + */ ++ (void)configureWithName:(NSString *)name options:(FIROptions *)options; + +/** + * Returns the default app, or nil if the default app does not exist. + */ ++ (nullable FIRApp *)defaultApp NS_SWIFT_NAME(defaultApp()); + +/** + * Returns a previously created FIRApp instance with the given name, or nil if no such app exists. + * This method is thread safe. + */ ++ (nullable FIRApp *)appNamed:(NSString *)name; + +/** + * Returns the set of all extant FIRApp instances, or nil if there are no FIRApp instances. This + * method is thread safe. + */ ++ (nullable NSDictionary *)allApps; + +/** + * Cleans up the current FIRApp, freeing associated data and returning its name to the pool for + * future use. This method is thread safe. + */ +- (void)deleteApp:(FIRAppVoidBoolCallback)completion; + +/** + * FIRApp instances should not be initialized directly. Call +[FIRApp configure], + * +[FIRApp configureWithOptions:], or +[FIRApp configureWithNames:options:] directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Gets the name of this app. + */ +@property(nonatomic, copy, readonly) NSString *name; + +/** + * Gets the options for this app. + */ +@property(nonatomic, readonly) FIROptions *options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRConfiguration.h b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRConfiguration.h new file mode 100755 index 0000000..a25647b --- /dev/null +++ b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRConfiguration.h @@ -0,0 +1,52 @@ +#import + +#import "FIRAnalyticsConfiguration.h" +#import "FIRLoggerLevel.h" + +/** + * The log levels used by FIRConfiguration. + */ +typedef NS_ENUM(NSInteger, FIRLogLevel) { + /** Error */ + kFIRLogLevelError __deprecated = 0, + /** Warning */ + kFIRLogLevelWarning __deprecated, + /** Info */ + kFIRLogLevelInfo __deprecated, + /** Debug */ + kFIRLogLevelDebug __deprecated, + /** Assert */ + kFIRLogLevelAssert __deprecated, + /** Max */ + kFIRLogLevelMax __deprecated = kFIRLogLevelAssert +} DEPRECATED_MSG_ATTRIBUTE( + "Use -FIRDebugEnabled and -FIRDebugDisabled or setLoggerLevel. See FIRApp.h for more details."); + +/** + * This interface provides global level properties that the developer can tweak, and the singleton + * of the Firebase Analytics configuration class. + */ +@interface FIRConfiguration : NSObject + +/** Returns the shared configuration object. */ ++ (FIRConfiguration *)sharedInstance; + +/** The configuration class for Firebase Analytics. */ +@property(nonatomic, readwrite) FIRAnalyticsConfiguration *analyticsConfiguration; + +/** Global log level. Defaults to kFIRLogLevelError. */ +@property(nonatomic, readwrite, assign) FIRLogLevel logLevel DEPRECATED_MSG_ATTRIBUTE( + "Use -FIRDebugEnabled and -FIRDebugDisabled or setLoggerLevel. See FIRApp.h for more details."); + +/** + * Sets the logging level for internal Firebase logging. Firebase will only log messages + * that are logged at or below loggerLevel. The messages are logged both to the Xcode + * console and to the device's log. Note that if an app is running from AppStore, it will + * never log above FIRLoggerLevelNotice even if loggerLevel is set to a higher (more verbose) + * setting. + * + * @param loggerLevel The maximum logging level. The default level is set to FIRLoggerLevelNotice. + */ +- (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel; + +@end diff --git a/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRLoggerLevel.h b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRLoggerLevel.h new file mode 100755 index 0000000..ddf683f --- /dev/null +++ b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRLoggerLevel.h @@ -0,0 +1,12 @@ +/** + * The log levels used by internal logging. + */ +typedef NS_ENUM(NSInteger, FIRLoggerLevel) { + FIRLoggerLevelError = 3 /*ASL_LEVEL_ERR*/, + FIRLoggerLevelWarning = 4 /*ASL_LEVEL_WARNING*/, + FIRLoggerLevelNotice = 5 /*ASL_LEVEL_NOTICE*/, + FIRLoggerLevelInfo = 6 /*ASL_LEVEL_INFO*/, + FIRLoggerLevelDebug = 7 /*ASL_LEVEL_DEBUG*/, + FIRLoggerLevelMin = FIRLoggerLevelError, + FIRLoggerLevelMax = FIRLoggerLevelDebug +}; diff --git a/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIROptions.h b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIROptions.h new file mode 100755 index 0000000..083082a --- /dev/null +++ b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIROptions.h @@ -0,0 +1,93 @@ +#import + +/** + * This class provides constant fields of Google APIs. + */ +@interface FIROptions : NSObject + +/** + * Returns the default options. + */ ++ (FIROptions *)defaultOptions; + +/** + * An iOS API key used for authenticating requests from your app, e.g. + * @"AIzaSyDdVgKwhZl0sTTTLZ7iTmt1r3N2cJLnaDk", used to identify your app to Google servers. + */ +@property(nonatomic, readonly, copy) NSString *APIKey; + +/** + * The OAuth2 client ID for iOS application used to authenticate Google users, for example + * @"12345.apps.googleusercontent.com", used for signing in with Google. + */ +@property(nonatomic, readonly, copy) NSString *clientID; + +/** + * The tracking ID for Google Analytics, e.g. @"UA-12345678-1", used to configure Google Analytics. + */ +@property(nonatomic, readonly, copy) NSString *trackingID; + +/** + * The Project Number from the Google Developer's console, for example @"012345678901", used to + * configure Google Cloud Messaging. + */ +@property(nonatomic, readonly, copy) NSString *GCMSenderID; + +/** + * The Project ID from the Firebase console, for example @"abc-xyz-123". Currently only populated + * when using [FIROptions defaultOptions]. + */ +@property(nonatomic, readonly, copy) NSString *projectID; + +/** + * The Android client ID used in Google AppInvite when an iOS app has its Android version, for + * example @"12345.apps.googleusercontent.com". + */ +@property(nonatomic, readonly, copy) NSString *androidClientID; + +/** + * The Google App ID that is used to uniquely identify an instance of an app. + */ +@property(nonatomic, readonly, copy) NSString *googleAppID; + +/** + * The database root URL, e.g. @"http://abc-xyz-123.firebaseio.com". + */ +@property(nonatomic, readonly, copy) NSString *databaseURL; + +/** + * The URL scheme used to set up Durable Deep Link service. + */ +@property(nonatomic, readwrite, copy) NSString *deepLinkURLScheme; + +/** + * The Google Cloud Storage bucket name, e.g. @"abc-xyz-123.storage.firebase.com". + */ +@property(nonatomic, readonly, copy) NSString *storageBucket; + +/** + * Initializes a customized instance of FIROptions with keys. googleAppID, bundleID and GCMSenderID + * are required. Other keys may required for configuring specific services. + */ +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + bundleID:(NSString *)bundleID + GCMSenderID:(NSString *)GCMSenderID + APIKey:(NSString *)APIKey + clientID:(NSString *)clientID + trackingID:(NSString *)trackingID + androidClientID:(NSString *)androidClientID + databaseURL:(NSString *)databaseURL + storageBucket:(NSString *)storageBucket + deepLinkURLScheme:(NSString *)deepLinkURLScheme; + +/** + * Initializes a customized instance of FIROptions from the file at the given plist file path. + * For example, + * NSString *filePath = + * [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"]; + * FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath]; + * Returns nil if the plist file does not exist or is invalid. + */ +- (instancetype)initWithContentsOfFile:(NSString *)plistPath; + +@end diff --git a/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FirebaseCore.h b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FirebaseCore.h new file mode 100755 index 0000000..52a222f --- /dev/null +++ b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FirebaseCore.h @@ -0,0 +1,5 @@ +#import "FIRAnalyticsConfiguration.h" +#import "FIRApp.h" +#import "FIRConfiguration.h" +#import "FIRLoggerLevel.h" +#import "FIROptions.h" diff --git a/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Modules/module.modulemap b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Modules/module.modulemap new file mode 100755 index 0000000..b2936ab --- /dev/null +++ b/Task Master/Pods/FirebaseCore/Frameworks/FirebaseCore.framework/Modules/module.modulemap @@ -0,0 +1,7 @@ +framework module FirebaseCore { + umbrella header "FirebaseCore.h" + export * + module * { export *} + link "c++" + link "z" +} \ No newline at end of file diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/FirebaseDatabase b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/FirebaseDatabase new file mode 100755 index 0000000..a10bc3d Binary files /dev/null and b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/FirebaseDatabase differ diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataEventType.h b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataEventType.h new file mode 100755 index 0000000..245fd2d --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataEventType.h @@ -0,0 +1,48 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Firebase_FIRDataEventType_h +#define Firebase_FIRDataEventType_h + +/** + * This enum is the set of events that you can observe at a Firebase Database location. + */ +typedef NS_ENUM(NSInteger, FIRDataEventType) { + /// A new child node is added to a location. + FIRDataEventTypeChildAdded, + /// A child node is removed from a location. + FIRDataEventTypeChildRemoved, + /// A child node at a location changes. + FIRDataEventTypeChildChanged, + /// A child node moves relative to the other child nodes at a location. + FIRDataEventTypeChildMoved, + /// Any data changes at a location or, recursively, at any child node. + FIRDataEventTypeValue +}; + +#endif diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataSnapshot.h b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataSnapshot.h new file mode 100755 index 0000000..5890dd4 --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataSnapshot.h @@ -0,0 +1,158 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class FIRDatabaseReference; + +/** + * A FIRDataSnapshot contains data from a Firebase Database location. Any time you read + * Firebase data, you receive the data as a FIRDataSnapshot. + * + * FIRDataSnapshots are passed to the blocks you attach with observeEventType:withBlock: or observeSingleEvent:withBlock:. + * They are efficiently-generated immutable copies of the data at a Firebase Database location. + * They can't be modified and will never change. To modify data at a location, + * use a FIRDatabaseReference (e.g. with setValue:). + */ +@interface FIRDataSnapshot : NSObject + + +#pragma mark - Navigating and inspecting a snapshot + +/** + * Gets a FIRDataSnapshot for the location at the specified relative path. + * The relative path can either be a simple child key (e.g. 'fred') + * or a deeper slash-separated path (e.g. 'fred/name/first'). If the child + * location has no data, an empty FIRDataSnapshot is returned. + * + * @param childPathString A relative path to the location of child data. + * @return The FIRDataSnapshot for the child location. + */ +- (FIRDataSnapshot *)childSnapshotForPath:(NSString *)childPathString; + + +/** + * Return YES if the specified child exists. + * + * @param childPathString A relative path to the location of a potential child. + * @return YES if data exists at the specified childPathString, else NO. + */ +- (BOOL) hasChild:(NSString *)childPathString; + + +/** + * Return YES if the DataSnapshot has any children. + * + * @return YES if this snapshot has any children, else NO. + */ +- (BOOL) hasChildren; + + +/** + * Return YES if the DataSnapshot contains a non-null value. + * + * @return YES if this snapshot contains a non-null value, else NO. + */ +- (BOOL) exists; + + +#pragma mark - Data export + +/** + * Returns the raw value at this location, coupled with any metadata, such as priority. + * + * Priorities, where they exist, are accessible under the ".priority" key in instances of NSDictionary. + * For leaf locations with priorities, the value will be under the ".value" key. + */ +- (id __nullable) valueInExportFormat; + + +#pragma mark - Properties + +/** + * Returns the contents of this data snapshot as native types. + * + * Data types returned: + * + NSDictionary + * + NSArray + * + NSNumber (also includes booleans) + * + NSString + * + * @return The data as a native object. + */ +@property (strong, readonly, nonatomic, nullable) id value; + + +/** + * Gets the number of children for this DataSnapshot. + * + * @return An integer indicating the number of children. + */ +@property (readonly, nonatomic) NSUInteger childrenCount; + + +/** + * Gets a FIRDatabaseReference for the location that this data came from. + * + * @return A FIRDatabaseReference instance for the location of this data. + */ +@property (nonatomic, readonly, strong) FIRDatabaseReference * ref; + + +/** + * The key of the location that generated this FIRDataSnapshot. + * + * @return An NSString containing the key for the location of this FIRDataSnapshot. + */ +@property (strong, readonly, nonatomic) NSString* key; + + +/** + * An iterator for snapshots of the child nodes in this snapshot. + * You can use the native for..in syntax: + * + * for (FIRDataSnapshot* child in snapshot.children) { + * ... + * } + * + * @return An NSEnumerator of the children. + */ +@property (strong, readonly, nonatomic) NSEnumerator* children; + +/** + * The priority of the data in this FIRDataSnapshot. + * + * @return The priority as a string, or nil if no priority was set. + */ +@property (strong, readonly, nonatomic, nullable) id priority; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabase.h b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabase.h new file mode 100755 index 0000000..237d52d --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabase.h @@ -0,0 +1,150 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "FIRDatabaseReference.h" + +@class FIRApp; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The entry point for accessing a Firebase Database. You can get an instance by calling + * [FIRDatabase database]. To access a location in the database and read or write data, + * use [FIRDatabase reference]. + */ +@interface FIRDatabase : NSObject + +/** + * Gets the instance of FIRDatabase for the default FIRApp. + * + * @return A FIRDatabase instance. + */ ++ (FIRDatabase *) database NS_SWIFT_NAME(database()); + +/** + * Gets an instance of FIRDatabase for a specific FIRApp. + * + * @param app The FIRApp to get a FIRDatabase for. + * @return A FIRDatabase instance. + */ ++ (FIRDatabase *) databaseForApp:(FIRApp*)app NS_SWIFT_NAME(database(app:)); + +/** The FIRApp instance to which this FIRDatabase belongs. */ +@property (weak, readonly, nonatomic) FIRApp *app; + +/** + * Gets a FIRDatabaseReference for the root of your Firebase Database. + */ +- (FIRDatabaseReference *) reference; + +/** + * Gets a FIRDatabaseReference for the provided path. + * + * @param path Path to a location in your Firebase Database. + * @return A FIRDatabaseReference pointing to the specified path. + */ +- (FIRDatabaseReference *) referenceWithPath:(NSString *)path; + +/** + * Gets a FIRDatabaseReference for the provided URL. The URL must be a URL to a path + * within this Firebase Database. To create a FIRDatabaseReference to a different database, + * create a FIRApp} with a FIROptions object configured with the appropriate database URL. + * + * @param url A URL to a path within your database. + * @return A FIRDatabaseReference for the provided URL. +*/ +- (FIRDatabaseReference *) referenceFromURL:(NSString *)databaseUrl; + +/** + * The Firebase Database client automatically queues writes and sends them to the server at the earliest opportunity, + * depending on network connectivity. In some cases (e.g. offline usage) there may be a large number of writes + * waiting to be sent. Calling this method will purge all outstanding writes so they are abandoned. + * + * All writes will be purged, including transactions and onDisconnect writes. The writes will + * be rolled back locally, perhaps triggering events for affected event listeners, and the client will not + * (re-)send them to the Firebase Database backend. + */ +- (void)purgeOutstandingWrites; + +/** + * Shuts down our connection to the Firebase Database backend until goOnline is called. + */ +- (void)goOffline; + +/** + * Resumes our connection to the Firebase Database backend after a previous goOffline call. + */ +- (void)goOnline; + +/** + * The Firebase Database client will cache synchronized data and keep track of all writes you've + * initiated while your application is running. It seamlessly handles intermittent network + * connections and re-sends write operations when the network connection is restored. + * + * However by default your write operations and cached data are only stored in-memory and will + * be lost when your app restarts. By setting this value to `YES`, the data will be persisted + * to on-device (disk) storage and will thus be available again when the app is restarted + * (even when there is no network connectivity at that time). Note that this property must be + * set before creating your first Database reference and only needs to be called once per + * application. + * + */ +@property (nonatomic) BOOL persistenceEnabled; + +/** + * By default the Firebase Database client will use up to 10MB of disk space to cache data. If the cache grows beyond + * this size, the client will start removing data that hasn't been recently used. If you find that your application + * caches too little or too much data, call this method to change the cache size. This property must be set before + * creating your first FIRDatabaseReference and only needs to be called once per application. + * + * Note that the specified cache size is only an approximation and the size on disk may temporarily exceed it + * at times. Cache sizes smaller than 1 MB or greater than 100 MB are not supported. + */ +@property (nonatomic) NSUInteger persistenceCacheSizeBytes; + +/** + * Sets the dispatch queue on which all events are raised. The default queue is the main queue. + * + * Note that this must be set before creating your first Database reference. + */ +@property (nonatomic, strong) dispatch_queue_t callbackQueue; + +/** + * Enables verbose diagnostic logging. + * + * @param enabled YES to enable logging, NO to disable. + */ ++ (void) setLoggingEnabled:(BOOL)enabled; + +/** Retrieve the Firebase Database SDK version. */ ++ (NSString *) sdkVersion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseQuery.h b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseQuery.h new file mode 100755 index 0000000..9e0acf8 --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseQuery.h @@ -0,0 +1,325 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "FIRDataEventType.h" +#import "FIRDataSnapshot.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * A FIRDatabaseHandle is used to identify listeners of Firebase Database events. These handles + * are returned by observeEventType: and and can later be passed to removeObserverWithHandle: to + * stop receiving updates. + */ +typedef NSUInteger FIRDatabaseHandle; + +/** + * A FIRDatabaseQuery instance represents a query over the data at a particular location. + * + * You create one by calling one of the query methods (queryOrderedByChild:, queryStartingAtValue:, etc.) + * on a FIRDatabaseReference. The query methods can be chained to further specify the data you are interested in + * observing + */ +@interface FIRDatabaseQuery : NSObject + + +#pragma mark - Attach observers to read data + +/** + * observeEventType:withBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot + * and the previous child's key. + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; + + +/** + * observeEventType:withBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. + * + * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that should be called if this client no longer has permission to receive these events + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot + * and the previous child's key. + * @param cancelBlock The block that should be called if this client no longer has permission to receive these events + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * + * The cancelBlock will be called if you do not have permission to read data at this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that will be called if you don't have permission to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you do not have permission to read data at this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that will be called if you don't have permission to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +#pragma mark - Detaching observers + +/** + * Detach a block previously attached with observeEventType:withBlock:. + * + * @param handle The handle returned by the call to observeEventType:withBlock: which we are trying to remove. + */ +- (void) removeObserverWithHandle:(FIRDatabaseHandle)handle; + + +/** + * Detach all blocks previously attached to this Firebase Database location with observeEventType:withBlock: + */ +- (void) removeAllObservers; + +/** + * By calling `keepSynced:YES` on a location, the data for that location will automatically be downloaded and + * kept in sync, even when no listeners are attached for that location. Additionally, while a location is kept + * synced, it will not be evicted from the persistent disk cache. + * + * @param keepSynced Pass YES to keep this location synchronized, pass NO to stop synchronization. +*/ + - (void) keepSynced:(BOOL)keepSynced; + + +#pragma mark - Querying and limiting + +/** +* queryLimitedToFirst: is used to generate a reference to a limited view of the data at this location. +* The FIRDatabaseQuery instance returned by queryLimitedToFirst: will respond to at most the first limit child nodes. +* +* @param limit The upper bound, inclusive, for the number of child nodes to receive events for +* @return A FIRDatabaseQuery instance, limited to at most limit child nodes. +*/ +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit; + + +/** +* queryLimitedToLast: is used to generate a reference to a limited view of the data at this location. +* The FIRDatabaseQuery instance returned by queryLimitedToLast: will respond to at most the last limit child nodes. +* +* @param limit The upper bound, inclusive, for the number of child nodes to receive events for +* @return A FIRDatabaseQuery instance, limited to at most limit child nodes. +*/ +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit; + +/** + * queryOrderBy: is used to generate a reference to a view of the data that's been sorted by the values of + * a particular child key. This method is intended to be used in combination with queryStartingAtValue:, + * queryEndingAtValue:, or queryEqualToValue:. + * + * @param key The child key to use in ordering data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, ordered by the values of the specified child key. +*/ +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key; + +/** + * queryOrderedByKey: is used to generate a reference to a view of the data that's been sorted by child key. + * This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, + * or queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child keys. + */ +- (FIRDatabaseQuery *) queryOrderedByKey; + +/** + * queryOrderedByValue: is used to generate a reference to a view of the data that's been sorted by child value. + * This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, + * or queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child value. + */ +- (FIRDatabaseQuery *) queryOrderedByValue; + +/** + * queryOrderedByPriority: is used to generate a reference to a view of the data that's been sorted by child + * priority. This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, + * or queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child priorities. + */ +- (FIRDatabaseQuery *) queryOrderedByPriority; + +/** + * queryStartingAtValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryStartingAtValue: will respond to events at nodes with a value + * greater than or equal to startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue; + +/** + * queryStartingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryStartingAtValue:childKey will respond to events at nodes with a value + * greater than startValue, or equal to startValue and with a key greater than or equal to childKey. This is most + * useful when implementing pagination in a case where multiple nodes can match the startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @param childKey The lower bound, inclusive, for the key of nodes with value equal to startValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue childKey:(nullable NSString *)childKey; + +/** + * queryEndingAtValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEndingAtValue: will respond to events at nodes with a value + * less than or equal to endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue; + +/** + * queryEndingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEndingAtValue:childKey will respond to events at nodes with a value + * less than endValue, or equal to endValue and with a key less than or equal to childKey. This is most useful when + * implementing pagination in a case where multiple nodes can match the endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @param childKey The upper bound, inclusive, for the key of nodes with value equal to endValue + * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue childKey:(nullable NSString *)childKey; + +/** + * queryEqualToValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEqualToValue: will respond to events at nodes with a value equal + * to the supplied argument. + * + * @param value The value that the data returned by this FIRDatabaseQuery will have + * @return A FIRDatabaseQuery instance, limited to data with the supplied value. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value; + +/** + * queryEqualToValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEqualToValue:childKey will respond to events at nodes with a value + * equal to the supplied argument and with their key equal to childKey. There will be at most one node that matches + * because child keys are unique. + * + * @param value The value that the data returned by this FIRDatabaseQuery will have + * @param childKey The name of nodes with the right value + * @return A FIRDatabaseQuery instance, limited to data with the supplied value and the key. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value childKey:(nullable NSString *)childKey; + + +#pragma mark - Properties + +/** +* Gets a FIRDatabaseReference for the location of this query. +* +* @return A FIRDatabaseReference for the location of this query. +*/ +@property (nonatomic, readonly, strong) FIRDatabaseReference * ref; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseReference.h b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseReference.h new file mode 100755 index 0000000..44e697d --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseReference.h @@ -0,0 +1,730 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#import +#import "FIRDatabaseQuery.h" +#import "FIRDatabase.h" +#import "FIRDataSnapshot.h" +#import "FIRMutableData.h" +#import "FIRTransactionResult.h" +#import "FIRServerValue.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRDatabase; + +/** + * A FIRDatabaseReference represents a particular location in your Firebase Database + * and can be used for reading or writing data to that Firebase Database location. + * + * This class is the starting point for all Firebase Database operations. After you've + * obtained your first FIRDatabaseReference via [FIRDatabase reference], you can use it + * to read data (ie. observeEventType:withBlock:), write data (ie. setValue:), and to + * create new FIRDatabaseReferences (ie. child:). + */ +@interface FIRDatabaseReference : FIRDatabaseQuery + + +#pragma mark - Getting references to children locations + +/** + * Gets a FIRDatabaseReference for the location at the specified relative path. + * The relative path can either be a simple child key (e.g. 'fred') or a + * deeper slash-separated path (e.g. 'fred/name/first'). + * + * @param pathString A relative path from this location to the desired child location. + * @return A FIRDatabaseReference for the specified relative path. + */ +- (FIRDatabaseReference *)child:(NSString *)pathString; + +/** + * childByAppendingPath: is deprecated, use child: instead. + */ +- (FIRDatabaseReference *)childByAppendingPath:(NSString *)pathString __deprecated_msg("use child: instead"); + +/** + * childByAutoId generates a new child location using a unique key and returns a + * FIRDatabaseReference to it. This is useful when the children of a Firebase Database + * location represent a list of items. + * + * The unique key generated by childByAutoId: is prefixed with a client-generated + * timestamp so that the resulting list will be chronologically-sorted. + * + * @return A FIRDatabaseReference for the generated location. + */ +- (FIRDatabaseReference *) childByAutoId; + + +#pragma mark - Writing data + +/** Write data to this Firebase Database location. + +This will overwrite any data at this location and all child locations. + +Data types that can be set are: + +- NSString -- @"Hello World" +- NSNumber (also includes boolean) -- @YES, @43, @4.333 +- NSDictionary -- @{@"key": @"value", @"nested": @{@"another": @"value"} } +- NSArray + +The effect of the write will be visible immediately and the corresponding +events will be triggered. Synchronization of the data to the Firebase Database +servers will also be started. + +Passing null for the new value is equivalent to calling remove:; +all data at this location or any child location will be deleted. + +Note that setValue: will remove any priority stored at this location, so if priority +is meant to be preserved, you should use setValue:andPriority: instead. + +@param value The value to be written. + */ +- (void) setValue:(nullable id)value; + + +/** + * The same as setValue: with a block that gets triggered after the write operation has + * been committed to the Firebase Database servers. + * + * @param value The value to be written. + * @param block The block to be called after the write has been committed to the Firebase Database servers. + */ +- (void) setValue:(nullable id)value withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +/** + * The same as setValue: with an additional priority to be attached to the data being written. + * Priorities are used to order items. + * + * @param value The value to be written. + * @param priority The priority to be attached to that data. + */ +- (void) setValue:(nullable id)value andPriority:(nullable id)priority; + + +/** + * The same as setValue:andPriority: with a block that gets triggered after the write operation has + * been committed to the Firebase Database servers. + * + * @param value The value to be written. + * @param priority The priority to be attached to that data. + * @param block The block to be called after the write has been committed to the Firebase Database servers. + */ +- (void) setValue:(nullable id)value andPriority:(nullable id)priority withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +/** + * Remove the data at this Firebase Database location. Any data at child locations will also be deleted. + * + * The effect of the delete will be visible immediately and the corresponding events + * will be triggered. Synchronization of the delete to the Firebase Database servers will + * also be started. + * + * remove: is equivalent to calling setValue:nil + */ +- (void) removeValue; + + +/** + * The same as remove: with a block that gets triggered after the remove operation has + * been committed to the Firebase Database servers. + * + * @param block The block to be called after the remove has been committed to the Firebase Database servers. + */ +- (void) removeValueWithCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + +/** + * Sets a priority for the data at this Firebase Database location. + * Priorities can be used to provide a custom ordering for the children at a location + * (if no priorities are specified, the children are ordered by key). + * + * You cannot set a priority on an empty location. For this reason + * setValue:andPriority: should be used when setting initial data with a specific priority + * and setPriority: should be used when updating the priority of existing data. + * + * Children are sorted based on this priority using the following rules: + * + * Children with no priority come first. + * Children with a number as their priority come next. They are sorted numerically by priority (small to large). + * Children with a string as their priority come last. They are sorted lexicographically by priority. + * Whenever two children have the same priority (including no priority), they are sorted by key. Numeric + * keys come first (sorted numerically), followed by the remaining keys (sorted lexicographically). + * + * Note that priorities are parsed and ordered as IEEE 754 double-precision floating-point numbers. + * Keys are always stored as strings and are treated as numbers only when they can be parsed as a + * 32-bit integer + * + * @param priority The priority to set at the specified location. + */ +- (void) setPriority:(nullable id)priority; + + +/** + * The same as setPriority: with a block that is called once the priority has + * been committed to the Firebase Database servers. + * + * @param priority The priority to set at the specified location. + * @param block The block that is triggered after the priority has been written on the servers. + */ +- (void) setPriority:(nullable id)priority withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + +/** + * Updates the values at the specified paths in the dictionary without overwriting other + * keys at this location. + * + * @param values A dictionary of the keys to change and their new values + */ +- (void) updateChildValues:(NSDictionary *)values; + +/** + * The same as update: with a block that is called once the update has been committed to the + * Firebase Database servers + * + * @param values A dictionary of the keys to change and their new values + * @param block The block that is triggered after the update has been written on the Firebase Database servers + */ +- (void) updateChildValues:(NSDictionary *)values withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +#pragma mark - Attaching observers to read data + +/** + * observeEventType:withBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. + * + * Use removeObserverWithHandle: to stop receiving updates. + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot + * and the previous child's key. + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; + + +/** + * observeEventType:withBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. + * + * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that should be called if this client no longer has permission to receive these events + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block will be triggered + * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot + * and the previous child's key. + * @param cancelBlock The block that should be called if this client no longer has permission to receive these events + * @return A handle used to unregister this block later using removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * + * The cancelBlock will be called if you do not have permission to read data at this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that will be called if you don't have permission to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + + +/** + * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you do not have permission to read data at this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that will be called if you don't have permission to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + +#pragma mark - Detaching observers + +/** + * Detach a block previously attached with observeEventType:withBlock:. + * + * @param handle The handle returned by the call to observeEventType:withBlock: which we are trying to remove. + */ +- (void) removeObserverWithHandle:(FIRDatabaseHandle)handle; + +/** + * By calling `keepSynced:YES` on a location, the data for that location will automatically be downloaded and + * kept in sync, even when no listeners are attached for that location. Additionally, while a location is kept + * synced, it will not be evicted from the persistent disk cache. + * + * @param keepSynced Pass YES to keep this location synchronized, pass NO to stop synchronization. + */ +- (void) keepSynced:(BOOL)keepSynced; + + +/** + * Removes all observers at the current reference, but does not remove any observers at child references. + * removeAllObservers must be called again for each child reference where a listener was established to remove the observers. + */ +- (void) removeAllObservers; + +#pragma mark - Querying and limiting + + +/** + * queryLimitedToFirst: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryLimitedToFirst: will respond to at most the first limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit; + + +/** + * queryLimitedToLast: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryLimitedToLast: will respond to at most the last limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit; + +/** + * queryOrderBy: is used to generate a reference to a view of the data that's been sorted by the values of + * a particular child key. This method is intended to be used in combination with queryStartingAtValue:, + * queryEndingAtValue:, or queryEqualToValue:. + * + * @param key The child key to use in ordering data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, ordered by the values of the specified child key. + */ +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key; + +/** + * queryOrderedByKey: is used to generate a reference to a view of the data that's been sorted by child key. + * This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, + * or queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child keys. + */ +- (FIRDatabaseQuery *) queryOrderedByKey; + +/** + * queryOrderedByPriority: is used to generate a reference to a view of the data that's been sorted by child + * priority. This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, + * or queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child priorities. + */ +- (FIRDatabaseQuery *) queryOrderedByPriority; + +/** + * queryStartingAtValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryStartingAtValue: will respond to events at nodes with a value + * greater than or equal to startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue; + +/** + * queryStartingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryStartingAtValue:childKey will respond to events at nodes with a value + * greater than startValue, or equal to startValue and with a key greater than or equal to childKey. + * + * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @param childKey The lower bound, inclusive, for the key of nodes with value equal to startValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue childKey:(nullable NSString *)childKey; + +/** + * queryEndingAtValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEndingAtValue: will respond to events at nodes with a value + * less than or equal to endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue; + +/** + * queryEndingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEndingAtValue:childKey will respond to events at nodes with a value + * less than endValue, or equal to endValue and with a key less than or equal to childKey. + * + * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery + * @param childKey The upper bound, inclusive, for the key of nodes with value equal to endValue + * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue childKey:(nullable NSString *)childKey; + +/** + * queryEqualToValue: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEqualToValue: will respond to events at nodes with a value equal + * to the supplied argument. + * + * @param value The value that the data returned by this FIRDatabaseQuery will have + * @return A FIRDatabaseQuery instance, limited to data with the supplied value. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value; + +/** + * queryEqualToValue:childKey: is used to generate a reference to a limited view of the data at this location. + * The FIRDatabaseQuery instance returned by queryEqualToValue:childKey will respond to events at nodes with a value + * equal to the supplied argument with a key equal to childKey. There will be at most one node that matches because + * child keys are unique. + * + * @param value The value that the data returned by this FIRDatabaseQuery will have + * @param childKey The key of nodes with the right value + * @return A FIRDatabaseQuery instance, limited to data with the supplied value and the key. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value childKey:(nullable NSString *)childKey; + +#pragma mark - Managing presence + +/** + * Ensure the data at this location is set to the specified value when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * onDisconnectSetValue: is especially useful for implementing "presence" systems, + * where a value should be changed or cleared when a user disconnects + * so that he appears "offline" to other users. + * + * @param value The value to be set after the connection is lost. + */ +- (void) onDisconnectSetValue:(nullable id)value; + + +/** + * Ensure the data at this location is set to the specified value when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * The completion block will be triggered when the operation has been successfully queued up on the Firebase Database servers + * + * @param value The value to be set after the connection is lost. + * @param block Block to be triggered when the operation has been queued up on the Firebase Database servers + */ +- (void) onDisconnectSetValue:(nullable id)value withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +/** + * Ensure the data at this location is set to the specified value and priority when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * @param value The value to be set after the connection is lost. + * @param priority The priority to be set after the connection is lost. + */ +- (void) onDisconnectSetValue:(nullable id)value andPriority:(id)priority; + + +/** + * Ensure the data at this location is set to the specified value and priority when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * The completion block will be triggered when the operation has been successfully queued up on the Firebase Database servers + * + * @param value The value to be set after the connection is lost. + * @param priority The priority to be set after the connection is lost. + * @param block Block to be triggered when the operation has been queued up on the Firebase Database servers + */ +- (void) onDisconnectSetValue:(nullable id)value andPriority:(nullable id)priority withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +/** + * Ensure the data at this location is removed when + * the client is disconnected (due to closing the app, navigating + * to a new page, or network issues). + * + * onDisconnectRemoveValue is especially useful for implementing "presence" systems. + */ +- (void) onDisconnectRemoveValue; + + +/** + * Ensure the data at this location is removed when + * the client is disconnected (due to closing the app, navigating + * to a new page, or network issues). + * + * onDisconnectRemoveValueWithCompletionBlock: is especially useful for implementing "presence" systems. + * + * @param block Block to be triggered when the operation has been queued up on the Firebase Database servers + */ +- (void) onDisconnectRemoveValueWithCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + + +/** + * Ensure the data has the specified child values updated when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * + * @param values A dictionary of child node keys and the values to set them to after the connection is lost. + */ +- (void) onDisconnectUpdateChildValues:(NSDictionary *)values; + + +/** + * Ensure the data has the specified child values updated when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * + * @param values A dictionary of child node keys and the values to set them to after the connection is lost. + * @param block A block that will be called once the operation has been queued up on the Firebase Database servers + */ +- (void) onDisconnectUpdateChildValues:(NSDictionary *)values withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +/** + * Cancel any operations that are set to run on disconnect. If you previously called onDisconnectSetValue:, + * onDisconnectRemoveValue:, or onDisconnectUpdateChildValues:, and no longer want the values updated when the + * connection is lost, call cancelDisconnectOperations: + */ +- (void) cancelDisconnectOperations; + + +/** + * Cancel any operations that are set to run on disconnect. If you previously called onDisconnectSetValue:, + * onDisconnectRemoveValue:, or onDisconnectUpdateChildValues:, and no longer want the values updated when the + * connection is lost, call cancelDisconnectOperations: + * + * @param block A block that will be triggered once the Firebase Database servers have acknowledged the cancel request. + */ +- (void) cancelDisconnectOperationsWithCompletionBlock:(nullable void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; + + +#pragma mark - Manual Connection Management + +/** + * Manually disconnect the Firebase Database client from the server and disable automatic reconnection. + * + * The Firebase Database client automatically maintains a persistent connection to the Firebase Database server, + * which will remain active indefinitely and reconnect when disconnected. However, the goOffline( ) + * and goOnline( ) methods may be used to manually control the client connection in cases where + * a persistent connection is undesirable. + * + * While offline, the Firebase Database client will no longer receive data updates from the server. However, + * all database operations performed locally will continue to immediately fire events, allowing + * your application to continue behaving normally. Additionally, each operation performed locally + * will automatically be queued and retried upon reconnection to the Firebase Database server. + * + * To reconnect to the Firebase Database server and begin receiving remote events, see goOnline( ). + * Once the connection is reestablished, the Firebase Database client will transmit the appropriate data + * and fire the appropriate events so that your client "catches up" automatically. + * + * Note: Invoking this method will impact all Firebase Database connections. + */ ++ (void) goOffline; + +/** + * Manually reestablish a connection to the Firebase Database server and enable automatic reconnection. + * + * The Firebase Database client automatically maintains a persistent connection to the Firebase Database server, + * which will remain active indefinitely and reconnect when disconnected. However, the goOffline( ) + * and goOnline( ) methods may be used to manually control the client connection in cases where + * a persistent connection is undesirable. + * + * This method should be used after invoking goOffline( ) to disable the active connection. + * Once reconnected, the Firebase Database client will automatically transmit the proper data and fire + * the appropriate events so that your client "catches up" automatically. + * + * To disconnect from the Firebase Database server, see goOffline( ). + * + * Note: Invoking this method will impact all Firebase Database connections. + */ ++ (void) goOnline; + + +#pragma mark - Transactions + +/** + * Performs an optimistic-concurrency transactional update to the data at this location. Your block will be called with a FIRMutableData + * instance that contains the current data at this location. Your block should update this data to the value you + * wish to write to this location, and then return an instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had stale data, your block will be run + * again with the latest data from the server. + * + * When your block is run, you may decide to abort the transaction by returning [FIRTransactionResult abort]. + * + * @param block This block receives the current data at this location and must return an instance of FIRTransactionResult + */ +- (void) runTransactionBlock:(FIRTransactionResult * (^) (FIRMutableData* currentData))block; + + +/** + * Performs an optimistic-concurrency transactional update to the data at this location. Your block will be called with a FIRMutableData + * instance that contains the current data at this location. Your block should update this data to the value you + * wish to write to this location, and then return an instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had stale data, your block will be run + * again with the latest data from the server. + * + * When your block is run, you may decide to abort the transaction by returning [FIRTransactionResult abort]. + * + * @param block This block receives the current data at this location and must return an instance of FIRTransactionResult + * @param completionBlock This block will be triggered once the transaction is complete, whether it was successful or not. It will indicate if there was an error, whether or not the data was committed, and what the current value of the data at this location is. + */ +- (void)runTransactionBlock:(FIRTransactionResult * (^) (FIRMutableData* currentData))block andCompletionBlock:(void (^) (NSError *__nullable error, BOOL committed, FIRDataSnapshot *__nullable snapshot))completionBlock; + + + +/** + * Performs an optimistic-concurrency transactional update to the data at this location. Your block will be called with a FIRMutableData + * instance that contains the current data at this location. Your block should update this data to the value you + * wish to write to this location, and then return an instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had stale data, your block will be run + * again with the latest data from the server. + * + * When your block is run, you may decide to abort the transaction by return [FIRTransactionResult abort]. + * + * Since your block may be run multiple times, this client could see several immediate states that don't exist on the server. You can suppress those immediate states until the server confirms the final state of the transaction. + * + * @param block This block receives the current data at this location and must return an instance of FIRTransactionResult + * @param completionBlock This block will be triggered once the transaction is complete, whether it was successful or not. It will indicate if there was an error, whether or not the data was committed, and what the current value of the data at this location is. + * @param localEvents Set this to NO to suppress events raised for intermediate states, and only get events based on the final state of the transaction. + */ +- (void)runTransactionBlock:(FIRTransactionResult * (^) (FIRMutableData* currentData))block andCompletionBlock:(nullable void (^) (NSError *__nullable error, BOOL committed, FIRDataSnapshot *__nullable snapshot))completionBlock withLocalEvents:(BOOL)localEvents; + + +#pragma mark - Retrieving String Representation + +/** + * Gets the absolute URL of this Firebase Database location. + * + * @return The absolute URL of the referenced Firebase Database location. + */ +- (NSString *) description; + +#pragma mark - Properties + +/** + * Gets a FIRDatabaseReference for the parent location. + * If this instance refers to the root of your Firebase Database, it has no parent, + * and therefore parent( ) will return null. + * + * @return A FIRDatabaseReference for the parent location. + */ +@property (strong, readonly, nonatomic, nullable) FIRDatabaseReference * parent; + + +/** + * Gets a FIRDatabaseReference for the root location + * + * @return A new FIRDatabaseReference to root location. + */ +@property (strong, readonly, nonatomic) FIRDatabaseReference * root; + + +/** + * Gets the last token in a Firebase Database location (e.g. 'fred' in https://SampleChat.firebaseIO-demo.com/users/fred) + * + * @return The key of the location this reference points to. + */ +@property (strong, readonly, nonatomic) NSString* key; + +/** + * Gets the URL for the Firebase Database location referenced by this FIRDatabaseReference. + * + * @return The url of the location this reference points to. + */ +@property (strong, readonly, nonatomic) NSString* URL; + +/** + * Gets the FIRDatabase instance associated with this reference. + * + * @return The FIRDatabase object for this reference. + */ +@property (strong, readonly, nonatomic) FIRDatabase *database; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRMutableData.h b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRMutableData.h new file mode 100755 index 0000000..fc42ec9 --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRMutableData.h @@ -0,0 +1,140 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A FIRMutableData instance is populated with data from a Firebase Database location. + * When you are using runTransactionBlock:, you will be given an instance containing the current + * data at that location. Your block will be responsible for updating that instance to the data + * you wish to save at that location, and then returning using [FIRTransactionResult successWithValue:]. + * + * To modify the data, set its value property to any of the native types support by Firebase Database: + * + * + NSNumber (includes BOOL) + * + NSDictionary + * + NSArray + * + NSString + * + nil / NSNull to remove the data + * + * Note that changes made to a child FIRMutableData instance will be visible to the parent. + */ +@interface FIRMutableData : NSObject + + +#pragma mark - Inspecting and navigating the data + + +/** + * Returns boolean indicating whether this mutable data has children. + * + * @return YES if this data contains child nodes. + */ +- (BOOL) hasChildren; + + +/** + * Indicates whether this mutable data has a child at the given path. + * + * @param path A path string, consisting either of a single segment, like 'child', or multiple segments, 'a/deeper/child' + * @return YES if this data contains a child at the specified relative path + */ +- (BOOL) hasChildAtPath:(NSString *)path; + + +/** + * Used to obtain a FIRMutableData instance that encapsulates the data at the given relative path. + * Note that changes made to the child will be visible to the parent. + * + * @param path A path string, consisting either of a single segment, like 'child', or multiple segments, 'a/deeper/child' + * @return A FIRMutableData instance containing the data at the given path + */ +- (FIRMutableData *)childDataByAppendingPath:(NSString *)path; + + +#pragma mark - Properties + + +/** + * To modify the data contained by this instance of FIRMutableData, set this to any of the native types supported by Firebase Database: + * + * + NSNumber (includes BOOL) + * + NSDictionary + * + NSArray + * + NSString + * + nil / NSNull to remove the data + * + * Note that setting this value will override the priority at this location. + * + * @return The current data at this location as a native object + */ +@property (strong, nonatomic, nullable) id value; + + +/** + * Set this property to update the priority of the data at this location. Can be set to the following types: + * + * + NSNumber + * + NSString + * + nil / NSNull to remove the priority + * + * @return The priority of the data at this location + */ +@property (strong, nonatomic, nullable) id priority; + + +/** + * @return The number of child nodes at this location + */ +@property (readonly, nonatomic) NSUInteger childrenCount; + + +/** + * Used to iterate over the children at this location. You can use the native for .. in syntax: + * + * for (FIRMutableData* child in data.children) { + * ... + * } + * + * Note that this enumerator operates on an immutable copy of the child list. So, you can modify the instance + * during iteration, but the new additions will not be visible until you get a new enumerator. + */ +@property (readonly, nonatomic, strong) NSEnumerator* children; + + +/** + * @return The key name of this node, or nil if it is the top-most location + */ +@property (readonly, nonatomic, strong, nullable) NSString* key; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRServerValue.h b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRServerValue.h new file mode 100755 index 0000000..c93a524 --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRServerValue.h @@ -0,0 +1,44 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +NS_ASSUME_NONNULL_BEGIN + +/** + * Placeholder values you may write into Firebase Database as a value or priority + * that will automatically be populated by the Firebase Database server. + */ +@interface FIRServerValue : NSObject + +/** + * Placeholder value for the number of milliseconds since the Unix epoch + */ ++ (NSDictionary *) timestamp; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRTransactionResult.h b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRTransactionResult.h new file mode 100755 index 0000000..07439e1 --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRTransactionResult.h @@ -0,0 +1,57 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2013 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "FIRMutableData.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Used for runTransactionBlock:. An FIRTransactionResult instance is a container for the results of the transaction. + */ +@interface FIRTransactionResult : NSObject + +/** + * Used for runTransactionBlock:. Indicates that the new value should be saved at this location + * + * @param value A FIRMutableData instance containing the new value to be set + * @return An FIRTransactionResult instance that can be used as a return value from the block given to runTransactionBlock: + */ ++ (FIRTransactionResult *)successWithValue:(FIRMutableData *)value; + + +/** + * Used for runTransactionBlock:. Indicates that the current transaction should no longer proceed. + * + * @return An FIRTransactionResult instance that can be used as a return value from the block given to runTransactionBlock: + */ ++ (FIRTransactionResult *) abort; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FirebaseDatabase.h b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FirebaseDatabase.h new file mode 100755 index 0000000..d903c1b --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FirebaseDatabase.h @@ -0,0 +1,41 @@ +/* + * Firebase iOS Client Library + * + * Copyright © 2016 Firebase - All Rights Reserved + * https://www.firebase.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binaryform must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FirebaseDatabase_h +#define FirebaseDatabase_h + +#import "FIRDatabase.h" +#import "FIRDatabaseQuery.h" +#import "FIRDatabaseReference.h" +#import "FIRDataEventType.h" +#import "FIRDataSnapshot.h" +#import "FIRMutableData.h" +#import "FIRServerValue.h" +#import "FIRTransactionResult.h" + +#endif /* FirebaseDatabase_h */ diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Info.plist b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Info.plist new file mode 100755 index 0000000..4174f41 Binary files /dev/null and b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Info.plist differ diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Modules/module.modulemap b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Modules/module.modulemap new file mode 100755 index 0000000..28b323e --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Modules/module.modulemap @@ -0,0 +1,13 @@ +framework module FirebaseDatabase { + umbrella header "FirebaseDatabase.h" + + export * + module * { export * } + + link framework "CFNetwork" + link framework "Security" + link framework "SystemConfiguration" + + link "c++" + link "icucore" +} diff --git a/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/NOTICE b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/NOTICE new file mode 100755 index 0000000..410cbd6 --- /dev/null +++ b/Task Master/Pods/FirebaseDatabase/Frameworks/FirebaseDatabase.framework/NOTICE @@ -0,0 +1,47 @@ +Google LevelDB +Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +* Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-- + +Square Socket Rocket +Copyright 2012 Square Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +-- + +APLevelDB +Created by Adam Preble on 1/23/12. +Copyright (c) 2012 Adam Preble. All rights reserved. + +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/Task Master/Pods/FirebaseInstanceID/CHANGELOG.md b/Task Master/Pods/FirebaseInstanceID/CHANGELOG.md new file mode 100755 index 0000000..adb6b81 --- /dev/null +++ b/Task Master/Pods/FirebaseInstanceID/CHANGELOG.md @@ -0,0 +1,40 @@ +# 2017-03-31 -- v1.0.10 + +- Improvements to token-fetching logic +- Fixed some warnings in Instance ID +- Improved error messages if Instance ID couldn't be initialized properly +- Improvements to console logging + +# 2017-01-31 -- v1.0.9 + +- Removed an error being mistakenly logged to the console. + +# 2016-07-06 -- v1.0.8 + +- Don't store InstanceID plists in Documents folder. + +# 2016-06-19 -- v1.0.7 + +- Fix remote-notifications warning on app submission. + +# 2016-05-16 -- v1.0.6 + +- Fix CocoaPod linter issues for InstanceID pod. + +# 2016-05-13 -- v1.0.5 + +- Fix Authorization errors for InstanceID tokens. + +# 2016-05-11 -- v1.0.4 + +- Reduce wait for InstanceID token during parallel requests. + +# 2016-04-18 -- v1.0.3 + +- Change flag to disable swizzling to *FirebaseAppDelegateProxyEnabled*. +- Fix incessant Keychain errors while accessing InstanceID. +- Fix max retries for fetching IID token. + +# 2016-04-18 -- v1.0.2 + +- Register for remote notifications on iOS8+ in the SDK itself. diff --git a/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/FirebaseInstanceID b/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/FirebaseInstanceID new file mode 100755 index 0000000..7c22eea Binary files /dev/null and b/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/FirebaseInstanceID differ diff --git a/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FIRInstanceID.h b/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FIRInstanceID.h new file mode 100755 index 0000000..342b154 --- /dev/null +++ b/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FIRInstanceID.h @@ -0,0 +1,245 @@ +#import + +/** + * @memberof FIRInstanceID + * + * The scope to be used when fetching/deleting a token for Firebase Messaging. + */ +FOUNDATION_EXPORT NSString * __nonnull const kFIRInstanceIDScopeFirebaseMessaging; + +/** + * Called when the system determines that tokens need to be refreshed. + * This method is also called if Instance ID has been reset in which + * case, tokens and FCM topic subscriptions also need to be refreshed. + * + * Instance ID service will throttle the refresh event across all devices + * to control the rate of token updates on application servers. + */ +FOUNDATION_EXPORT NSString * __nonnull const kFIRInstanceIDTokenRefreshNotification; + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the InstanceID token returns. If + * the call fails we return the appropriate `error code` as described below. + * + * @param token The valid token as returned by InstanceID backend. + * + * @param error The error describing why generating a new token + * failed. See the error codes below for a more detailed + * description. + */ +typedef void(^FIRInstanceIDTokenHandler)( NSString * __nullable token, NSError * __nullable error); + + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the InstanceID `deleteToken` returns. If + * the call fails we return the appropriate `error code` as described below + * + * @param error The error describing why deleting the token failed. + * See the error codes below for a more detailed description. + */ +typedef void(^FIRInstanceIDDeleteTokenHandler)(NSError * __nullable error); + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the app identity is created. If the + * identity wasn't created for some reason we return the appropriate error code. + * + * @param identity A valid identity for the app instance, nil if there was an error + * while creating an identity. + * @param error The error if fetching the identity fails else nil. + */ +typedef void(^FIRInstanceIDHandler)(NSString * __nullable identity, NSError * __nullable error); + +/** + * @related FIRInstanceID + * + * The completion handler invoked when the app identity and all the tokens associated + * with it are deleted. Returns a valid error object in case of failure else nil. + * + * @param error The error if deleting the identity and all the tokens associated with + * it fails else nil. + */ +typedef void(^FIRInstanceIDDeleteHandler)(NSError * __nullable error); + +/** + * @enum FIRInstanceIDError + */ +typedef NS_ENUM(NSUInteger, FIRInstanceIDError) { + // Http related errors. + + /// Unknown error. + FIRInstanceIDErrorUnknown = 0, + + /// Auth Error -- GCM couldn't validate request from this client. + FIRInstanceIDErrorAuthentication = 1, + + /// NoAccess -- InstanceID service cannot be accessed. + FIRInstanceIDErrorNoAccess = 2, + + /// Timeout -- Request to InstanceID backend timed out. + FIRInstanceIDErrorTimeout = 3, + + /// Network -- No network available to reach the servers. + FIRInstanceIDErrorNetwork = 4, + + /// OperationInProgress -- Another similar operation in progress, + /// bailing this one. + FIRInstanceIDErrorOperationInProgress = 5, + + /// InvalidRequest -- Some parameters of the request were invalid. + FIRInstanceIDErrorInvalidRequest = 7, +}; + +/** + * The APNS token type for the app. If the token type is set to `UNKNOWN` + * InstanceID will implicitly try to figure out what the actual token type + * is from the provisioning profile. + */ +typedef NS_ENUM(NSInteger, FIRInstanceIDAPNSTokenType) { + /// Unknown token type. + FIRInstanceIDAPNSTokenTypeUnknown, + /// Sandbox token type. + FIRInstanceIDAPNSTokenTypeSandbox, + /// Production token type. + FIRInstanceIDAPNSTokenTypeProd, +}; + +/** + * Instance ID provides a unique identifier for each app instance and a mechanism + * to authenticate and authorize actions (for example, sending an FCM message). + * + * Instance ID is long lived but, may be reset if the device is not used for + * a long time or the Instance ID service detects a problem. + * If Instance ID is reset, the app will be notified via + * `kFIRInstanceIDTokenRefreshNotification`. + * + * If the Instance ID has become invalid, the app can request a new one and + * send it to the app server. + * To prove ownership of Instance ID and to allow servers to access data or + * services associated with the app, call + * `[FIRInstanceID tokenWithAuthorizedEntity:scope:options:handler]`. + */ +@interface FIRInstanceID : NSObject + +/** + * FIRInstanceID. + * + * @return A shared instance of FIRInstanceID. + */ ++ (nonnull instancetype)instanceID NS_SWIFT_NAME(instanceID()); + +/** + * Unavailable. Use +instanceID instead. + */ +- (nonnull instancetype)init __attribute__((unavailable("Use +instanceID instead."))); + +/** + * Set APNS token for the application. This APNS token will be used to register + * with Firebase Messaging using `token` or + * `tokenWithAuthorizedEntity:scope:options:handler`. If the token type is set to + * `FIRInstanceIDAPNSTokenTypeUnknown` InstanceID will read the provisioning profile + * to find out the token type. + * + * @param token The APNS token for the application. + * @param type The APNS token type for the above token. + */ +- (void)setAPNSToken:(nonnull NSData *)token + type:(FIRInstanceIDAPNSTokenType)type; + +#pragma mark - Tokens + +/** + * Returns a Firebase Messaging scoped token for the firebase app. + * + * @return Null Returns null if the device has not yet been registerd with + * Firebase Message else returns a valid token. + */ +- (nullable NSString *)token; + +/** + * Returns a token that authorizes an Entity (example: cloud service) to perform + * an action on behalf of the application identified by Instance ID. + * + * This is similar to an OAuth2 token except, it applies to the + * application instance instead of a user. + * + * This is an asynchronous call. If the token fetching fails for some reason + * we invoke the completion callback with nil `token` and the appropriate + * error. + * + * Note, you can only have one `token` or `deleteToken` call for a given + * authorizedEntity and scope at any point of time. Making another such call with the + * same authorizedEntity and scope before the last one finishes will result in an + * error with code `OperationInProgress`. + * + * @see FIRInstanceID deleteTokenWithAuthorizedEntity:scope:handler: + * + * @param authorizedEntity Entity authorized by the token. + * @param scope Action authorized for authorizedEntity. + * @param options The extra options to be sent with your token request. The + * value for the `apns_token` should be the NSData object + * passed to UIApplication's + * `didRegisterForRemoteNotificationsWithDeviceToken` method. + * All other keys and values in the options dict need to be + * instances of NSString or else they will be discarded. Bundle + * keys starting with 'GCM.' and 'GOOGLE.' are reserved. + * @param handler The callback handler which is invoked when the token is + * successfully fetched. In case of success a valid `token` and + * `nil` error are returned. In case of any error the `token` + * is nil and a valid `error` is returned. The valid error + * codes have been documented above. + */ +- (void)tokenWithAuthorizedEntity:(nonnull NSString *)authorizedEntity + scope:(nonnull NSString *)scope + options:(nullable NSDictionary *)options + handler:(nonnull FIRInstanceIDTokenHandler)handler; + +/** + * Revokes access to a scope (action) for an entity previously + * authorized by `[FIRInstanceID tokenWithAuthorizedEntity:scope:options:handler]`. + * + * This is an asynchronous call. Call this on the main thread since InstanceID lib + * is not thread safe. In case token deletion fails for some reason we invoke the + * `handler` callback passed in with the appropriate error code. + * + * Note, you can only have one `token` or `deleteToken` call for a given + * authorizedEntity and scope at a point of time. Making another such call with the + * same authorizedEntity and scope before the last one finishes will result in an error + * with code `OperationInProgress`. + * + * @param authorizedEntity Entity that must no longer have access. + * @param scope Action that entity is no longer authorized to perform. + * @param handler The handler that is invoked once the unsubscribe call ends. + * In case of error an appropriate error object is returned + * else error is nil. + */ +- (void)deleteTokenWithAuthorizedEntity:(nonnull NSString *)authorizedEntity + scope:(nonnull NSString *)scope + handler:(nonnull FIRInstanceIDDeleteTokenHandler)handler; + +#pragma mark - Identity + +/** + * Asynchronously fetch a stable identifier that uniquely identifies the app + * instance. If the identifier has been revoked or has expired, this method will + * return a new identifier. + * + * + * @param handler The handler to invoke once the identifier has been fetched. + * In case of error an appropriate error object is returned else + * a valid identifier is returned and a valid identifier for the + * application instance. + */ +- (void)getIDWithHandler:(nonnull FIRInstanceIDHandler)handler; + +/** + * Resets Instance ID and revokes all tokens. + */ +- (void)deleteIDWithHandler:(nonnull FIRInstanceIDDeleteHandler)handler; + +@end diff --git a/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FirebaseInstanceID.h b/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FirebaseInstanceID.h new file mode 100755 index 0000000..053ec2b --- /dev/null +++ b/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FirebaseInstanceID.h @@ -0,0 +1 @@ +#import "FIRInstanceID.h" diff --git a/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Modules/module.modulemap b/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Modules/module.modulemap new file mode 100755 index 0000000..4b3b912 --- /dev/null +++ b/Task Master/Pods/FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Modules/module.modulemap @@ -0,0 +1,7 @@ +framework module FirebaseInstanceID { + umbrella header "FirebaseInstanceID.h" + export * + module * { export *} + link "c++" + link "z" +} \ No newline at end of file diff --git a/Task Master/Pods/FirebaseInstanceID/README.md b/Task Master/Pods/FirebaseInstanceID/README.md new file mode 100755 index 0000000..25fe219 --- /dev/null +++ b/Task Master/Pods/FirebaseInstanceID/README.md @@ -0,0 +1,10 @@ +# InstanceID SDK for iOS + +Instance ID provides a unique ID per instance of your apps and also provides a +mechanism to authenticate and authorize actions, like sending messages via +Firebase Cloud Messaging (FCM). + + +Please visit [our developer +site](https://developers.google.com/instance-id/) for integration instructions, +documentation, support information, and terms of service. diff --git a/Task Master/Pods/GTMSessionFetcher/LICENSE b/Task Master/Pods/GTMSessionFetcher/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Task Master/Pods/GTMSessionFetcher/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Task Master/Pods/GTMSessionFetcher/README.md b/Task Master/Pods/GTMSessionFetcher/README.md new file mode 100644 index 0000000..478efde --- /dev/null +++ b/Task Master/Pods/GTMSessionFetcher/README.md @@ -0,0 +1,23 @@ +# Google Toolbox for Mac - Session Fetcher # + +**Project site**
+**Discussion group** + +[![Build Status](https://travis-ci.org/google/gtm-session-fetcher.svg?branch=master)](https://travis-ci.org/google/gtm-session-fetcher) + +`GTMSessionFetcher` makes it easy for Cocoa applications to perform http +operations. The fetcher is implemented as a wrapper on `NSURLSession`, so its +behavior is asynchronous and uses operating-system settings on iOS and Mac OS X. + +Features include: +- Simple to build; only one source/header file pair is required +- Simple to use: takes just two lines of code to fetch a request +- Supports upload and download sessions +- Flexible cookie storage +- Automatic retry on errors, with exponential backoff +- Support for generating multipart MIME upload streams +- Easy, convenient logging of http requests and responses +- Supports plug-in authentication such as with GTMAppAuth +- Easily testable; self-mocking +- Automatic rate limiting when created by the `GTMSessionFetcherService` factory class +- Fully independent of other projects diff --git a/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h new file mode 100644 index 0000000..a649cf0 --- /dev/null +++ b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h @@ -0,0 +1,1308 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// GTMSessionFetcher is a wrapper around NSURLSession for http operations. +// +// What does this offer on top of of NSURLSession? +// +// - Block-style callbacks for useful functionality like progress rather +// than delegate methods. +// - Out-of-process uploads and downloads using NSURLSession, including +// management of fetches after relaunch. +// - Integration with GTMAppAuth for invisible management and refresh of +// authorization tokens. +// - Pretty-printed http logging. +// - Cookies handling that does not interfere with or get interfered with +// by WebKit cookies or on Mac by Safari and other apps. +// - Credentials handling for the http operation. +// - Rate-limiting and cookie grouping when fetchers are created with +// GTMSessionFetcherService. +// +// If the bodyData or bodyFileURL property is set, then a POST request is assumed. +// +// Each fetcher is assumed to be for a one-shot fetch request; don't reuse the object +// for a second fetch. +// +// The fetcher will be self-retained as long as a connection is pending. +// +// To keep user activity private, URLs must have an https scheme (unless the property +// allowedInsecureSchemes is set to permit the scheme.) +// +// Callbacks will be released when the fetch completes or is stopped, so there is no need +// to use weak self references in the callback blocks. +// +// Sample usage: +// +// _fetcherService = [[GTMSessionFetcherService alloc] init]; +// +// GTMSessionFetcher *myFetcher = [_fetcherService fetcherWithURLString:myURLString]; +// myFetcher.retryEnabled = YES; +// myFetcher.comment = @"First profile image"; +// +// // Optionally specify a file URL or NSData for the request body to upload. +// myFetcher.bodyData = [postString dataUsingEncoding:NSUTF8StringEncoding]; +// +// [myFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { +// if (error != nil) { +// // Server status code or network error. +// // +// // If the domain is kGTMSessionFetcherStatusDomain then the error code +// // is a failure status from the server. +// } else { +// // Fetch succeeded. +// } +// }]; +// +// There is also a beginFetch call that takes a pointer and selector for the completion handler; +// a pointer and selector is a better style when the callback is a substantial, separate method. +// +// NOTE: Fetches may retrieve data from the server even though the server +// returned an error, so the criteria for success is a non-nil error. +// The completion handler is called when the server status is >= 300 with an NSError +// having domain kGTMSessionFetcherStatusDomain and code set to the server status. +// +// Status codes are at +// +// +// Background session support: +// +// Out-of-process uploads and downloads may be created by setting the fetcher's +// useBackgroundSession property. Data to be uploaded should be provided via +// the uploadFileURL property; the download destination should be specified with +// the destinationFileURL. NOTE: Background upload files should be in a location +// that will be valid even after the device is restarted, so the file should not +// be uploaded from a system temporary or cache directory. +// +// Background session transfers are slower, and should typically be used only +// for very large downloads or uploads (hundreds of megabytes). +// +// When background sessions are used in iOS apps, the application delegate must +// pass through the parameters from UIApplicationDelegate's +// application:handleEventsForBackgroundURLSession:completionHandler: to the +// fetcher class. +// +// When the application has been relaunched, it may also create a new fetcher +// instance to handle completion of the transfers. +// +// - (void)application:(UIApplication *)application +// handleEventsForBackgroundURLSession:(NSString *)identifier +// completionHandler:(void (^)())completionHandler { +// // Application was re-launched on completing an out-of-process download. +// +// // Pass the URLSession info related to this re-launch to the fetcher class. +// [GTMSessionFetcher application:application +// handleEventsForBackgroundURLSession:identifier +// completionHandler:completionHandler]; +// +// // Get a fetcher related to this re-launch and re-hook up a completionHandler to it. +// GTMSessionFetcher *fetcher = [GTMSessionFetcher fetcherWithSessionIdentifier:identifier]; +// NSURL *destinationFileURL = fetcher.destinationFileURL; +// fetcher.completionHandler = ^(NSData *data, NSError *error) { +// [self downloadCompletedToFile:destinationFileURL error:error]; +// }; +// } +// +// +// Threading and queue support: +// +// Networking always happens on a background thread; there is no advantage to +// changing thread or queue to create or start a fetcher. +// +// Callbacks are run on the main thread; alternatively, the app may set the +// fetcher's callbackQueue to a dispatch queue. +// +// Once the fetcher's beginFetch method has been called, the fetcher's methods and +// properties may be accessed from any thread. +// +// Downloading to disk: +// +// To have downloaded data saved directly to disk, specify a file URL for the +// destinationFileURL property. +// +// HTTP methods and headers: +// +// Alternative HTTP methods, like PUT, and custom headers can be specified by +// creating the fetcher with an appropriate NSMutableURLRequest. +// +// +// Caching: +// +// The fetcher avoids caching. That is best for API requests, but may hurt +// repeat fetches of static data. Apps may enable a persistent disk cache by +// customizing the config: +// +// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher, +// NSURLSessionConfiguration *config) { +// config.URLCache = [NSURLCache sharedURLCache]; +// }; +// +// Or use the standard system config to share cookie storage with web views +// and to enable disk caching: +// +// fetcher.configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; +// +// +// Cookies: +// +// There are three supported mechanisms for remembering cookies between fetches. +// +// By default, a standalone GTMSessionFetcher uses a mutable array held +// statically to track cookies for all instantiated fetchers. This avoids +// cookies being set by servers for the application from interfering with +// Safari and WebKit cookie settings, and vice versa. +// The fetcher cookies are lost when the application quits. +// +// To rely instead on WebKit's global NSHTTPCookieStorage, set the fetcher's +// cookieStorage property: +// myFetcher.cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; +// +// To share cookies with other apps, use the method introduced in iOS 9/OS X 10.11: +// myFetcher.cookieStorage = +// [NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:kMyCompanyContainedID]; +// +// To ignore existing cookies and only have cookies related to the single fetch +// be applied, make a temporary cookie storage object: +// myFetcher.cookieStorage = [[GTMSessionCookieStorage alloc] init]; +// +// Note: cookies set while following redirects will be sent to the server, as +// the redirects are followed by the fetcher. +// +// To completely disable cookies, similar to setting cookieStorageMethod to +// kGTMHTTPFetcherCookieStorageMethodNone, adjust the session configuration +// appropriately in the fetcher or fetcher service: +// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher, +// NSURLSessionConfiguration *config) { +// config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever; +// config.HTTPShouldSetCookies = NO; +// }; +// +// If the fetcher is created from a GTMSessionFetcherService object +// then the cookie storage mechanism is set to use the cookie storage in the +// service object rather than the static storage. Disabling cookies in the +// session configuration set on a service object will disable cookies for all +// fetchers created from that GTMSessionFetcherService object, since the session +// configuration is propagated to the fetcher. +// +// +// Monitoring data transfers. +// +// The fetcher supports a variety of properties for progress monitoring +// progress with callback blocks. +// GTMSessionFetcherSendProgressBlock sendProgressBlock +// GTMSessionFetcherReceivedProgressBlock receivedProgressBlock +// GTMSessionFetcherDownloadProgressBlock downloadProgressBlock +// +// If supplied by the server, the anticipated total download size is available +// as [[myFetcher response] expectedContentLength] (and may be -1 for unknown +// download sizes.) +// +// +// Automatic retrying of fetches +// +// The fetcher can optionally create a timer and reattempt certain kinds of +// fetch failures (status codes 408, request timeout; 502, gateway failure; +// 503, service unavailable; 504, gateway timeout; networking errors +// NSURLErrorTimedOut and NSURLErrorNetworkConnectionLost.) The user may +// set a retry selector to customize the type of errors which will be retried. +// +// Retries are done in an exponential-backoff fashion (that is, after 1 second, +// 2, 4, 8, and so on.) +// +// Enabling automatic retries looks like this: +// myFetcher.retryEnabled = YES; +// +// With retries enabled, the completion callbacks are called only +// when no more retries will be attempted. Calling the fetcher's stopFetching +// method will terminate the retry timer, without the finished or failure +// selectors being invoked. +// +// Optionally, the client may set the maximum retry interval: +// myFetcher.maxRetryInterval = 60.0; // in seconds; default is 60 seconds +// // for downloads, 600 for uploads +// +// Servers should never send a 400 or 500 status for errors that are retryable +// by clients, as those values indicate permanent failures. In nearly all +// cases, the default standard retry behavior is correct for clients, and no +// custom client retry behavior is needed or appropriate. Servers that send +// non-retryable status codes and expect the client to retry the request are +// faulty. +// +// Still, the client may provide a block to determine if a status code or other +// error should be retried. The block returns YES to set the retry timer or NO +// to fail without additional fetch attempts. +// +// The retry method may return the |suggestedWillRetry| argument to get the +// default retry behavior. Server status codes are present in the +// error argument, and have the domain kGTMSessionFetcherStatusDomain. The +// user's method may look something like this: +// +// myFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *error, +// GTMSessionFetcherRetryResponse response) { +// // Perhaps examine error.domain and error.code, or fetcher.retryCount +// // +// // Respond with YES to start the retry timer, NO to proceed to the failure +// // callback, or suggestedWillRetry to get default behavior for the +// // current error domain and code values. +// response(suggestedWillRetry); +// }; + + +#import + +#if TARGET_OS_IPHONE +#import +#endif +#if TARGET_OS_WATCH +#import +#endif + +// By default it is stripped from non DEBUG builds. Developers can override +// this in their project settings. +#ifndef STRIP_GTM_FETCH_LOGGING + #if !DEBUG + #define STRIP_GTM_FETCH_LOGGING 1 + #else + #define STRIP_GTM_FETCH_LOGGING 0 + #endif +#endif + +// Logs in debug builds. +#ifndef GTMSESSION_LOG_DEBUG + #if DEBUG + #define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__) + #else + #define GTMSESSION_LOG_DEBUG(...) do { } while (0) + #endif +#endif + +// Asserts in debug builds (or logs in debug builds if GTMSESSION_ASSERT_AS_LOG +// or NS_BLOCK_ASSERTIONS are defined.) +#ifndef GTMSESSION_ASSERT_DEBUG + #if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG + #undef GTMSESSION_ASSERT_AS_LOG + #define GTMSESSION_ASSERT_AS_LOG 1 + #endif + + #if DEBUG && !GTMSESSION_ASSERT_AS_LOG + #define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__) + #elif DEBUG + #define GTMSESSION_ASSERT_DEBUG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); } + #else + #define GTMSESSION_ASSERT_DEBUG(pred, ...) do { } while (0) + #endif +#endif + +// Asserts in debug builds, logs in release builds (or logs in debug builds if +// GTMSESSION_ASSERT_AS_LOG is defined.) +#ifndef GTMSESSION_ASSERT_DEBUG_OR_LOG + #if DEBUG && !GTMSESSION_ASSERT_AS_LOG + #define GTMSESSION_ASSERT_DEBUG_OR_LOG(...) NSAssert(__VA_ARGS__) + #else + #define GTMSESSION_ASSERT_DEBUG_OR_LOG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); } + #endif +#endif + +// Macro useful for examining messages from NSURLSession during debugging. +#if 0 +#define GTM_LOG_SESSION_DELEGATE(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__) +#else +#define GTM_LOG_SESSION_DELEGATE(...) +#endif + +#ifndef GTM_NULLABLE + #if __has_feature(nullability) // Available starting in Xcode 6.3 + #define GTM_NULLABLE_TYPE __nullable + #define GTM_NONNULL_TYPE __nonnull + #define GTM_NULLABLE nullable + #define GTM_NONNULL_DECL nonnull // GTM_NONNULL is used by GTMDefines.h + #define GTM_NULL_RESETTABLE null_resettable + + #define GTM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN + #define GTM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END + #else + #define GTM_NULLABLE_TYPE + #define GTM_NONNULL_TYPE + #define GTM_NULLABLE + #define GTM_NONNULL_DECL + #define GTM_NULL_RESETTABLE + #define GTM_ASSUME_NONNULL_BEGIN + #define GTM_ASSUME_NONNULL_END + #endif // __has_feature(nullability) +#endif // GTM_NULLABLE + +#if (TARGET_OS_TV \ + || TARGET_OS_WATCH \ + || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0)) +#define GTMSESSION_DEPRECATE_ON_2016_SDKS(_MSG) __attribute__((deprecated("" _MSG))) +#else +#define GTMSESSION_DEPRECATE_ON_2016_SDKS(_MSG) +#endif + +#ifndef GTM_DECLARE_GENERICS + #if __has_feature(objc_generics) + #define GTM_DECLARE_GENERICS 1 + #else + #define GTM_DECLARE_GENERICS 0 + #endif +#endif + +#ifndef GTM_NSArrayOf + #if GTM_DECLARE_GENERICS + #define GTM_NSArrayOf(value) NSArray + #define GTM_NSDictionaryOf(key, value) NSDictionary + #else + #define GTM_NSArrayOf(value) NSArray + #define GTM_NSDictionaryOf(key, value) NSDictionary + #endif // __has_feature(objc_generics) +#endif // GTM_NSArrayOf + +// For iOS, the fetcher can declare itself a background task to allow fetches +// to finish when the app leaves the foreground. +// +// (This is unrelated to providing a background configuration, which allows +// out-of-process uploads and downloads.) +// +// To disallow use of background tasks during fetches, the target should define +// GTM_BACKGROUND_TASK_FETCHING to 0, or alternatively may set the +// skipBackgroundTask property to YES. +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !defined(GTM_BACKGROUND_TASK_FETCHING) + #define GTM_BACKGROUND_TASK_FETCHING 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if (TARGET_OS_TV \ + || TARGET_OS_WATCH \ + || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0)) + #ifndef GTM_USE_SESSION_FETCHER + #define GTM_USE_SESSION_FETCHER 1 + #endif +#endif + +#if !defined(GTMBridgeFetcher) + // These bridge macros should be identical in GTMHTTPFetcher.h and GTMSessionFetcher.h + #if GTM_USE_SESSION_FETCHER + // Macros to new fetcher class. + #define GTMBridgeFetcher GTMSessionFetcher + #define GTMBridgeFetcherService GTMSessionFetcherService + #define GTMBridgeFetcherServiceProtocol GTMSessionFetcherServiceProtocol + #define GTMBridgeAssertValidSelector GTMSessionFetcherAssertValidSelector + #define GTMBridgeCookieStorage GTMSessionCookieStorage + #define GTMBridgeCleanedUserAgentString GTMFetcherCleanedUserAgentString + #define GTMBridgeSystemVersionString GTMFetcherSystemVersionString + #define GTMBridgeApplicationIdentifier GTMFetcherApplicationIdentifier + #define kGTMBridgeFetcherStatusDomain kGTMSessionFetcherStatusDomain + #define kGTMBridgeFetcherStatusBadRequest GTMSessionFetcherStatusBadRequest + #else + // Macros to old fetcher class. + #define GTMBridgeFetcher GTMHTTPFetcher + #define GTMBridgeFetcherService GTMHTTPFetcherService + #define GTMBridgeFetcherServiceProtocol GTMHTTPFetcherServiceProtocol + #define GTMBridgeAssertValidSelector GTMAssertSelectorNilOrImplementedWithArgs + #define GTMBridgeCookieStorage GTMCookieStorage + #define GTMBridgeCleanedUserAgentString GTMCleanedUserAgentString + #define GTMBridgeSystemVersionString GTMSystemVersionString + #define GTMBridgeApplicationIdentifier GTMApplicationIdentifier + #define kGTMBridgeFetcherStatusDomain kGTMHTTPFetcherStatusDomain + #define kGTMBridgeFetcherStatusBadRequest kGTMHTTPFetcherStatusBadRequest + #endif // GTM_USE_SESSION_FETCHER +#endif + +GTM_ASSUME_NONNULL_BEGIN + +// Notifications +// +// Fetch started and stopped, and fetch retry delay started and stopped. +extern NSString *const kGTMSessionFetcherStartedNotification; +extern NSString *const kGTMSessionFetcherStoppedNotification; +extern NSString *const kGTMSessionFetcherRetryDelayStartedNotification; +extern NSString *const kGTMSessionFetcherRetryDelayStoppedNotification; + +// Completion handler notification. This is intended for use by code capturing +// and replaying fetch requests and results for testing. For fetches where +// destinationFileURL or accumulateDataBlock is set for the fetcher, the data +// will be nil for successful fetches. +// +// This notification is posted on the main thread. +extern NSString *const kGTMSessionFetcherCompletionInvokedNotification; +extern NSString *const kGTMSessionFetcherCompletionDataKey; +extern NSString *const kGTMSessionFetcherCompletionErrorKey; + +// Constants for NSErrors created by the fetcher (excluding server status errors, +// and error objects originating in the OS.) +extern NSString *const kGTMSessionFetcherErrorDomain; + +// The fetcher turns server error status values (3XX, 4XX, 5XX) into NSErrors +// with domain kGTMSessionFetcherStatusDomain. +// +// Any server response body data accompanying the status error is added to the +// userInfo dictionary with key kGTMSessionFetcherStatusDataKey. +extern NSString *const kGTMSessionFetcherStatusDomain; +extern NSString *const kGTMSessionFetcherStatusDataKey; + +// When a fetch fails with an error, these keys are included in the error userInfo +// dictionary if retries were attempted. +extern NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey; +extern NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey; + +// Background session support requires access to NSUserDefaults. +// If [NSUserDefaults standardUserDefaults] doesn't yield the correct NSUserDefaults for your usage, +// ie for an App Extension, then implement this class/method to return the correct NSUserDefaults. +// https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW6 +@interface GTMSessionFetcherUserDefaultsFactory : NSObject + ++ (NSUserDefaults *)fetcherUserDefaults; + +@end + +#ifdef __cplusplus +} +#endif + +typedef NS_ENUM(NSInteger, GTMSessionFetcherError) { + GTMSessionFetcherErrorDownloadFailed = -1, + GTMSessionFetcherErrorUploadChunkUnavailable = -2, + GTMSessionFetcherErrorBackgroundExpiration = -3, + GTMSessionFetcherErrorBackgroundFetchFailed = -4, + GTMSessionFetcherErrorInsecureRequest = -5, + GTMSessionFetcherErrorTaskCreationFailed = -6, +}; + +typedef NS_ENUM(NSInteger, GTMSessionFetcherStatus) { + // Standard http status codes. + GTMSessionFetcherStatusNotModified = 304, + GTMSessionFetcherStatusBadRequest = 400, + GTMSessionFetcherStatusUnauthorized = 401, + GTMSessionFetcherStatusForbidden = 403, + GTMSessionFetcherStatusPreconditionFailed = 412 +}; + +#ifdef __cplusplus +extern "C" { +#endif + +@class GTMSessionCookieStorage; +@class GTMSessionFetcher; + +// The configuration block is for modifying the NSURLSessionConfiguration only. +// DO NOT change any fetcher properties in the configuration block. +typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher, + NSURLSessionConfiguration *configuration); +typedef void (^GTMSessionFetcherSystemCompletionHandler)(void); +typedef void (^GTMSessionFetcherCompletionHandler)(NSData * GTM_NULLABLE_TYPE data, + NSError * GTM_NULLABLE_TYPE error); +typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream); +typedef void (^GTMSessionFetcherBodyStreamProvider)(GTMSessionFetcherBodyStreamProviderResponse response); +typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)(NSURLSessionResponseDisposition disposition); +typedef void (^GTMSessionFetcherDidReceiveResponseBlock)(NSURLResponse *response, + GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock); +typedef void (^GTMSessionFetcherChallengeDispositionBlock)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential); +typedef void (^GTMSessionFetcherChallengeBlock)(GTMSessionFetcher *fetcher, + NSURLAuthenticationChallenge *challenge, + GTMSessionFetcherChallengeDispositionBlock dispositionBlock); +typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest * GTM_NULLABLE_TYPE redirectedRequest); +typedef void (^GTMSessionFetcherWillRedirectBlock)(NSHTTPURLResponse *redirectResponse, + NSURLRequest *redirectRequest, + GTMSessionFetcherWillRedirectResponse response); +typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData * GTM_NULLABLE_TYPE buffer); +typedef void (^GTMSessionFetcherSimulateByteTransferBlock)(NSData * GTM_NULLABLE_TYPE buffer, + int64_t bytesWritten, + int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite); +typedef void (^GTMSessionFetcherReceivedProgressBlock)(int64_t bytesWritten, + int64_t totalBytesWritten); +typedef void (^GTMSessionFetcherDownloadProgressBlock)(int64_t bytesWritten, + int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite); +typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent, + int64_t totalBytesSent, + int64_t totalBytesExpectedToSend); +typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)(NSCachedURLResponse * GTM_NULLABLE_TYPE cachedResponse); +typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)(NSCachedURLResponse *proposedResponse, + GTMSessionFetcherWillCacheURLResponseResponse responseBlock); +typedef void (^GTMSessionFetcherRetryResponse)(BOOL shouldRetry); +typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry, + NSError * GTM_NULLABLE_TYPE error, + GTMSessionFetcherRetryResponse response); + +typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse * GTM_NULLABLE_TYPE response, + NSData * GTM_NULLABLE_TYPE data, + NSError * GTM_NULLABLE_TYPE error); +typedef void (^GTMSessionFetcherTestBlock)(GTMSessionFetcher *fetcherToTest, + GTMSessionFetcherTestResponse testResponse); + +void GTMSessionFetcherAssertValidSelector(id GTM_NULLABLE_TYPE obj, SEL GTM_NULLABLE_TYPE sel, ...); + +// Utility functions for applications self-identifying to servers via a +// user-agent header + +// The "standard" user agent includes the application identifier, taken from the bundle, +// followed by a space and the system version string. Pass nil to use +mainBundle as the source +// of the bundle identifier. +// +// Applications may use this as a starting point for their own user agent strings, perhaps +// with additional sections appended. Use GTMFetcherCleanedUserAgentString() below to +// clean up any string being added to the user agent. +NSString *GTMFetcherStandardUserAgentString(NSBundle * GTM_NULLABLE_TYPE bundle); + +// Make a generic name and version for the current application, like +// com.example.MyApp/1.2.3 relying on the bundle identifier and the +// CFBundleShortVersionString or CFBundleVersion. +// +// The bundle ID may be overridden as the base identifier string by +// adding to the bundle's Info.plist a "GTMUserAgentID" key. +// +// If no bundle ID or override is available, the process name preceded +// by "proc_" is used. +NSString *GTMFetcherApplicationIdentifier(NSBundle * GTM_NULLABLE_TYPE bundle); + +// Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1 hw/iPod1_1" +NSString *GTMFetcherSystemVersionString(void); + +// Make a parseable user-agent identifier from the given string, replacing whitespace +// and commas with underscores, and removing other characters that may interfere +// with parsing of the full user-agent string. +// +// For example, @"[My App]" would become @"My_App" +NSString *GTMFetcherCleanedUserAgentString(NSString *str); + +// Grab the data from an input stream. Since streams cannot be assumed to be rewindable, +// this may be destructive; the caller can try to rewind the stream (by setting the +// NSStreamFileCurrentOffsetKey property) or can just use the NSData to make a new +// NSInputStream. This function is intended to facilitate testing rather than be used in +// production. +// +// This function operates synchronously on the current thread. Depending on how the +// input stream is implemented, it may be appropriate to dispatch to a different +// queue before calling this function. +// +// Failure is indicated by a returned data value of nil. +NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError); + +#ifdef __cplusplus +} // extern "C" +#endif + + +#if !GTM_USE_SESSION_FETCHER +@protocol GTMHTTPFetcherServiceProtocol; +#endif + +// This protocol allows abstract references to the fetcher service, primarily for +// fetchers (which may be compiled without the fetcher service class present.) +// +// Apps should not need to use this protocol. +@protocol GTMSessionFetcherServiceProtocol +// This protocol allows us to call into the service without requiring +// GTMSessionFetcherService sources in this project + +@property(atomic, strong) dispatch_queue_t callbackQueue; + +- (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher; + +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request; +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher; + +@property(atomic, assign) BOOL reuseSession; +- (GTM_NULLABLE NSURLSession *)session; +- (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation; +- (GTM_NULLABLE id)sessionDelegate; +- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate; + +// Methods for compatibility with the old GTMHTTPFetcher. +@property(readonly, strong, GTM_NULLABLE) NSOperationQueue *delegateQueue; + +@end // @protocol GTMSessionFetcherServiceProtocol + +#ifndef GTM_FETCHER_AUTHORIZATION_PROTOCOL +#define GTM_FETCHER_AUTHORIZATION_PROTOCOL 1 +@protocol GTMFetcherAuthorizationProtocol +@required +// This protocol allows us to call the authorizer without requiring its sources +// in this project. +- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request + delegate:(id)delegate + didFinishSelector:(SEL)sel; + +- (void)stopAuthorization; + +- (void)stopAuthorizationForRequest:(NSURLRequest *)request; + +- (BOOL)isAuthorizingRequest:(NSURLRequest *)request; + +- (BOOL)isAuthorizedRequest:(NSURLRequest *)request; + +@property(strong, readonly, GTM_NULLABLE) NSString *userEmail; + +@optional + +// Indicate if authorization may be attempted. Even if this succeeds, +// authorization may fail if the user's permissions have been revoked. +@property(readonly) BOOL canAuthorize; + +// For development only, allow authorization of non-SSL requests, allowing +// transmission of the bearer token unencrypted. +@property(assign) BOOL shouldAuthorizeAllRequests; + +- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request + completionHandler:(void (^)(NSError * GTM_NULLABLE_TYPE error))handler; + +#if GTM_USE_SESSION_FETCHER +@property (weak, GTM_NULLABLE) id fetcherService; +#else +@property (weak, GTM_NULLABLE) id fetcherService; +#endif + +- (BOOL)primeForRefresh; + +@end +#endif // GTM_FETCHER_AUTHORIZATION_PROTOCOL + +#if TARGET_OS_IPHONE +// A protocol for an alternative target for messages from GTMSessionFetcher to UIApplication. +// Set the target using +[GTMSessionFetcher setSubstituteUIApplication:] +@protocol GTMUIApplicationProtocol +- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName + expirationHandler:(void(^ __nullable)(void))handler; +- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier; +@end +#endif + +#pragma mark - + +// GTMSessionFetcher objects are used for async retrieval of an http get or post +// +// See additional comments at the beginning of this file +@interface GTMSessionFetcher : NSObject + +// Create a fetcher +// +// fetcherWithRequest will return an autoreleased fetcher, but if +// the connection is successfully created, the connection should retain the +// fetcher for the life of the connection as well. So the caller doesn't have +// to retain the fetcher explicitly unless they want to be able to cancel it. ++ (instancetype)fetcherWithRequest:(GTM_NULLABLE NSURLRequest *)request; + +// Convenience methods that make a request, like +fetcherWithRequest ++ (instancetype)fetcherWithURL:(NSURL *)requestURL; ++ (instancetype)fetcherWithURLString:(NSString *)requestURLString; + +// Methods for creating fetchers to continue previous fetches. ++ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData; ++ (GTM_NULLABLE instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier; + +// Returns an array of currently active fetchers for background sessions, +// both restarted and newly created ones. ++ (GTM_NSArrayOf(GTMSessionFetcher *) *)fetchersForBackgroundSessions; + +// Designated initializer. +// +// Applications should create fetchers with a "fetcherWith..." method on a fetcher +// service or a class method, not with this initializer. +// +// The configuration should typically be nil. Applications needing to customize +// the configuration may do so by setting the configurationBlock property. +- (instancetype)initWithRequest:(GTM_NULLABLE NSURLRequest *)request + configuration:(GTM_NULLABLE NSURLSessionConfiguration *)configuration; + +// The fetcher's request. This may not be set after beginFetch has been invoked. The request +// may change due to redirects. +@property(strong, GTM_NULLABLE) NSURLRequest *request; + +// Set a header field value on the request. Header field value changes will not +// affect a fetch after the fetch has begun. +- (void)setRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field; + +// The fetcher's request (deprecated.) +// +// Exposing a mutable object in the interface was convenient but a bad design decision due +// to thread-safety requirements. Clients should use the request property and +// setRequestValue:forHTTPHeaderField: instead. +@property(atomic, readonly, GTM_NULLABLE) NSMutableURLRequest *mutableRequest + GTMSESSION_DEPRECATE_ON_2016_SDKS("use 'request' or '-setRequestValue:forHTTPHeaderField:'"); + +// Data used for resuming a download task. +@property(atomic, readonly, GTM_NULLABLE) NSData *downloadResumeData; + +// The configuration; this must be set before the fetch begins. If no configuration is +// set or inherited from the fetcher service, then the fetcher uses an ephemeral config. +// +// NOTE: This property should typically be nil. Applications needing to customize +// the configuration should do so by setting the configurationBlock property. +// That allows the fetcher to pick an appropriate base configuration, with the +// application setting only the configuration properties it needs to customize. +@property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration; + +// A block the client may use to customize the configuration used to create the session. +// +// This is called synchronously, either on the thread that begins the fetch or, during a retry, +// on the main thread. The configuration block may be called repeatedly if multiple fetchers are +// created. +// +// The configuration block is for modifying the NSURLSessionConfiguration only. +// DO NOT change any fetcher properties in the configuration block. Fetcher properties +// may be set in the fetcher service prior to fetcher creation, or on the fetcher prior +// to invoking beginFetch. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock; + +// A session is created as needed by the fetcher. A fetcher service object +// may maintain sessions for multiple fetches to the same host. +@property(atomic, strong, GTM_NULLABLE) NSURLSession *session; + +// The task in flight. +@property(atomic, readonly, GTM_NULLABLE) NSURLSessionTask *sessionTask; + +// The background session identifier. +@property(atomic, readonly, GTM_NULLABLE) NSString *sessionIdentifier; + +// Indicates a fetcher created to finish a background session task. +@property(atomic, readonly) BOOL wasCreatedFromBackgroundSession; + +// Additional user-supplied data to encode into the session identifier. Since session identifier +// length limits are unspecified, this should be kept small. Key names beginning with an underscore +// are reserved for use by the fetcher. +@property(atomic, strong, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *sessionUserInfo; + +// The human-readable description to be assigned to the task. +@property(atomic, copy, GTM_NULLABLE) NSString *taskDescription; + +// The priority assigned to the task, if any. Use NSURLSessionTaskPriorityLow, +// NSURLSessionTaskPriorityDefault, or NSURLSessionTaskPriorityHigh. +@property(atomic, assign) float taskPriority; + +// The fetcher encodes information used to resume a session in the session identifier. +// This method, intended for internal use returns the encoded information. The sessionUserInfo +// dictionary is stored as identifier metadata. +- (GTM_NULLABLE GTM_NSDictionaryOf(NSString *, NSString *) *)sessionIdentifierMetadata; + +#if TARGET_OS_IPHONE +// The app should pass to this method the completion handler passed in the app delegate method +// application:handleEventsForBackgroundURLSession:completionHandler: ++ (void)application:(UIApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler; +#endif + +// Indicate that a newly created session should be a background session. +// A new session identifier will be created by the fetcher. +// +// Warning: The only thing background sessions are for is rare download +// of huge, batched files of data. And even just for those, there's a lot +// of pain and hackery needed to get transfers to actually happen reliably +// with background sessions. +// +// Don't try to upload or download in many background sessions, since the system +// will impose an exponentially increasing time penalty to prevent the app from +// getting too much background execution time. +// +// References: +// +// "Moving to Fewer, Larger Transfers" +// https://forums.developer.apple.com/thread/14853 +// +// "NSURLSession’s Resume Rate Limiter" +// https://forums.developer.apple.com/thread/14854 +// +// "Background Session Task state persistence" +// https://forums.developer.apple.com/thread/11554 +// +@property(assign) BOOL useBackgroundSession; + +// Indicates if the fetcher was started using a background session. +@property(atomic, readonly, getter=isUsingBackgroundSession) BOOL usingBackgroundSession; + +// Indicates if uploads should use an upload task. This is always set for file or stream-provider +// bodies, but may be set explicitly for NSData bodies. +@property(atomic, assign) BOOL useUploadTask; + +// Indicates that the fetcher is using a session that may be shared with other fetchers. +@property(atomic, readonly) BOOL canShareSession; + +// By default, the fetcher allows only secure (https) schemes unless this +// property is set, or the GTM_ALLOW_INSECURE_REQUESTS build flag is set. +// +// For example, during debugging when fetching from a development server that lacks SSL support, +// this may be set to @[ @"http" ], or when the fetcher is used to retrieve local files, +// this may be set to @[ @"file" ]. +// +// This should be left as nil for release builds to avoid creating the opportunity for +// leaking private user behavior and data. If a server is providing insecure URLs +// for fetching by the client app, report the problem as server security & privacy bug. +// +// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when +// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist. +@property(atomic, copy, GTM_NULLABLE) GTM_NSArrayOf(NSString *) *allowedInsecureSchemes; + +// By default, the fetcher prohibits localhost requests unless this property is set, +// or the GTM_ALLOW_INSECURE_REQUESTS build flag is set. +// +// For localhost requests, the URL scheme is not checked when this property is set. +// +// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when +// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist. +@property(atomic, assign) BOOL allowLocalhostRequest; + +// By default, the fetcher requires valid server certs. This may be bypassed +// temporarily for development against a test server with an invalid cert. +@property(atomic, assign) BOOL allowInvalidServerCertificates; + +// Cookie storage object for this fetcher. If nil, the fetcher will use a static cookie +// storage instance shared among fetchers. If this fetcher was created by a fetcher service +// object, it will be set to use the service object's cookie storage. See Cookies section above for +// the full discussion. +// +// Because as of Jan 2014 standalone instances of NSHTTPCookieStorage do not actually +// store any cookies (Radar 15735276) we use our own subclass, GTMSessionCookieStorage, +// to hold cookies in memory. +@property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage; + +// Setting the credential is optional; it is used if the connection receives +// an authentication challenge. +@property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential; + +// Setting the proxy credential is optional; it is used if the connection +// receives an authentication challenge from a proxy. +@property(atomic, strong, GTM_NULLABLE) NSURLCredential *proxyCredential; + +// If body data, body file URL, or body stream provider is not set, then a GET request +// method is assumed. +@property(atomic, strong, GTM_NULLABLE) NSData *bodyData; + +// File to use as the request body. This forces use of an upload task. +@property(atomic, strong, GTM_NULLABLE) NSURL *bodyFileURL; + +// Length of body to send, expected or actual. +@property(atomic, readonly) int64_t bodyLength; + +// The body stream provider may be called repeatedly to provide a body. +// Setting a body stream provider forces use of an upload task. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherBodyStreamProvider bodyStreamProvider; + +// Object to add authorization to the request, if needed. +// +// This may not be changed once beginFetch has been invoked. +@property(atomic, strong, GTM_NULLABLE) id authorizer; + +// The service object that created and monitors this fetcher, if any. +@property(atomic, strong) id service; + +// The host, if any, used to classify this fetcher in the fetcher service. +@property(atomic, copy, GTM_NULLABLE) NSString *serviceHost; + +// The priority, if any, used for starting fetchers in the fetcher service. +// +// Lower values are higher priority; the default is 0, and values may +// be negative or positive. This priority affects only the start order of +// fetchers that are being delayed by a fetcher service when the running fetchers +// exceeds the service's maxRunningFetchersPerHost. A priority of NSIntegerMin will +// exempt this fetcher from delay. +@property(atomic, assign) NSInteger servicePriority; + +// The delegate's optional didReceiveResponse block may be used to inspect or alter +// the session task response. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock; + +// The delegate's optional challenge block may be used to inspect or alter +// the session task challenge. +// +// If this block is not set, the fetcher's default behavior for the NSURLSessionTask +// didReceiveChallenge: delegate method is to use the fetcher's respondToChallenge: method +// which relies on the fetcher's credential and proxyCredential properties. +// +// Warning: This may be called repeatedly if the challenge fails. Check +// challenge.previousFailureCount to identify repeated invocations. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock; + +// The delegate's optional willRedirect block may be used to inspect or alter +// the redirection. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillRedirectBlock willRedirectBlock; + +// The optional send progress block reports body bytes uploaded. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherSendProgressBlock sendProgressBlock; + +// The optional accumulate block may be set by clients wishing to accumulate data +// themselves rather than let the fetcher append each buffer to an NSData. +// +// When this is called with nil data (such as on redirect) the client +// should empty its accumulation buffer. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherAccumulateDataBlock accumulateDataBlock; + +// The optional received progress block may be used to monitor data +// received from a data task. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherReceivedProgressBlock receivedProgressBlock; + +// The delegate's optional downloadProgress block may be used to monitor download +// progress in writing to disk. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDownloadProgressBlock downloadProgressBlock; + +// The delegate's optional willCacheURLResponse block may be used to alter the cached +// NSURLResponse. The user may prevent caching by passing nil to the block's response. +// +// This is called on the callback queue. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock; + +// Enable retrying; see comments at the top of this file. Setting +// retryEnabled=YES resets the min and max retry intervals. +@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled; + +// Retry block is optional for retries. +// +// If present, this block should call the response block with YES to cause a retry or NO to end the +// fetch. +// See comments at the top of this file. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherRetryBlock retryBlock; + +// Retry intervals must be strictly less than maxRetryInterval, else +// they will be limited to maxRetryInterval and no further retries will +// be attempted. Setting maxRetryInterval to 0.0 will reset it to the +// default value, 60 seconds for downloads and 600 seconds for uploads. +@property(atomic, assign) NSTimeInterval maxRetryInterval; + +// Starting retry interval. Setting minRetryInterval to 0.0 will reset it +// to a random value between 1.0 and 2.0 seconds. Clients should normally not +// set this except for unit testing. +@property(atomic, assign) NSTimeInterval minRetryInterval; + +// Multiplier used to increase the interval between retries, typically 2.0. +// Clients should not need to set this. +@property(atomic, assign) double retryFactor; + +// Number of retries attempted. +@property(atomic, readonly) NSUInteger retryCount; + +// Interval delay to precede next retry. +@property(atomic, readonly) NSTimeInterval nextRetryInterval; + +#if GTM_BACKGROUND_TASK_FETCHING +// Skip use of a UIBackgroundTask, thus requiring fetches to complete when the app is in the +// foreground. +// +// Targets should define GTM_BACKGROUND_TASK_FETCHING to 0 to avoid use of a UIBackgroundTask +// on iOS to allow fetches to complete in the background. This property is available when +// it's not practical to set the preprocessor define. +@property(atomic, assign) BOOL skipBackgroundTask; +#endif // GTM_BACKGROUND_TASK_FETCHING + +// Begin fetching the request +// +// The delegate may optionally implement the callback or pass nil for the selector or handler. +// +// The delegate and all callback blocks are retained between the beginFetch call until after the +// finish callback, or until the fetch is stopped. +// +// An error is passed to the callback for server statuses 300 or +// higher, with the status stored as the error object's code. +// +// finishedSEL has a signature like: +// - (void)fetcher:(GTMSessionFetcher *)fetcher +// finishedWithData:(NSData *)data +// error:(NSError *)error; +// +// If the application has specified a destinationFileURL or an accumulateDataBlock +// for the fetcher, the data parameter passed to the callback will be nil. + +- (void)beginFetchWithDelegate:(GTM_NULLABLE id)delegate + didFinishSelector:(GTM_NULLABLE SEL)finishedSEL; + +- (void)beginFetchWithCompletionHandler:(GTM_NULLABLE GTMSessionFetcherCompletionHandler)handler; + +// Returns YES if this fetcher is in the process of fetching a URL. +@property(atomic, readonly, getter=isFetching) BOOL fetching; + +// Cancel the fetch of the request that's currently in progress. The completion handler +// will not be called. +- (void)stopFetching; + +// A block to be called when the fetch completes. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherCompletionHandler completionHandler; + +// A block to be called if download resume data becomes available. +@property(atomic, strong, GTM_NULLABLE) void (^resumeDataBlock)(NSData *); + +// Return the status code from the server response. +@property(atomic, readonly) NSInteger statusCode; + +// Return the http headers from the response. +@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *responseHeaders; + +// The response, once it's been received. +@property(atomic, strong, readonly, GTM_NULLABLE) NSURLResponse *response; + +// Bytes downloaded so far. +@property(atomic, readonly) int64_t downloadedLength; + +// Buffer of currently-downloaded data, if available. +@property(atomic, readonly, strong, GTM_NULLABLE) NSData *downloadedData; + +// Local path to which the downloaded file will be moved. +// +// If a file already exists at the path, it will be overwritten. +// Will create the enclosing folders if they are not present. +@property(atomic, strong, GTM_NULLABLE) NSURL *destinationFileURL; + +// The time this fetcher originally began fetching. This is useful as a time +// barrier for ignoring irrelevant fetch notifications or callbacks. +@property(atomic, strong, readonly, GTM_NULLABLE) NSDate *initialBeginFetchDate; + +// userData is retained solely for the convenience of the client. +@property(atomic, strong, GTM_NULLABLE) id userData; + +// Stored property values are retained solely for the convenience of the client. +@property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties; + +- (void)setProperty:(GTM_NULLABLE id)obj forKey:(NSString *)key; // Pass nil for obj to remove the property. +- (GTM_NULLABLE id)propertyForKey:(NSString *)key; + +- (void)addPropertiesFromDictionary:(GTM_NSDictionaryOf(NSString *, id) *)dict; + +// Comments are useful for logging, so are strongly recommended for each fetcher. +@property(atomic, copy, GTM_NULLABLE) NSString *comment; + +- (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2); + +// Log of request and response, if logging is enabled +@property(atomic, copy, GTM_NULLABLE) NSString *log; + +// Callbacks are run on this queue. If none is supplied, the main queue is used. +@property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue; + +// The queue used internally by the session to invoke its delegate methods in the fetcher. +// +// Application callbacks are always called by the fetcher on the callbackQueue above, +// not on this queue. Apps should generally not change this queue. +// +// The default delegate queue is the main queue. +// +// This value is ignored after the session has been created, so this +// property should be set in the fetcher service rather in the fetcher as it applies +// to a shared session. +@property(atomic, strong, GTM_NULL_RESETTABLE) NSOperationQueue *sessionDelegateQueue; + +// Spin the run loop or sleep the thread, discarding events, until the fetch has completed. +// +// This is only for use in testing or in tools without a user interface. +// +// Note: Synchronous fetches should never be used by shipping apps; they are +// sufficient reason for rejection from the app store. +// +// Returns NO if timed out. +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds; + +// Test block is optional for testing. +// +// If present, this block will cause the fetcher to skip starting the session, and instead +// use the test block response values when calling the completion handler and delegate code. +// +// Test code can set this on the fetcher or on the fetcher service. For testing libraries +// that use a fetcher without exposing either the fetcher or the fetcher service, the global +// method setGlobalTestBlock: will set the block for all fetchers that do not have a test +// block set. +// +// The test code can pass nil for all response parameters to indicate that the fetch +// should proceed. +// +// Applications can exclude test block support by setting GTM_DISABLE_FETCHER_TEST_BLOCK. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock; + ++ (void)setGlobalTestBlock:(GTM_NULLABLE GTMSessionFetcherTestBlock)block; + +// When using the testBlock, |testBlockAccumulateDataChunkCount| is the desired number of chunks to +// divide the response data into if the client has streaming enabled. The data will be divided up to +// |testBlockAccumulateDataChunkCount| chunks; however, the exact amount may vary depending on the +// size of the response data (e.g. a 1-byte response can only be divided into one chunk). +@property(atomic, readwrite) NSUInteger testBlockAccumulateDataChunkCount; + +#if TARGET_OS_IPHONE +// For testing or to override UIApplication invocations, apps may specify an alternative +// target for messages to UIApplication. ++ (void)setSubstituteUIApplication:(nullable id)substituteUIApplication; ++ (nullable id)substituteUIApplication; +#endif // TARGET_OS_IPHONE + +// Exposed for testing. ++ (GTMSessionCookieStorage *)staticCookieStorage; ++ (BOOL)appAllowsInsecureRequests; + +#if STRIP_GTM_FETCH_LOGGING +// If logging is stripped, provide a stub for the main method +// for controlling logging. ++ (void)setLoggingEnabled:(BOOL)flag; ++ (BOOL)isLoggingEnabled; + +#else + +// These methods let an application log specific body text, such as the text description of a binary +// request or response. The application should set the fetcher to defer response body logging until +// the response has been received and the log response body has been set by the app. For example: +// +// fetcher.logRequestBody = [binaryObject stringDescription]; +// fetcher.deferResponseBodyLogging = YES; +// [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { +// if (error == nil) { +// fetcher.logResponseBody = [[[MyThing alloc] initWithData:data] stringDescription]; +// } +// fetcher.deferResponseBodyLogging = NO; +// }]; + +@property(atomic, copy, GTM_NULLABLE) NSString *logRequestBody; +@property(atomic, assign) BOOL deferResponseBodyLogging; +@property(atomic, copy, GTM_NULLABLE) NSString *logResponseBody; + +// Internal logging support. +@property(atomic, readonly) NSData *loggedStreamData; +@property(atomic, assign) BOOL hasLoggedError; +@property(atomic, strong, GTM_NULLABLE) NSURL *redirectedFromURL; +- (void)appendLoggedStreamData:(NSData *)dataToAdd; +- (void)clearLoggedStreamData; + +#endif // STRIP_GTM_FETCH_LOGGING + +@end + +@interface GTMSessionFetcher (BackwardsCompatibilityOnly) +// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves. +// This method is just for compatibility with the old GTMHTTPFetcher class. +- (void)setCookieStorageMethod:(NSInteger)method; +@end + +// Until we can just instantiate NSHTTPCookieStorage for local use, we'll +// implement all the public methods ourselves. This stores cookies only in +// memory. Additional methods are provided for testing. +// +// iOS 9/OS X 10.11 added +[NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:] +// which may also be used to create cookie storage. +@interface GTMSessionCookieStorage : NSHTTPCookieStorage + +// Add the array off cookies to the storage, replacing duplicates. +// Also removes expired cookies from the storage. +- (void)setCookies:(GTM_NULLABLE GTM_NSArrayOf(NSHTTPCookie *) *)cookies; + +- (void)removeAllCookies; + +@end + +// Macros to monitor synchronization blocks in debug builds. +// These report problems using GTMSessionCheckDebug. +// +// GTMSessionMonitorSynchronized Start monitoring a top-level-only +// @sync scope. +// GTMSessionMonitorRecursiveSynchronized Start monitoring a top-level or +// recursive @sync scope. +// GTMSessionCheckSynchronized Verify that the current execution +// is inside a @sync scope. +// GTMSessionCheckNotSynchronized Verify that the current execution +// is not inside a @sync scope. +// +// Example usage: +// +// - (void)myExternalMethod { +// @synchronized(self) { +// GTMSessionMonitorSynchronized(self) +// +// - (void)myInternalMethod { +// GTMSessionCheckSynchronized(self); +// +// - (void)callMyCallbacks { +// GTMSessionCheckNotSynchronized(self); +// +// GTMSessionCheckNotSynchronized is available for verifying the code isn't +// in a deadlockable @sync state when posting notifications and invoking +// callbacks. Don't use GTMSessionCheckNotSynchronized immediately before a +// @sync scope; the normal recursiveness check of GTMSessionMonitorSynchronized +// can catch those. + +#ifdef __OBJC__ +#if DEBUG + #define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) \ + varname ## counter + #define __GTMSessionMonitorSynchronizedVariable(varname, counter) \ + __GTMSessionMonitorSynchronizedVariableInner(varname, counter) + + #define GTMSessionMonitorSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id \ + __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:NO \ + functionName:__func__] + + #define GTMSessionMonitorRecursiveSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id \ + __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:YES \ + functionName:__func__] + + #define GTMSessionCheckSynchronized(obj) { \ + GTMSESSION_ASSERT_DEBUG( \ + [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \ + @" on " #obj " in %s. Call stack:\n%@", \ + __func__, [NSThread callStackSymbols]); \ + } + + #define GTMSessionCheckNotSynchronized(obj) { \ + GTMSESSION_ASSERT_DEBUG( \ + ![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \ + @" on " #obj " in %s by %@. Call stack:\n%@", __func__, \ + [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + [NSThread callStackSymbols]); \ + } + +// GTMSessionSyncMonitorInternal is a private class that keeps track of the +// beginning and end of synchronized scopes. +// +// This class should not be used directly, but only via the +// GTMSessionMonitorSynchronized macro. +@interface GTMSessionSyncMonitorInternal : NSObject +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName; +// Return the names of the functions that hold sync on the object, or nil if none. ++ (NSArray *)functionsHoldingSynchronizationOnObject:(id)object; +@end + +#else + #define GTMSessionMonitorSynchronized(obj) do { } while (0) + #define GTMSessionMonitorRecursiveSynchronized(obj) do { } while (0) + #define GTMSessionCheckSynchronized(obj) do { } while (0) + #define GTMSessionCheckNotSynchronized(obj) do { } while (0) +#endif // !DEBUG +#endif // __OBJC__ + + +GTM_ASSUME_NONNULL_END diff --git a/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m new file mode 100644 index 0000000..e3f52d8 --- /dev/null +++ b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m @@ -0,0 +1,4549 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcher.h" + +#import + +#ifndef STRIP_GTM_FETCH_LOGGING + #error GTMSessionFetcher headers should have defaulted this if it wasn't already defined. +#endif + +GTM_ASSUME_NONNULL_BEGIN + +NSString *const kGTMSessionFetcherStartedNotification = @"kGTMSessionFetcherStartedNotification"; +NSString *const kGTMSessionFetcherStoppedNotification = @"kGTMSessionFetcherStoppedNotification"; +NSString *const kGTMSessionFetcherRetryDelayStartedNotification = @"kGTMSessionFetcherRetryDelayStartedNotification"; +NSString *const kGTMSessionFetcherRetryDelayStoppedNotification = @"kGTMSessionFetcherRetryDelayStoppedNotification"; + +NSString *const kGTMSessionFetcherCompletionInvokedNotification = @"kGTMSessionFetcherCompletionInvokedNotification"; +NSString *const kGTMSessionFetcherCompletionDataKey = @"data"; +NSString *const kGTMSessionFetcherCompletionErrorKey = @"error"; + +NSString *const kGTMSessionFetcherErrorDomain = @"com.google.GTMSessionFetcher"; +NSString *const kGTMSessionFetcherStatusDomain = @"com.google.HTTPStatus"; +NSString *const kGTMSessionFetcherStatusDataKey = @"data"; // data returned with a kGTMSessionFetcherStatusDomain error + +NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey = @"kGTMSessionFetcherNumberOfRetriesDoneKey"; +NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey = @"kGTMSessionFetcherElapsedIntervalWithRetriesKey"; + +static NSString *const kGTMSessionIdentifierPrefix = @"com.google.GTMSessionFetcher"; +static NSString *const kGTMSessionIdentifierDestinationFileURLMetadataKey = @"_destURL"; +static NSString *const kGTMSessionIdentifierBodyFileURLMetadataKey = @"_bodyURL"; + +// The default max retry interview is 10 minutes for uploads (POST/PUT/PATCH), +// 1 minute for downloads. +static const NSTimeInterval kUnsetMaxRetryInterval = -1.0; +static const NSTimeInterval kDefaultMaxDownloadRetryInterval = 60.0; +static const NSTimeInterval kDefaultMaxUploadRetryInterval = 60.0 * 10.; + +#ifdef GTMSESSION_PERSISTED_DESTINATION_KEY +// Projects using unique class names should also define a unique persisted destination key. +static NSString * const kGTMSessionFetcherPersistedDestinationKey = + GTMSESSION_PERSISTED_DESTINATION_KEY; +#else +static NSString * const kGTMSessionFetcherPersistedDestinationKey = + @"com.google.GTMSessionFetcher.downloads"; +#endif + +GTM_ASSUME_NONNULL_END + +// +// GTMSessionFetcher +// + +#if 0 +#define GTM_LOG_BACKGROUND_SESSION(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__) +#else +#define GTM_LOG_BACKGROUND_SESSION(...) +#endif + +#ifndef GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY + #if (TARGET_OS_TV \ + || TARGET_OS_WATCH \ + || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0)) + #define GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY 1 + #endif +#endif + +@interface GTMSessionFetcher () + +@property(atomic, strong, readwrite, GTM_NULLABLE) NSData *downloadedData; +@property(atomic, strong, readwrite, GTM_NULLABLE) NSData *downloadResumeData; + +#if GTM_BACKGROUND_TASK_FETCHING +// Should always be accessed within an @synchranized(self). +@property(assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier; +#endif + +@property(atomic, readwrite, getter=isUsingBackgroundSession) BOOL usingBackgroundSession; + +@end + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (GTMSessionFetcherLoggingInternal) +- (void)logFetchWithError:(NSError *)error; +- (void)logNowWithError:(GTM_NULLABLE NSError *)error; +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream; +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider; +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +GTM_ASSUME_NONNULL_BEGIN + +static NSTimeInterval InitialMinRetryInterval(void) { + return 1.0 + ((double)(arc4random_uniform(0x0FFFF)) / (double) 0x0FFFF); +} + +static BOOL IsLocalhost(NSString * GTM_NULLABLE_TYPE host) { + // We check if there's host, and then make the comparisons. + if (host == nil) return NO; + return ([host caseInsensitiveCompare:@"localhost"] == NSOrderedSame + || [host isEqual:@"::1"] + || [host isEqual:@"127.0.0.1"]); +} + +static GTMSessionFetcherTestBlock GTM_NULLABLE_TYPE gGlobalTestBlock; + +@implementation GTMSessionFetcher { + NSMutableURLRequest *_request; // after beginFetch, changed only in delegate callbacks + BOOL _useUploadTask; // immutable after beginFetch + NSURL *_bodyFileURL; // immutable after beginFetch + GTMSessionFetcherBodyStreamProvider _bodyStreamProvider; // immutable after beginFetch + NSURLSession *_session; + BOOL _shouldInvalidateSession; // immutable after beginFetch + NSURLSession *_sessionNeedingInvalidation; + NSURLSessionConfiguration *_configuration; + NSURLSessionTask *_sessionTask; + NSString *_taskDescription; + float _taskPriority; + NSURLResponse *_response; + NSString *_sessionIdentifier; + BOOL _wasCreatedFromBackgroundSession; + BOOL _didCreateSessionIdentifier; + NSString *_sessionIdentifierUUID; + BOOL _userRequestedBackgroundSession; + BOOL _usingBackgroundSession; + NSMutableData * GTM_NULLABLE_TYPE _downloadedData; + NSError *_downloadFinishedError; + NSData *_downloadResumeData; // immutable after construction + NSURL *_destinationFileURL; + int64_t _downloadedLength; + NSURLCredential *_credential; // username & password + NSURLCredential *_proxyCredential; // credential supplied to proxy servers + BOOL _isStopNotificationNeeded; // set when start notification has been sent + BOOL _isUsingTestBlock; // set when a test block was provided (remains set when the block is released) + id _userData; // retained, if set by caller + NSMutableDictionary *_properties; // more data retained for caller + dispatch_queue_t _callbackQueue; + dispatch_group_t _callbackGroup; // read-only after creation + NSOperationQueue *_delegateQueue; // immutable after beginFetch + + id _authorizer; // immutable after beginFetch + + // The service object that created and monitors this fetcher, if any. + id _service; // immutable; set by the fetcher service upon creation + NSString *_serviceHost; + NSInteger _servicePriority; // immutable after beginFetch + BOOL _hasStoppedFetching; // counterpart to _initialBeginFetchDate + BOOL _userStoppedFetching; + + BOOL _isRetryEnabled; // user wants auto-retry + NSTimer *_retryTimer; + NSUInteger _retryCount; + NSTimeInterval _maxRetryInterval; // default 60 (download) or 600 (upload) seconds + NSTimeInterval _minRetryInterval; // random between 1 and 2 seconds + NSTimeInterval _retryFactor; // default interval multiplier is 2 + NSTimeInterval _lastRetryInterval; + NSDate *_initialBeginFetchDate; // date that beginFetch was first invoked; immutable after initial beginFetch + NSDate *_initialRequestDate; // date of first request to the target server (ignoring auth) + BOOL _hasAttemptedAuthRefresh; // accessed only in shouldRetryNowForStatus: + + NSString *_comment; // comment for log + NSString *_log; +#if !STRIP_GTM_FETCH_LOGGING + NSMutableData *_loggedStreamData; + NSURL *_redirectedFromURL; + NSString *_logRequestBody; + NSString *_logResponseBody; + BOOL _hasLoggedError; + BOOL _deferResponseBodyLogging; +#endif +} + +#if !GTMSESSION_UNIT_TESTING ++ (void)load { + [self fetchersForBackgroundSessions]; +} +#endif + ++ (instancetype)fetcherWithRequest:(GTM_NULLABLE NSURLRequest *)request { + return [[self alloc] initWithRequest:request configuration:nil]; +} + ++ (instancetype)fetcherWithURL:(NSURL *)requestURL { + return [self fetcherWithRequest:[NSURLRequest requestWithURL:requestURL]]; +} + ++ (instancetype)fetcherWithURLString:(NSString *)requestURLString { + return [self fetcherWithURL:(NSURL *)[NSURL URLWithString:requestURLString]]; +} + ++ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData { + GTMSessionFetcher *fetcher = [self fetcherWithRequest:nil]; + fetcher.comment = @"Resuming download"; + fetcher.downloadResumeData = resumeData; + return fetcher; +} + ++ (GTM_NULLABLE instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (!fetcher && [sessionIdentifier hasPrefix:kGTMSessionIdentifierPrefix]) { + fetcher = [self fetcherWithRequest:nil]; + [fetcher setSessionIdentifier:sessionIdentifier]; + [sessionIdentifierToFetcherMap setObject:fetcher forKey:sessionIdentifier]; + fetcher->_wasCreatedFromBackgroundSession = YES; + [fetcher setCommentWithFormat:@"Resuming %@", + fetcher && fetcher->_sessionIdentifierUUID ? fetcher->_sessionIdentifierUUID : @"?"]; + } + return fetcher; +} + ++ (NSMapTable *)sessionIdentifierToFetcherMap { + // TODO: What if a service is involved in creating the fetcher? Currently, when re-creating + // fetchers, if a service was involved, it is not re-created. Should the service maintain a map? + static NSMapTable *gSessionIdentifierToFetcherMap = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gSessionIdentifierToFetcherMap = [NSMapTable strongToWeakObjectsMapTable]; + }); + return gSessionIdentifierToFetcherMap; +} + +#if !GTM_ALLOW_INSECURE_REQUESTS ++ (BOOL)appAllowsInsecureRequests { + // If the main bundle Info.plist key NSAppTransportSecurity is present, and it specifies + // NSAllowsArbitraryLoads, then we need to explicitly enforce secure schemes. +#if GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY + static BOOL allowsInsecureRequests; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSBundle *mainBundle = [NSBundle mainBundle]; + NSDictionary *appTransportSecurity = + [mainBundle objectForInfoDictionaryKey:@"NSAppTransportSecurity"]; + allowsInsecureRequests = + [[appTransportSecurity objectForKey:@"NSAllowsArbitraryLoads"] boolValue]; + }); + return allowsInsecureRequests; +#else + // For builds targeting iOS 8 or 10.10 and earlier, we want to require fetcher + // security checks. + return YES; +#endif // GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY +} +#else // GTM_ALLOW_INSECURE_REQUESTS ++ (BOOL)appAllowsInsecureRequests { + return YES; +} +#endif // !GTM_ALLOW_INSECURE_REQUESTS + + +- (instancetype)init { + return [self initWithRequest:nil configuration:nil]; +} + +- (instancetype)initWithRequest:(NSURLRequest *)request { + return [self initWithRequest:request configuration:nil]; +} + +- (instancetype)initWithRequest:(GTM_NULLABLE NSURLRequest *)request + configuration:(GTM_NULLABLE NSURLSessionConfiguration *)configuration { + self = [super init]; + if (self) { + if (![NSURLSession class]) { + Class oldFetcherClass = NSClassFromString(@"GTMHTTPFetcher"); + if (oldFetcherClass && request) { + self = [[oldFetcherClass alloc] initWithRequest:(NSURLRequest *)request]; + } else { + self = nil; + } + return self; + } +#if GTM_BACKGROUND_TASK_FETCHING + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; +#endif + _request = [request mutableCopy]; + _configuration = configuration; + + NSData *bodyData = request.HTTPBody; + if (bodyData) { + _bodyLength = (int64_t)bodyData.length; + } else { + _bodyLength = NSURLSessionTransferSizeUnknown; + } + + _callbackQueue = dispatch_get_main_queue(); + _callbackGroup = dispatch_group_create(); + _delegateQueue = [NSOperationQueue mainQueue]; + + _minRetryInterval = InitialMinRetryInterval(); + _maxRetryInterval = kUnsetMaxRetryInterval; + + _taskPriority = -1.0f; // Valid values if set are 0.0...1.0. + + _testBlockAccumulateDataChunkCount = 1; + +#if !STRIP_GTM_FETCH_LOGGING + // Encourage developers to set the comment property or use + // setCommentWithFormat: by providing a default string. + _comment = @"(No fetcher comment set)"; +#endif + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + // disallow use of fetchers in a copy property + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (NSString *)description { + NSString *requestStr = self.request.URL.description; + if (requestStr.length == 0) { + if (self.downloadResumeData.length > 0) { + requestStr = @""; + } else if (_wasCreatedFromBackgroundSession) { + requestStr = @""; + } else { + requestStr = @""; + } + } + return [NSString stringWithFormat:@"%@ %p (%@)", [self class], self, requestStr]; +} + +- (void)dealloc { + GTMSESSION_ASSERT_DEBUG(!_isStopNotificationNeeded, + @"unbalanced fetcher notification for %@", _request.URL); + [self forgetSessionIdentifierForFetcherWithoutSyncCheck]; + + // Note: if a session task or a retry timer was pending, then this instance + // would be retained by those so it wouldn't be getting dealloc'd, + // hence we don't need to stopFetch here +} + +#pragma mark - + +// Begin fetching the URL (or begin a retry fetch). The delegate is retained +// for the duration of the fetch connection. + +- (void)beginFetchWithCompletionHandler:(GTM_NULLABLE GTMSessionFetcherCompletionHandler)handler { + GTMSessionCheckNotSynchronized(self); + + _completionHandler = [handler copy]; + + // The user may have called setDelegate: earlier if they want to use other + // delegate-style callbacks during the fetch; otherwise, the delegate is nil, + // which is fine. + [self beginFetchMayDelay:YES mayAuthorize:YES]; +} + +- (GTMSessionFetcherCompletionHandler)completionHandlerWithTarget:(GTM_NULLABLE_TYPE id)target + didFinishSelector:(GTM_NULLABLE_TYPE SEL)finishedSelector { + GTMSessionFetcherAssertValidSelector(target, finishedSelector, @encode(GTMSessionFetcher *), + @encode(NSData *), @encode(NSError *), 0); + GTMSessionFetcherCompletionHandler completionHandler = ^(NSData *data, NSError *error) { + if (target && finishedSelector) { + id selfArg = self; // Placate ARC. + NSMethodSignature *sig = [target methodSignatureForSelector:finishedSelector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setSelector:(SEL)finishedSelector]; + [invocation setTarget:target]; + [invocation setArgument:&selfArg atIndex:2]; + [invocation setArgument:&data atIndex:3]; + [invocation setArgument:&error atIndex:4]; + [invocation invoke]; + } + }; + return completionHandler; +} + +- (void)beginFetchWithDelegate:(GTM_NULLABLE_TYPE id)target + didFinishSelector:(GTM_NULLABLE_TYPE SEL)finishedSelector { + GTMSessionCheckNotSynchronized(self); + + GTMSessionFetcherCompletionHandler handler = [self completionHandlerWithTarget:target + didFinishSelector:finishedSelector]; + [self beginFetchWithCompletionHandler:handler]; +} + +- (void)beginFetchMayDelay:(BOOL)mayDelay + mayAuthorize:(BOOL)mayAuthorize { + // This is the internal entry point for re-starting fetches. + GTMSessionCheckNotSynchronized(self); + + NSMutableURLRequest *fetchRequest = _request; // The request property is now externally immutable. + NSURL *fetchRequestURL = fetchRequest.URL; + NSString *priorSessionIdentifier = self.sessionIdentifier; + + // A utility block for creating error objects when we fail to start the fetch. + NSError *(^beginFailureError)(NSInteger) = ^(NSInteger code){ + NSString *urlString = fetchRequestURL.absoluteString; + NSDictionary *userInfo = @{ + NSURLErrorFailingURLStringErrorKey : (urlString ? urlString : @"(missing URL)") + }; + return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:code + userInfo:userInfo]; + }; + + // Catch delegate queue maxConcurrentOperationCount values other than 1, particularly + // NSOperationQueueDefaultMaxConcurrentOperationCount (-1), to avoid the additional complexity + // of simultaneous or out-of-order delegate callbacks. + GTMSESSION_ASSERT_DEBUG(_delegateQueue.maxConcurrentOperationCount == 1, + @"delegate queue %@ should support one concurrent operation, not %zd", + _delegateQueue.name, _delegateQueue.maxConcurrentOperationCount); + + if (!_initialBeginFetchDate) { + // This ivar is set only here on the initial beginFetch so need not be synchronized. + _initialBeginFetchDate = [[NSDate alloc] init]; + } + + if (self.sessionTask != nil) { + // If cached fetcher returned through fetcherWithSessionIdentifier:, then it's + // already begun, but don't consider this a failure, since the user need not know this. + if (self.sessionIdentifier != nil) { + return; + } + GTMSESSION_ASSERT_DEBUG(NO, @"Fetch object %@ being reused; this should never happen", self); + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorDownloadFailed)]; + return; + } + + if (fetchRequestURL == nil && !_downloadResumeData && !priorSessionIdentifier) { + GTMSESSION_ASSERT_DEBUG(NO, @"Beginning a fetch requires a request with a URL"); + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorDownloadFailed)]; + return; + } + + // We'll respect the user's request for a background session (unless this is + // an upload fetcher, which does its initial request foreground.) + self.usingBackgroundSession = self.useBackgroundSession && [self canFetchWithBackgroundSession]; + + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSError *fileCheckError; + if (![bodyFileURL checkResourceIsReachableAndReturnError:&fileCheckError]) { + // This assert fires when the file being uploaded no longer exists once + // the fetcher is ready to start the upload. + GTMSESSION_ASSERT_DEBUG_OR_LOG(0, @"Body file is unreachable: %@\n %@", + bodyFileURL.path, fileCheckError); + [self failToBeginFetchWithError:fileCheckError]; + return; + } + } + + NSString *requestScheme = fetchRequestURL.scheme; + BOOL isDataRequest = [requestScheme isEqual:@"data"]; + if (isDataRequest) { + // NSURLSession does not support data URLs in background sessions. +#if DEBUG + if (priorSessionIdentifier || self.sessionIdentifier) { + GTMSESSION_LOG_DEBUG(@"Converting background to foreground session for %@", + fetchRequest); + } +#endif + [self setSessionIdentifierInternal:nil]; + self.useBackgroundSession = NO; + } + +#if GTM_ALLOW_INSECURE_REQUESTS + BOOL shouldCheckSecurity = NO; +#else + BOOL shouldCheckSecurity = (fetchRequestURL != nil + && !isDataRequest + && [[self class] appAllowsInsecureRequests]); +#endif + + if (shouldCheckSecurity) { + // Allow https only for requests, unless overridden by the client. + // + // Non-https requests may too easily be snooped, so we disallow them by default. + // + // file: and data: schemes are usually safe if they are hardcoded in the client or provided + // by a trusted source, but since it's fairly rare to need them, it's safest to make clients + // explicitly whitelist them. + BOOL isSecure = + requestScheme != nil && [requestScheme caseInsensitiveCompare:@"https"] == NSOrderedSame; + if (!isSecure) { + BOOL allowRequest = NO; + NSString *host = fetchRequestURL.host; + + // Check schemes first. A file scheme request may be allowed here, or as a localhost request. + for (NSString *allowedScheme in _allowedInsecureSchemes) { + if (requestScheme != nil && + [requestScheme caseInsensitiveCompare:allowedScheme] == NSOrderedSame) { + allowRequest = YES; + break; + } + } + if (!allowRequest) { + // Check for localhost requests. Security checks only occur for non-https requests, so + // this check won't happen for an https request to localhost. + BOOL isLocalhostRequest = (host.length == 0 && [fetchRequestURL isFileURL]) || IsLocalhost(host); + if (isLocalhostRequest) { + if (self.allowLocalhostRequest) { + allowRequest = YES; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Fetch request for localhost but fetcher" + @" allowLocalhostRequest is not set: %@", fetchRequestURL); + } + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Insecure fetch request has a scheme (%@)" + @" not found in fetcher allowedInsecureSchemes (%@): %@", + requestScheme, _allowedInsecureSchemes ?: @" @[] ", fetchRequestURL); + } + } + + if (!allowRequest) { +#if !DEBUG + NSLog(@"Insecure fetch disallowed for %@", fetchRequestURL.description ?: @"nil request URL"); +#endif + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorInsecureRequest)]; + return; + } + } // !isSecure + } // (requestURL != nil) && !isDataRequest + + if (self.cookieStorage == nil) { + self.cookieStorage = [[self class] staticCookieStorage]; + } + + BOOL isRecreatingSession = (self.sessionIdentifier != nil) && (fetchRequest == nil); + + self.canShareSession = !isRecreatingSession && !self.usingBackgroundSession; + + if (!self.session && self.canShareSession) { + self.session = [_service sessionForFetcherCreation]; + // If _session is nil, then the service's session creation semaphore will block + // until this fetcher invokes fetcherDidCreateSession: below, so this *must* invoke + // that method, even if the session fails to be created. + } + + if (!self.session) { + // Create a session. + if (!_configuration) { + if (priorSessionIdentifier || self.usingBackgroundSession) { + NSString *sessionIdentifier = priorSessionIdentifier; + if (!sessionIdentifier) { + sessionIdentifier = [self createSessionIdentifierWithMetadata:nil]; + } + NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap]; + [sessionIdentifierToFetcherMap setObject:self forKey:self.sessionIdentifier]; + +#if (TARGET_OS_TV \ + || TARGET_OS_WATCH \ + || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0)) + // iOS 8/10.10 builds require the new backgroundSessionConfiguration method name. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionIdentifier]; +#elif (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0) + // Do a runtime check to avoid a deprecation warning about using + // +backgroundSessionConfiguration: on iOS 8. + if ([NSURLSessionConfiguration respondsToSelector:@selector(backgroundSessionConfigurationWithIdentifier:)]) { + // Running on iOS 8+/OS X 10.10+. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionIdentifier]; + } else { + // Running on iOS 7/OS X 10.9. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier]; + } +#else + // Building with an SDK earlier than iOS 8/OS X 10.10. + _configuration = + [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier]; +#endif + self.usingBackgroundSession = YES; + self.canShareSession = NO; + } else { + _configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + } +#if !GTM_ALLOW_INSECURE_REQUESTS + _configuration.TLSMinimumSupportedProtocol = kTLSProtocol12; +#endif + } // !_configuration + _configuration.HTTPCookieStorage = self.cookieStorage; + + if (_configurationBlock) { + _configurationBlock(self, _configuration); + } + + id delegate = [_service sessionDelegate]; + if (!delegate || !self.canShareSession) { + delegate = self; + } + self.session = [NSURLSession sessionWithConfiguration:_configuration + delegate:delegate + delegateQueue:self.sessionDelegateQueue]; + GTMSESSION_ASSERT_DEBUG(self.session, @"Couldn't create session"); + + // Tell the service about the session created by this fetcher. This also signals the + // service's semaphore to allow other fetchers to request this session. + [_service fetcherDidCreateSession:self]; + + // If this assertion fires, the client probably tried to use a session identifier that was + // already used. The solution is to make the client use a unique identifier (or better yet let + // the session fetcher assign the identifier). + GTMSESSION_ASSERT_DEBUG(self.session.delegate == delegate, @"Couldn't assign delegate."); + + if (self.session) { + BOOL isUsingSharedDelegate = (delegate != self); + if (!isUsingSharedDelegate) { + _shouldInvalidateSession = YES; + } + } + } + + if (isRecreatingSession) { + _shouldInvalidateSession = YES; + + // Let's make sure there are tasks still running or if not that we get a callback from a + // completed one; otherwise, we assume the tasks failed. + // This is the observed behavior perhaps 25% of the time within the Simulator running 7.0.3 on + // exiting the app after starting an upload and relaunching the app if we manage to relaunch + // after the task has completed, but before the system relaunches us in the background. + [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, + NSArray *downloadTasks) { + if (dataTasks.count == 0 && uploadTasks.count == 0 && downloadTasks.count == 0) { + double const kDelayInSeconds = 1.0; // We should get progress indication or completion soon + dispatch_time_t checkForFeedbackDelay = + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelayInSeconds * NSEC_PER_SEC)); + dispatch_after(checkForFeedbackDelay, dispatch_get_main_queue(), ^{ + if (!self.sessionTask && !fetchRequest) { + // If our task and/or request haven't been restored, then we assume task feedback lost. + [self removePersistedBackgroundSessionFromDefaults]; + NSError *sessionError = + [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorBackgroundFetchFailed + userInfo:nil]; + [self failToBeginFetchWithError:sessionError]; + } + }); + } + }]; + return; + } + + self.downloadedData = nil; + self.downloadedLength = 0; + + if (_servicePriority == NSIntegerMin) { + mayDelay = NO; + } + if (mayDelay && _service) { + BOOL shouldFetchNow = [_service fetcherShouldBeginFetching:self]; + if (!shouldFetchNow) { + // The fetch is deferred, but will happen later. + // + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after the fetcher is restarted. + if (self.canShareSession) { + self.session = nil; + } + return; + } + } + + NSString *effectiveHTTPMethod = [fetchRequest valueForHTTPHeaderField:@"X-HTTP-Method-Override"]; + if (effectiveHTTPMethod == nil) { + effectiveHTTPMethod = fetchRequest.HTTPMethod; + } + BOOL isEffectiveHTTPGet = (effectiveHTTPMethod == nil + || [effectiveHTTPMethod isEqual:@"GET"]); + + BOOL needsUploadTask = (self.useUploadTask || self.bodyFileURL || self.bodyStreamProvider); + if (_bodyData || self.bodyStreamProvider || fetchRequest.HTTPBodyStream) { + if (isEffectiveHTTPGet) { + fetchRequest.HTTPMethod = @"POST"; + isEffectiveHTTPGet = NO; + } + + if (_bodyData) { + if (!needsUploadTask) { + fetchRequest.HTTPBody = _bodyData; + } +#if !STRIP_GTM_FETCH_LOGGING + } else if (fetchRequest.HTTPBodyStream) { + if ([self respondsToSelector:@selector(loggedInputStreamForInputStream:)]) { + fetchRequest.HTTPBodyStream = + [self performSelector:@selector(loggedInputStreamForInputStream:) + withObject:fetchRequest.HTTPBodyStream]; + } +#endif + } + } + + // We authorize after setting up the http method and body in the request + // because OAuth 1 may need to sign the request body + if (mayAuthorize && _authorizer && !isDataRequest) { + BOOL isAuthorized = [_authorizer isAuthorizedRequest:fetchRequest]; + if (!isAuthorized) { + // Authorization needed. + // + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after authorization completes. + if (self.canShareSession) { + self.session = nil; + } + + // Authorizing the request will recursively call this beginFetch:mayDelay: + // or failToBeginFetchWithError:. + [self authorizeRequest]; + return; + } + } + + // set the default upload or download retry interval, if necessary + if ([self isRetryEnabled] && self.maxRetryInterval <= 0) { + if (isEffectiveHTTPGet || [effectiveHTTPMethod isEqual:@"HEAD"]) { + [self setMaxRetryInterval:kDefaultMaxDownloadRetryInterval]; + } else { + [self setMaxRetryInterval:kDefaultMaxUploadRetryInterval]; + } + } + + // finally, start the connection + NSURLSessionTask *newSessionTask; + BOOL needsDataAccumulator = NO; + if (_downloadResumeData) { + newSessionTask = [_session downloadTaskWithResumeData:_downloadResumeData]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed downloadTaskWithResumeData for %@, resume data %tu bytes", + _session, _downloadResumeData.length); + } else if (_destinationFileURL && !isDataRequest) { + newSessionTask = [_session downloadTaskWithRequest:fetchRequest]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, @"Failed downloadTaskWithRequest for %@, %@", + _session, fetchRequest); + } else if (needsUploadTask) { + if (bodyFileURL) { + newSessionTask = [_session uploadTaskWithRequest:fetchRequest + fromFile:bodyFileURL]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithRequest for %@, %@, file %@", + _session, fetchRequest, bodyFileURL.path); + } else if (self.bodyStreamProvider) { + newSessionTask = [_session uploadTaskWithStreamedRequest:fetchRequest]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithStreamedRequest for %@, %@", + _session, fetchRequest); + } else { + GTMSESSION_ASSERT_DEBUG_OR_LOG(_bodyData != nil, + @"Upload task needs body data, %@", fetchRequest); + newSessionTask = [_session uploadTaskWithRequest:fetchRequest + fromData:(NSData * GTM_NONNULL_TYPE)_bodyData]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithRequest for %@, %@, body data %tu bytes", + _session, fetchRequest, _bodyData.length); + } + needsDataAccumulator = YES; + } else { + newSessionTask = [_session dataTaskWithRequest:fetchRequest]; + needsDataAccumulator = YES; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, @"Failed dataTaskWithRequest for %@, %@", + _session, fetchRequest); + } + self.sessionTask = newSessionTask; + + if (!newSessionTask) { + // We shouldn't get here; if we're here, an earlier assertion should have fired to explain + // which session task creation failed. + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorTaskCreationFailed)]; + return; + } + + if (needsDataAccumulator && _accumulateDataBlock == nil) { + self.downloadedData = [NSMutableData data]; + } + if (_taskDescription) { + newSessionTask.taskDescription = _taskDescription; + } + if (_taskPriority >= 0) { +#if TARGET_OS_TV || TARGET_OS_WATCH + BOOL hasTaskPriority = YES; +#elif (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0) + BOOL hasTaskPriority = YES; +#else + BOOL hasTaskPriority = [newSessionTask respondsToSelector:@selector(setPriority:)]; +#endif + if (hasTaskPriority) { + newSessionTask.priority = _taskPriority; + } + } + +#if GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSESSION_ASSERT_DEBUG(_testBlock == nil && gGlobalTestBlock == nil, @"test blocks disabled"); + _testBlock = nil; +#else + if (!_testBlock) { + if (gGlobalTestBlock) { + // Note that the test block may pass nil for all of its response parameters, + // indicating that the fetch should actually proceed. This is useful when the + // global test block has been set, and the app is only testing a specific + // fetcher. The block simulation code will then resume the task. + _testBlock = gGlobalTestBlock; + } + } + _isUsingTestBlock = (_testBlock != nil); +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK + +#if GTM_BACKGROUND_TASK_FETCHING + id app = [[self class] fetcherUIApplication]; + // Background tasks seem to interfere with out-of-process uploads and downloads. + if (app && !self.skipBackgroundTask && !self.useBackgroundSession) { + // Tell UIApplication that we want to continue even when the app is in the + // background. +#if DEBUG + NSString *bgTaskName = [NSString stringWithFormat:@"%@-%@", + [self class], fetchRequest.URL.host]; +#else + NSString *bgTaskName = @"GTMSessionFetcher"; +#endif + __block UIBackgroundTaskIdentifier bgTaskID = [app beginBackgroundTaskWithName:bgTaskName + expirationHandler:^{ + // Background task expiration callback - this block is always invoked by + // UIApplication on the main thread. + if (bgTaskID != UIBackgroundTaskInvalid) { + @synchronized(self) { + if (bgTaskID == self.backgroundTaskIdentifier) { + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + } + [app endBackgroundTask:bgTaskID]; + } + }]; + @synchronized(self) { + self.backgroundTaskIdentifier = bgTaskID; + } + } +#endif + + if (!_initialRequestDate) { + _initialRequestDate = [[NSDate alloc] init]; + } + + // We don't expect to reach here even on retry or auth until a stop notification has been sent + // for the previous task, but we should ensure that we don't unbalance that. + GTMSESSION_ASSERT_DEBUG(!_isStopNotificationNeeded, @"Start notification without a prior stop"); + [self sendStopNotificationIfNeeded]; + + [self addPersistedBackgroundSessionToDefaults]; + + [self setStopNotificationNeeded:YES]; + + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherStartedNotification + userInfo:nil + requireAsync:NO]; + + // The service needs to know our task if it is serving as NSURLSession delegate. + [_service fetcherDidBeginFetching:self]; + + if (_testBlock) { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + [self simulateFetchForTestBlock]; +#endif + } else { + // We resume the session task after posting the notification since the + // delegate callbacks may happen immediately if the fetch is started off + // the main thread or the session delegate queue is on a background thread, + // and we don't want to post a start notification after a premature finish + // of the session task. + [newSessionTask resume]; + } +} + +NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError) { + NSMutableData *data = [NSMutableData data]; + + [inputStream open]; + NSInteger numberOfBytesRead = 0; + while ([inputStream hasBytesAvailable]) { + uint8_t buffer[512]; + numberOfBytesRead = [inputStream read:buffer maxLength:sizeof(buffer)]; + if (numberOfBytesRead > 0) { + [data appendBytes:buffer length:(NSUInteger)numberOfBytesRead]; + } else { + break; + } + } + [inputStream close]; + NSError *streamError = inputStream.streamError; + + if (streamError) { + data = nil; + } + if (outError) { + *outError = streamError; + } + return data; +} + +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + +- (void)simulateFetchForTestBlock { + // This is invoked on the same thread as the beginFetch method was. + // + // Callbacks will all occur on the callback queue. + _testBlock(self, ^(NSURLResponse *response, NSData *responseData, NSError *error) { + // Callback from test block. + if (response == nil && responseData == nil && error == nil) { + // Assume the fetcher should execute rather than be tested. + _testBlock = nil; + _isUsingTestBlock = NO; + [_sessionTask resume]; + return; + } + + GTMSessionFetcherBodyStreamProvider bodyStreamProvider = self.bodyStreamProvider; + if (bodyStreamProvider) { + bodyStreamProvider(^(NSInputStream *bodyStream){ + // Read from the input stream into an NSData buffer. We'll drain the stream + // explicitly on a background queue. + [self invokeOnCallbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) + afterUserStopped:NO + block:^{ + NSError *streamError; + NSData *streamedData = GTMDataFromInputStream(bodyStream, &streamError); + + dispatch_async(dispatch_get_main_queue(), ^{ + // Continue callbacks on the main thread, since serial behavior + // is more reliable for tests. + [self simulateDataCallbacksForTestBlockWithBodyData:streamedData + response:response + responseData:responseData + error:(error ?: streamError)]; + }); + }]; + }); + } else { + // No input stream; use the supplied data or file URL. + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSError *readError; + _bodyData = [NSData dataWithContentsOfURL:bodyFileURL + options:NSDataReadingMappedIfSafe + error:&readError]; + error = readError; + } + + // No stream provider. + + // In real fetches, nothing happens until the run loop spins, so apps have leeway to + // set callbacks after they call beginFetch. We'll mirror that fetcher behavior by + // delaying callbacks here at least to the next spin of the run loop. That keeps + // immediate, synchronous setting of callback blocks after beginFetch working in tests. + dispatch_async(dispatch_get_main_queue(), ^{ + [self simulateDataCallbacksForTestBlockWithBodyData:_bodyData + response:response + responseData:responseData + error:error]; + }); + } + }); +} + +- (void)simulateByteTransferReportWithDataLength:(int64_t)totalDataLength + block:(GTMSessionFetcherSendProgressBlock)block { + // This utility method simulates transfer progress with up to three callbacks. + // It is used to call back to any of the progress blocks. + int64_t sendReportSize = totalDataLength / 3 + 1; + int64_t totalSent = 0; + while (totalSent < totalDataLength) { + int64_t bytesRemaining = totalDataLength - totalSent; + sendReportSize = MIN(sendReportSize, bytesRemaining); + totalSent += sendReportSize; + [self invokeOnCallbackQueueUnlessStopped:^{ + block(sendReportSize, totalSent, totalDataLength); + }]; + } +} + +- (void)simulateDataCallbacksForTestBlockWithBodyData:(NSData * GTM_NULLABLE_TYPE)bodyData + response:(NSURLResponse *)response + responseData:(NSData *)suppliedData + error:(NSError *)suppliedError { + __block NSData *responseData = suppliedData; + __block NSError *responseError = suppliedError; + + // This method does the test simulation of callbacks once the upload + // and download data are known. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Get copies of ivars we'll access in async invocations. This simulation assumes + // they won't change during fetcher execution. + NSURL *destinationFileURL = _destinationFileURL; + GTMSessionFetcherWillRedirectBlock willRedirectBlock = _willRedirectBlock; + GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock = _didReceiveResponseBlock; + GTMSessionFetcherSendProgressBlock sendProgressBlock = _sendProgressBlock; + GTMSessionFetcherDownloadProgressBlock downloadProgressBlock = _downloadProgressBlock; + GTMSessionFetcherAccumulateDataBlock accumulateDataBlock = _accumulateDataBlock; + GTMSessionFetcherReceivedProgressBlock receivedProgressBlock = _receivedProgressBlock; + GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock = + _willCacheURLResponseBlock; + + // Simulate receipt of redirection. + if (willRedirectBlock) { + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + willRedirectBlock((NSHTTPURLResponse *)response, _request, + ^(NSURLRequest *redirectRequest) { + // For simulation, we'll assume the app will just continue. + }); + }]; + } + + // If the fetcher has a challenge block, simulate a challenge. + // + // It might be nice to eventually let the user determine which testBlock + // fetches get challenged rather than always executing the supplied + // challenge block. + if (_challengeBlock) { + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + if (_challengeBlock) { + NSURL *requestURL = _request.URL; + NSString *host = requestURL.host; + NSURLProtectionSpace *pspace = + [[NSURLProtectionSpace alloc] initWithHost:host + port:requestURL.port.integerValue + protocol:requestURL.scheme + realm:nil + authenticationMethod:NSURLAuthenticationMethodHTTPBasic]; + id unusedSender = + (id)[NSNull null]; + NSURLAuthenticationChallenge *challenge = + [[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:pspace + proposedCredential:nil + previousFailureCount:0 + failureResponse:nil + error:nil + sender:unusedSender]; + _challengeBlock(self, challenge, ^(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential){ + // We could change the responseData and responseError based on the disposition, + // but it's easier for apps to just supply the expected data and error + // directly to the test block. So this simulation ignores the disposition. + }); + } + }]; + } + + // Simulate receipt of an initial response. + if (response && didReceiveResponseBlock) { + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + didReceiveResponseBlock(response, ^(NSURLSessionResponseDisposition desiredDisposition) { + // For simulation, we'll assume the disposition is to continue. + }); + }]; + } + + // Simulate reporting send progress. + if (sendProgressBlock) { + [self simulateByteTransferReportWithDataLength:(int64_t)bodyData.length + block:^(int64_t bytesSent, + int64_t totalBytesSent, + int64_t totalBytesExpectedToSend) { + // This is invoked on the callback queue unless stopped. + sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpectedToSend); + }]; + } + + if (destinationFileURL) { + // Simulate download to file progress. + if (downloadProgressBlock) { + [self simulateByteTransferReportWithDataLength:(int64_t)responseData.length + block:^(int64_t bytesDownloaded, + int64_t totalBytesDownloaded, + int64_t totalBytesExpectedToDownload) { + // This is invoked on the callback queue unless stopped. + downloadProgressBlock(bytesDownloaded, totalBytesDownloaded, + totalBytesExpectedToDownload); + }]; + } + + NSError *writeError; + [responseData writeToURL:destinationFileURL + options:NSDataWritingAtomic + error:&writeError]; + if (writeError) { + // Tell the test code that writing failed. + responseError = writeError; + } + } else { + // Simulate download to NSData progress. + if ((accumulateDataBlock || receivedProgressBlock) && responseData) { + [self simulateByteTransferWithData:responseData + block:^(NSData *data, + int64_t bytesReceived, + int64_t totalBytesReceived, + int64_t totalBytesExpectedToReceive) { + // This is invoked on the callback queue unless stopped. + if (accumulateDataBlock) { + accumulateDataBlock(data); + } + + if (receivedProgressBlock) { + receivedProgressBlock(bytesReceived, totalBytesReceived); + } + }]; + } + + if (!accumulateDataBlock) { + _downloadedData = [responseData mutableCopy]; + } + + if (willCacheURLResponseBlock) { + // Simulate letting the client inspect and alter the cached response. + NSData *cachedData = responseData ?: [[NSData alloc] init]; // Always have non-nil data. + NSCachedURLResponse *cachedResponse = + [[NSCachedURLResponse alloc] initWithResponse:response + data:cachedData]; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES + block:^{ + willCacheURLResponseBlock(cachedResponse, ^(NSCachedURLResponse *responseToCache){ + // The app may provide an alternative response, or nil to defeat caching. + }); + }]; + } + } + _response = response; + } // @synchronized(self) + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + // Rather than invoke failToBeginFetchWithError: we want to simulate completion of + // a connection that started and ended, so we'll call down to finishWithError: + NSInteger status = responseError ? responseError.code : 200; + if (status >= 200 && status <= 399) { + [self finishWithError:nil shouldRetry:NO]; + } else { + [self shouldRetryNowForStatus:status + error:responseError + forceAssumeRetry:NO + response:^(BOOL shouldRetry) { + [self finishWithError:responseError shouldRetry:shouldRetry]; + }]; + } + }]; +} + +- (void)simulateByteTransferWithData:(NSData *)responseData + block:(GTMSessionFetcherSimulateByteTransferBlock)transferBlock { + // This utility method simulates transfering data to the client. It divides the data into at most + // "chunkCount" chunks and then passes each chunk along with a progress update to transferBlock. + // This function can be used with accumulateDataBlock or receivedProgressBlock. + + NSUInteger chunkCount = MAX(self.testBlockAccumulateDataChunkCount, (NSUInteger) 1); + NSUInteger totalDataLength = responseData.length; + NSUInteger sendDataSize = totalDataLength / chunkCount + 1; + NSUInteger totalSent = 0; + while (totalSent < totalDataLength) { + NSUInteger bytesRemaining = totalDataLength - totalSent; + sendDataSize = MIN(sendDataSize, bytesRemaining); + NSData *chunkData = [responseData subdataWithRange:NSMakeRange(totalSent, sendDataSize)]; + totalSent += sendDataSize; + [self invokeOnCallbackQueueUnlessStopped:^{ + transferBlock(chunkData, + (int64_t)sendDataSize, + (int64_t)totalSent, + (int64_t)totalDataLength); + }]; + } +} + +#endif // !GTM_DISABLE_FETCHER_TEST_BLOCK + +- (void)setSessionTask:(NSURLSessionTask *)sessionTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionTask != sessionTask) { + _sessionTask = sessionTask; + if (_sessionTask) { + // Request could be nil on restoring this fetcher from a background session. + if (!_request) { + _request = [_sessionTask.originalRequest mutableCopy]; + } + } + } + } // @synchronized(self) +} + +- (NSURLSessionTask * GTM_NULLABLE_TYPE)sessionTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionTask; + } // @synchronized(self) +} + ++ (NSUserDefaults *)fetcherUserDefaults { + static NSUserDefaults *gFetcherUserDefaults = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class fetcherUserDefaultsClass = NSClassFromString(@"GTMSessionFetcherUserDefaultsFactory"); + if (fetcherUserDefaultsClass) { + gFetcherUserDefaults = [fetcherUserDefaultsClass fetcherUserDefaults]; + } else { + gFetcherUserDefaults = [NSUserDefaults standardUserDefaults]; + } + }); + return gFetcherUserDefaults; +} + +- (void)addPersistedBackgroundSessionToDefaults { + NSString *sessionIdentifier = self.sessionIdentifier; + if (!sessionIdentifier) { + return; + } + NSArray *oldBackgroundSessions = [[self class] activePersistedBackgroundSessions]; + if ([oldBackgroundSessions containsObject:_sessionIdentifier]) { + return; + } + NSMutableArray *newBackgroundSessions = + [NSMutableArray arrayWithArray:oldBackgroundSessions]; + [newBackgroundSessions addObject:sessionIdentifier]; + GTM_LOG_BACKGROUND_SESSION(@"Add to background sessions: %@", newBackgroundSessions); + + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + [userDefaults setObject:newBackgroundSessions + forKey:kGTMSessionFetcherPersistedDestinationKey]; + [userDefaults synchronize]; +} + +- (void)removePersistedBackgroundSessionFromDefaults { + NSString *sessionIdentifier = self.sessionIdentifier; + if (!sessionIdentifier) return; + + NSArray *oldBackgroundSessions = [[self class] activePersistedBackgroundSessions]; + if (!oldBackgroundSessions) { + return; + } + NSMutableArray *newBackgroundSessions = + [NSMutableArray arrayWithArray:oldBackgroundSessions]; + NSUInteger sessionIndex = [newBackgroundSessions indexOfObject:sessionIdentifier]; + if (sessionIndex == NSNotFound) { + return; + } + [newBackgroundSessions removeObjectAtIndex:sessionIndex]; + GTM_LOG_BACKGROUND_SESSION(@"Remove from background sessions: %@", newBackgroundSessions); + + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + if (newBackgroundSessions.count == 0) { + [userDefaults removeObjectForKey:kGTMSessionFetcherPersistedDestinationKey]; + } else { + [userDefaults setObject:newBackgroundSessions + forKey:kGTMSessionFetcherPersistedDestinationKey]; + } + [userDefaults synchronize]; +} + ++ (GTM_NULLABLE NSArray *)activePersistedBackgroundSessions { + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + NSArray *oldBackgroundSessions = + [userDefaults arrayForKey:kGTMSessionFetcherPersistedDestinationKey]; + if (oldBackgroundSessions.count == 0) { + return nil; + } + NSMutableArray *activeBackgroundSessions = nil; + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + for (NSString *sessionIdentifier in oldBackgroundSessions) { + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (fetcher) { + if (!activeBackgroundSessions) { + activeBackgroundSessions = [[NSMutableArray alloc] init]; + } + [activeBackgroundSessions addObject:sessionIdentifier]; + } + } + return activeBackgroundSessions; +} + ++ (NSArray *)fetchersForBackgroundSessions { + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + NSArray *backgroundSessions = + [userDefaults arrayForKey:kGTMSessionFetcherPersistedDestinationKey]; + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + NSMutableArray *fetchers = [NSMutableArray array]; + for (NSString *sessionIdentifier in backgroundSessions) { + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (!fetcher) { + fetcher = [self fetcherWithSessionIdentifier:sessionIdentifier]; + GTMSESSION_ASSERT_DEBUG(fetcher != nil, + @"Unexpected invalid session identifier: %@", sessionIdentifier); + [fetcher beginFetchWithCompletionHandler:nil]; + } + GTM_LOG_BACKGROUND_SESSION(@"%@ restoring session %@ by creating fetcher %@ %p", + [self class], sessionIdentifier, fetcher, fetcher); + if (fetcher != nil) { + [fetchers addObject:fetcher]; + } + } + return fetchers; +} + +#if TARGET_OS_IPHONE ++ (void)application:(UIApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler { + GTMSessionFetcher *fetcher = [self fetcherWithSessionIdentifier:identifier]; + if (fetcher != nil) { + fetcher.systemCompletionHandler = completionHandler; + } else { + GTM_LOG_BACKGROUND_SESSION(@"%@ did not create background session identifier: %@", + [self class], identifier); + } +} +#endif + +- (NSString * GTM_NULLABLE_TYPE)sessionIdentifier { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionIdentifier; + } // @synchronized(self) +} + +- (void)setSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(!_session, @"Unable to set session identifier after session created"); + _sessionIdentifier = [sessionIdentifier copy]; + _usingBackgroundSession = YES; + _canShareSession = NO; + [self restoreDefaultStateForSessionIdentifierMetadata]; + } // @synchronized(self) +} + +- (void)setSessionIdentifierInternal:(GTM_NULLABLE NSString *)sessionIdentifier { + // This internal method only does a synchronized set of the session identifier. + // It does not have side effects on the background session, shared session, or + // session identifier metadata. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _sessionIdentifier = [sessionIdentifier copy]; + } // @synchronized(self) +} + +- (NSDictionary * GTM_NULLABLE_TYPE)sessionUserInfo { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionUserInfo == nil) { + // We'll return the metadata dictionary with internal keys removed. This avoids the user + // re-using the userInfo dictionary later and accidentally including the internal keys. + NSMutableDictionary *metadata = [[self sessionIdentifierMetadataUnsynchronized] mutableCopy]; + NSSet *keysToRemove = [metadata keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) { + return [key hasPrefix:@"_"]; + }]; + [metadata removeObjectsForKeys:[keysToRemove allObjects]]; + if (metadata.count > 0) { + _sessionUserInfo = metadata; + } + } + return _sessionUserInfo; + } // @synchronized(self) +} + +- (void)setSessionUserInfo:(NSDictionary * GTM_NULLABLE_TYPE)dictionary { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(_sessionIdentifier == nil, @"Too late to assign userInfo"); + _sessionUserInfo = dictionary; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSDictionary *)sessionIdentifierDefaultMetadata { + GTMSessionCheckSynchronized(self); + + NSMutableDictionary *defaultUserInfo = [[NSMutableDictionary alloc] init]; + if (_destinationFileURL) { + defaultUserInfo[kGTMSessionIdentifierDestinationFileURLMetadataKey] = + [_destinationFileURL absoluteString]; + } + if (_bodyFileURL) { + defaultUserInfo[kGTMSessionIdentifierBodyFileURLMetadataKey] = [_bodyFileURL absoluteString]; + } + return (defaultUserInfo.count > 0) ? defaultUserInfo : nil; +} + +- (void)restoreDefaultStateForSessionIdentifierMetadata { + GTMSessionCheckSynchronized(self); + + NSDictionary *metadata = [self sessionIdentifierMetadataUnsynchronized]; + NSString *destinationFileURLString = metadata[kGTMSessionIdentifierDestinationFileURLMetadataKey]; + if (destinationFileURLString) { + _destinationFileURL = [NSURL URLWithString:destinationFileURLString]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring destination file URL: %@", _destinationFileURL); + } + NSString *bodyFileURLString = metadata[kGTMSessionIdentifierBodyFileURLMetadataKey]; + if (bodyFileURLString) { + _bodyFileURL = [NSURL URLWithString:bodyFileURLString]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring body file URL: %@", _bodyFileURL); + } +} + +- (NSDictionary * GTM_NULLABLE_TYPE)sessionIdentifierMetadata { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [self sessionIdentifierMetadataUnsynchronized]; + } +} + +- (NSDictionary * GTM_NULLABLE_TYPE)sessionIdentifierMetadataUnsynchronized { + GTMSessionCheckSynchronized(self); + + // Session Identifier format: "com.google.__ + if (!_sessionIdentifier) { + return nil; + } + NSScanner *metadataScanner = [NSScanner scannerWithString:_sessionIdentifier]; + [metadataScanner setCharactersToBeSkipped:nil]; + NSString *metadataString; + NSString *uuid; + if ([metadataScanner scanUpToString:@"_" intoString:NULL] && + [metadataScanner scanString:@"_" intoString:NULL] && + [metadataScanner scanUpToString:@"_" intoString:&uuid] && + [metadataScanner scanString:@"_" intoString:NULL] && + [metadataScanner scanUpToString:@"\n" intoString:&metadataString]) { + _sessionIdentifierUUID = uuid; + NSData *metadataData = [metadataString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *error; + NSDictionary *metadataDict = + [NSJSONSerialization JSONObjectWithData:metadataData + options:0 + error:&error]; + GTM_LOG_BACKGROUND_SESSION(@"User Info from session identifier: %@ %@", + metadataDict, error ? error : @""); + return metadataDict; + } + return nil; +} + +- (NSString *)createSessionIdentifierWithMetadata:(NSDictionary * GTM_NULLABLE_TYPE)metadataToInclude { + NSString *result; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Session Identifier format: "com.google.__ + GTMSESSION_ASSERT_DEBUG(!_sessionIdentifier, @"Session identifier already created"); + _sessionIdentifierUUID = [[NSUUID UUID] UUIDString]; + _sessionIdentifier = + [NSString stringWithFormat:@"%@_%@", kGTMSessionIdentifierPrefix, _sessionIdentifierUUID]; + // Start with user-supplied keys so they cannot accidentally override the fetcher's keys. + NSMutableDictionary *metadataDict = + [NSMutableDictionary dictionaryWithDictionary:(NSDictionary * GTM_NONNULL_TYPE)_sessionUserInfo]; + + if (metadataToInclude) { + [metadataDict addEntriesFromDictionary:(NSDictionary *)metadataToInclude]; + } + NSDictionary *defaultMetadataDict = [self sessionIdentifierDefaultMetadata]; + if (defaultMetadataDict) { + [metadataDict addEntriesFromDictionary:defaultMetadataDict]; + } + if (metadataDict.count > 0) { + NSData *metadataData = [NSJSONSerialization dataWithJSONObject:metadataDict + options:0 + error:NULL]; + GTMSESSION_ASSERT_DEBUG(metadataData != nil, + @"Session identifier user info failed to convert to JSON"); + if (metadataData.length > 0) { + NSString *metadataString = [[NSString alloc] initWithData:metadataData + encoding:NSUTF8StringEncoding]; + _sessionIdentifier = + [_sessionIdentifier stringByAppendingFormat:@"_%@", metadataString]; + } + } + _didCreateSessionIdentifier = YES; + result = _sessionIdentifier; + } // @synchronized(self) + return result; +} + +- (void)failToBeginFetchWithError:(NSError *)error { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _hasStoppedFetching = YES; + } + + if (error == nil) { + error = [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorDownloadFailed + userInfo:nil]; + } + + [self invokeFetchCallbacksOnCallbackQueueWithData:nil + error:error]; + [self releaseCallbacks]; + + [_service fetcherDidStop:self]; + + self.authorizer = nil; +} + ++ (GTMSessionCookieStorage *)staticCookieStorage { + static GTMSessionCookieStorage *gCookieStorage = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gCookieStorage = [[GTMSessionCookieStorage alloc] init]; + }); + return gCookieStorage; +} + +#if GTM_BACKGROUND_TASK_FETCHING + +- (void)endBackgroundTask { + // Whenever the connection stops or background execution expires, + // we need to tell UIApplication we're done. + UIBackgroundTaskIdentifier bgTaskID; + @synchronized(self) { + bgTaskID = self.backgroundTaskIdentifier; + if (bgTaskID != UIBackgroundTaskInvalid) { + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + } + + if (bgTaskID != UIBackgroundTaskInvalid) { + id app = [[self class] fetcherUIApplication]; + [app endBackgroundTask:bgTaskID]; + } +} + +#endif // GTM_BACKGROUND_TASK_FETCHING + +- (void)authorizeRequest { + GTMSessionCheckNotSynchronized(self); + + id authorizer = self.authorizer; + SEL asyncAuthSel = @selector(authorizeRequest:delegate:didFinishSelector:); + if ([authorizer respondsToSelector:asyncAuthSel]) { + SEL callbackSel = @selector(authorizer:request:finishedWithError:); + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + [authorizer authorizeRequest:mutableRequest + delegate:self + didFinishSelector:callbackSel]; + } else { + GTMSESSION_ASSERT_DEBUG(authorizer == nil, @"invalid authorizer for fetch"); + + // No authorizing possible, and authorizing happens only after any delay; + // just begin fetching + [self beginFetchMayDelay:NO + mayAuthorize:NO]; + } +} + +- (void)authorizer:(id)auth + request:(NSMutableURLRequest *)authorizedRequest + finishedWithError:(NSError *)error { + GTMSessionCheckNotSynchronized(self); + + if (error != nil) { + // We can't fetch without authorization + [self failToBeginFetchWithError:error]; + } else { + @synchronized(self) { + _request = authorizedRequest; + } + [self beginFetchMayDelay:NO + mayAuthorize:NO]; + } +} + + +- (BOOL)canFetchWithBackgroundSession { + // Subclasses may override. + return YES; +} + +// Returns YES if the fetcher has been started and has not yet stopped. +// +// Fetching includes waiting for authorization or for retry, waiting to be allowed by the +// service object to start the request, and actually fetching the request. +- (BOOL)isFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [self isFetchingUnsynchronized]; + } +} + +- (BOOL)isFetchingUnsynchronized { + GTMSessionCheckSynchronized(self); + + BOOL hasBegun = (_initialBeginFetchDate != nil); + return hasBegun && !_hasStoppedFetching; +} + +- (NSURLResponse * GTM_NULLABLE_TYPE)response { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + return response; + } // @synchronized(self) +} + +- (NSURLResponse * GTM_NULLABLE_TYPE)responseUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = _sessionTask.response; + if (!response) response = _response; + return response; +} + +- (NSInteger)statusCode { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSInteger statusCode = [self statusCodeUnsynchronized]; + return statusCode; + } // @synchronized(self) +} + +- (NSInteger)statusCodeUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + NSInteger statusCode; + + if ([response respondsToSelector:@selector(statusCode)]) { + statusCode = [(NSHTTPURLResponse *)response statusCode]; + } else { + // Default to zero, in hopes of hinting "Unknown" (we can't be + // sure that things are OK enough to use 200). + statusCode = 0; + } + return statusCode; +} + +- (NSDictionary * GTM_NULLABLE_TYPE)responseHeaders { + GTMSessionCheckNotSynchronized(self); + + NSURLResponse *response = self.response; + if ([response respondsToSelector:@selector(allHeaderFields)]) { + NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; + return headers; + } + return nil; +} + +- (NSDictionary * GTM_NULLABLE_TYPE)responseHeadersUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + if ([response respondsToSelector:@selector(allHeaderFields)]) { + NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; + return headers; + } + return nil; +} + +- (void)releaseCallbacks { + // Avoid releasing blocks in the sync section since objects dealloc'd by + // the blocks being released may call back into the fetcher or fetcher + // service. + dispatch_queue_t NS_VALID_UNTIL_END_OF_SCOPE holdCallbackQueue; + GTMSessionFetcherCompletionHandler NS_VALID_UNTIL_END_OF_SCOPE holdCompletionHandler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + holdCallbackQueue = _callbackQueue; + holdCompletionHandler = _completionHandler; + + _callbackQueue = nil; + _completionHandler = nil; // Setter overridden in upload. Setter assumed to be used externally. + } + + // Set local callback pointers to nil here rather than let them release at the end of the scope + // to make any problems due to the blocks being released be a bit more obvious in a stack trace. + holdCallbackQueue = nil; + holdCompletionHandler = nil; + + self.configurationBlock = nil; + self.didReceiveResponseBlock = nil; + self.challengeBlock = nil; + self.willRedirectBlock = nil; + self.sendProgressBlock = nil; + self.receivedProgressBlock = nil; + self.downloadProgressBlock = nil; + self.accumulateDataBlock = nil; + self.willCacheURLResponseBlock = nil; + self.retryBlock = nil; + self.testBlock = nil; + self.resumeDataBlock = nil; +} + +- (void)forgetSessionIdentifierForFetcher { + GTMSessionCheckSynchronized(self); + [self forgetSessionIdentifierForFetcherWithoutSyncCheck]; +} + +- (void)forgetSessionIdentifierForFetcherWithoutSyncCheck { + // This should be called inside a @synchronized block (except during dealloc.) + if (_sessionIdentifier) { + NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap]; + [sessionIdentifierToFetcherMap removeObjectForKey:_sessionIdentifier]; + _sessionIdentifier = nil; + _didCreateSessionIdentifier = NO; + } +} + +// External stop method +- (void)stopFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Prevent enqueued callbacks from executing. + _userStoppedFetching = YES; + } // @synchronized(self) + [self stopFetchReleasingCallbacks:YES]; +} + +// Cancel the fetch of the URL that's currently in progress. +// +// If shouldReleaseCallbacks is NO then the fetch will be retried so the callbacks +// need to still be retained. +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks { + [self removePersistedBackgroundSessionFromDefaults]; + + id service; + NSMutableURLRequest *request; + + // If the task or the retry timer is all that's retaining the fetcher, + // we want to be sure this instance survives stopping at least long enough for + // the stack to unwind. + __autoreleasing GTMSessionFetcher *holdSelf = self; + + BOOL hasCanceledTask = NO; + + [holdSelf destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _hasStoppedFetching = YES; + + service = _service; + request = _request; + + if (_sessionTask) { + // In case cancelling the task or session calls this recursively, we want + // to ensure that we'll only release the task and delegate once, + // so first set _sessionTask to nil + // + // This may be called in a callback from the task, so use autorelease to avoid + // releasing the task in its own callback. + __autoreleasing NSURLSessionTask *oldTask = _sessionTask; + if (!_isUsingTestBlock) { + _response = _sessionTask.response; + } + _sessionTask = nil; + + if ([oldTask state] != NSURLSessionTaskStateCompleted) { + // For download tasks, when the fetch is stopped, we may provide resume data that can + // be used to create a new session. + BOOL mayResume = (_resumeDataBlock + && [oldTask respondsToSelector:@selector(cancelByProducingResumeData:)]); + if (!mayResume) { + [oldTask cancel]; + // A side effect of stopping the task is that URLSession:task:didCompleteWithError: + // will be invoked asynchronously on the delegate queue. + } else { + void (^resumeBlock)(NSData *) = _resumeDataBlock; + _resumeDataBlock = nil; + + // Save callbackQueue since releaseCallbacks clears it. + dispatch_queue_t callbackQueue = _callbackQueue; + dispatch_group_enter(_callbackGroup); + [(NSURLSessionDownloadTask *)oldTask cancelByProducingResumeData:^(NSData *resumeData) { + [self invokeOnCallbackQueue:callbackQueue + afterUserStopped:YES + block:^{ + resumeBlock(resumeData); + dispatch_group_leave(_callbackGroup); + }]; + }]; + } + hasCanceledTask = YES; + } + } + + // If the task was canceled, wait until the URLSession:task:didCompleteWithError: to call + // finishTasksAndInvalidate, since calling it immediately tends to crash, see radar 18471901. + if (_session) { + BOOL shouldInvalidate = _shouldInvalidateSession; +#if TARGET_OS_IPHONE + // Don't invalidate if we've got a systemCompletionHandler, since + // URLSessionDidFinishEventsForBackgroundURLSession: won't be called if invalidated. + shouldInvalidate = shouldInvalidate && !self.systemCompletionHandler; +#endif + if (shouldInvalidate) { + __autoreleasing NSURLSession *oldSession = _session; + _session = nil; + + if (!hasCanceledTask) { + [oldSession finishTasksAndInvalidate]; + } else { + _sessionNeedingInvalidation = oldSession; + } + } + } + } // @synchronized(self) + + // send the stopped notification + [self sendStopNotificationIfNeeded]; + + [_authorizer stopAuthorizationForRequest:request]; + + if (shouldReleaseCallbacks) { + [self releaseCallbacks]; + + self.authorizer = nil; + } + + [service fetcherDidStop:self]; + +#if GTM_BACKGROUND_TASK_FETCHING + [self endBackgroundTask]; +#endif +} + +- (void)setStopNotificationNeeded:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _isStopNotificationNeeded = flag; + } // @synchronized(self) +} + +- (void)sendStopNotificationIfNeeded { + BOOL sendNow = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_isStopNotificationNeeded) { + _isStopNotificationNeeded = NO; + sendNow = YES; + } + } // @synchronized(self) + + if (sendNow) { + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherStoppedNotification + userInfo:nil + requireAsync:NO]; + } +} + +- (void)retryFetch { + [self stopFetchReleasingCallbacks:NO]; + + GTMSessionFetcherCompletionHandler completionHandler; + + // A retry will need a configuration with a fresh session identifier. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionIdentifier && _didCreateSessionIdentifier) { + [self forgetSessionIdentifierForFetcher]; + _configuration = nil; + } + + if (_canShareSession) { + // Force a grab of the current session from the fetcher service in case + // the service's old one has become invalid. + _session = nil; + } + + completionHandler = _completionHandler; + } // @synchronized(self) + + [self beginFetchWithCompletionHandler:completionHandler]; +} + +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds { + // Uncovered in upload fetcher testing, because the chunk fetcher is being waited on, and gets + // released by the upload code. The uploader just holds onto it with an ivar, and that gets + // nilled in the chunk fetcher callback. + // Used once in while loop just to avoid unused variable compiler warning. + __autoreleasing GTMSessionFetcher *holdSelf = self; + + NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + + BOOL shouldSpinRunLoop = ([NSThread isMainThread] && + (!self.callbackQueue + || self.callbackQueue == dispatch_get_main_queue())); + BOOL expired = NO; + + // Loop until the callbacks have been called and released, and until + // the connection is no longer pending, until there are no callback dispatches + // in flight, or until the timeout has expired. + int64_t delta = (int64_t)(100 * NSEC_PER_MSEC); // 100 ms + while (1) { + BOOL isTaskInProgress = (holdSelf->_sessionTask + && [_sessionTask state] != NSURLSessionTaskStateCompleted); + BOOL needsToCallCompletion = (_completionHandler != nil); + BOOL isCallbackInProgress = (_callbackGroup + && dispatch_group_wait(_callbackGroup, dispatch_time(DISPATCH_TIME_NOW, delta))); + + if (!isTaskInProgress && !needsToCallCompletion && !isCallbackInProgress) break; + + expired = ([giveUpDate timeIntervalSinceNow] < 0); + if (expired) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher waitForCompletionWithTimeout:%0.1f expired -- " + @"%@%@%@", timeoutInSeconds, + isTaskInProgress ? @"taskInProgress " : @"", + needsToCallCompletion ? @"needsToCallCompletion " : @"", + isCallbackInProgress ? @"isCallbackInProgress" : @""); + break; + } + + // Run the current run loop 1/1000 of a second to give the networking + // code a chance to work + const NSTimeInterval kSpinInterval = 0.001; + if (shouldSpinRunLoop) { + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:kSpinInterval]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + [NSThread sleepForTimeInterval:kSpinInterval]; + } + } + return !expired; +} + ++ (void)setGlobalTestBlock:(GTMSessionFetcherTestBlock GTM_NULLABLE_TYPE)block { +#if GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSESSION_ASSERT_DEBUG(block == nil, @"test blocks disabled"); +#endif + gGlobalTestBlock = [block copy]; +} + +#if TARGET_OS_IPHONE + +static GTM_NULLABLE_TYPE id gSubstituteUIApp; + ++ (void)setSubstituteUIApplication:(nullable id)app { + gSubstituteUIApp = app; +} + ++ (nullable id)substituteUIApplication { + return gSubstituteUIApp; +} + ++ (nullable id)fetcherUIApplication { + id app = gSubstituteUIApp; + if (app) return app; + + // iOS App extensions should not call [UIApplication sharedApplication], even + // if UIApplication responds to it. + + static Class applicationClass = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + BOOL isAppExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + if (!isAppExtension) { + Class cls = NSClassFromString(@"UIApplication"); + if (cls && [cls respondsToSelector:NSSelectorFromString(@"sharedApplication")]) { + applicationClass = cls; + } + } + }); + + if (applicationClass) { + app = (id)[applicationClass sharedApplication]; + } + return app; +} +#endif // TARGET_OS_IPHONE + +#pragma mark NSURLSession Delegate Methods + +// NSURLSession documentation indicates that redirectRequest can be passed to the handler +// but empirically redirectRequest lacks the HTTP body, so passing it will break POSTs. +// Instead, we construct a new request, a copy of the original, with overrides from the +// redirect. + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +willPerformHTTPRedirection:(NSHTTPURLResponse *)redirectResponse + newRequest:(NSURLRequest *)redirectRequest + completionHandler:(void (^)(NSURLRequest * GTM_NULLABLE_TYPE))handler { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ willPerformHTTPRedirection:%@ newRequest:%@", + [self class], self, session, task, redirectResponse, redirectRequest); + + if ([self userStoppedFetching]) { + handler(nil); + return; + } + if (redirectRequest && redirectResponse) { + // Copy the original request, including the body. + NSURLRequest *originalRequest = self.request; + NSMutableURLRequest *newRequest = [originalRequest mutableCopy]; + + // Disallow scheme changes (say, from https to http). + NSURL *originalRequestURL = originalRequest.URL; + NSURL *redirectRequestURL = redirectRequest.URL; + + NSString *originalScheme = originalRequestURL.scheme; + NSString *redirectScheme = redirectRequestURL.scheme; + + if (originalScheme != nil + && [originalScheme caseInsensitiveCompare:@"http"] == NSOrderedSame + && redirectScheme != nil + && [redirectScheme caseInsensitiveCompare:@"https"] == NSOrderedSame) { + // Allow the change from http to https. + } else { + // Disallow any other scheme changes. + redirectScheme = originalScheme; + } + // The new requests's URL overrides the original's URL. + NSURLComponents *components = [NSURLComponents componentsWithURL:redirectRequestURL + resolvingAgainstBaseURL:NO]; + components.scheme = redirectScheme; + NSURL *newURL = components.URL; + [newRequest setURL:newURL]; + + // Any headers in the redirect override headers in the original. + NSDictionary *redirectHeaders = redirectRequest.allHTTPHeaderFields; + for (NSString *key in redirectHeaders) { + NSString *value = [redirectHeaders objectForKey:key]; + [newRequest setValue:value forHTTPHeaderField:key]; + } + + redirectRequest = newRequest; + + // Log the response we just received + [self setResponse:redirectResponse]; + [self logNowWithError:nil]; + + GTMSessionFetcherWillRedirectBlock willRedirectBlock = self.willRedirectBlock; + if (willRedirectBlock) { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + willRedirectBlock(redirectResponse, redirectRequest, ^(NSURLRequest *clientRequest) { + + // Update the request for future logging. + [self updateMutableRequest:[clientRequest mutableCopy]]; + + handler(clientRequest); + }); + }]; + } // @synchronized(self) + return; + } + // Continues here if the client did not provide a redirect block. + + // Update the request for future logging. + [self updateMutableRequest:[redirectRequest mutableCopy]]; + } + handler(redirectRequest); +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))handler { + [self setSessionTask:dataTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didReceiveResponse:%@", + [self class], self, session, dataTask, response); + void (^accumulateAndFinish)(NSURLSessionResponseDisposition) = + ^(NSURLSessionResponseDisposition dispositionValue) { + // This method is called when the server has determined that it + // has enough information to create the NSURLResponse + // it can be called multiple times, for example in the case of a + // redirect, so each time we reset the data. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL hadPreviousData = _downloadedLength > 0; + + [_downloadedData setLength:0]; + _downloadedLength = 0; + + if (hadPreviousData && (dispositionValue != NSURLSessionResponseCancel)) { + // Tell the accumulate block to discard prior data. + GTMSessionFetcherAccumulateDataBlock accumulateBlock = _accumulateDataBlock; + if (accumulateBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateBlock(nil); + }]; + } + } + } // @synchronized(self) + handler(dispositionValue); + }; + + GTMSessionFetcherDidReceiveResponseBlock receivedResponseBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + receivedResponseBlock = _didReceiveResponseBlock; + if (receivedResponseBlock) { + // We will ultimately need to call back to NSURLSession's handler with the disposition value + // for this delegate method even if the user has stopped the fetcher. + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + receivedResponseBlock(response, ^(NSURLSessionResponseDisposition desiredDisposition) { + accumulateAndFinish(desiredDisposition); + }); + }]; + } + } // @synchronized(self) + + if (receivedResponseBlock == nil) { + accumulateAndFinish(NSURLSessionResponseAllow); + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didBecomeDownloadTask:%@", + [self class], self, session, dataTask, downloadTask); + [self setSessionTask:downloadTask]; +} + + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential))handler { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didReceiveChallenge:%@", + [self class], self, session, task, challenge); + + GTMSessionFetcherChallengeBlock challengeBlock = self.challengeBlock; + if (challengeBlock) { + // The fetcher user has provided custom challenge handling. + // + // We will ultimately need to call back to NSURLSession's handler with the disposition value + // for this delegate method even if the user has stopped the fetcher. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + challengeBlock(self, challenge, handler); + }]; + } + } else { + // No challenge block was provided by the client. + [self respondToChallenge:challenge + completionHandler:handler]; + } +} + +- (void)respondToChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * GTM_NULLABLE_TYPE credential))handler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSInteger previousFailureCount = [challenge previousFailureCount]; + if (previousFailureCount <= 2) { + NSURLProtectionSpace *protectionSpace = [challenge protectionSpace]; + NSString *authenticationMethod = [protectionSpace authenticationMethod]; + if ([authenticationMethod isEqual:NSURLAuthenticationMethodServerTrust]) { + // SSL. + // + // Background sessions seem to require an explicit check of the server trust object + // rather than default handling. + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + if (serverTrust == NULL) { + // No server trust information is available. + handler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } else { + // Server trust information is available. + void (^callback)(SecTrustRef, BOOL) = ^(SecTrustRef trustRef, BOOL allow){ + if (allow) { + NSURLCredential *trustCredential = [NSURLCredential credentialForTrust:trustRef]; + handler(NSURLSessionAuthChallengeUseCredential, trustCredential); + } else { + GTMSESSION_LOG_DEBUG(@"Cancelling authentication challenge for %@", _request.URL); + handler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + }; + if (_allowInvalidServerCertificates) { + callback(serverTrust, YES); + } else { + [[self class] evaluateServerTrust:serverTrust + forRequest:_request + completionHandler:callback]; + } + } + return; + } + + NSURLCredential *credential = _credential; + + if ([[challenge protectionSpace] isProxy] && _proxyCredential != nil) { + credential = _proxyCredential; + } + + if (credential) { + handler(NSURLSessionAuthChallengeUseCredential, credential); + } else { + // The credential is still nil; tell the OS to use the default handling. This is needed + // for things that can come out of the keychain (proxies, client certificates, etc.). + // + // Note: Looking up a credential with NSURLCredentialStorage's + // defaultCredentialForProtectionSpace: is *not* the same invoking the handler with + // NSURLSessionAuthChallengePerformDefaultHandling. In the case of + // NSURLAuthenticationMethodClientCertificate, you can get nil back from + // NSURLCredentialStorage, while using this code path instead works. + handler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } + + } else { + // We've failed auth 3 times. The completion handler will be called with code + // NSURLErrorCancelled. + handler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + } // @synchronized(self) +} + +// Validate the certificate chain. +// +// This may become a public method if it appears to be useful to users. ++ (void)evaluateServerTrust:(SecTrustRef)serverTrust + forRequest:(NSURLRequest *)request + completionHandler:(void (^)(SecTrustRef trustRef, BOOL allow))handler { + // Retain the trust object to avoid a SecTrustEvaluate() crash on iOS 7. + CFRetain(serverTrust); + + // Evaluate the certificate chain. + // + // The delegate queue may be the main thread. Trust evaluation could cause some + // blocking network activity, so we must evaluate async, as documented at + // https://developer.apple.com/library/ios/technotes/tn2232/ + // + // We must also avoid multiple uses of the trust object, per docs: + // "It is not safe to call this function concurrently with any other function that uses + // the same trust management object, or to re-enter this function for the same trust + // management object." + // + // SecTrustEvaluateAsync both does sync execution of Evaluate and calls back on the + // queue passed to it, according to at sources in + // http://www.opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-55050.9/lib/SecTrust.cpp + // It would require a global serial queue to ensure the evaluate happens only on a + // single thread at a time, so we'll stick with using SecTrustEvaluate on a background + // thread. + dispatch_queue_t evaluateBackgroundQueue = + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(evaluateBackgroundQueue, ^{ + // It looks like the implementation of SecTrustEvaluate() on Mac grabs a global lock, + // so it may be redundant for us to also lock, but it's easy to synchronize here + // anyway. + SecTrustResultType trustEval = kSecTrustResultInvalid; + BOOL shouldAllow; + OSStatus trustError; + @synchronized([GTMSessionFetcher class]) { + GTMSessionMonitorSynchronized([GTMSessionFetcher class]); + + trustError = SecTrustEvaluate(serverTrust, &trustEval); + } + if (trustError != errSecSuccess) { + GTMSESSION_LOG_DEBUG(@"Error %d evaluating trust for %@", + (int)trustError, request); + shouldAllow = NO; + } else { + // Having a trust level "unspecified" by the user is the usual result, described at + // https://developer.apple.com/library/mac/qa/qa1360 + if (trustEval == kSecTrustResultUnspecified + || trustEval == kSecTrustResultProceed) { + shouldAllow = YES; + } else { + shouldAllow = NO; + GTMSESSION_LOG_DEBUG(@"Challenge SecTrustResultType %u for %@, properties: %@", + trustEval, request.URL.host, + CFBridgingRelease(SecTrustCopyProperties(serverTrust))); + } + } + handler(serverTrust, shouldAllow); + + CFRelease(serverTrust); + }); +} + +- (void)invokeOnCallbackQueueUnlessStopped:(void (^)(void))block { + [self invokeOnCallbackQueueAfterUserStopped:NO + block:block]; +} + +- (void)invokeOnCallbackQueueAfterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + GTMSessionCheckSynchronized(self); + + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:afterStopped + block:block]; +} + +- (void)invokeOnCallbackUnsynchronizedQueueAfterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + // testBlock simulation code may not be synchronizing when this is invoked. + [self invokeOnCallbackQueue:_callbackQueue + afterUserStopped:afterStopped + block:block]; +} + +- (void)invokeOnCallbackQueue:(dispatch_queue_t)callbackQueue + afterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + if (callbackQueue) { + dispatch_group_async(_callbackGroup, callbackQueue, ^{ + if (!afterStopped) { + NSDate *serviceStoppedAllDate = [_service stoppedAllFetchersDate]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Avoid a race between stopFetching and the callback. + if (_userStoppedFetching) { + return; + } + + // Also avoid calling back if the service has stopped all fetchers + // since this one was created. The fetcher may have stopped before + // stopAllFetchers was invoked, so _userStoppedFetching wasn't set, + // but the app still won't expect the callback to fire after + // the service's stopAllFetchers was invoked. + if (serviceStoppedAllDate + && [_initialBeginFetchDate compare:serviceStoppedAllDate] != NSOrderedDescending) { + // stopAllFetchers was called after this fetcher began. + return; + } + } // @synchronized(self) + } + block(); + }); + } +} + +- (void)invokeFetchCallbacksOnCallbackQueueWithData:(GTM_NULLABLE NSData *)data + error:(GTM_NULLABLE NSError *)error { + // Callbacks will be released in the method stopFetchReleasingCallbacks: + GTMSessionFetcherCompletionHandler handler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + handler = _completionHandler; + + if (handler) { + [self invokeOnCallbackQueueUnlessStopped:^{ + handler(data, error); + + // Post a notification, primarily to allow code to collect responses for + // testing. + // + // The observing code is not likely on the fetcher's callback + // queue, so this posts explicitly to the main queue. + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (data) { + userInfo[kGTMSessionFetcherCompletionDataKey] = data; + } + if (error) { + userInfo[kGTMSessionFetcherCompletionErrorKey] = error; + } + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherCompletionInvokedNotification + userInfo:userInfo + requireAsync:NO]; + }]; + } + } // @synchronized(self) +} + +- (void)postNotificationOnMainThreadWithName:(NSString *)noteName + userInfo:(GTM_NULLABLE NSDictionary *)userInfo + requireAsync:(BOOL)requireAsync { + dispatch_block_t postBlock = ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:noteName + object:self + userInfo:userInfo]; + }; + + if ([NSThread isMainThread] && !requireAsync) { + // Post synchronously for compatibility with older code using the fetcher. + + // Avoid calling out to other code from inside a sync block to avoid risk + // of a deadlock or of recursive sync. + GTMSessionCheckNotSynchronized(self); + + postBlock(); + } else { + dispatch_async(dispatch_get_main_queue(), postBlock); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)uploadTask + needNewBodyStream:(void (^)(NSInputStream * GTM_NULLABLE_TYPE bodyStream))completionHandler { + [self setSessionTask:uploadTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ needNewBodyStream:", + [self class], self, session, uploadTask); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSessionFetcherBodyStreamProvider provider = _bodyStreamProvider; +#if !STRIP_GTM_FETCH_LOGGING + if ([self respondsToSelector:@selector(loggedStreamProviderForStreamProvider:)]) { + provider = [self performSelector:@selector(loggedStreamProviderForStreamProvider:) + withObject:provider]; + } +#endif + if (provider) { + [self invokeOnCallbackQueueUnlessStopped:^{ + provider(completionHandler); + }]; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"NSURLSession expects a stream provider"); + + completionHandler(nil); + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didSendBodyData:%lld" + @" totalBytesSent:%lld totalBytesExpectedToSend:%lld", + [self class], self, session, task, bytesSent, totalBytesSent, + totalBytesExpectedToSend); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (!_sendProgressBlock) { + return; + } + // We won't hold on to send progress block; it's ok to not send it if the upload finishes. + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherSendProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = _sendProgressBlock; + } + if (progressBlock) { + progressBlock(bytesSent, totalBytesSent, totalBytesExpectedToSend); + } + }]; + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + [self setSessionTask:dataTask]; + NSUInteger bufferLength = data.length; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didReceiveData:%p (%llu bytes)", + [self class], self, session, dataTask, data, + (unsigned long long)bufferLength); + if (bufferLength == 0) { + // Observed on completing an out-of-process upload. + return; + } + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSessionFetcherAccumulateDataBlock accumulateBlock = _accumulateDataBlock; + if (accumulateBlock) { + // Let the client accumulate the data. + _downloadedLength += bufferLength; + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateBlock(data); + }]; + } else if (!_userStoppedFetching) { + // Append to the mutable data buffer unless the fetch has been cancelled. + + // Resumed upload tasks may not yet have a data buffer. + if (_downloadedData == nil) { + // Using NSClassFromString for iOS 6 compatibility. + GTMSESSION_ASSERT_DEBUG( + ![dataTask isKindOfClass:NSClassFromString(@"NSURLSessionDownloadTask")], + @"Resumed download tasks should not receive data bytes"); + _downloadedData = [[NSMutableData alloc] init]; + } + + [_downloadedData appendData:data]; + _downloadedLength = (int64_t)_downloadedData.length; + + // We won't hold on to receivedProgressBlock here; it's ok to not send + // it if the transfer finishes. + if (_receivedProgressBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherReceivedProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = _receivedProgressBlock; + } + if (progressBlock) { + progressBlock((int64_t)bufferLength, _downloadedLength); + } + }]; + } + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ willCacheResponse:%@ %@", + [self class], self, session, dataTask, + proposedResponse, proposedResponse.response); + GTMSessionFetcherWillCacheURLResponseBlock callback; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + callback = _willCacheURLResponseBlock; + + if (callback) { + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + callback(proposedResponse, completionHandler); + }]; + } + } // @synchronized(self) + if (!callback) { + completionHandler(proposedResponse); + } +} + + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalBytesWritten +totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didWriteData:%lld" + @" bytesWritten:%lld totalBytesExpectedToWrite:%lld", + [self class], self, session, downloadTask, bytesWritten, + totalBytesWritten, totalBytesExpectedToWrite); + [self setSessionTask:downloadTask]; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if ((totalBytesExpectedToWrite != NSURLSessionTransferSizeUnknown) && + (totalBytesExpectedToWrite < totalBytesWritten)) { + // Have observed cases were bytesWritten == totalBytesExpectedToWrite, + // but totalBytesWritten > totalBytesExpectedToWrite, so setting to unkown in these cases. + totalBytesExpectedToWrite = NSURLSessionTransferSizeUnknown; + } + // We won't hold on to download progress block during the enqueue; + // it's ok to not send it if the upload finishes. + + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherDownloadProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = _downloadProgressBlock; + } + if (progressBlock) { + progressBlock(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + } + }]; + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset +expectedTotalBytes:(int64_t)expectedTotalBytes { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didResumeAtOffset:%lld" + @" expectedTotalBytes:%lld", + [self class], self, session, downloadTask, fileOffset, + expectedTotalBytes); + [self setSessionTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask +didFinishDownloadingToURL:(NSURL *)downloadLocationURL { + // Download may have relaunched app, so update _sessionTask. + [self setSessionTask:downloadTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didFinishDownloadingToURL:%@", + [self class], self, session, downloadTask, downloadLocationURL); + NSNumber *fileSizeNum; + [downloadLocationURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:NULL]; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURL *destinationURL = _destinationFileURL; + + _downloadedLength = fileSizeNum.longLongValue; + + // Overwrite any previous file at the destination URL. + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSError *removeError; + if (![fileMgr removeItemAtURL:destinationURL error:&removeError] + && removeError.code != NSFileNoSuchFileError) { + GTMSESSION_LOG_DEBUG(@"Could not remove previous file at %@ due to %@", + downloadLocationURL.path, removeError); + } + + NSInteger statusCode = [self statusCodeUnsynchronized]; + if (statusCode < 200 || statusCode > 399) { + // In OS X 10.11, the response body is written to a file even on a server + // status error. For convenience of the fetcher client, we'll skip saving the + // downloaded body to the destination URL so that clients do not need to know + // to delete the file following fetch errors. A downside of this is that + // the server may have included error details in the response body, and + // abandoning the downloaded file here means that the details from the + // body are not available to the fetcher client. + GTMSESSION_LOG_DEBUG(@"Abandoning download due to status %zd, file %@", + statusCode, downloadLocationURL.path); + } else { + NSError *moveError; + NSURL *destinationFolderURL = [destinationURL URLByDeletingLastPathComponent]; + BOOL didMoveDownload = NO; + if ([fileMgr createDirectoryAtURL:destinationFolderURL + withIntermediateDirectories:YES + attributes:nil + error:&moveError]) { + didMoveDownload = [fileMgr moveItemAtURL:downloadLocationURL + toURL:destinationURL + error:&moveError]; + } + if (!didMoveDownload) { + _downloadFinishedError = moveError; + } + GTM_LOG_BACKGROUND_SESSION(@"%@ %p Moved download from \"%@\" to \"%@\" %@", + [self class], self, + downloadLocationURL.path, destinationURL.path, + error ? error : @""); + } + } // @synchronized(self) +} + +/* Sent as the last message related to a specific task. Error may be + * nil, which implies that no error occurred and this task is complete. + */ +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didCompleteWithError:%@", + [self class], self, session, task, error); + + NSInteger status = self.statusCode; + BOOL forceAssumeRetry = NO; + BOOL succeeded = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + // The task is never resumed when a testBlock is used. When the session is destroyed, + // we should ignore the callback, since the testBlock support code itself invokes + // shouldRetryNowForStatus: and finishWithError:shouldRetry: + if (_isUsingTestBlock) return; +#endif + + if (error == nil) { + error = _downloadFinishedError; + } + succeeded = (error == nil && status >= 0 && status < 300); + if (succeeded) { + // Succeeded. + _bodyLength = task.countOfBytesSent; + } + } // @synchronized(self) + + if (succeeded) { + [self finishWithError:nil shouldRetry:NO]; + return; + } + // For background redirects, no delegate method is called, so we cannot restore a stripped + // Authorization header, so if a 403 ("Forbidden") was generated due to a missing OAuth 2 header, + // set the current request's URL to the redirected URL, so we in effect restore the Authorization + // header. + if ((status == 403) && self.usingBackgroundSession) { + NSURL *redirectURL = self.response.URL; + NSURLRequest *request = self.request; + if (![request.URL isEqual:redirectURL]) { + NSString *authorizationHeader = [request.allHTTPHeaderFields objectForKey:@"Authorization"]; + if (authorizationHeader != nil) { + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + mutableRequest.URL = redirectURL; + [self updateMutableRequest:mutableRequest]; + // Avoid assuming the session is still valid. + self.session = nil; + forceAssumeRetry = YES; + } + } + } + + // If invalidating the session was deferred in stopFetchReleasingCallbacks: then do it now. + NSURLSession *oldSession = self.sessionNeedingInvalidation; + if (oldSession) { + [self setSessionNeedingInvalidation:NULL]; + [oldSession finishTasksAndInvalidate]; + } + + // Failed. + [self shouldRetryNowForStatus:status + error:error + forceAssumeRetry:forceAssumeRetry + response:^(BOOL shouldRetry) { + [self finishWithError:error shouldRetry:shouldRetry]; + }]; +} + +#if TARGET_OS_IPHONE +- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSessionDidFinishEventsForBackgroundURLSession:%@", + [self class], self, session); + [self removePersistedBackgroundSessionFromDefaults]; + + GTMSessionFetcherSystemCompletionHandler handler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + handler = self.systemCompletionHandler; + self.systemCompletionHandler = nil; + } // @synchronized(self) + if (handler) { + GTM_LOG_BACKGROUND_SESSION(@"%@ %p Calling system completionHandler", [self class], self); + handler(); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLSession *oldSession = _session; + _session = nil; + if (_shouldInvalidateSession) { + [oldSession finishTasksAndInvalidate]; + } + } // @synchronized(self) + } +} +#endif + +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(GTM_NULLABLE NSError *)error { + // This may happen repeatedly for retries. On authentication callbacks, the retry + // may begin before the prior session sends the didBecomeInvalid delegate message. + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", + [self class], self, session, error); + if (session == (NSURLSession *)self.session) { + GTM_LOG_SESSION_DELEGATE(@" Unexpected retained invalid session: %@", session); + self.session = nil; + } +} + +- (void)finishWithError:(GTM_NULLABLE NSError *)error shouldRetry:(BOOL)shouldRetry { + [self removePersistedBackgroundSessionFromDefaults]; + + BOOL shouldStopFetching = YES; + NSData *downloadedData = nil; +#if !STRIP_GTM_FETCH_LOGGING + BOOL shouldDeferLogging = NO; +#endif + BOOL shouldBeginRetryTimer = NO; + NSInteger status = [self statusCode]; + NSURL *destinationURL = self.destinationFileURL; + + BOOL fetchSucceeded = (error == nil && status >= 0 && status < 300); + +#if !STRIP_GTM_FETCH_LOGGING + if (!fetchSucceeded) { + if (!shouldDeferLogging && !self.hasLoggedError) { + [self logNowWithError:error]; + self.hasLoggedError = YES; + } + } +#endif // !STRIP_GTM_FETCH_LOGGING + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if !STRIP_GTM_FETCH_LOGGING + shouldDeferLogging = _deferResponseBodyLogging; +#endif + if (fetchSucceeded) { + // Success + if ((_downloadedData.length > 0) && (destinationURL != nil)) { + // Overwrite any previous file at the destination URL. + NSFileManager *fileMgr = [NSFileManager defaultManager]; + [fileMgr removeItemAtURL:destinationURL + error:NULL]; + NSURL *destinationFolderURL = [destinationURL URLByDeletingLastPathComponent]; + BOOL didMoveDownload = NO; + if ([fileMgr createDirectoryAtURL:destinationFolderURL + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + didMoveDownload = [_downloadedData writeToURL:destinationURL + options:NSDataWritingAtomic + error:&error]; + } + if (didMoveDownload) { + _downloadedData = nil; + } else { + _downloadFinishedError = error; + } + } + downloadedData = _downloadedData; + } else { + // Unsuccessful with error or status over 300. Retry or notify the delegate of failure + if (shouldRetry) { + // Retrying. + shouldBeginRetryTimer = YES; + shouldStopFetching = NO; + } else { + if (error == nil) { + // Create an error. + NSDictionary *userInfo = nil; + if (_downloadedData.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : _downloadedData }; + } + error = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:status + userInfo:userInfo]; + } else { + // If the error had resume data, and the client supplied a resume block, pass the + // data to the client. + void (^resumeBlock)(NSData *) = _resumeDataBlock; + _resumeDataBlock = nil; + if (resumeBlock) { + NSData *resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]; + if (resumeData) { + [self invokeOnCallbackQueueAfterUserStopped:YES block:^{ + resumeBlock(resumeData); + }]; + } + } + } + if (_downloadedData.length > 0) { + downloadedData = _downloadedData; + } + // If the error occurred after retries, report the number and duration of the + // retries. This provides a clue to a developer looking at the error description + // that the fetcher did retry before failing with this error. + if (_retryCount > 0) { + NSMutableDictionary *userInfoWithRetries = + [NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)error.userInfo]; + NSTimeInterval timeSinceInitialRequest = -[_initialRequestDate timeIntervalSinceNow]; + [userInfoWithRetries setObject:@(timeSinceInitialRequest) + forKey:kGTMSessionFetcherElapsedIntervalWithRetriesKey]; + [userInfoWithRetries setObject:@(_retryCount) + forKey:kGTMSessionFetcherNumberOfRetriesDoneKey]; + error = [NSError errorWithDomain:(NSString *)error.domain + code:error.code + userInfo:userInfoWithRetries]; + } + } + } + } // @synchronized(self) + + if (shouldBeginRetryTimer) { + [self beginRetryTimer]; + } + + // We want to send the stop notification before calling the delegate's + // callback selector, since the callback selector may release all of + // the fetcher properties that the client is using to track the fetches. + // + // We'll also stop now so that, to any observers watching the notifications, + // it doesn't look like our wait for a retry (which may be long, + // 30 seconds or more) is part of the network activity. + [self sendStopNotificationIfNeeded]; + + if (shouldStopFetching) { + [self invokeFetchCallbacksOnCallbackQueueWithData:downloadedData + error:error]; + // The upload subclass doesn't want to release callbacks until upload chunks have completed. + BOOL shouldRelease = [self shouldReleaseCallbacksUponCompletion]; + [self stopFetchReleasingCallbacks:shouldRelease]; + } + +#if !STRIP_GTM_FETCH_LOGGING + // _hasLoggedError is only set by this method + if (!shouldDeferLogging && !_hasLoggedError) { + [self logNowWithError:error]; + } +#endif +} + +- (BOOL)shouldReleaseCallbacksUponCompletion { + // A subclass can override this to keep callbacks around after the + // connection has finished successfully + return YES; +} + +- (void)logNowWithError:(GTM_NULLABLE NSError *)error { + GTMSessionCheckNotSynchronized(self); + + // If the logging category is available, then log the current request, + // response, data, and error + if ([self respondsToSelector:@selector(logFetchWithError:)]) { + [self performSelector:@selector(logFetchWithError:) withObject:error]; + } +} + +#pragma mark Retries + +- (BOOL)isRetryError:(NSError *)error { + struct RetryRecord { + __unsafe_unretained NSString *const domain; + NSInteger code; + }; + + struct RetryRecord retries[] = { + { kGTMSessionFetcherStatusDomain, 408 }, // request timeout + { kGTMSessionFetcherStatusDomain, 502 }, // failure gatewaying to another server + { kGTMSessionFetcherStatusDomain, 503 }, // service unavailable + { kGTMSessionFetcherStatusDomain, 504 }, // request timeout + { NSURLErrorDomain, NSURLErrorTimedOut }, + { NSURLErrorDomain, NSURLErrorNetworkConnectionLost }, + { nil, 0 } + }; + + // NSError's isEqual always returns false for equal but distinct instances + // of NSError, so we have to compare the domain and code values explicitly + NSString *domain = error.domain; + NSInteger code = error.code; + for (int idx = 0; retries[idx].domain != nil; idx++) { + if (code == retries[idx].code && [domain isEqual:retries[idx].domain]) { + return YES; + } + } + return NO; +} + +// shouldRetryNowForStatus:error: responds with YES if the user has enabled retries +// and the status or error is one that is suitable for retrying. "Suitable" +// means either the isRetryError:'s list contains the status or error, or the +// user's retry block is present and returns YES when called, or the +// authorizer may be able to fix. +- (void)shouldRetryNowForStatus:(NSInteger)status + error:(NSError *)error + forceAssumeRetry:(BOOL)forceAssumeRetry + response:(GTMSessionFetcherRetryResponse)response { + // Determine if a refreshed authorizer may avoid an authorization error + BOOL willRetry = NO; + + // We assume _authorizer is immutable after beginFetch, and _hasAttemptedAuthRefresh is modified + // only in this method, and this method is invoked on the serial delegate queue. + // + // We want to avoid calling the authorizer from inside a sync block. + BOOL isFirstAuthError = (_authorizer != nil + && !_hasAttemptedAuthRefresh + && status == GTMSessionFetcherStatusUnauthorized); // 401 + + BOOL hasPrimed = NO; + if (isFirstAuthError) { + if ([_authorizer respondsToSelector:@selector(primeForRefresh)]) { + hasPrimed = [_authorizer primeForRefresh]; + } + } + + BOOL shouldRetryForAuthRefresh = NO; + if (hasPrimed) { + shouldRetryForAuthRefresh = YES; + _hasAttemptedAuthRefresh = YES; + [self updateRequestValue:nil forHTTPHeaderField:@"Authorization"]; + } + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL shouldDoRetry = [self isRetryEnabledUnsynchronized]; + if (shouldDoRetry && ![self hasRetryAfterInterval]) { + + // Determine if we're doing exponential backoff retries + shouldDoRetry = [self nextRetryIntervalUnsynchronized] < _maxRetryInterval; + + if (shouldDoRetry) { + // If an explicit max retry interval was set, we expect repeated backoffs to take + // up to roughly twice that for repeated fast failures. If the initial attempt is + // already more than 3 times the max retry interval, then failures have taken a long time + // (such as from network timeouts) so don't retry again to avoid the app becoming + // unexpectedly unresponsive. + if (_maxRetryInterval > 0) { + NSTimeInterval maxAllowedIntervalBeforeRetry = _maxRetryInterval * 3; + NSTimeInterval timeSinceInitialRequest = -[_initialRequestDate timeIntervalSinceNow]; + if (timeSinceInitialRequest > maxAllowedIntervalBeforeRetry) { + shouldDoRetry = NO; + } + } + } + } + BOOL canRetry = shouldRetryForAuthRefresh || forceAssumeRetry || shouldDoRetry; + if (canRetry) { + NSDictionary *userInfo = nil; + if (_downloadedData.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : _downloadedData }; + } + NSError *statusError = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:status + userInfo:userInfo]; + if (error == nil) { + error = statusError; + } + willRetry = shouldRetryForAuthRefresh || + forceAssumeRetry || + [self isRetryError:error] || + ((error != statusError) && [self isRetryError:statusError]); + + // If the user has installed a retry callback, consult that. + GTMSessionFetcherRetryBlock retryBlock = _retryBlock; + if (retryBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + retryBlock(willRetry, error, response); + }]; + return; + } + } + } // @synchronized(self) + response(willRetry); +} + +- (BOOL)hasRetryAfterInterval { + GTMSessionCheckSynchronized(self); + + NSDictionary *responseHeaders = [self responseHeadersUnsynchronized]; + NSString *retryAfterValue = [responseHeaders valueForKey:@"Retry-After"]; + return (retryAfterValue != nil); +} + +- (NSTimeInterval)retryAfterInterval { + GTMSessionCheckSynchronized(self); + + NSDictionary *responseHeaders = [self responseHeadersUnsynchronized]; + NSString *retryAfterValue = [responseHeaders valueForKey:@"Retry-After"]; + if (retryAfterValue == nil) { + return 0; + } + // Retry-After formatted as HTTP-date | delta-seconds + // Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + NSDateFormatter *rfc1123DateFormatter = [[NSDateFormatter alloc] init]; + rfc1123DateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; + rfc1123DateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + rfc1123DateFormatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss z"; + NSDate *retryAfterDate = [rfc1123DateFormatter dateFromString:retryAfterValue]; + NSTimeInterval retryAfterInterval = (retryAfterDate != nil) ? + retryAfterDate.timeIntervalSinceNow : retryAfterValue.intValue; + retryAfterInterval = MAX(0, retryAfterInterval); + return retryAfterInterval; +} + +- (void)beginRetryTimer { + if (![NSThread isMainThread]) { + // Defer creating and starting the timer until we're on the main thread to ensure it has + // a run loop. + dispatch_group_async(_callbackGroup, dispatch_get_main_queue(), ^{ + [self beginRetryTimer]; + }); + return; + } + + [self destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval nextInterval = [self nextRetryIntervalUnsynchronized]; + NSTimeInterval maxInterval = _maxRetryInterval; + NSTimeInterval newInterval = MIN(nextInterval, (maxInterval > 0 ? maxInterval : DBL_MAX)); + NSTimeInterval newIntervalTolerance = (newInterval / 10) > 1.0 ?: 1.0; + + _lastRetryInterval = newInterval; + + _retryTimer = [NSTimer timerWithTimeInterval:newInterval + target:self + selector:@selector(retryTimerFired:) + userInfo:nil + repeats:NO]; + _retryTimer.tolerance = newIntervalTolerance; + [[NSRunLoop mainRunLoop] addTimer:_retryTimer + forMode:NSDefaultRunLoopMode]; + } // @synchronized(self) + + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherRetryDelayStartedNotification + userInfo:nil + requireAsync:NO]; +} + +- (void)retryTimerFired:(NSTimer *)timer { + [self destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _retryCount++; + } // @synchronized(self) + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + [self retryFetch]; + }]; +} + +- (void)destroyRetryTimer { + BOOL shouldNotify = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_retryTimer) { + [_retryTimer invalidate]; + _retryTimer = nil; + shouldNotify = YES; + } + } + + if (shouldNotify) { + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherRetryDelayStoppedNotification + userInfo:nil + requireAsync:NO]; + } +} + +- (NSUInteger)retryCount { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _retryCount; + } // @synchronized(self) +} + +- (NSTimeInterval)nextRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval interval = [self nextRetryIntervalUnsynchronized]; + return interval; + } // @synchronized(self) +} + +- (NSTimeInterval)nextRetryIntervalUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSInteger statusCode = [self statusCodeUnsynchronized]; + if ((statusCode == 503) && [self hasRetryAfterInterval]) { + NSTimeInterval secs = [self retryAfterInterval]; + return secs; + } + // The next wait interval is the factor (2.0) times the last interval, + // but never less than the minimum interval. + NSTimeInterval secs = _lastRetryInterval * _retryFactor; + if (_maxRetryInterval > 0) { + secs = MIN(secs, _maxRetryInterval); + } + secs = MAX(secs, _minRetryInterval); + + return secs; +} + +- (NSTimer *)retryTimer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _retryTimer; + } // @synchronized(self) +} + +- (BOOL)isRetryEnabled { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isRetryEnabled; + } // @synchronized(self) +} + +- (BOOL)isRetryEnabledUnsynchronized { + GTMSessionCheckSynchronized(self); + + return _isRetryEnabled; +} + +- (void)setRetryEnabled:(BOOL)flag { + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag && !_isRetryEnabled) { + // We defer initializing these until the user calls setRetryEnabled + // to avoid using the random number generator if it's not needed. + // However, this means min and max intervals for this fetcher are reset + // as a side effect of calling setRetryEnabled. + // + // Make an initial retry interval random between 1.0 and 2.0 seconds + _minRetryInterval = InitialMinRetryInterval(); + _maxRetryInterval = kUnsetMaxRetryInterval; + _retryFactor = 2.0; + _lastRetryInterval = 0.0; + } + _isRetryEnabled = flag; + } // @synchronized(self) +}; + +- (NSTimeInterval)maxRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _maxRetryInterval; + } // @synchronized(self) +} + +- (void)setMaxRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _maxRetryInterval = secs; + } else { + _maxRetryInterval = kUnsetMaxRetryInterval; + } + } // @synchronized(self) +} + +- (double)minRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _minRetryInterval; + } // @synchronized(self) +} + +- (void)setMinRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _minRetryInterval = secs; + } else { + // Set min interval to a random value between 1.0 and 2.0 seconds + // so that if multiple clients start retrying at the same time, they'll + // repeat at different times and avoid overloading the server + _minRetryInterval = InitialMinRetryInterval(); + } + } // @synchronized(self) + +} + +#pragma mark iOS System Completion Handlers + +#if TARGET_OS_IPHONE +static NSMutableDictionary *gSystemCompletionHandlers = nil; + +- (GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler { + return [[self class] systemCompletionHandlerForSessionIdentifier:_sessionIdentifier]; +} + +- (void)setSystemCompletionHandler:(GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler { + [[self class] setSystemCompletionHandler:systemCompletionHandler + forSessionIdentifier:_sessionIdentifier]; +} + ++ (void)setSystemCompletionHandler:(GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler + forSessionIdentifier:(NSString *)sessionIdentifier { + if (!sessionIdentifier) { + NSLog(@"%s with nil identifier", __PRETTY_FUNCTION__); + return; + } + + @synchronized([GTMSessionFetcher class]) { + if (gSystemCompletionHandlers == nil && systemCompletionHandler != nil) { + gSystemCompletionHandlers = [[NSMutableDictionary alloc] init]; + } + // Use setValue: to remove the object if completionHandler is nil. + [gSystemCompletionHandlers setValue:systemCompletionHandler + forKey:sessionIdentifier]; + } +} + ++ (GTM_NULLABLE GTMSessionFetcherSystemCompletionHandler)systemCompletionHandlerForSessionIdentifier:(NSString *)sessionIdentifier { + if (!sessionIdentifier) { + return nil; + } + @synchronized([GTMSessionFetcher class]) { + return [gSystemCompletionHandlers objectForKey:sessionIdentifier]; + } +} +#endif // TARGET_OS_IPHONE + +#pragma mark Getters and Setters + +@synthesize downloadResumeData = _downloadResumeData, + configuration = _configuration, + configurationBlock = _configurationBlock, + sessionTask = _sessionTask, + wasCreatedFromBackgroundSession = _wasCreatedFromBackgroundSession, + sessionUserInfo = _sessionUserInfo, + taskDescription = _taskDescription, + taskPriority = _taskPriority, + usingBackgroundSession = _usingBackgroundSession, + canShareSession = _canShareSession, + completionHandler = _completionHandler, + credential = _credential, + proxyCredential = _proxyCredential, + bodyData = _bodyData, + bodyLength = _bodyLength, + service = _service, + serviceHost = _serviceHost, + accumulateDataBlock = _accumulateDataBlock, + receivedProgressBlock = _receivedProgressBlock, + downloadProgressBlock = _downloadProgressBlock, + resumeDataBlock = _resumeDataBlock, + didReceiveResponseBlock = _didReceiveResponseBlock, + challengeBlock = _challengeBlock, + willRedirectBlock = _willRedirectBlock, + sendProgressBlock = _sendProgressBlock, + willCacheURLResponseBlock = _willCacheURLResponseBlock, + retryBlock = _retryBlock, + retryFactor = _retryFactor, + allowedInsecureSchemes = _allowedInsecureSchemes, + allowLocalhostRequest = _allowLocalhostRequest, + allowInvalidServerCertificates = _allowInvalidServerCertificates, + cookieStorage = _cookieStorage, + callbackQueue = _callbackQueue, + initialBeginFetchDate = _initialBeginFetchDate, + testBlock = _testBlock, + testBlockAccumulateDataChunkCount = _testBlockAccumulateDataChunkCount, + comment = _comment, + log = _log; + +#if !STRIP_GTM_FETCH_LOGGING +@synthesize redirectedFromURL = _redirectedFromURL, + logRequestBody = _logRequestBody, + logResponseBody = _logResponseBody, + hasLoggedError = _hasLoggedError; +#endif + +#if GTM_BACKGROUND_TASK_FETCHING +@synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier, + skipBackgroundTask = _skipBackgroundTask; +#endif + +- (GTM_NULLABLE NSURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_request copy]; + } // @synchronized(self) +} + +- (void)setRequest:(GTM_NULLABLE NSURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (![self isFetchingUnsynchronized]) { + _request = [request mutableCopy]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"request may not be set after beginFetch has been invoked"); + } + } // @synchronized(self) +} + +- (GTM_NULLABLE NSMutableURLRequest *)mutableRequestForTesting { + // Allow tests only to modify the request, useful during retries. + return _request; +} + +- (GTM_NULLABLE NSMutableURLRequest *)mutableRequest { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_LOG_DEBUG(@"[GTMSessionFetcher mutableRequest] is deprecated; use -request or" + @" -setRequestValue:forHTTPHeaderField:"); + + return _request; + } // @synchronized(self) +} + +- (void)setMutableRequest:(GTM_NULLABLE NSMutableURLRequest *)request { + GTMSESSION_LOG_DEBUG(@"[GTMSessionFetcher setMutableRequest:] is deprecated; use -request or" + @" -setRequestValue:forHTTPHeaderField:"); + + GTMSESSION_ASSERT_DEBUG(![self isFetching], + @"mutableRequest should not change after beginFetch has been invoked"); + [self updateMutableRequest:request]; +} + +// Internal method for updating the request property such as on redirects. +- (void)updateMutableRequest:(GTM_NULLABLE NSMutableURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _request = request; + } // @synchronized(self) +} + +// Set a header field value on the request. Header field value changes will not +// affect a fetch after the fetch has begun. +- (void)setRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field { + if (![self isFetching]) { + [self updateRequestValue:value forHTTPHeaderField:field]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"request may not be set after beginFetch has been invoked"); + } +} + +// Internal method for updating request headers. +- (void)updateRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_request setValue:value forHTTPHeaderField:field]; + } // @synchronized(self) +} + +- (void)setResponse:(GTM_NULLABLE NSURLResponse *)response { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _response = response; + } // @synchronized(self) +} + +- (int64_t)bodyLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_bodyLength == NSURLSessionTransferSizeUnknown) { + if (_bodyData) { + _bodyLength = (int64_t)_bodyData.length; + } else if (_bodyFileURL) { + NSNumber *fileSizeNum = nil; + NSError *fileSizeError = nil; + if ([_bodyFileURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:&fileSizeError]) { + _bodyLength = [fileSizeNum longLongValue]; + } + } + } + return _bodyLength; + } // @synchronized(self) +} + +- (BOOL)useUploadTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _useUploadTask; + } // @synchronized(self) +} + +- (void)setUseUploadTask:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag != _useUploadTask) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"useUploadTask should not change after beginFetch has been invoked"); + _useUploadTask = flag; + } + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURL *)bodyFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _bodyFileURL; + } // @synchronized(self) +} + +- (void)setBodyFileURL:(GTM_NULLABLE NSURL *)fileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // The comparison here is a trivial optimization and forgiveness for any client that + // repeatedly sets the property, so it just uses pointer comparison rather than isEqual:. + if (fileURL != _bodyFileURL) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"fileURL should not change after beginFetch has been invoked"); + + _bodyFileURL = fileURL; + } + } // @synchronized(self) +} + +- (GTM_NULLABLE GTMSessionFetcherBodyStreamProvider)bodyStreamProvider { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _bodyStreamProvider; + } // @synchronized(self) +} + +- (void)setBodyStreamProvider:(GTM_NULLABLE GTMSessionFetcherBodyStreamProvider)block { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"stream provider should not change after beginFetch has been invoked"); + + _bodyStreamProvider = [block copy]; + } // @synchronized(self) +} + +- (GTM_NULLABLE id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _authorizer; + } // @synchronized(self) +} + +- (void)setAuthorizer:(GTM_NULLABLE id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (authorizer != _authorizer) { + if ([self isFetchingUnsynchronized]) { + GTMSESSION_ASSERT_DEBUG(0, @"authorizer should not change after beginFetch has been invoked"); + } else { + _authorizer = authorizer; + } + } + } // @synchronized(self) +} + +- (GTM_NULLABLE NSData *)downloadedData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _downloadedData; + } // @synchronized(self) +} + +- (void)setDownloadedData:(GTM_NULLABLE NSData *)data { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _downloadedData = [data mutableCopy]; + } // @synchronized(self) +} + +- (int64_t)downloadedLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _downloadedLength; + } // @synchronized(self) +} + +- (void)setDownloadedLength:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _downloadedLength = length; + } // @synchronized(self) +} + +- (dispatch_queue_t GTM_NONNULL_TYPE)callbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _callbackQueue; + } // @synchronized(self) +} + +- (void)setCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _callbackQueue = queue ?: dispatch_get_main_queue(); + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _session; + } // @synchronized(self) +} + +- (NSInteger)servicePriority { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _servicePriority; + } // @synchronized(self) +} + +- (void)setServicePriority:(NSInteger)value { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (value != _servicePriority) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"servicePriority should not change after beginFetch has been invoked"); + + _servicePriority = value; + } + } // @synchronized(self) +} + + +- (void)setSession:(GTM_NULLABLE NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = session; + } // @synchronized(self) +} + +- (BOOL)canShareSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _canShareSession; + } // @synchronized(self) +} + +- (void)setCanShareSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _canShareSession = flag; + } // @synchronized(self) +} + +- (BOOL)useBackgroundSession { + // This reflects if the user requested a background session, not necessarily + // if one was created. That is tracked with _usingBackgroundSession. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userRequestedBackgroundSession; + } // @synchronized(self) +} + +- (void)setUseBackgroundSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag != _userRequestedBackgroundSession) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"useBackgroundSession should not change after beginFetch has been invoked"); + + _userRequestedBackgroundSession = flag; + } + } // @synchronized(self) +} + +- (BOOL)isUsingBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _usingBackgroundSession; + } // @synchronized(self) +} + +- (void)setUsingBackgroundSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _usingBackgroundSession = flag; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURLSession *)sessionNeedingInvalidation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionNeedingInvalidation; + } // @synchronized(self) +} + +- (void)setSessionNeedingInvalidation:(GTM_NULLABLE NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _sessionNeedingInvalidation = session; + } // @synchronized(self) +} + +- (NSOperationQueue * GTM_NONNULL_TYPE)sessionDelegateQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateQueue; + } // @synchronized(self) +} + +- (void)setSessionDelegateQueue:(NSOperationQueue * GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (queue != _delegateQueue) { + if ([self isFetchingUnsynchronized]) { + GTMSESSION_ASSERT_DEBUG(0, @"sessionDelegateQueue should not change after fetch begins"); + } else { + _delegateQueue = queue ?: [NSOperationQueue mainQueue]; + } + } + } // @synchronized(self) +} + +- (BOOL)userStoppedFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userStoppedFetching; + } // @synchronized(self) +} + +- (GTM_NULLABLE id)userData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userData; + } // @synchronized(self) +} + +- (void)setUserData:(GTM_NULLABLE id)theObj { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _userData = theObj; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSURL *)destinationFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _destinationFileURL; + } // @synchronized(self) +} + +- (void)setDestinationFileURL:(GTM_NULLABLE NSURL *)destinationFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (((_destinationFileURL == nil) && (destinationFileURL == nil)) || + [_destinationFileURL isEqual:destinationFileURL]) { + return; + } + if (_sessionIdentifier) { + // This is something we don't expect to happen in production. + // However if it ever happen, leave a system log. + NSLog(@"%@: Destination File URL changed from (%@) to (%@) after session identifier has " + @"been created.", + [self class], _destinationFileURL, destinationFileURL); +#if DEBUG + // On both the simulator and devices, the path can change to the download file, but the name + // shouldn't change. Technically, this isn't supported in the fetcher, but the change of + // URL is expected to happen only across development runs through Xcode. + NSString *oldFilename = [_destinationFileURL lastPathComponent]; + NSString *newFilename = [destinationFileURL lastPathComponent]; + #pragma unused(oldFilename) + #pragma unused(newFilename) + GTMSESSION_ASSERT_DEBUG([oldFilename isEqualToString:newFilename], + @"Destination File URL cannot be changed after session identifier has been created"); +#endif + } + _destinationFileURL = destinationFileURL; + } // @synchronized(self) +} + +- (void)setProperties:(GTM_NULLABLE NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _properties = [dict mutableCopy]; + } // @synchronized(self) +} + +- (GTM_NULLABLE NSDictionary *)properties { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _properties; + } // @synchronized(self) +} + +- (void)setProperty:(GTM_NULLABLE id)obj forKey:(NSString *)key { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_properties == nil && obj != nil) { + _properties = [[NSMutableDictionary alloc] init]; + } + [_properties setValue:obj forKey:key]; + } // @synchronized(self) +} + +- (GTM_NULLABLE id)propertyForKey:(NSString *)key { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_properties objectForKey:key]; + } // @synchronized(self) +} + +- (void)addPropertiesFromDictionary:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_properties == nil && dict != nil) { + [self setProperties:[dict mutableCopy]]; + } else { + [_properties addEntriesFromDictionary:dict]; + } + } // @synchronized(self) +} + +- (void)setCommentWithFormat:(id)format, ... { +#if !STRIP_GTM_FETCH_LOGGING + NSString *result = format; + if (format) { + va_list argList; + va_start(argList, format); + + result = [[NSString alloc] initWithFormat:format + arguments:argList]; + va_end(argList); + } + [self setComment:result]; +#endif +} + +#if !STRIP_GTM_FETCH_LOGGING +- (NSData *)loggedStreamData { + return _loggedStreamData; +} + +- (void)appendLoggedStreamData:dataToAdd { + if (!_loggedStreamData) { + _loggedStreamData = [NSMutableData data]; + } + [_loggedStreamData appendData:dataToAdd]; +} + +- (void)clearLoggedStreamData { + _loggedStreamData = nil; +} + +- (void)setDeferResponseBodyLogging:(BOOL)deferResponseBodyLogging { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (deferResponseBodyLogging != _deferResponseBodyLogging) { + _deferResponseBodyLogging = deferResponseBodyLogging; + if (!deferResponseBodyLogging && !self.hasLoggedError) { + [_delegateQueue addOperationWithBlock:^{ + [self logNowWithError:nil]; + }]; + } + } + } // @synchronized(self) +} + +- (BOOL)deferResponseBodyLogging { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _deferResponseBodyLogging; + } // @synchronized(self) +} + +#else ++ (void)setLoggingEnabled:(BOOL)flag { +} + ++ (BOOL)isLoggingEnabled { + return NO; +} +#endif // STRIP_GTM_FETCH_LOGGING + +@end + +@implementation GTMSessionFetcher (BackwardsCompatibilityOnly) + +- (void)setCookieStorageMethod:(NSInteger)method { + // For backwards compatibility with the old fetcher, we'll support the old constants. + // + // Clients using the GTMSessionFetcher class should set the cookie storage explicitly + // themselves. + NSHTTPCookieStorage *storage = nil; + switch(method) { + case 0: // kGTMHTTPFetcherCookieStorageMethodStatic + // nil storage will use [[self class] staticCookieStorage] when the fetch begins. + break; + case 1: // kGTMHTTPFetcherCookieStorageMethodFetchHistory + // Do nothing; use whatever was set by the fetcher service. + return; + case 2: // kGTMHTTPFetcherCookieStorageMethodSystemDefault + storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + break; + case 3: // kGTMHTTPFetcherCookieStorageMethodNone + // Create temporary storage for this fetcher only. + storage = [[GTMSessionCookieStorage alloc] init]; + break; + default: + GTMSESSION_ASSERT_DEBUG(0, @"Invalid cookie storage method: %d", (int)method); + } + self.cookieStorage = storage; +} + +@end + +@implementation GTMSessionCookieStorage { + NSMutableArray *_cookies; + NSHTTPCookieAcceptPolicy _policy; +} + +- (id)init { + self = [super init]; + if (self != nil) { + _cookies = [[NSMutableArray alloc] init]; + } + return self; +} + +- (GTM_NULLABLE NSArray *)cookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_cookies copy]; + } // @synchronized(self) +} + +- (void)setCookie:(NSHTTPCookie *)cookie { + if (!cookie) return; + if (_policy == NSHTTPCookieAcceptPolicyNever) return; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self internalSetCookie:cookie]; + } // @synchronized(self) +} + +// Note: this should only be called from inside a @synchronized(self) block. +- (void)internalSetCookie:(NSHTTPCookie *)newCookie { + GTMSessionCheckSynchronized(self); + + if (_policy == NSHTTPCookieAcceptPolicyNever) return; + + BOOL isValidCookie = (newCookie.name.length > 0 + && newCookie.domain.length > 0 + && newCookie.path.length > 0); + GTMSESSION_ASSERT_DEBUG(isValidCookie, @"invalid cookie: %@", newCookie); + + if (isValidCookie) { + // Remove the cookie if it's currently in the array. + NSHTTPCookie *oldCookie = [self cookieMatchingCookie:newCookie]; + if (oldCookie) { + [_cookies removeObjectIdenticalTo:oldCookie]; + } + + if (![[self class] hasCookieExpired:newCookie]) { + [_cookies addObject:newCookie]; + } + } +} + +// Add all cookies in the new cookie array to the storage, +// replacing stored cookies as appropriate. +// +// Side effect: removes expired cookies from the storage array. +- (void)setCookies:(GTM_NULLABLE NSArray *)newCookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self removeExpiredCookies]; + + for (NSHTTPCookie *newCookie in newCookies) { + [self internalSetCookie:newCookie]; + } + } // @synchronized(self) +} + +- (void)setCookies:(NSArray *)cookies forURL:(GTM_NULLABLE NSURL *)URL mainDocumentURL:(GTM_NULLABLE NSURL *)mainDocumentURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_policy == NSHTTPCookieAcceptPolicyNever) { + return; + } + + if (_policy == NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain) { + NSString *mainHost = mainDocumentURL.host; + NSString *associatedHost = URL.host; + if (!mainHost || ![associatedHost hasSuffix:mainHost]) { + return; + } + } + } // @synchronized(self) + [self setCookies:cookies]; +} + +- (void)deleteCookie:(NSHTTPCookie *)cookie { + if (!cookie) return; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSHTTPCookie *foundCookie = [self cookieMatchingCookie:cookie]; + if (foundCookie) { + [_cookies removeObjectIdenticalTo:foundCookie]; + } + } // @synchronized(self) +} + +// Retrieve all cookies appropriate for the given URL, considering +// domain, path, cookie name, expiration, security setting. +// Side effect: removed expired cookies from the storage array. +- (GTM_NULLABLE NSArray *)cookiesForURL:(NSURL *)theURL { + NSMutableArray *foundCookies = nil; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self removeExpiredCookies]; + + // We'll prepend "." to the desired domain, since we want the + // actual domain "nytimes.com" to still match the cookie domain + // ".nytimes.com" when we check it below with hasSuffix. + NSString *host = theURL.host.lowercaseString; + NSString *path = theURL.path; + NSString *scheme = [theURL scheme]; + + NSString *requestingDomain = nil; + BOOL isLocalhostRetrieval = NO; + + if (IsLocalhost(host)) { + isLocalhostRetrieval = YES; + } else { + if (host.length > 0) { + requestingDomain = [@"." stringByAppendingString:host]; + } + } + + for (NSHTTPCookie *storedCookie in _cookies) { + NSString *cookieDomain = storedCookie.domain.lowercaseString; + NSString *cookiePath = storedCookie.path; + BOOL cookieIsSecure = [storedCookie isSecure]; + + BOOL isDomainOK; + + if (isLocalhostRetrieval) { + // Prior to 10.5.6, the domain stored into NSHTTPCookies for localhost + // is "localhost.local" + isDomainOK = (IsLocalhost(cookieDomain) + || [cookieDomain isEqual:@"localhost.local"]); + } else { + // Ensure we're matching exact domain names. We prepended a dot to the + // requesting domain, so we can also prepend one here if needed before + // checking if the request contains the cookie domain. + if (![cookieDomain hasPrefix:@"."]) { + cookieDomain = [@"." stringByAppendingString:cookieDomain]; + } + isDomainOK = [requestingDomain hasSuffix:cookieDomain]; + } + + BOOL isPathOK = [cookiePath isEqual:@"/"] || [path hasPrefix:cookiePath]; + BOOL isSecureOK = (!cookieIsSecure + || [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame); + + if (isDomainOK && isPathOK && isSecureOK) { + if (foundCookies == nil) { + foundCookies = [NSMutableArray array]; + } + [foundCookies addObject:storedCookie]; + } + } + } // @synchronized(self) + return foundCookies; +} + +// Override methods from the NSHTTPCookieStorage (NSURLSessionTaskAdditions) category. +- (void)storeCookies:(NSArray *)cookies forTask:(NSURLSessionTask *)task { + NSURLRequest *currentRequest = task.currentRequest; + [self setCookies:cookies forURL:currentRequest.URL mainDocumentURL:nil]; +} + +- (void)getCookiesForTask:(NSURLSessionTask *)task + completionHandler:(void (^)(GTM_NSArrayOf(NSHTTPCookie *) *))completionHandler { + if (completionHandler) { + NSURLRequest *currentRequest = task.currentRequest; + NSURL *currentRequestURL = currentRequest.URL; + NSArray *cookies = [self cookiesForURL:currentRequestURL]; + completionHandler(cookies); + } +} + +// Return a cookie from the array with the same name, domain, and path as the +// given cookie, or else return nil if none found. +// +// Both the cookie being tested and all cookies in the storage array should +// be valid (non-nil name, domains, paths). +// +// Note: this should only be called from inside a @synchronized(self) block +- (GTM_NULLABLE NSHTTPCookie *)cookieMatchingCookie:(NSHTTPCookie *)cookie { + GTMSessionCheckSynchronized(self); + + NSString *name = cookie.name; + NSString *domain = cookie.domain; + NSString *path = cookie.path; + + GTMSESSION_ASSERT_DEBUG(name && domain && path, + @"Invalid stored cookie (name:%@ domain:%@ path:%@)", name, domain, path); + + for (NSHTTPCookie *storedCookie in _cookies) { + if ([storedCookie.name isEqual:name] + && [storedCookie.domain isEqual:domain] + && [storedCookie.path isEqual:path]) { + return storedCookie; + } + } + return nil; +} + +// Internal routine to remove any expired cookies from the array, excluding +// cookies with nil expirations. +// +// Note: this should only be called from inside a @synchronized(self) block +- (void)removeExpiredCookies { + GTMSessionCheckSynchronized(self); + + // Count backwards since we're deleting items from the array + for (NSInteger idx = (NSInteger)_cookies.count - 1; idx >= 0; idx--) { + NSHTTPCookie *storedCookie = [_cookies objectAtIndex:(NSUInteger)idx]; + if ([[self class] hasCookieExpired:storedCookie]) { + [_cookies removeObjectAtIndex:(NSUInteger)idx]; + } + } +} + ++ (BOOL)hasCookieExpired:(NSHTTPCookie *)cookie { + NSDate *expiresDate = [cookie expiresDate]; + if (expiresDate == nil) { + // Cookies seem to have a Expires property even when the expiresDate method returns nil. + id expiresVal = [[cookie properties] objectForKey:NSHTTPCookieExpires]; + if ([expiresVal isKindOfClass:[NSDate class]]) { + expiresDate = expiresVal; + } + } + BOOL hasExpired = (expiresDate != nil && [expiresDate timeIntervalSinceNow] < 0); + return hasExpired; +} + +- (void)removeAllCookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_cookies removeAllObjects]; + } // @synchronized(self) +} + +- (NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _policy; + } // @synchronized(self) +} + +- (void)setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _policy = cookieAcceptPolicy; + } // @synchronized(self) +} + +@end + +void GTMSessionFetcherAssertValidSelector(id GTM_NULLABLE_TYPE obj, SEL GTM_NULLABLE_TYPE sel, ...) { + // Verify that the object's selector is implemented with the proper + // number and type of arguments +#if DEBUG + va_list argList; + va_start(argList, sel); + + if (obj && sel) { + // Check that the selector is implemented + if (![obj respondsToSelector:sel]) { + NSLog(@"\"%@\" selector \"%@\" is unimplemented or misnamed", + NSStringFromClass([(id)obj class]), + NSStringFromSelector((SEL)sel)); + NSCAssert(0, @"callback selector unimplemented or misnamed"); + } else { + const char *expectedArgType; + unsigned int argCount = 2; // skip self and _cmd + NSMethodSignature *sig = [obj methodSignatureForSelector:sel]; + + // Check that each expected argument is present and of the correct type + while ((expectedArgType = va_arg(argList, const char*)) != 0) { + + if ([sig numberOfArguments] > argCount) { + const char *foundArgType = [sig getArgumentTypeAtIndex:argCount]; + + if (0 != strncmp(foundArgType, expectedArgType, strlen(expectedArgType))) { + NSLog(@"\"%@\" selector \"%@\" argument %d should be type %s", + NSStringFromClass([(id)obj class]), + NSStringFromSelector((SEL)sel), (argCount - 2), expectedArgType); + NSCAssert(0, @"callback selector argument type mistake"); + } + } + argCount++; + } + + // Check that the proper number of arguments are present in the selector + if (argCount != [sig numberOfArguments]) { + NSLog(@"\"%@\" selector \"%@\" should have %d arguments", + NSStringFromClass([(id)obj class]), + NSStringFromSelector((SEL)sel), (argCount - 2)); + NSCAssert(0, @"callback selector arguments incorrect"); + } + } + } + + va_end(argList); +#endif +} + +NSString *GTMFetcherCleanedUserAgentString(NSString *str) { + // Reference http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html + // and http://www-archive.mozilla.org/build/user-agent-strings.html + + if (str == nil) return @""; + + NSMutableString *result = [NSMutableString stringWithString:str]; + + // Replace spaces and commas with underscores + [result replaceOccurrencesOfString:@" " + withString:@"_" + options:0 + range:NSMakeRange(0, result.length)]; + [result replaceOccurrencesOfString:@"," + withString:@"_" + options:0 + range:NSMakeRange(0, result.length)]; + + // Delete http token separators and remaining whitespace + static NSCharacterSet *charsToDelete = nil; + if (charsToDelete == nil) { + // Make a set of unwanted characters + NSString *const kSeparators = @"()<>@;:\\\"/[]?={}"; + + NSMutableCharacterSet *mutableChars = + [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy]; + [mutableChars addCharactersInString:kSeparators]; + charsToDelete = [mutableChars copy]; // hang on to an immutable copy + } + + while (1) { + NSRange separatorRange = [result rangeOfCharacterFromSet:charsToDelete]; + if (separatorRange.location == NSNotFound) break; + + [result deleteCharactersInRange:separatorRange]; + }; + + return result; +} + +NSString *GTMFetcherSystemVersionString(void) { + static NSString *sSavedSystemString; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // The Xcode 8 SDKs finally cleaned up this mess by providing TARGET_OS_OSX + // and TARGET_OS_IOS, but to build with older SDKs, those don't exist and + // instead one has to rely on TARGET_OS_MAC (which is true for iOS, watchOS, + // and tvOS) and TARGET_OS_IPHONE (which is true for iOS, watchOS, tvOS). So + // one has to order these carefully so you pick off the specific things + // first. + // If the code can ever assume Xcode 8 or higher (even when building for + // older OSes), then + // TARGET_OS_MAC -> TARGET_OS_OSX + // TARGET_OS_IPHONE -> TARGET_OS_IOS + // TARGET_IPHONE_SIMULATOR -> TARGET_OS_SIMULATOR +#if TARGET_OS_WATCH + // watchOS - WKInterfaceDevice + + WKInterfaceDevice *currentDevice = [WKInterfaceDevice currentDevice]; + + NSString *rawModel = [currentDevice model]; + NSString *model = GTMFetcherCleanedUserAgentString(rawModel); + + NSString *systemVersion = [currentDevice systemVersion]; + +#if TARGET_OS_SIMULATOR + NSString *hardwareModel = @"sim"; +#else + NSString *hardwareModel; + struct utsname unameRecord; + if (uname(&unameRecord) == 0) { + NSString *machineName = @(unameRecord.machine); + hardwareModel = GTMFetcherCleanedUserAgentString(machineName); + } + if (hardwareModel.length == 0) { + hardwareModel = @"unk"; + } +#endif + + sSavedSystemString = [[NSString alloc] initWithFormat:@"%@/%@ hw/%@", + model, systemVersion, hardwareModel]; + // Example: Apple_Watch/3.0 hw/Watch1_2 +#elif TARGET_OS_TV || TARGET_OS_IPHONE + // iOS and tvOS have UIDevice, use that. + UIDevice *currentDevice = [UIDevice currentDevice]; + + NSString *rawModel = [currentDevice model]; + NSString *model = GTMFetcherCleanedUserAgentString(rawModel); + + NSString *systemVersion = [currentDevice systemVersion]; + +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_SIMULATOR + NSString *hardwareModel = @"sim"; +#else + NSString *hardwareModel; + struct utsname unameRecord; + if (uname(&unameRecord) == 0) { + NSString *machineName = @(unameRecord.machine); + hardwareModel = GTMFetcherCleanedUserAgentString(machineName); + } + if (hardwareModel.length == 0) { + hardwareModel = @"unk"; + } +#endif + + sSavedSystemString = [[NSString alloc] initWithFormat:@"%@/%@ hw/%@", + model, systemVersion, hardwareModel]; + // Example: iPod_Touch/2.2 hw/iPod1_1 + // Example: Apple_TV/9.2 hw/AppleTV5,3 +#elif TARGET_OS_MAC + // Mac build + NSProcessInfo *procInfo = [NSProcessInfo processInfo]; +#if !defined(MAC_OS_X_VERSION_10_10) + BOOL hasOperatingSystemVersion = NO; +#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10 + BOOL hasOperatingSystemVersion = + [procInfo respondsToSelector:@selector(operatingSystemVersion)]; +#else + BOOL hasOperatingSystemVersion = YES; +#endif + NSString *versString; + if (hasOperatingSystemVersion) { +#if defined(MAC_OS_X_VERSION_10_10) + // A reference to NSOperatingSystemVersion requires the 10.10 SDK. + NSOperatingSystemVersion version = procInfo.operatingSystemVersion; + versString = [NSString stringWithFormat:@"%zd.%zd.%zd", + version.majorVersion, version.minorVersion, version.patchVersion]; +#else +#pragma unused(procInfo) +#endif + } else { + // With Gestalt inexplicably deprecated in 10.8, we're reduced to reading + // the system plist file. + NSString *const kPath = @"/System/Library/CoreServices/SystemVersion.plist"; + NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:kPath]; + versString = [plist objectForKey:@"ProductVersion"]; + if (versString.length == 0) { + versString = @"10.?.?"; + } + } + + sSavedSystemString = [[NSString alloc] initWithFormat:@"MacOSX/%@", versString]; +#elif defined(_SYS_UTSNAME_H) + // Foundation-only build + struct utsname unameRecord; + uname(&unameRecord); + + sSavedSystemString = [NSString stringWithFormat:@"%s/%s", + unameRecord.sysname, unameRecord.release]; // "Darwin/8.11.1" +#else +#error No branch taken for a default user agent +#endif + }); + return sSavedSystemString; +} + +NSString *GTMFetcherStandardUserAgentString(NSBundle * GTM_NULLABLE_TYPE bundle) { + NSString *result = [NSString stringWithFormat:@"%@ %@", + GTMFetcherApplicationIdentifier(bundle), + GTMFetcherSystemVersionString()]; + return result; +} + +NSString *GTMFetcherApplicationIdentifier(NSBundle * GTM_NULLABLE_TYPE bundle) { + @synchronized([GTMSessionFetcher class]) { + static NSMutableDictionary *sAppIDMap = nil; + + // If there's a bundle ID, use that; otherwise, use the process name + if (bundle == nil) { + bundle = [NSBundle mainBundle]; + } + NSString *bundleID = [bundle bundleIdentifier]; + if (bundleID == nil) { + bundleID = @""; + } + + NSString *identifier = [sAppIDMap objectForKey:bundleID]; + if (identifier) return identifier; + + // Apps may add a string to the info.plist to uniquely identify different builds. + identifier = [bundle objectForInfoDictionaryKey:@"GTMUserAgentID"]; + if (identifier.length == 0) { + if (bundleID.length > 0) { + identifier = bundleID; + } else { + // Fall back on the procname, prefixed by "proc" to flag that it's + // autogenerated and perhaps unreliable + NSString *procName = [[NSProcessInfo processInfo] processName]; + identifier = [NSString stringWithFormat:@"proc_%@", procName]; + } + } + + // Clean up whitespace and special characters + identifier = GTMFetcherCleanedUserAgentString(identifier); + + // If there's a version number, append that + NSString *version = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + if (version.length == 0) { + version = [bundle objectForInfoDictionaryKey:@"CFBundleVersion"]; + } + + // Clean up whitespace and special characters + version = GTMFetcherCleanedUserAgentString(version); + + // Glue the two together (cleanup done above or else cleanup would strip the + // slash) + if (version.length > 0) { + identifier = [identifier stringByAppendingFormat:@"/%@", version]; + } + + if (sAppIDMap == nil) { + sAppIDMap = [[NSMutableDictionary alloc] init]; + } + [sAppIDMap setObject:identifier forKey:bundleID]; + return identifier; + } +} + +#if DEBUG +@implementation GTMSessionSyncMonitorInternal { + NSValue *_objectKey; // The synchronize target object. + const char *_functionName; // The function containing the monitored sync block. +} + +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName { + self = [super init]; + if (self) { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + _objectKey = [NSValue valueWithNonretainedObject:object]; + _functionName = functionName; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + if (counters == nil) { + counters = [NSMutableDictionary dictionary]; + threadDict[(id)threadKey] = counters; + } + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSUInteger numberOfSyncingFunctions = functionNamesCounter.count; + + if (!allowRecursive) { + BOOL isTopLevelSyncScope = (numberOfSyncingFunctions == 0); + NSArray *stack = [NSThread callStackSymbols]; + GTMSESSION_ASSERT_DEBUG(isTopLevelSyncScope, + @"*** Recursive sync on %@ at %s; previous sync at %@\n%@", + [object class], functionName, functionNamesCounter.allObjects, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + } + + if (!functionNamesCounter) { + functionNamesCounter = [NSCountedSet set]; + counters[_objectKey] = functionNamesCounter; + } + [functionNamesCounter addObject:@(functionName)]; + } + return self; +} + +- (void)dealloc { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSString *functionNameStr = @(_functionName); + NSUInteger numberOfSyncsByThisFunction = [functionNamesCounter countForObject:functionNameStr]; + NSArray *stack = [NSThread callStackSymbols]; + GTMSESSION_ASSERT_DEBUG(numberOfSyncsByThisFunction > 0, @"Sync not found on %@ at %s\n%@", + [_objectKey.nonretainedObjectValue class], _functionName, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + [functionNamesCounter removeObject:functionNameStr]; + if (functionNamesCounter.count == 0) { + [counters removeObjectForKey:_objectKey]; + } +} + ++ (NSArray *)functionsHoldingSynchronizationOnObject:(id)object { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + NSValue *localObjectKey = [NSValue valueWithNonretainedObject:object]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[localObjectKey]; + return functionNamesCounter.count > 0 ? functionNamesCounter.allObjects : nil; +} +@end +#endif // DEBUG +GTM_ASSUME_NONNULL_END diff --git a/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h new file mode 100644 index 0000000..bc0a65c --- /dev/null +++ b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h @@ -0,0 +1,107 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GTMSessionFetcher.h" + +// GTM HTTP Logging +// +// All traffic using GTMSessionFetcher can be easily logged. Call +// +// [GTMSessionFetcher setLoggingEnabled:YES]; +// +// to begin generating log files. +// +// Log files are put into a folder on the desktop called "GTMHTTPDebugLogs" +// unless another directory is specified with +setLoggingDirectory. +// +// In the iPhone simulator, the default logs location is the user's home +// directory in ~/Library/Application Support. On the iPhone device, the +// default logs location is the application's documents directory on the device. +// +// Tip: use the Finder's "Sort By Date" to find the most recent logs. +// +// Each run of an application gets a separate set of log files. An html +// file is generated to simplify browsing the run's http transactions. +// The html file includes javascript links for inline viewing of uploaded +// and downloaded data. +// +// A symlink is created in the logs folder to simplify finding the html file +// for the latest run of the application; the symlink is called +// +// AppName_http_log_newest.html +// +// For better viewing of XML logs, use Camino or Firefox rather than Safari. +// +// Each fetcher may be given a comment to be inserted as a label in the logs, +// such as +// [fetcher setCommentWithFormat:@"retrieve item %@", itemName]; +// +// Projects may define STRIP_GTM_FETCH_LOGGING to remove logging code. + +#if !STRIP_GTM_FETCH_LOGGING + +@interface GTMSessionFetcher (GTMSessionFetcherLogging) + +// Note: the default logs directory is ~/Desktop/GTMHTTPDebugLogs; it will be +// created as needed. If a custom directory is set, the directory should +// already exist. ++ (void)setLoggingDirectory:(NSString *)path; ++ (NSString *)loggingDirectory; + +// client apps can turn logging on and off ++ (void)setLoggingEnabled:(BOOL)isLoggingEnabled; ++ (BOOL)isLoggingEnabled; + +// client apps can turn off logging to a file if they want to only check +// the fetcher's log property ++ (void)setLoggingToFileEnabled:(BOOL)isLoggingToFileEnabled; ++ (BOOL)isLoggingToFileEnabled; + +// client apps can optionally specify process name and date string used in +// log file names ++ (void)setLoggingProcessName:(NSString *)processName; ++ (NSString *)loggingProcessName; + ++ (void)setLoggingDateStamp:(NSString *)dateStamp; ++ (NSString *)loggingDateStamp; + +// client apps can specify the directory for the log for this specific run, +// typically to match the directory used by another fetcher class, like: +// +// [GTMSessionFetcher setLogDirectoryForCurrentRun:[GTMHTTPFetcher logDirectoryForCurrentRun]]; +// +// Setting this overrides the logging directory, process name, and date stamp when writing +// the log file. ++ (void)setLogDirectoryForCurrentRun:(NSString *)logDirectoryForCurrentRun; ++ (NSString *)logDirectoryForCurrentRun; + +// Prunes old log directories that have not been modified since the provided date. +// This will not delete the current run's log directory. ++ (void)deleteLogDirectoriesOlderThanDate:(NSDate *)date; + +// internal; called by fetcher +- (void)logFetchWithError:(NSError *)error; +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream; +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider; + +// internal; accessors useful for viewing logs ++ (NSString *)processNameLogPrefix; ++ (NSString *)symlinkNameSuffix; ++ (NSString *)htmlFileName; + +@end + +#endif // !STRIP_GTM_FETCH_LOGGING diff --git a/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m new file mode 100644 index 0000000..02b46b6 --- /dev/null +++ b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m @@ -0,0 +1,976 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#include +#include + +#import "GTMSessionFetcherLogging.h" + +#ifndef STRIP_GTM_FETCH_LOGGING + #error GTMSessionFetcher headers should have defaulted this if it wasn't already defined. +#endif + +#if !STRIP_GTM_FETCH_LOGGING + +// Sensitive credential strings are replaced in logs with _snip_ +// +// Apps that must see the contents of sensitive tokens can set this to 1 +#ifndef SKIP_GTM_FETCH_LOGGING_SNIPPING +#define SKIP_GTM_FETCH_LOGGING_SNIPPING 0 +#endif + +// If GTMReadMonitorInputStream is available, it can be used for +// capturing uploaded streams of data +// +// We locally declare methods of GTMReadMonitorInputStream so we +// do not need to import the header, as some projects may not have it available +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMReadMonitorInputStream : NSInputStream + ++ (instancetype)inputStreamWithStream:(NSInputStream *)input; + +@property (assign) id readDelegate; +@property (assign) SEL readSelector; + +@end +#else +@class GTMReadMonitorInputStream; +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionFetcher (GTMHTTPFetcherLoggingUtilities) + ++ (NSString *)headersStringForDictionary:(NSDictionary *)dict; ++ (NSString *)snipSubstringOfString:(NSString *)originalStr + betweenStartString:(NSString *)startStr + endString:(NSString *)endStr; +- (void)inputStream:(GTMReadMonitorInputStream *)stream + readIntoBuffer:(void *)buffer + length:(int64_t)length; + +@end + +@implementation GTMSessionFetcher (GTMSessionFetcherLogging) + +// fetchers come and fetchers go, but statics are forever +static BOOL gIsLoggingEnabled = NO; +static BOOL gIsLoggingToFile = YES; +static NSString *gLoggingDirectoryPath = nil; +static NSString *gLogDirectoryForCurrentRun = nil; +static NSString *gLoggingDateStamp = nil; +static NSString *gLoggingProcessName = nil; + ++ (void)setLoggingDirectory:(NSString *)path { + gLoggingDirectoryPath = [path copy]; +} + ++ (NSString *)loggingDirectory { + if (!gLoggingDirectoryPath) { + NSArray *paths = nil; +#if TARGET_IPHONE_SIMULATOR + // default to a directory called GTMHTTPDebugLogs into a sandbox-safe + // directory that a developer can find easily, the application home + paths = @[ NSHomeDirectory() ]; +#elif TARGET_OS_IPHONE + // Neither ~/Desktop nor ~/Home is writable on an actual iOS, watchOS, or tvOS device. + // Put it in ~/Documents. + paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); +#else + // default to a directory called GTMHTTPDebugLogs in the desktop folder + paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES); +#endif + + NSString *desktopPath = paths.firstObject; + if (desktopPath) { + NSString *const kGTMLogFolderName = @"GTMHTTPDebugLogs"; + NSString *logsFolderPath = [desktopPath stringByAppendingPathComponent:kGTMLogFolderName]; + + NSFileManager *fileMgr = [NSFileManager defaultManager]; + BOOL isDir; + BOOL doesFolderExist = [fileMgr fileExistsAtPath:logsFolderPath isDirectory:&isDir]; + if (!doesFolderExist) { + // make the directory + doesFolderExist = [fileMgr createDirectoryAtPath:logsFolderPath + withIntermediateDirectories:YES + attributes:nil + error:NULL]; + } + if (doesFolderExist) { + // it's there; store it in the global + gLoggingDirectoryPath = [logsFolderPath copy]; + } + } + } + return gLoggingDirectoryPath; +} + ++ (void)setLogDirectoryForCurrentRun:(NSString *)logDirectoryForCurrentRun { + // Set the path for this run's logs. + gLogDirectoryForCurrentRun = [logDirectoryForCurrentRun copy]; +} + ++ (NSString *)logDirectoryForCurrentRun { + // make a directory for this run's logs, like SyncProto_logs_10-16_01-56-58PM + if (gLogDirectoryForCurrentRun) return gLogDirectoryForCurrentRun; + + NSString *parentDir = [self loggingDirectory]; + NSString *logNamePrefix = [self processNameLogPrefix]; + NSString *dateStamp = [self loggingDateStamp]; + NSString *dirName = [NSString stringWithFormat:@"%@%@", logNamePrefix, dateStamp]; + NSString *logDirectory = [parentDir stringByAppendingPathComponent:dirName]; + + if (gIsLoggingToFile) { + NSFileManager *fileMgr = [NSFileManager defaultManager]; + // Be sure that the first time this app runs, it's not writing to a preexisting folder + static BOOL gShouldReuseFolder = NO; + if (!gShouldReuseFolder) { + gShouldReuseFolder = YES; + NSString *origLogDir = logDirectory; + for (int ctr = 2; ctr < 20; ++ctr) { + if (![fileMgr fileExistsAtPath:logDirectory]) break; + + // append a digit + logDirectory = [origLogDir stringByAppendingFormat:@"_%d", ctr]; + } + } + if (![fileMgr createDirectoryAtPath:logDirectory + withIntermediateDirectories:YES + attributes:nil + error:NULL]) return nil; + } + gLogDirectoryForCurrentRun = logDirectory; + + return gLogDirectoryForCurrentRun; +} + ++ (void)setLoggingEnabled:(BOOL)isLoggingEnabled { + gIsLoggingEnabled = isLoggingEnabled; +} + ++ (BOOL)isLoggingEnabled { + return gIsLoggingEnabled; +} + ++ (void)setLoggingToFileEnabled:(BOOL)isLoggingToFileEnabled { + gIsLoggingToFile = isLoggingToFileEnabled; +} + ++ (BOOL)isLoggingToFileEnabled { + return gIsLoggingToFile; +} + ++ (void)setLoggingProcessName:(NSString *)processName { + gLoggingProcessName = [processName copy]; +} + ++ (NSString *)loggingProcessName { + // get the process name (once per run) replacing spaces with underscores + if (!gLoggingProcessName) { + NSString *procName = [[NSProcessInfo processInfo] processName]; + gLoggingProcessName = [procName stringByReplacingOccurrencesOfString:@" " withString:@"_"]; + } + return gLoggingProcessName; +} + ++ (void)setLoggingDateStamp:(NSString *)dateStamp { + gLoggingDateStamp = [dateStamp copy]; +} + ++ (NSString *)loggingDateStamp { + // We'll pick one date stamp per run, so a run that starts at a later second + // will get a unique results html file + if (!gLoggingDateStamp) { + // produce a string like 08-21_01-41-23PM + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + [formatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [formatter setDateFormat:@"M-dd_hh-mm-ssa"]; + + gLoggingDateStamp = [formatter stringFromDate:[NSDate date]]; + } + return gLoggingDateStamp; +} + ++ (NSString *)processNameLogPrefix { + static NSString *gPrefix = nil; + if (!gPrefix) { + NSString *processName = [self loggingProcessName]; + gPrefix = [[NSString alloc] initWithFormat:@"%@_log_", processName]; + } + return gPrefix; +} + ++ (NSString *)symlinkNameSuffix { + return @"_log_newest.html"; +} + ++ (NSString *)htmlFileName { + return @"aperçu_http_log.html"; +} + ++ (void)deleteLogDirectoriesOlderThanDate:(NSDate *)cutoffDate { + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSURL *parentDir = [NSURL fileURLWithPath:[[self class] loggingDirectory]]; + NSURL *logDirectoryForCurrentRun = + [NSURL fileURLWithPath:[[self class] logDirectoryForCurrentRun]]; + NSError *error; + NSArray *contents = [fileMgr contentsOfDirectoryAtURL:parentDir + includingPropertiesForKeys:@[ NSURLContentModificationDateKey ] + options:0 + error:&error]; + for (NSURL *itemURL in contents) { + if ([itemURL isEqual:logDirectoryForCurrentRun]) continue; + + NSDate *modDate; + if ([itemURL getResourceValue:&modDate + forKey:NSURLContentModificationDateKey + error:&error]) { + if ([modDate compare:cutoffDate] == NSOrderedAscending) { + if (![fileMgr removeItemAtURL:itemURL error:&error]) { + NSLog(@"deleteLogDirectoriesOlderThanDate failed to delete %@: %@", + itemURL.path, error); + } + } + } else { + NSLog(@"deleteLogDirectoriesOlderThanDate failed to get mod date of %@: %@", + itemURL.path, error); + } + } +} + +// formattedStringFromData returns a prettyprinted string for XML or JSON input, +// and a plain string for other input data +- (NSString *)formattedStringFromData:(NSData *)inputData + contentType:(NSString *)contentType + JSON:(NSDictionary **)outJSON { + if (!inputData) return nil; + + // if the content type is JSON and we have the parsing class available, use that + if ([contentType hasPrefix:@"application/json"] && inputData.length > 5) { + // convert from JSON string to NSObjects and back to a formatted string + NSMutableDictionary *obj = [NSJSONSerialization JSONObjectWithData:inputData + options:NSJSONReadingMutableContainers + error:NULL]; + if (obj) { + if (outJSON) *outJSON = obj; + if ([obj isKindOfClass:[NSMutableDictionary class]]) { + // for security and privacy, omit OAuth 2 response access and refresh tokens + if ([obj valueForKey:@"refresh_token"] != nil) { + [obj setObject:@"_snip_" forKey:@"refresh_token"]; + } + if ([obj valueForKey:@"access_token"] != nil) { + [obj setObject:@"_snip_" forKey:@"access_token"]; + } + } + NSData *data = [NSJSONSerialization dataWithJSONObject:obj + options:NSJSONWritingPrettyPrinted + error:NULL]; + if (data) { + NSString *jsonStr = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + return jsonStr; + } + } + } + +#if !TARGET_OS_IPHONE && !GTM_SKIP_LOG_XMLFORMAT + // verify that this data starts with the bytes indicating XML + + NSString *const kXMLLintPath = @"/usr/bin/xmllint"; + static BOOL gHasCheckedAvailability = NO; + static BOOL gIsXMLLintAvailable = NO; + + if (!gHasCheckedAvailability) { + gIsXMLLintAvailable = [[NSFileManager defaultManager] fileExistsAtPath:kXMLLintPath]; + gHasCheckedAvailability = YES; + } + if (gIsXMLLintAvailable + && inputData.length > 5 + && strncmp(inputData.bytes, " 0) { + // success + inputData = formattedData; + } + } +#else + // we can't call external tasks on the iPhone; leave the XML unformatted +#endif + + NSString *dataStr = [[NSString alloc] initWithData:inputData + encoding:NSUTF8StringEncoding]; + return dataStr; +} + +// stringFromStreamData creates a string given the supplied data +// +// If NSString can create a UTF-8 string from the data, then that is returned. +// +// Otherwise, this routine tries to find a MIME boundary at the beginning of the data block, and +// uses that to break up the data into parts. Each part will be used to try to make a UTF-8 string. +// For parts that fail, a replacement string showing the part header and <> is supplied +// in place of the binary data. + +- (NSString *)stringFromStreamData:(NSData *)data + contentType:(NSString *)contentType { + + if (!data) return nil; + + // optimistically, see if the whole data block is UTF-8 + NSString *streamDataStr = [self formattedStringFromData:data + contentType:contentType + JSON:NULL]; + if (streamDataStr) return streamDataStr; + + // Munge a buffer by replacing non-ASCII bytes with underscores, and turn that munged buffer an + // NSString. That gives us a string we can use with NSScanner. + NSMutableData *mutableData = [NSMutableData dataWithData:data]; + unsigned char *bytes = (unsigned char *)mutableData.mutableBytes; + + for (unsigned int idx = 0; idx < mutableData.length; ++idx) { + if (bytes[idx] > 0x7F || bytes[idx] == 0) { + bytes[idx] = '_'; + } + } + + NSString *mungedStr = [[NSString alloc] initWithData:mutableData + encoding:NSUTF8StringEncoding]; + if (mungedStr) { + + // scan for the boundary string + NSString *boundary = nil; + NSScanner *scanner = [NSScanner scannerWithString:mungedStr]; + + if ([scanner scanUpToString:@"\r\n" intoString:&boundary] + && [boundary hasPrefix:@"--"]) { + + // we found a boundary string; use it to divide the string into parts + NSArray *mungedParts = [mungedStr componentsSeparatedByString:boundary]; + + // look at each munged part in the original string, and try to convert those into UTF-8 + NSMutableArray *origParts = [NSMutableArray array]; + NSUInteger offset = 0; + for (NSString *mungedPart in mungedParts) { + NSUInteger partSize = mungedPart.length; + NSData *origPartData = [data subdataWithRange:NSMakeRange(offset, partSize)]; + NSString *origPartStr = [[NSString alloc] initWithData:origPartData + encoding:NSUTF8StringEncoding]; + if (origPartStr) { + // we could make this original part into UTF-8; use the string + [origParts addObject:origPartStr]; + } else { + // this part can't be made into UTF-8; scan the header, if we can + NSString *header = nil; + NSScanner *headerScanner = [NSScanner scannerWithString:mungedPart]; + if (![headerScanner scanUpToString:@"\r\n\r\n" intoString:&header]) { + // we couldn't find a header + header = @""; + } + // make a part string with the header and <> + NSString *binStr = [NSString stringWithFormat:@"\r%@\r<<%lu bytes>>\r", + header, (long)(partSize - header.length)]; + [origParts addObject:binStr]; + } + offset += partSize + boundary.length; + } + // rejoin the original parts + streamDataStr = [origParts componentsJoinedByString:boundary]; + } + } + if (!streamDataStr) { + // give up; just make a string showing the uploaded bytes + streamDataStr = [NSString stringWithFormat:@"<<%u bytes>>", (unsigned int)data.length]; + } + return streamDataStr; +} + +// logFetchWithError is called following a successful or failed fetch attempt +// +// This method does all the work for appending to and creating log files + +- (void)logFetchWithError:(NSError *)error { + if (![[self class] isLoggingEnabled]) return; + NSString *logDirectory = [[self class] logDirectoryForCurrentRun]; + if (!logDirectory) return; + NSString *processName = [[self class] loggingProcessName]; + + // TODO: add Javascript to display response data formatted in hex + + // each response's NSData goes into its own xml or txt file, though all responses for this run of + // the app share a main html file. This counter tracks all fetch responses for this app run. + // + // we'll use a local variable since this routine may be reentered while waiting for XML formatting + // to be completed by an external task + static int gResponseCounter = 0; + int responseCounter = ++gResponseCounter; + + NSURLResponse *response = [self response]; + NSDictionary *responseHeaders = [self responseHeaders]; + NSString *responseDataStr = nil; + NSDictionary *responseJSON = nil; + + // if there's response data, decide what kind of file to put it in based on the first bytes of the + // file or on the mime type supplied by the server + NSString *responseMIMEType = [response MIMEType]; + BOOL isResponseImage = NO; + + // file name for an image data file + NSString *responseDataFileName = nil; + + int64_t responseDataLength = self.downloadedLength; + if (responseDataLength > 0) { + NSData *downloadedData = self.downloadedData; + if (downloadedData == nil + && responseDataLength > 0 + && responseDataLength < 20000 + && self.destinationFileURL) { + // There's a download file that's not too big, so get the data to display from the downloaded + // file. + NSURL *destinationURL = self.destinationFileURL; + downloadedData = [NSData dataWithContentsOfURL:destinationURL]; + } + NSString *responseType = [responseHeaders valueForKey:@"Content-Type"]; + responseDataStr = [self formattedStringFromData:downloadedData + contentType:responseType + JSON:&responseJSON]; + NSString *responseDataExtn = nil; + NSData *dataToWrite = nil; + if (responseDataStr) { + // we were able to make a UTF-8 string from the response data + if ([responseMIMEType isEqual:@"application/atom+xml"] + || [responseMIMEType hasSuffix:@"/xml"]) { + responseDataExtn = @"xml"; + dataToWrite = [responseDataStr dataUsingEncoding:NSUTF8StringEncoding]; + } + } else if ([responseMIMEType isEqual:@"image/jpeg"]) { + responseDataExtn = @"jpg"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else if ([responseMIMEType isEqual:@"image/gif"]) { + responseDataExtn = @"gif"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else if ([responseMIMEType isEqual:@"image/png"]) { + responseDataExtn = @"png"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else { + // add more non-text types here + } + // if we have an extension, save the raw data in a file with that extension + if (responseDataExtn && dataToWrite) { + // generate a response file base name like + NSString *responseBaseName = [NSString stringWithFormat:@"fetch_%d_response", responseCounter]; + responseDataFileName = [responseBaseName stringByAppendingPathExtension:responseDataExtn]; + NSString *responseDataFilePath = [logDirectory stringByAppendingPathComponent:responseDataFileName]; + + NSError *downloadedError = nil; + if (gIsLoggingToFile && ![dataToWrite writeToFile:responseDataFilePath + options:0 + error:&downloadedError]) { + NSLog(@"%@ logging write error:%@ (%@)", [self class], downloadedError, responseDataFileName); + } + } + } + // we'll have one main html file per run of the app + NSString *htmlName = [[self class] htmlFileName]; + NSString *htmlPath =[logDirectory stringByAppendingPathComponent:htmlName]; + + // if the html file exists (from logging previous fetches) we don't need + // to re-write the header or the scripts + NSFileManager *fileMgr = [NSFileManager defaultManager]; + BOOL didFileExist = [fileMgr fileExistsAtPath:htmlPath]; + + NSMutableString* outputHTML = [NSMutableString string]; + + // we need a header to say we'll have UTF-8 text + if (!didFileExist) { + [outputHTML appendFormat:@"%@ HTTP fetch log %@", + processName, [[self class] loggingDateStamp]]; + } + // now write the visible html elements + NSString *copyableFileName = [NSString stringWithFormat:@"fetch_%d.txt", responseCounter]; + + NSDate *now = [NSDate date]; + // write the date & time, the comment, and the link to the plain-text (copyable) log + [outputHTML appendFormat:@"%@      ", now]; + + NSString *comment = [self comment]; + if (comment.length > 0) { + [outputHTML appendFormat:@"%@      ", comment]; + } + [outputHTML appendFormat:@"request/response log
", copyableFileName]; + NSTimeInterval elapsed = -self.initialBeginFetchDate.timeIntervalSinceNow; + [outputHTML appendFormat:@"elapsed: %5.3fsec
", elapsed]; + + // write the request URL + NSURLRequest *request = self.request; + NSString *requestMethod = request.HTTPMethod; + NSURL *requestURL = request.URL; + + // Save the request URL for next time in case this redirects. + NSString *redirectedFromURLString = [self.redirectedFromURL absoluteString]; + self.redirectedFromURL = [requestURL copy]; + if (redirectedFromURLString) { + [outputHTML appendFormat:@"redirected from %@
", + redirectedFromURLString]; + } + [outputHTML appendFormat:@"request: %@ %@
\n", requestMethod, requestURL]; + + // write the request headers + NSDictionary *requestHeaders = request.allHTTPHeaderFields; + NSUInteger numberOfRequestHeaders = requestHeaders.count; + if (numberOfRequestHeaders > 0) { + // Indicate if the request is authorized; warn if the request is authorized but non-SSL + NSString *auth = [requestHeaders objectForKey:@"Authorization"]; + NSString *headerDetails = @""; + if (auth) { + BOOL isInsecure = [[requestURL scheme] isEqual:@"http"]; + if (isInsecure) { + // 26A0 = ⚠ + headerDetails = + @"   authorized, non-SSL "; + } else { + headerDetails = @"   authorized"; + } + } + NSString *cookiesHdr = [requestHeaders objectForKey:@"Cookie"]; + if (cookiesHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   cookies"]; + } + NSString *matchHdr = [requestHeaders objectForKey:@"If-Match"]; + if (matchHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   if-match"]; + } + matchHdr = [requestHeaders objectForKey:@"If-None-Match"]; + if (matchHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   if-none-match"]; + } + [outputHTML appendFormat:@"   headers: %d %@
", + (int)numberOfRequestHeaders, headerDetails]; + } else { + [outputHTML appendFormat:@"   headers: none
"]; + } + // write the request post data + NSData *bodyData = nil; + NSData *loggedStreamData = self.loggedStreamData; + if (loggedStreamData) { + bodyData = loggedStreamData; + } else { + bodyData = self.bodyData; + if (bodyData == nil) { + bodyData = self.request.HTTPBody; + } + } + uint64_t bodyDataLength = bodyData.length; + + if (bodyData.length == 0) { + // If the data is in a body upload file URL, read that in if it's not huge. + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSNumber *fileSizeNum = nil; + NSError *fileSizeError = nil; + if ([bodyFileURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:&fileSizeError]) { + bodyDataLength = [fileSizeNum unsignedLongLongValue]; + if (bodyDataLength > 0 && bodyDataLength < 50000) { + bodyData = [NSData dataWithContentsOfURL:bodyFileURL + options:NSDataReadingUncached + error:&fileSizeError]; + } + } + } + } + NSString *bodyDataStr = nil; + NSString *postType = [requestHeaders valueForKey:@"Content-Type"]; + + if (bodyDataLength > 0) { + [outputHTML appendFormat:@"   data: %llu bytes, %@
\n", + bodyDataLength, postType ? postType : @"(no type)"]; + NSString *logRequestBody = self.logRequestBody; + if (logRequestBody) { + bodyDataStr = [logRequestBody copy]; + self.logRequestBody = nil; + } else { + bodyDataStr = [self stringFromStreamData:bodyData + contentType:postType]; + if (bodyDataStr) { + // remove OAuth 2 client secret and refresh token + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"client_secret=" + endString:@"&"]; + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"refresh_token=" + endString:@"&"]; + // remove ClientLogin password + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"&Passwd=" + endString:@"&"]; + } + } + } else { + // no post data + } + // write the response status, MIME type, URL + NSInteger status = [self statusCode]; + if (response) { + NSString *statusString = @""; + if (status != 0) { + if (status == 200 || status == 201) { + statusString = [NSString stringWithFormat:@"%ld", (long)status]; + + // report any JSON-RPC error + if ([responseJSON isKindOfClass:[NSDictionary class]]) { + NSDictionary *jsonError = [responseJSON objectForKey:@"error"]; + if ([jsonError isKindOfClass:[NSDictionary class]]) { + NSString *jsonCode = [[jsonError valueForKey:@"code"] description]; + NSString *jsonMessage = [jsonError valueForKey:@"message"]; + if (jsonCode || jsonMessage) { + // 2691 = ⚑ + NSString *const jsonErrFmt = + @"   JSON error: %@ %@  ⚑"; + statusString = [statusString stringByAppendingFormat:jsonErrFmt, + jsonCode ? jsonCode : @"", + jsonMessage ? jsonMessage : @""]; + } + } + } + } else { + // purple for anything other than 200 or 201 + NSString *flag = status >= 400 ? @" ⚑" : @""; // 2691 = ⚑ + NSString *explanation = [NSHTTPURLResponse localizedStringForStatusCode:status]; + NSString *const statusFormat = @"%ld %@ %@"; + statusString = [NSString stringWithFormat:statusFormat, (long)status, explanation, flag]; + } + } + // show the response URL only if it's different from the request URL + NSString *responseURLStr = @""; + NSURL *responseURL = response.URL; + + if (responseURL && ![responseURL isEqual:request.URL]) { + NSString *const responseURLFormat = + @"response URL: %@
\n"; + responseURLStr = [NSString stringWithFormat:responseURLFormat, [responseURL absoluteString]]; + } + [outputHTML appendFormat:@"response:  status %@
\n%@", + statusString, responseURLStr]; + // Write the response headers + NSUInteger numberOfResponseHeaders = responseHeaders.count; + if (numberOfResponseHeaders > 0) { + // Indicate if the server is setting cookies + NSString *cookiesSet = [responseHeaders valueForKey:@"Set-Cookie"]; + NSString *cookiesStr = + cookiesSet ? @"  sets cookies" : @""; + // Indicate if the server is redirecting + NSString *location = [responseHeaders valueForKey:@"Location"]; + BOOL isRedirect = status >= 300 && status <= 399 && location != nil; + NSString *redirectsStr = + isRedirect ? @"  redirects" : @""; + [outputHTML appendFormat:@"   headers: %d %@ %@
\n", + (int)numberOfResponseHeaders, cookiesStr, redirectsStr]; + } else { + [outputHTML appendString:@"   headers: none
\n"]; + } + } + // error + if (error) { + [outputHTML appendFormat:@"Error: %@
\n", error.description]; + } + // Write the response data + if (responseDataFileName) { + if (isResponseImage) { + // Make a small inline image that links to the full image file + [outputHTML appendFormat:@"   data: %lld bytes, %@
", + responseDataLength, responseMIMEType]; + NSString *const fmt = + @"image\n"; + [outputHTML appendFormat:fmt, responseDataFileName, responseDataFileName]; + } else { + // The response data was XML; link to the xml file + NSString *const fmt = + @"   data: %lld bytes, %@   %@\n"; + [outputHTML appendFormat:fmt, responseDataLength, responseMIMEType, + responseDataFileName, [responseDataFileName pathExtension]]; + } + } else { + // The response data was not an image; just show the length and MIME type + [outputHTML appendFormat:@"   data: %lld bytes, %@\n", + responseDataLength, responseMIMEType ? responseMIMEType : @"(no response type)"]; + } + // Make a single string of the request and response, suitable for copying + // to the clipboard and pasting into a bug report + NSMutableString *copyable = [NSMutableString string]; + if (comment) { + [copyable appendFormat:@"%@\n\n", comment]; + } + [copyable appendFormat:@"%@ elapsed: %5.3fsec\n", now, elapsed]; + if (redirectedFromURLString) { + [copyable appendFormat:@"Redirected from %@\n", redirectedFromURLString]; + } + [copyable appendFormat:@"Request: %@ %@\n", requestMethod, requestURL]; + if (requestHeaders.count > 0) { + [copyable appendFormat:@"Request headers:\n%@\n", + [[self class] headersStringForDictionary:requestHeaders]]; + } + if (bodyDataLength > 0) { + [copyable appendFormat:@"Request body: (%llu bytes)\n", bodyDataLength]; + if (bodyDataStr) { + [copyable appendFormat:@"%@\n", bodyDataStr]; + } + [copyable appendString:@"\n"]; + } + if (response) { + [copyable appendFormat:@"Response: status %d\n", (int) status]; + [copyable appendFormat:@"Response headers:\n%@\n", + [[self class] headersStringForDictionary:responseHeaders]]; + [copyable appendFormat:@"Response body: (%lld bytes)\n", responseDataLength]; + if (responseDataLength > 0) { + NSString *logResponseBody = self.logResponseBody; + if (logResponseBody) { + // The user has provided the response body text. + responseDataStr = [logResponseBody copy]; + self.logResponseBody = nil; + } + if (responseDataStr != nil) { + [copyable appendFormat:@"%@\n", responseDataStr]; + } else { + // Even though it's redundant, we'll put in text to indicate that all the bytes are binary. + if (self.destinationFileURL) { + [copyable appendFormat:@"<<%lld bytes>> to file %@\n", + responseDataLength, self.destinationFileURL.path]; + } else { + [copyable appendFormat:@"<<%lld bytes>>\n", responseDataLength]; + } + } + } + } + if (error) { + [copyable appendFormat:@"Error: %@\n", error]; + } + // Save to log property before adding the separator + self.log = copyable; + + [copyable appendString:@"-----------------------------------------------------------\n"]; + + // Write the copyable version to another file (linked to at the top of the html file, above) + // + // Ideally, something to just copy this to the clipboard like + // Copy here." + // would work everywhere, but it only works in Safari as of 8/2010 + if (gIsLoggingToFile) { + NSString *parentDir = [[self class] loggingDirectory]; + NSString *copyablePath = [logDirectory stringByAppendingPathComponent:copyableFileName]; + NSError *copyableError = nil; + if (![copyable writeToFile:copyablePath + atomically:NO + encoding:NSUTF8StringEncoding + error:©ableError]) { + // Error writing to file + NSLog(@"%@ logging write error:%@ (%@)", [self class], copyableError, copyablePath); + } + [outputHTML appendString:@"

"]; + + // Append the HTML to the main output file + const char* htmlBytes = outputHTML.UTF8String; + NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:htmlPath + append:YES]; + [stream open]; + [stream write:(const uint8_t *) htmlBytes maxLength:strlen(htmlBytes)]; + [stream close]; + + // Make a symlink to the latest html + NSString *const symlinkNameSuffix = [[self class] symlinkNameSuffix]; + NSString *symlinkName = [processName stringByAppendingString:symlinkNameSuffix]; + NSString *symlinkPath = [parentDir stringByAppendingPathComponent:symlinkName]; + + [fileMgr removeItemAtPath:symlinkPath error:NULL]; + [fileMgr createSymbolicLinkAtPath:symlinkPath + withDestinationPath:htmlPath + error:NULL]; +#if TARGET_OS_IPHONE + static BOOL gReportedLoggingPath = NO; + if (!gReportedLoggingPath) { + gReportedLoggingPath = YES; + NSLog(@"GTMSessionFetcher logging to \"%@\"", parentDir); + } +#endif + } +} + +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream { + if (!inputStream) return nil; + if (![GTMSessionFetcher isLoggingEnabled]) return inputStream; + + [self clearLoggedStreamData]; // Clear any previous data. + Class monitorClass = NSClassFromString(@"GTMReadMonitorInputStream"); + if (!monitorClass) { + NSString const *str = @"<>"; + NSData *stringData = [str dataUsingEncoding:NSUTF8StringEncoding]; + [self appendLoggedStreamData:stringData]; + return inputStream; + } + inputStream = [monitorClass inputStreamWithStream:inputStream]; + + GTMReadMonitorInputStream *readMonitorInputStream = (GTMReadMonitorInputStream *)inputStream; + [readMonitorInputStream setReadDelegate:self]; + SEL readSel = @selector(inputStream:readIntoBuffer:length:); + [readMonitorInputStream setReadSelector:readSel]; + + return inputStream; +} + +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider { + if (!streamProvider) return nil; + if (![GTMSessionFetcher isLoggingEnabled]) return streamProvider; + + [self clearLoggedStreamData]; // Clear any previous data. + Class monitorClass = NSClassFromString(@"GTMReadMonitorInputStream"); + if (!monitorClass) { + NSString const *str = @"<>"; + NSData *stringData = [str dataUsingEncoding:NSUTF8StringEncoding]; + [self appendLoggedStreamData:stringData]; + return streamProvider; + } + GTMSessionFetcherBodyStreamProvider loggedStreamProvider = + ^(GTMSessionFetcherBodyStreamProviderResponse response) { + streamProvider(^(NSInputStream *bodyStream) { + bodyStream = [self loggedInputStreamForInputStream:bodyStream]; + response(bodyStream); + }); + }; + return loggedStreamProvider; +} + +@end + +@implementation GTMSessionFetcher (GTMSessionFetcherLoggingUtilities) + +- (void)inputStream:(GTMReadMonitorInputStream *)stream + readIntoBuffer:(void *)buffer + length:(int64_t)length { + // append the captured data + NSData *data = [NSData dataWithBytesNoCopy:buffer + length:(NSUInteger)length + freeWhenDone:NO]; + [self appendLoggedStreamData:data]; +} + +#pragma mark Fomatting Utilities + ++ (NSString *)snipSubstringOfString:(NSString *)originalStr + betweenStartString:(NSString *)startStr + endString:(NSString *)endStr { +#if SKIP_GTM_FETCH_LOGGING_SNIPPING + return originalStr; +#else + if (!originalStr) return nil; + + // Find the start string, and replace everything between it + // and the end string (or the end of the original string) with "_snip_" + NSRange startRange = [originalStr rangeOfString:startStr]; + if (startRange.location == NSNotFound) return originalStr; + + // We found the start string + NSUInteger originalLength = originalStr.length; + NSUInteger startOfTarget = NSMaxRange(startRange); + NSRange targetAndRest = NSMakeRange(startOfTarget, originalLength - startOfTarget); + NSRange endRange = [originalStr rangeOfString:endStr + options:0 + range:targetAndRest]; + NSRange replaceRange; + if (endRange.location == NSNotFound) { + // Found no end marker so replace to end of string + replaceRange = targetAndRest; + } else { + // Replace up to the endStr + replaceRange = NSMakeRange(startOfTarget, endRange.location - startOfTarget); + } + NSString *result = [originalStr stringByReplacingCharactersInRange:replaceRange + withString:@"_snip_"]; + return result; +#endif // SKIP_GTM_FETCH_LOGGING_SNIPPING +} + ++ (NSString *)headersStringForDictionary:(NSDictionary *)dict { + // Format the dictionary in http header style, like + // Accept: application/json + // Cache-Control: no-cache + // Content-Type: application/json; charset=utf-8 + // + // Pad the key names, but not beyond 16 chars, since long custom header + // keys just create too much whitespace + NSArray *keys = [dict.allKeys sortedArrayUsingSelector:@selector(compare:)]; + + NSMutableString *str = [NSMutableString string]; + for (NSString *key in keys) { + NSString *value = [dict valueForKey:key]; + if ([key isEqual:@"Authorization"]) { + // Remove OAuth 1 token + value = [[self class] snipSubstringOfString:value + betweenStartString:@"oauth_token=\"" + endString:@"\""]; + + // Remove OAuth 2 bearer token (draft 16, and older form) + value = [[self class] snipSubstringOfString:value + betweenStartString:@"Bearer " + endString:@"\n"]; + value = [[self class] snipSubstringOfString:value + betweenStartString:@"OAuth " + endString:@"\n"]; + + // Remove Google ClientLogin + value = [[self class] snipSubstringOfString:value + betweenStartString:@"GoogleLogin auth=" + endString:@"\n"]; + } + [str appendFormat:@" %@: %@\n", key, value]; + } + return str; +} + +@end + +#endif // !STRIP_GTM_FETCH_LOGGING diff --git a/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h new file mode 100644 index 0000000..a696ac7 --- /dev/null +++ b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h @@ -0,0 +1,190 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// For best performance and convenient usage, fetchers should be generated by a common +// GTMSessionFetcherService instance, like +// +// _fetcherService = [[GTMSessionFetcherService alloc] init]; +// GTMSessionFetcher* myFirstFetcher = [_fetcherService fetcherWithRequest:request1]; +// GTMSessionFetcher* mySecondFetcher = [_fetcherService fetcherWithRequest:request2]; + +#import "GTMSessionFetcher.h" + +GTM_ASSUME_NONNULL_BEGIN + +// Notifications. + +// This notification indicates a reusable session has become invalid. It is intended mainly for the +// service's unit tests. +// +// The notification object is the fetcher service. +// The invalid session is provided via the userInfo kGTMSessionFetcherServiceSessionKey key. +extern NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification; +extern NSString *const kGTMSessionFetcherServiceSessionKey; + +@interface GTMSessionFetcherService : NSObject + +// Queues of delayed and running fetchers. Each dictionary contains arrays +// of GTMSessionFetcher *fetchers, keyed by NSString *host +@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSArray *) *delayedFetchersByHost; +@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSArray *) *runningFetchersByHost; + +// A max value of 0 means no fetchers should be delayed. +// The default limit is 10 simultaneous fetchers targeting each host. +// This does not apply to fetchers whose useBackgroundSession property is YES. Since services are +// not resurrected on an app relaunch, delayed fetchers would effectively be abandoned. +@property(atomic, assign) NSUInteger maxRunningFetchersPerHost; + +// Properties to be applied to each fetcher; see GTMSessionFetcher.h for descriptions +@property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration; +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock; +@property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage; +@property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue; +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock; +@property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential; +@property(atomic, strong) NSURLCredential *proxyCredential; +@property(atomic, copy, GTM_NULLABLE) GTM_NSArrayOf(NSString *) *allowedInsecureSchemes; +@property(atomic, assign) BOOL allowLocalhostRequest; +@property(atomic, assign) BOOL allowInvalidServerCertificates; +@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled; +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherRetryBlock retryBlock; +@property(atomic, assign) NSTimeInterval maxRetryInterval; +@property(atomic, assign) NSTimeInterval minRetryInterval; +@property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties; + +#if GTM_BACKGROUND_TASK_FETCHING +@property(atomic, assign) BOOL skipBackgroundTask; +#endif + +// A default useragent of GTMFetcherStandardUserAgentString(nil) will be given to each fetcher +// created by this service unless the request already has a user-agent header set. +// This default will be added starting with builds with the SDKs for OS X 10.11 and iOS 9. +// +// To use the configuration's default user agent, set this property to nil. +@property(atomic, copy, GTM_NULLABLE) NSString *userAgent; + +// The authorizer to attach to the created fetchers. If a specific fetcher should +// not authorize its requests, the fetcher's authorizer property may be set to nil +// before the fetch begins. +@property(atomic, strong, GTM_NULLABLE) id authorizer; + +// Delegate queue used by the session when calling back to the fetcher. The default +// is the main queue. Changing this does not affect the queue used to call back to the +// application; that is specified by the callbackQueue property above. +@property(atomic, strong, GTM_NULL_RESETTABLE) NSOperationQueue *sessionDelegateQueue; + +// When enabled, indicates the same session should be used by subsequent fetchers. +// +// This is enabled by default. +@property(atomic, assign) BOOL reuseSession; + +// Sets the delay until an unused session is invalidated. +// The default interval is 60 seconds. +// +// If the interval is set to 0, then any reused session is not invalidated except by +// explicitly invoking -resetSession. Be aware that setting the interval to 0 thus +// causes the session's delegate to be retained until the session is explicitly reset. +@property(atomic, assign) NSTimeInterval unusedSessionTimeout; + +// If shouldReuseSession is enabled, this will force creation of a new session when future +// fetchers begin. +- (void)resetSession; + +// Create a fetcher +// +// These methods will return a fetcher. If successfully created, the connection +// will hold a strong reference to it for the life of the connection as well. +// So the caller doesn't have to hold onto the fetcher explicitly unless they +// want to be able to monitor or cancel it. +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request; +- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL; +- (GTMSessionFetcher *)fetcherWithURLString:(NSString *)requestURLString; + +// Common method for fetcher creation. +// +// -fetcherWithRequest:fetcherClass: may be overridden to customize creation of +// fetchers. This is the ONLY method in the GTMSessionFetcher library intended to +// be overridden. +- (id)fetcherWithRequest:(NSURLRequest *)request + fetcherClass:(Class)fetcherClass; + +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher; + +- (NSUInteger)numberOfFetchers; // running + delayed fetchers +- (NSUInteger)numberOfRunningFetchers; +- (NSUInteger)numberOfDelayedFetchers; + +// Return a list of all running or delayed fetchers. This includes fetchers created +// by the service which have been started and have not yet stopped. +// +// Returns an array of fetcher objects, or nil if none. +- (GTM_NULLABLE GTM_NSArrayOf(GTMSessionFetcher *) *)issuedFetchers; + +// Search for running or delayed fetchers with the specified URL. +// +// Returns an array of fetcher objects found, or nil if none found. +- (GTM_NULLABLE GTM_NSArrayOf(GTMSessionFetcher *) *)issuedFetchersWithRequestURL:(NSURL *)requestURL; + +- (void)stopAllFetchers; + +// Methods for use by the fetcher class only. +- (GTM_NULLABLE NSURLSession *)session; +- (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation; +- (GTM_NULLABLE id)sessionDelegate; +- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate; + +// The testBlock can inspect its fetcher parameter's request property to +// determine which fetcher is being faked. +@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock; + +@end + +@interface GTMSessionFetcherService (TestingSupport) + +// Convenience method to create a fetcher service for testing. +// +// Fetchers generated by this mock fetcher service will not perform any +// network operation, but will invoke callbacks and provide the supplied data +// or error to the completion handler. +// +// You can make more customized mocks by setting the test block property of the service +// or fetcher; the test block can inspect the fetcher's request or other properties. +// +// See the description of the testBlock property below. ++ (instancetype)mockFetcherServiceWithFakedData:(GTM_NULLABLE NSData *)fakedDataOrNil + fakedError:(GTM_NULLABLE NSError *)fakedErrorOrNil; + +// Spin the run loop and discard events (or, if not on the main thread, just sleep the thread) +// until all running and delayed fetchers have completed. +// +// This is only for use in testing or in tools without a user interface. +// +// Synchronous fetches should never be done by shipping apps; they are +// sufficient reason for rejection from the app store. +// +// Returns NO if timed out. +- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds; + +@end + +@interface GTMSessionFetcherService (BackwardsCompatibilityOnly) + +// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves. +// This method is just for compatibility with the old fetcher. +@property(atomic, assign) NSInteger cookieStorageMethod; + +@end + +GTM_ASSUME_NONNULL_END diff --git a/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m new file mode 100644 index 0000000..fc6e6d9 --- /dev/null +++ b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m @@ -0,0 +1,1352 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcherService.h" + +NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification + = @"kGTMSessionFetcherServiceSessionBecameInvalidNotification"; +NSString *const kGTMSessionFetcherServiceSessionKey + = @"kGTMSessionFetcherServiceSessionKey"; + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (ServiceMethods) +- (BOOL)beginFetchMayDelay:(BOOL)mayDelay + mayAuthorize:(BOOL)mayAuthorize; +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionFetcherService () + +@property(atomic, strong, readwrite) NSDictionary *delayedFetchersByHost; +@property(atomic, strong, readwrite) NSDictionary *runningFetchersByHost; + +@end + +// Since NSURLSession doesn't support a separate delegate per task (!), instances of this +// class serve as a session delegate trampoline. +// +// This class maps a session's tasks to fetchers, and resends delegate messages to the task's +// fetcher. +@interface GTMSessionFetcherSessionDelegateDispatcher : NSObject + +// The session for the tasks in this dispatcher's task-to-fetcher map. +@property(atomic) NSURLSession *session; + +// The timer interval for invalidating a session that has no active tasks. +@property(atomic) NSTimeInterval discardInterval; + +// The current discard timer. +@property(atomic, readonly) NSTimer *discardTimer; + + +- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService + sessionDiscardInterval:(NSTimeInterval)discardInterval; + +- (void)setFetcher:(GTMSessionFetcher *)fetcher + forTask:(NSURLSessionTask *)task; +- (void)removeFetcher:(GTMSessionFetcher *)fetcher; + +// Before using a session, tells the delegate dispatcher to stop the discard timer. +- (void)startSessionUsage; + +// When abandoning a delegate dispatcher, we want to avoid the session retaining +// the delegate after tasks complete. +- (void)abandon; + +@end + + +@implementation GTMSessionFetcherService { + NSMutableDictionary *_delayedFetchersByHost; + NSMutableDictionary *_runningFetchersByHost; + NSUInteger _maxRunningFetchersPerHost; + + // When this ivar is nil, the service will not reuse sessions. + GTMSessionFetcherSessionDelegateDispatcher *_delegateDispatcher; + + // Fetchers will wait on this if another fetcher is creating the shared NSURLSession. + dispatch_semaphore_t _sessionCreationSemaphore; + + dispatch_queue_t _callbackQueue; + NSOperationQueue *_delegateQueue; + NSHTTPCookieStorage *_cookieStorage; + NSString *_userAgent; + NSTimeInterval _timeout; + + NSURLCredential *_credential; // Username & password. + NSURLCredential *_proxyCredential; // Credential supplied to proxy servers. + + NSInteger _cookieStorageMethod; + + id _authorizer; + + // For waitForCompletionOfAllFetchersWithTimeout: we need to wait on stopped fetchers since + // they've not yet finished invoking their queued callbacks. This array is nil except when + // waiting on fetchers. + NSMutableArray *_stoppedFetchersToWaitFor; + + // For fetchers that enqueued their callbacks before stopAllFetchers was called on the service, + // set a barrier so the callbacks know to bail out. + NSDate *_stoppedAllFetchersDate; +} + +@synthesize maxRunningFetchersPerHost = _maxRunningFetchersPerHost, + configuration = _configuration, + configurationBlock = _configurationBlock, + cookieStorage = _cookieStorage, + userAgent = _userAgent, + challengeBlock = _challengeBlock, + credential = _credential, + proxyCredential = _proxyCredential, + allowedInsecureSchemes = _allowedInsecureSchemes, + allowLocalhostRequest = _allowLocalhostRequest, + allowInvalidServerCertificates = _allowInvalidServerCertificates, + retryEnabled = _retryEnabled, + retryBlock = _retryBlock, + maxRetryInterval = _maxRetryInterval, + minRetryInterval = _minRetryInterval, + properties = _properties, + unusedSessionTimeout = _unusedSessionTimeout, + testBlock = _testBlock; + +#if GTM_BACKGROUND_TASK_FETCHING +@synthesize skipBackgroundTask = _skipBackgroundTask; +#endif + +- (instancetype)init { + self = [super init]; + if (self) { + _delayedFetchersByHost = [[NSMutableDictionary alloc] init]; + _runningFetchersByHost = [[NSMutableDictionary alloc] init]; + _maxRunningFetchersPerHost = 10; + _cookieStorageMethod = -1; + _unusedSessionTimeout = 60.0; + _delegateDispatcher = + [[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + _callbackQueue = dispatch_get_main_queue(); + + _delegateQueue = [[NSOperationQueue alloc] init]; + _delegateQueue.maxConcurrentOperationCount = 1; + _delegateQueue.name = @"com.google.GTMSessionFetcher.NSURLSessionDelegateQueue"; + + _sessionCreationSemaphore = dispatch_semaphore_create(1); + + // Starting with the SDKs for OS X 10.11/iOS 9, the service has a default useragent. + // Apps can remove this and get the default system "CFNetwork" useragent by setting the + // fetcher service's userAgent property to nil. +#if (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0) + _userAgent = GTMFetcherStandardUserAgentString(nil); +#endif + } + return self; +} + +- (void)dealloc { + [self detachAuthorizer]; + [_delegateDispatcher abandon]; +} + +#pragma mark Generate a new fetcher + +// Clients may override this method. Clients should not override any other library methods. +- (id)fetcherWithRequest:(NSURLRequest *)request + fetcherClass:(Class)fetcherClass { + GTMSessionFetcher *fetcher = [[fetcherClass alloc] initWithRequest:request + configuration:self.configuration]; + fetcher.callbackQueue = self.callbackQueue; + fetcher.sessionDelegateQueue = self.sessionDelegateQueue; + fetcher.challengeBlock = self.challengeBlock; + fetcher.credential = self.credential; + fetcher.proxyCredential = self.proxyCredential; + fetcher.authorizer = self.authorizer; + fetcher.cookieStorage = self.cookieStorage; + fetcher.allowedInsecureSchemes = self.allowedInsecureSchemes; + fetcher.allowLocalhostRequest = self.allowLocalhostRequest; + fetcher.allowInvalidServerCertificates = self.allowInvalidServerCertificates; + fetcher.configurationBlock = self.configurationBlock; + fetcher.retryEnabled = self.retryEnabled; + fetcher.retryBlock = self.retryBlock; + fetcher.maxRetryInterval = self.maxRetryInterval; + fetcher.minRetryInterval = self.minRetryInterval; + fetcher.properties = self.properties; + fetcher.service = self; + if (self.cookieStorageMethod >= 0) { + [fetcher setCookieStorageMethod:self.cookieStorageMethod]; + } + +#if GTM_BACKGROUND_TASK_FETCHING + fetcher.skipBackgroundTask = self.skipBackgroundTask; +#endif + + NSString *userAgent = self.userAgent; + if (userAgent.length > 0 + && [request valueForHTTPHeaderField:@"User-Agent"] == nil) { + [fetcher setRequestValue:userAgent + forHTTPHeaderField:@"User-Agent"]; + } + fetcher.testBlock = self.testBlock; + + return fetcher; +} + +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request { + return [self fetcherWithRequest:request + fetcherClass:[GTMSessionFetcher class]]; +} + +- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL { + return [self fetcherWithRequest:[NSURLRequest requestWithURL:requestURL]]; +} + +- (GTMSessionFetcher *)fetcherWithURLString:(NSString *)requestURLString { + NSURL *url = [NSURL URLWithString:requestURLString]; + return [self fetcherWithURL:url]; +} + +// Returns a session for the fetcher's host, or nil. +- (NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLSession *session = _delegateDispatcher.session; + return session; + } +} + +// Returns a session for the fetcher's host, or nil. For shared sessions, this +// waits on a semaphore, blocking other fetchers while the caller creates the +// session if needed. +- (NSURLSession *)sessionForFetcherCreation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + if (!_delegateDispatcher) { + // This fetcher is creating a non-shared session, so skip the semaphore usage. + return nil; + } + } + + // Wait if another fetcher is currently creating a session; avoid waiting + // inside the @synchronized block, as that can deadlock. + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Before getting the NSURLSession for task creation, it is + // important to invalidate and nil out the session discard timer; otherwise + // the session can be invalidated between when it is returned to the + // fetcher, and when the fetcher attempts to create its NSURLSessionTask. + [_delegateDispatcher startSessionUsage]; + + NSURLSession *session = _delegateDispatcher.session; + if (session) { + // The calling fetcher will receive a preexisting session, so + // we can allow other fetchers to create a session. + dispatch_semaphore_signal(_sessionCreationSemaphore); + } else { + // No existing session was obtained, so the calling fetcher will create the session; + // it *must* invoke fetcherDidCreateSession: to signal the dispatcher's semaphore after + // the session has been created (or fails to be created) to avoid a hang. + } + return session; + } +} + +- (id)sessionDelegate { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateDispatcher; + } +} + +#pragma mark Queue Management + +- (void)addRunningFetcher:(GTMSessionFetcher *)fetcher + forHost:(NSString *)host { + // Add to the array of running fetchers for this host, creating the array if needed. + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + if (runningForHost == nil) { + runningForHost = [NSMutableArray arrayWithObject:fetcher]; + [_runningFetchersByHost setObject:runningForHost forKey:host]; + } else { + [runningForHost addObject:fetcher]; + } +} + +- (void)addDelayedFetcher:(GTMSessionFetcher *)fetcher + forHost:(NSString *)host { + // Add to the array of delayed fetchers for this host, creating the array if needed. + NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + if (delayedForHost == nil) { + delayedForHost = [NSMutableArray arrayWithObject:fetcher]; + [_delayedFetchersByHost setObject:delayedForHost forKey:host]; + } else { + [delayedForHost addObject:fetcher]; + } +} + +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSString *host = fetcher.request.URL.host; + if (host == nil) { + return NO; + } + NSArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + NSUInteger idx = [delayedForHost indexOfObjectIdenticalTo:fetcher]; + BOOL isDelayed = (delayedForHost != nil) && (idx != NSNotFound); + return isDelayed; + } +} + +- (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher { + // Entry point from the fetcher + NSURL *requestURL = fetcher.request.URL; + NSString *host = requestURL.host; + + // Addresses "file:///path" case where localhost is the implicit host. + if (host.length == 0 && [requestURL isFileURL]) { + host = @"localhost"; + } + + if (host.length == 0) { + // Data URIs legitimately have no host, reject other hostless URLs. + GTMSESSION_ASSERT_DEBUG([[requestURL scheme] isEqual:@"data"], @"%@ lacks host", fetcher); + return YES; + } + + BOOL shouldBeginResult; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + if (runningForHost != nil + && [runningForHost indexOfObjectIdenticalTo:fetcher] != NSNotFound) { + GTMSESSION_ASSERT_DEBUG(NO, @"%@ was already running", fetcher); + return YES; + } + + BOOL shouldRunNow = (fetcher.usingBackgroundSession + || _maxRunningFetchersPerHost == 0 + || _maxRunningFetchersPerHost > + [[self class] numberOfNonBackgroundSessionFetchers:runningForHost]); + if (shouldRunNow) { + [self addRunningFetcher:fetcher forHost:host]; + shouldBeginResult = YES; + } else { + [self addDelayedFetcher:fetcher forHost:host]; + shouldBeginResult = NO; + } + } // @synchronized(self) + + // We'll save the host that serves as the key for this fetcher's array + // to avoid any chance of the underlying request changing, stranding + // the fetcher in the wrong array + fetcher.serviceHost = host; + + return shouldBeginResult; +} + +- (void)startFetcher:(GTMSessionFetcher *)fetcher { + [fetcher beginFetchMayDelay:NO + mayAuthorize:YES]; +} + +// Internal utility. Returns a fetcher's delegate if it's a dispatcher, or nil if the fetcher +// is its own delegate and has no dispatcher. +- (GTMSessionFetcherSessionDelegateDispatcher *)delegateDispatcherForFetcher:(GTMSessionFetcher *)fetcher { + GTMSessionCheckNotSynchronized(self); + + NSURLSession *fetcherSession = fetcher.session; + if (fetcherSession) { + id fetcherDelegate = fetcherSession.delegate; + BOOL hasDispatcher = (fetcherDelegate != nil && fetcherDelegate != fetcher); + if (hasDispatcher) { + GTMSESSION_ASSERT_DEBUG([fetcherDelegate isKindOfClass:[GTMSessionFetcherSessionDelegateDispatcher class]], + @"Fetcher delegate class: %@", [fetcherDelegate class]); + return (GTMSessionFetcherSessionDelegateDispatcher *)fetcherDelegate; + } + } + return nil; +} + +- (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher { + if (fetcher.canShareSession) { + NSURLSession *fetcherSession = fetcher.session; + GTMSESSION_ASSERT_DEBUG(fetcherSession != nil, @"Fetcher missing its session: %@", fetcher); + + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + if (delegateDispatcher) { + GTMSESSION_ASSERT_DEBUG(delegateDispatcher.session == nil, + @"Fetcher made an extra session: %@", fetcher); + + // Save this fetcher's session. + delegateDispatcher.session = fetcherSession; + + // Allow other fetchers to request this session now. + dispatch_semaphore_signal(_sessionCreationSemaphore); + } + } +} + +- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher { + // If this fetcher has a separate delegate with a shared session, then + // this fetcher should be added to the delegate's map of tasks to fetchers. + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + if (delegateDispatcher) { + GTMSESSION_ASSERT_DEBUG(fetcher.canShareSession, + @"Inappropriate shared session: %@", fetcher); + + // There should already be a session, from this or a previous fetcher. + // + // Sanity check that the fetcher's session is the delegate's shared session. + NSURLSession *sharedSession = delegateDispatcher.session; + NSURLSession *fetcherSession = fetcher.session; + GTMSESSION_ASSERT_DEBUG(sharedSession != nil, @"Missing delegate session: %@", fetcher); + GTMSESSION_ASSERT_DEBUG(fetcherSession == sharedSession, + @"Inconsistent session: %@ %@ (shared: %@)", + fetcher, fetcherSession, sharedSession); + + if (sharedSession != nil && fetcherSession == sharedSession) { + NSURLSessionTask *task = fetcher.sessionTask; + GTMSESSION_ASSERT_DEBUG(task != nil, @"Missing session task: %@", fetcher); + + if (task) { + [delegateDispatcher setFetcher:fetcher + forTask:task]; + } + } + } +} + +- (void)stopFetcher:(GTMSessionFetcher *)fetcher { + [fetcher stopFetching]; +} + +- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher { + // Entry point from the fetcher + NSString *host = fetcher.serviceHost; + if (!host) { + // fetcher has been stopped previously + return; + } + + // This removeFetcher: invocation is a fallback; typically, fetchers are removed from the task + // map when the task completes. + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + [delegateDispatcher removeFetcher:fetcher]; + + NSMutableArray *fetchersToStart; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // If a test is waiting for all fetchers to stop, it needs to wait for this one + // to invoke its callbacks on the callback queue. + [_stoppedFetchersToWaitFor addObject:fetcher]; + + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + [runningForHost removeObject:fetcher]; + + NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + [delayedForHost removeObject:fetcher]; + + while (delayedForHost.count > 0 + && [[self class] numberOfNonBackgroundSessionFetchers:runningForHost] + < _maxRunningFetchersPerHost) { + // Start another delayed fetcher running, scanning for the minimum + // priority value, defaulting to FIFO for equal priorities + GTMSessionFetcher *nextFetcher = nil; + for (GTMSessionFetcher *delayedFetcher in delayedForHost) { + if (nextFetcher == nil + || delayedFetcher.servicePriority < nextFetcher.servicePriority) { + nextFetcher = delayedFetcher; + } + } + + if (nextFetcher) { + [self addRunningFetcher:nextFetcher forHost:host]; + runningForHost = [_runningFetchersByHost objectForKey:host]; + + [delayedForHost removeObjectIdenticalTo:nextFetcher]; + + if (!fetchersToStart) { + fetchersToStart = [NSMutableArray array]; + } + [fetchersToStart addObject:nextFetcher]; + } + } + + if (runningForHost.count == 0) { + // None left; remove the empty array + [_runningFetchersByHost removeObjectForKey:host]; + } + + if (delayedForHost.count == 0) { + [_delayedFetchersByHost removeObjectForKey:host]; + } + } // @synchronized(self) + + // Start fetchers outside of the synchronized block to avoid a deadlock. + for (GTMSessionFetcher *nextFetcher in fetchersToStart) { + [self startFetcher:nextFetcher]; + } + + // The fetcher is no longer in the running or the delayed array, + // so remove its host and thread properties + fetcher.serviceHost = nil; +} + +- (NSUInteger)numberOfFetchers { + NSUInteger running = [self numberOfRunningFetchers]; + NSUInteger delayed = [self numberOfDelayedFetchers]; + return running + delayed; +} + +- (NSUInteger)numberOfRunningFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger sum = 0; + for (NSString *host in _runningFetchersByHost) { + NSArray *fetchers = [_runningFetchersByHost objectForKey:host]; + sum += fetchers.count; + } + return sum; + } +} + +- (NSUInteger)numberOfDelayedFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger sum = 0; + for (NSString *host in _delayedFetchersByHost) { + NSArray *fetchers = [_delayedFetchersByHost objectForKey:host]; + sum += fetchers.count; + } + return sum; + } +} + +- (NSArray *)issuedFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSMutableArray *allFetchers = [NSMutableArray array]; + void (^accumulateFetchers)(id, id, BOOL *) = ^(NSString *host, + NSArray *fetchersForHost, + BOOL *stop) { + [allFetchers addObjectsFromArray:fetchersForHost]; + }; + [_runningFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers]; + [_delayedFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers]; + + GTMSESSION_ASSERT_DEBUG(allFetchers.count == [NSSet setWithArray:allFetchers].count, + @"Fetcher appears multiple times\n running: %@\n delayed: %@", + _runningFetchersByHost, _delayedFetchersByHost); + + return allFetchers.count > 0 ? allFetchers : nil; + } +} + +- (NSArray *)issuedFetchersWithRequestURL:(NSURL *)requestURL { + NSString *host = requestURL.host; + if (host.length == 0) return nil; + + NSURL *targetURL = [requestURL absoluteURL]; + + NSArray *allFetchers = [self issuedFetchers]; + NSIndexSet *indexes = [allFetchers indexesOfObjectsPassingTest:^BOOL(GTMSessionFetcher *fetcher, + NSUInteger idx, + BOOL *stop) { + NSURL *fetcherURL = [fetcher.request.URL absoluteURL]; + return [fetcherURL isEqual:targetURL]; + }]; + + NSArray *result = nil; + if (indexes.count > 0) { + result = [allFetchers objectsAtIndexes:indexes]; + } + return result; +} + +- (void)stopAllFetchers { + NSArray *delayedFetchersByHost; + NSArray *runningFetchersByHost; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Set the time barrier so fetchers know not to call back even if + // the stop calls below occur after the fetchers naturally + // stopped and so were removed from _runningFetchersByHost, + // but while the callbacks were already enqueued before stopAllFetchers + // was invoked. + _stoppedAllFetchersDate = [[NSDate alloc] init]; + + // Remove fetchers from the delayed list to avoid fetcherDidStop: from + // starting more fetchers running as a side effect of stopping one + delayedFetchersByHost = _delayedFetchersByHost.allValues; + [_delayedFetchersByHost removeAllObjects]; + + runningFetchersByHost = _runningFetchersByHost.allValues; + [_runningFetchersByHost removeAllObjects]; + } + + for (NSArray *delayedForHost in delayedFetchersByHost) { + for (GTMSessionFetcher *fetcher in delayedForHost) { + [self stopFetcher:fetcher]; + } + } + + for (NSArray *runningForHost in runningFetchersByHost) { + for (GTMSessionFetcher *fetcher in runningForHost) { + [self stopFetcher:fetcher]; + } + } +} + +- (NSDate *)stoppedAllFetchersDate { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _stoppedAllFetchersDate; + } +} + +#pragma mark Accessors + +- (BOOL)reuseSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateDispatcher != nil; + } +} + +- (void)setReuseSession:(BOOL)shouldReuse { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL wasReusing = (_delegateDispatcher != nil); + if (shouldReuse != wasReusing) { + [self abandonDispatcher]; + if (shouldReuse) { + _delegateDispatcher = + [[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + } else { + _delegateDispatcher = nil; + } + } + } +} + +- (void)resetSession { + GTMSessionCheckNotSynchronized(self); + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + [self resetSessionInternal]; + } + + dispatch_semaphore_signal(_sessionCreationSemaphore); +} + +- (void)resetSessionInternal { + GTMSessionCheckSynchronized(self); + + // The old dispatchers may be retained as delegates of any ongoing sessions by those sessions. + if (_delegateDispatcher) { + [self abandonDispatcher]; + _delegateDispatcher = + [[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + } +} + +- (void)resetSessionForDispatcherDiscardTimer:(NSTimer *)timer { + GTMSessionCheckNotSynchronized(self); + + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_delegateDispatcher.discardTimer == timer) { + // If the delegate dispatcher's current discardTimer is the same object as the timer + // that fired, no fetcher has recently attempted to start using the session by calling + // startSessionUsage, which invalidates and nils out the timer. + [self resetSessionInternal]; + } else { + // A fetcher has invalidated the timer between its triggering and now, potentially + // meaning a fetcher has requested access to the NSURLSession, and may be in the process + // of starting a new task. The dispatcher should not be abandoned, as this can lead + // to a race condition between calling -finishTasksAndInvalidate on the NSURLSession + // and the fetcher attempting to create a new task. + } + } + + dispatch_semaphore_signal(_sessionCreationSemaphore); +} + +- (NSTimeInterval)unusedSessionTimeout { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _unusedSessionTimeout; + } +} + +- (void)setUnusedSessionTimeout:(NSTimeInterval)timeout { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _unusedSessionTimeout = timeout; + _delegateDispatcher.discardInterval = timeout; + } +} + +// This method should be called inside of @synchronized(self) +- (void)abandonDispatcher { + GTMSessionCheckSynchronized(self); + [_delegateDispatcher abandon]; +} + +- (NSDictionary *)runningFetchersByHost { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_runningFetchersByHost copy]; + } +} + +- (void)setRunningFetchersByHost:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _runningFetchersByHost = [dict mutableCopy]; + } +} + +- (NSDictionary *)delayedFetchersByHost { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_delayedFetchersByHost copy]; + } +} + +- (void)setDelayedFetchersByHost:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delayedFetchersByHost = [dict mutableCopy]; + } +} + +- (id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _authorizer; + } +} + +- (void)setAuthorizer:(id)obj { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (obj != _authorizer) { + [self detachAuthorizer]; + } + + _authorizer = obj; + } + + // Use the fetcher service for the authorization fetches if the auth + // object supports fetcher services + if ([obj respondsToSelector:@selector(setFetcherService:)]) { +#if GTM_USE_SESSION_FETCHER + [obj setFetcherService:self]; +#else + [obj setFetcherService:(id)self]; +#endif + } +} + +// This should be called inside a @synchronized(self) block except during dealloc. +- (void)detachAuthorizer { + // This method is called by the fetcher service's dealloc and setAuthorizer: + // methods; do not override. + // + // The fetcher service retains the authorizer, and the authorizer has a + // weak pointer to the fetcher service (a non-zeroing pointer for + // compatibility with iOS 4 and Mac OS X 10.5/10.6.) + // + // When this fetcher service no longer uses the authorizer, we want to remove + // the authorizer's dependence on the fetcher service. Authorizers can still + // function without a fetcher service. + if ([_authorizer respondsToSelector:@selector(fetcherService)]) { + id authFetcherService = [_authorizer fetcherService]; + if (authFetcherService == self) { + [_authorizer setFetcherService:nil]; + } + } +} + +- (dispatch_queue_t GTM_NONNULL_TYPE)callbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _callbackQueue; + } // @synchronized(self) +} + +- (void)setCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _callbackQueue = queue ?: dispatch_get_main_queue(); + } // @synchronized(self) +} + +- (NSOperationQueue * GTM_NONNULL_TYPE)sessionDelegateQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateQueue; + } // @synchronized(self) +} + +- (void)setSessionDelegateQueue:(NSOperationQueue * GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateQueue = queue ?: [NSOperationQueue mainQueue]; + } // @synchronized(self) +} + +- (NSOperationQueue *)delegateQueue { + // Provided for compatibility with the old fetcher service. The gtm-oauth2 code respects + // any custom delegate queue for calling the app. + return nil; +} + ++ (NSUInteger)numberOfNonBackgroundSessionFetchers:(NSArray *)fetchers { + NSUInteger sum = 0; + for (GTMSessionFetcher *fetcher in fetchers) { + if (!fetcher.usingBackgroundSession) { + ++sum; + } + } + return sum; +} + +@end + +@implementation GTMSessionFetcherService (TestingSupport) + ++ (instancetype)mockFetcherServiceWithFakedData:(NSData *)fakedDataOrNil + fakedError:(NSError *)fakedErrorOrNil { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + NSURL *url = [NSURL URLWithString:@"http://example.invalid"]; + NSHTTPURLResponse *fakedResponse = + [[NSHTTPURLResponse alloc] initWithURL:url + statusCode:(fakedErrorOrNil ? 500 : 200) + HTTPVersion:@"HTTP/1.1" + headerFields:nil]; + GTMSessionFetcherService *service = [[self alloc] init]; + service.allowedInsecureSchemes = @[ @"http" ]; + service.testBlock = ^(GTMSessionFetcher *fetcherToTest, + GTMSessionFetcherTestResponse testResponse) { + testResponse(fakedResponse, fakedDataOrNil, fakedErrorOrNil); + }; + return service; +#else + GTMSESSION_ASSERT_DEBUG(0, @"Test blocks disabled"); + return nil; +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK +} + +#pragma mark Synchronous Wait for Unit Testing + +- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds { + NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + _stoppedFetchersToWaitFor = [NSMutableArray array]; + + BOOL shouldSpinRunLoop = [NSThread isMainThread]; + const NSTimeInterval kSpinInterval = 0.001; + BOOL didTimeOut = NO; + while (([self numberOfFetchers] > 0 || _stoppedFetchersToWaitFor.count > 0)) { + didTimeOut = [giveUpDate timeIntervalSinceNow] < 0; + if (didTimeOut) break; + + GTMSessionFetcher *stoppedFetcher = _stoppedFetchersToWaitFor.firstObject; + if (stoppedFetcher) { + [_stoppedFetchersToWaitFor removeObject:stoppedFetcher]; + [stoppedFetcher waitForCompletionWithTimeout:10.0 * kSpinInterval]; + } + + if (shouldSpinRunLoop) { + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:kSpinInterval]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + [NSThread sleepForTimeInterval:kSpinInterval]; + } + } + _stoppedFetchersToWaitFor = nil; + + return !didTimeOut; +} + +@end + +@implementation GTMSessionFetcherService (BackwardsCompatibilityOnly) + +- (NSInteger)cookieStorageMethod { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _cookieStorageMethod; + } +} + +- (void)setCookieStorageMethod:(NSInteger)cookieStorageMethod { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _cookieStorageMethod = cookieStorageMethod; + } +} + +@end + +@implementation GTMSessionFetcherSessionDelegateDispatcher { + __weak GTMSessionFetcherService *_parentService; + NSURLSession *_session; + + // The task map maps NSURLSessionTasks to GTMSessionFetchers + NSMutableDictionary *_taskToFetcherMap; + // The discard timer will invalidate sessions after the session's last task completes. + NSTimer *_discardTimer; + NSTimeInterval _discardInterval; +} + +@synthesize discardInterval = _discardInterval, + session = _session; + +- (instancetype)init { + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService + sessionDiscardInterval:(NSTimeInterval)discardInterval { + self = [super init]; + if (self) { + _discardInterval = discardInterval; + _parentService = parentService; + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@ %p %@ %@", + [self class], self, + _session ?: @"", + _taskToFetcherMap.count > 0 ? _taskToFetcherMap : @""]; +} + +- (NSTimer *)discardTimer { + GTMSessionCheckNotSynchronized(self); + @synchronized(self) { + return _discardTimer; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)startDiscardTimer { + GTMSessionCheckSynchronized(self); + [_discardTimer invalidate]; + _discardTimer = nil; + if (_discardInterval > 0) { + _discardTimer = [NSTimer timerWithTimeInterval:_discardInterval + target:self + selector:@selector(discardTimerFired:) + userInfo:nil + repeats:NO]; + [_discardTimer setTolerance:(_discardInterval / 10)]; + [[NSRunLoop mainRunLoop] addTimer:_discardTimer forMode:NSRunLoopCommonModes]; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)destroyDiscardTimer { + GTMSessionCheckSynchronized(self); + [_discardTimer invalidate]; + _discardTimer = nil; +} + +- (void)discardTimerFired:(NSTimer *)timer { + GTMSessionFetcherService *service; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger numberOfTasks = _taskToFetcherMap.count; + if (numberOfTasks == 0) { + service = _parentService; + } + } + + // Inform the service that the discard timer has fired, and should check whether the + // service can abandon us. -resetSession cannot be called directly, as there is a + // race condition that must be guarded against with the NSURLSession being returned + // from sessionForFetcherCreation outside other locks. The service can take steps + // to prevent resetting the session if that has occurred. + // + // The service must be called from outside the @synchronized block. + [service resetSessionForDispatcherDiscardTimer:timer]; +} + +- (void)abandon { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self destroySessionAndTimer]; + } +} + +- (void)startSessionUsage { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self destroyDiscardTimer]; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)destroySessionAndTimer { + GTMSessionCheckSynchronized(self); + [self destroyDiscardTimer]; + + // Break any retain cycle from the session holding the delegate. + [_session finishTasksAndInvalidate]; + + // Immediately clear the session so no new task may be issued with it. + // + // The _taskToFetcherMap needs to stay valid until the outstanding tasks finish. + _session = nil; +} + +- (void)setFetcher:(GTMSessionFetcher *)fetcher forTask:(NSURLSessionTask *)task { + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"missing fetcher"); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_taskToFetcherMap == nil) { + _taskToFetcherMap = [[NSMutableDictionary alloc] init]; + } + + if (fetcher) { + [_taskToFetcherMap setObject:fetcher forKey:task]; + [self destroyDiscardTimer]; + } + } +} + +- (void)removeFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Typically, a fetcher should be removed when its task invokes + // URLSession:task:didCompleteWithError:. + // + // When fetching with a testBlock, though, the task completed delegate + // method may not be invoked, requiring cleanup here. + NSArray *tasks = [_taskToFetcherMap allKeysForObject:fetcher]; + GTMSESSION_ASSERT_DEBUG(tasks.count <= 1, @"fetcher task not unmapped: %@", tasks); + [_taskToFetcherMap removeObjectsForKeys:tasks]; + + if (_taskToFetcherMap.count == 0) { + [self startDiscardTimer]; + } + } +} + +// This helper method provides synchronized access to the task map for the delegate +// methods below. +- (id)fetcherForTask:(NSURLSessionTask *)task { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_taskToFetcherMap objectForKey:task]; + } +} + +- (void)removeTaskFromMap:(NSURLSessionTask *)task { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_taskToFetcherMap removeObjectForKey:task]; + } +} + +- (void)setSession:(NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = session; + } +} + +- (NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _session; + } +} + +- (NSTimeInterval)discardInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _discardInterval; + } +} + +- (void)setDiscardInterval:(NSTimeInterval)interval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _discardInterval = interval; + } +} + +// NSURLSessionDelegate protocol methods. + +// - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session; +// +// TODO(seh): How do we route this to an appropriate fetcher? + + +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", + [self class], self, session, error); + NSDictionary *localTaskToFetcherMap; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = nil; + + localTaskToFetcherMap = [_taskToFetcherMap copy]; + } + + // Any "suspended" tasks may not have received callbacks from NSURLSession when the session + // completes; we'll call them now. + [localTaskToFetcherMap enumerateKeysAndObjectsUsingBlock:^(NSURLSessionTask *task, + GTMSessionFetcher *fetcher, + BOOL *stop) { + if (fetcher.session == session) { + // Our delegate method URLSession:task:didCompleteWithError: will rely on + // _taskToFetcherMap so that should still contain this fetcher. + NSError *canceledError = [NSError errorWithDomain:NSURLErrorDomain + code:NSURLErrorCancelled + userInfo:nil]; + [self URLSession:session task:task didCompleteWithError:canceledError]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"Unexpected session in fetcher: %@ has %@ (expected %@)", + fetcher, fetcher.session, session); + } + }]; + + // Our tests rely on this notification to know the session discard timer fired. + NSDictionary *userInfo = @{ kGTMSessionFetcherServiceSessionKey : session }; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherServiceSessionBecameInvalidNotification + object:_parentService + userInfo:userInfo]; +} + + +#pragma mark - NSURLSessionTaskDelegate + +// NSURLSessionTaskDelegate protocol methods. +// +// We won't test here if the fetcher responds to these since we only want this +// class to implement the same delegate methods the fetcher does (so NSURLSession's +// tests for respondsToSelector: will have the same result whether the session +// delegate is the fetcher or this dispatcher.) + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task +willPerformHTTPRedirection:response + newRequest:request + completionHandler:completionHandler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))handler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + didReceiveChallenge:challenge + completionHandler:handler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + needNewBodyStream:(void (^)(NSInputStream *bodyStream))handler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + needNewBodyStream:handler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + didSendBodyData:bytesSent + totalBytesSent:totalBytesSent +totalBytesExpectedToSend:totalBytesExpectedToSend]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error { + id fetcher = [self fetcherForTask:task]; + + // This is the usual way tasks are removed from the task map. + [self removeTaskFromMap:task]; + + [fetcher URLSession:session + task:task + didCompleteWithError:error]; +} + +// NSURLSessionDataDelegate protocol methods. + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition))handler { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + didReceiveResponse:response + completionHandler:handler]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { + id fetcher = [self fetcherForTask:dataTask]; + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"Missing fetcher for %@", dataTask); + [self removeTaskFromMap:dataTask]; + if (fetcher) { + GTMSESSION_ASSERT_DEBUG([fetcher isKindOfClass:[GTMSessionFetcher class]], + @"Expecting GTMSessionFetcher"); + [self setFetcher:(GTMSessionFetcher *)fetcher forTask:downloadTask]; + } + + [fetcher URLSession:session + dataTask:dataTask +didBecomeDownloadTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + didReceiveData:data]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *))handler { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + willCacheResponse:proposedResponse + completionHandler:handler]; +} + +// NSURLSessionDownloadDelegate protocol methods. + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask +didFinishDownloadingToURL:(NSURL *)location { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask +didFinishDownloadingToURL:location]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalWritten +totalBytesExpectedToWrite:(int64_t)totalExpected { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask + didWriteData:bytesWritten + totalBytesWritten:totalWritten +totalBytesExpectedToWrite:totalExpected]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset +expectedTotalBytes:(int64_t)expectedTotalBytes { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask + didResumeAtOffset:fileOffset + expectedTotalBytes:expectedTotalBytes]; +} + +@end diff --git a/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h new file mode 100644 index 0000000..51372f2 --- /dev/null +++ b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h @@ -0,0 +1,128 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// GTMSessionUploadFetcher implements Google's resumable upload protocol. + +// +// This subclass of GTMSessionFetcher simulates the series of fetches +// needed for chunked upload as a single fetch operation. +// +// Protocol document: TBD +// +// To the client, the only fetcher that exists is this class; the subsidiary +// fetchers needed for uploading chunks are not visible (though the most recent +// chunk fetcher may be accessed via the -activeFetcher or -chunkFetcher methods, and +// -responseHeaders and -statusCode reflect results from the most recent chunk +// fetcher.) +// +// Chunk fetchers are discarded as soon as they have completed. +// + +// Note: Unlike the fetcher superclass, the methods of GTMSessionUploadFetcher should +// only be used from the main thread until further work is done to make this subclass +// thread-safe. + +#import "GTMSessionFetcher.h" +#import "GTMSessionFetcherService.h" + +GTM_ASSUME_NONNULL_BEGIN + +// Unless an application knows it needs a smaller chunk size, it should use the standard +// chunk size, which sends the entire file as a single chunk to minimize upload overhead. +extern int64_t const kGTMSessionUploadFetcherStandardChunkSize; + +// When uploading requires data buffer allocations (such as uploading from an NSData or +// an NSFileHandle) this is the maximum buffer size that will be created by the fetcher. +extern int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize; + +// Notification that the upload location URL was provided by the server. +extern NSString *const kGTMSessionFetcherUploadLocationObtainedNotification; + +// Block to provide data during uploads. +// +// Response data may be allocated with dataWithBytesNoCopy:length:freeWhenDone: for efficiency, +// and released after the response block returns. +// +// Pass nil as the data (and optionally an NSError) for a failure. +typedef void (^GTMSessionUploadFetcherDataProviderResponse)(NSData * GTM_NULLABLE_TYPE data, + NSError * GTM_NULLABLE_TYPE error); +typedef void (^GTMSessionUploadFetcherDataProvider)(int64_t offset, int64_t length, + GTMSessionUploadFetcherDataProviderResponse response); + +@interface GTMSessionUploadFetcher : GTMSessionFetcher + +// Create an upload fetcher specifying either the request or the resume location URL, +// then set an upload data source using one of these: +// +// setUploadFileURL: +// setUploadDataLength:provider: +// setUploadFileHandle: +// setUploadData: + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil; + ++ (instancetype)uploadFetcherWithLocation:(NSURL * GTM_NULLABLE_TYPE)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil; + +- (void)setUploadDataLength:(int64_t)fullLength + provider:(GTM_NULLABLE GTMSessionUploadFetcherDataProvider)block; + ++ (NSArray *)uploadFetchersForBackgroundSessions; ++ (GTM_NULLABLE instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier; + +- (void)pauseFetching; +- (void)resumeFetching; +- (BOOL)isPaused; + +@property(atomic, strong, GTM_NULLABLE) NSURL *uploadLocationURL; +@property(atomic, strong, GTM_NULLABLE) NSData *uploadData; +@property(atomic, strong, GTM_NULLABLE) NSURL *uploadFileURL; +@property(atomic, strong, GTM_NULLABLE) NSFileHandle *uploadFileHandle; +@property(atomic, copy, readonly, GTM_NULLABLE) GTMSessionUploadFetcherDataProvider uploadDataProvider; +@property(atomic, copy) NSString *uploadMIMEType; +@property(atomic, assign) int64_t chunkSize; +@property(atomic, readonly, assign) int64_t currentOffset; + +// The fetcher for the current data chunk, if any +@property(atomic, strong, GTM_NULLABLE) GTMSessionFetcher *chunkFetcher; + +// The active fetcher is the current chunk fetcher, or the upload fetcher itself +// if no chunk fetcher has yet been created. +@property(atomic, readonly) GTMSessionFetcher *activeFetcher; + +// The last request made by an active fetcher. Useful for testing. +@property(atomic, readonly, GTM_NULLABLE) NSURLRequest *lastChunkRequest; + +// The status code from the most recently-completed fetch. +@property(atomic, assign) NSInteger statusCode; + +// Exposed for testing only. +@property(atomic, readonly, GTM_NULLABLE) dispatch_queue_t delegateCallbackQueue; +@property(atomic, readonly, GTM_NULLABLE) GTMSessionFetcherCompletionHandler delegateCompletionHandler; + +@end + +@interface GTMSessionFetcher (GTMSessionUploadFetcherMethods) + +@property(readonly, GTM_NULLABLE) GTMSessionUploadFetcher *parentUploadFetcher; + +@end + +GTM_ASSUME_NONNULL_END diff --git a/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m new file mode 100644 index 0000000..a5ae0dc --- /dev/null +++ b/Task Master/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m @@ -0,0 +1,1804 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionUploadFetcher.h" + +static NSString *const kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey = @"_upChunk"; +static NSString *const kGTMSessionIdentifierUploadFileURLMetadataKey = @"_upFileURL"; +static NSString *const kGTMSessionIdentifierUploadFileLengthMetadataKey = @"_upFileLen"; +static NSString *const kGTMSessionIdentifierUploadLocationURLMetadataKey = @"_upLocURL"; +static NSString *const kGTMSessionIdentifierUploadMIMETypeMetadataKey = @"_uploadMIME"; +static NSString *const kGTMSessionIdentifierUploadChunkSizeMetadataKey = @"_upChSize"; +static NSString *const kGTMSessionIdentifierUploadCurrentOffsetMetadataKey = @"_upOffset"; + +static NSString *const kGTMSessionHeaderXGoogUploadChunkGranularity = @"X-Goog-Upload-Chunk-Granularity"; +static NSString *const kGTMSessionHeaderXGoogUploadCommand = @"X-Goog-Upload-Command"; +static NSString *const kGTMSessionHeaderXGoogUploadContentLength = @"X-Goog-Upload-Content-Length"; +static NSString *const kGTMSessionHeaderXGoogUploadContentType = @"X-Goog-Upload-Content-Type"; +static NSString *const kGTMSessionHeaderXGoogUploadOffset = @"X-Goog-Upload-Offset"; +static NSString *const kGTMSessionHeaderXGoogUploadProtocol = @"X-Goog-Upload-Protocol"; +static NSString *const kGTMSessionHeaderXGoogUploadSizeReceived = @"X-Goog-Upload-Size-Received"; +static NSString *const kGTMSessionHeaderXGoogUploadStatus = @"X-Goog-Upload-Status"; +static NSString *const kGTMSessionHeaderXGoogUploadURL = @"X-Goog-Upload-URL"; + +// Property of chunk fetchers identifying the parent upload fetcher. Non-retained NSValue. +static NSString *const kGTMSessionUploadFetcherChunkParentKey = @"_uploadFetcherChunkParent"; + +int64_t const kGTMSessionUploadFetcherStandardChunkSize = (int64_t)LLONG_MAX; + +#if TARGET_OS_IPHONE +int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = 10 * 1024 * 1024; // 10 MB for iOS, watchOS, tvOS +#else +int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = 100 * 1024 * 1024; // 100 MB for macOS +#endif + +typedef NS_ENUM(NSUInteger, GTMSessionUploadFetcherStatus) { + kStatusUnknown, + kStatusActive, + kStatusFinal, + kStatusCancelled, +}; + +NSString *const kGTMSessionFetcherUploadLocationObtainedNotification = + @"kGTMSessionFetcherUploadLocationObtainedNotification"; + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (ProtectedMethods) + +// Access to non-public method on the parent fetcher class. +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks; +- (void)createSessionIdentifierWithMetadata:(NSDictionary *)metadata; +- (GTMSessionFetcherCompletionHandler)completionHandlerWithTarget:(id)target + didFinishSelector:(SEL)finishedSelector; +- (void)invokeOnCallbackQueue:(dispatch_queue_t)callbackQueue + afterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block; +- (NSTimer *)retryTimer; + +@property(readwrite, strong) NSData *downloadedData; +- (void)releaseCallbacks; + +- (NSInteger)statusCodeUnsynchronized; + +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionUploadFetcher () + +// Changing readonly to readwrite. +@property(atomic, strong, readwrite) NSURLRequest *lastChunkRequest; +@property(atomic, readwrite, assign) int64_t currentOffset; + +// Internal properties. +@property(strong, atomic, GTM_NULLABLE) GTMSessionFetcher *fetcherInFlight; // Synchronized on self. + +@property(assign, atomic, getter=isSubdataGenerating) BOOL subdataGenerating; +@property(assign, atomic) BOOL shouldInitiateOffsetQuery; +@property(assign, atomic) int64_t uploadGranularity; + +@end + +@implementation GTMSessionUploadFetcher { + GTMSessionFetcher *_chunkFetcher; + + // We'll call through to the delegate's completion handler. + GTMSessionFetcherCompletionHandler _delegateCompletionHandler; + dispatch_queue_t _delegateCallbackQueue; + + // The initial fetch's body length and bytes actually sent are + // needed for calculating progress during subsequent chunk uploads + int64_t _initialBodyLength; + int64_t _initialBodySent; + + // The upload server address for the chunks of this upload session. + NSURL *_uploadLocationURL; + + // _uploadData, _uploadDataProvider, or _uploadFileHandle may be set, but only one. + NSData *_uploadData; + NSFileHandle *_uploadFileHandle; + GTMSessionUploadFetcherDataProvider _uploadDataProvider; + NSURL *_uploadFileURL; + int64_t _uploadFileLength; + NSString *_uploadMIMEType; + int64_t _chunkSize; + int64_t _uploadGranularity; + BOOL _isPaused; + BOOL _isRestartedUpload; + BOOL _shouldInitiateOffsetQuery; + + // Tied to useBackgroundSession property, since this property is applicable to chunk fetchers. + BOOL _useBackgroundSessionOnChunkFetchers; + + // We keep the latest offset into the upload data just for progress reporting. + int64_t _currentOffset; + + NSDictionary *_recentChunkReponseHeaders; + NSInteger _recentChunkStatusCode; + + // For waiting, we need to know the fetcher in flight, if any, and if subdata generation + // is in progress. + GTMSessionFetcher *_fetcherInFlight; + BOOL _isSubdataGenerating; +} + ++ (void)load { + [self uploadFetchersForBackgroundSessions]; +} + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTMSessionFetcherService *)fetcherService { + GTMSessionUploadFetcher *fetcher = [self uploadFetcherWithRequest:request + fetcherService:fetcherService]; + [fetcher setLocationURL:nil + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize]; + return fetcher; +} + ++ (instancetype)uploadFetcherWithLocation:(NSURL * GTM_NULLABLE_TYPE)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTMSessionFetcherService *)fetcherService { + GTMSessionUploadFetcher *fetcher = [self uploadFetcherWithRequest:nil + fetcherService:fetcherService]; + [fetcher setLocationURL:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize]; + return fetcher; +} + ++ (instancetype)uploadFetcherForSessionIdentifierMetadata:(NSDictionary *)metadata { + GTMSESSION_ASSERT_DEBUG( + [metadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] boolValue], + @"Session identifier metadata is not for an upload fetcher: %@", metadata); + + NSNumber *uploadFileLengthNum = metadata[kGTMSessionIdentifierUploadFileLengthMetadataKey]; + GTMSESSION_ASSERT_DEBUG(uploadFileLengthNum != nil, + @"Session metadata missing an UploadFileSize"); + if (uploadFileLengthNum == nil) return nil; + + int64_t uploadFileLength = [uploadFileLengthNum longLongValue]; + GTMSESSION_ASSERT_DEBUG(uploadFileLength >= 0, @"Session metadata UploadFileSize is unknown"); + + NSString *uploadFileURLString = metadata[kGTMSessionIdentifierUploadFileURLMetadataKey]; + GTMSESSION_ASSERT_DEBUG(uploadFileURLString, @"Session metadata missing an UploadFileURL"); + if (uploadFileURLString == nil) return nil; + + NSURL *uploadFileURL = [NSURL URLWithString:uploadFileURLString]; + // There used to be a call here to NSURL checkResourceIsReachableAndReturnError: to check for the + // existence of the file (also tried NSFileManager fileExistsAtPath:). We've determined + // empirically that the check can fail at startup even when the upload file does in fact exist. + // For now, we'll go ahead and restore the background upload fetcher. If the file doesn't exist, + // it will fail later. + + NSString *uploadLocationURLString = metadata[kGTMSessionIdentifierUploadLocationURLMetadataKey]; + NSURL *uploadLocationURL = + uploadLocationURLString ? [NSURL URLWithString:uploadLocationURLString] : nil; + + NSString *uploadMIMEType = + metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey]; + int64_t uploadChunkSize = + [metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] longLongValue]; + if (uploadChunkSize <= 0) { + uploadChunkSize = kGTMSessionUploadFetcherStandardChunkSize; + } + int64_t currentOffset = + [metadata[kGTMSessionIdentifierUploadCurrentOffsetMetadataKey] longLongValue]; + GTMSESSION_ASSERT_DEBUG(currentOffset <= uploadFileLength, + @"CurrentOffset (%lld) exceeds UploadFileSize (%lld)", + currentOffset, uploadFileLength); + if (currentOffset > uploadFileLength) return nil; + + GTMSessionUploadFetcher *uploadFetcher = [self uploadFetcherWithLocation:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:uploadChunkSize + fetcherService:nil]; + // Set the upload file length before setting the upload file URL tries to determine the length. + [uploadFetcher setUploadFileLength:uploadFileLength]; + + uploadFetcher.uploadFileURL = uploadFileURL; + uploadFetcher.sessionUserInfo = metadata; + uploadFetcher.useBackgroundSession = YES; + uploadFetcher.currentOffset = currentOffset; + uploadFetcher.allowedInsecureSchemes = @[ @"http" ]; // Allowed on restored upload fetcher. + return uploadFetcher; +} + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + fetcherService:(GTMSessionFetcherService *)fetcherService { + // Internal utility method for instantiating fetchers + GTMSessionUploadFetcher *fetcher; + if ([fetcherService isKindOfClass:[GTMSessionFetcherService class]]) { + fetcher = [fetcherService fetcherWithRequest:request + fetcherClass:self]; + } else { + fetcher = [self fetcherWithRequest:request]; + } + fetcher.useBackgroundSession = YES; + return fetcher; +} + ++ (NSPointerArray *)uploadFetcherPointerArrayForBackgroundSessions { + static NSPointerArray *gUploadFetcherPointerArrayForBackgroundSessions = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gUploadFetcherPointerArrayForBackgroundSessions = [NSPointerArray weakObjectsPointerArray]; + }); + return gUploadFetcherPointerArrayForBackgroundSessions; +} + ++ (instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + NSArray *uploadFetchersForBackgroundSessions = [self uploadFetchersForBackgroundSessions]; + for (GTMSessionUploadFetcher *uploadFetcher in uploadFetchersForBackgroundSessions) { + if ([uploadFetcher.chunkFetcher.sessionIdentifier isEqual:sessionIdentifier]) { + return uploadFetcher; + } + } + return nil; +} + ++ (NSArray *)uploadFetchersForBackgroundSessions { + // Collect the background session upload fetchers that are still in memory. + NSPointerArray *uploadFetcherPointerArray = [self uploadFetcherPointerArrayForBackgroundSessions]; + [uploadFetcherPointerArray compact]; + NSMutableSet *restoredSessionIdentifiers = [[NSMutableSet alloc] init]; + NSMutableArray *uploadFetchers = [[NSMutableArray alloc] init]; + for (GTMSessionUploadFetcher *uploadFetcher in uploadFetcherPointerArray) { + NSString *sessionIdentifier = uploadFetcher.chunkFetcher.sessionIdentifier; + if (sessionIdentifier) { + [restoredSessionIdentifiers addObject:sessionIdentifier]; + [uploadFetchers addObject:uploadFetcher]; + } + } + + // The system may have other ongoing background upload sessions. Restore upload fetchers for those + // too. + NSArray *fetchers = [GTMSessionFetcher fetchersForBackgroundSessions]; + for (GTMSessionFetcher *fetcher in fetchers) { + NSString *sessionIdentifier = fetcher.sessionIdentifier; + if (!sessionIdentifier || [restoredSessionIdentifiers containsObject:sessionIdentifier]) { + continue; + } + NSDictionary *sessionIdentifierMetadata = [fetcher sessionIdentifierMetadata]; + if (sessionIdentifierMetadata == nil) { + continue; + } + if (![sessionIdentifierMetadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] boolValue]) { + continue; + } + GTMSessionUploadFetcher *uploadFetcher = + [self uploadFetcherForSessionIdentifierMetadata:sessionIdentifierMetadata]; + if (uploadFetcher == nil) { + // Something went wrong with this upload fetcher, so kill the restored chunk fetcher. + [fetcher stopFetching]; + continue; + } + [uploadFetchers addObject:uploadFetcher]; + uploadFetcher->_chunkFetcher = fetcher; + uploadFetcher->_fetcherInFlight = fetcher; + [uploadFetcher attachSendProgressBlockToChunkFetcher:fetcher]; + fetcher.completionHandler = + [fetcher completionHandlerWithTarget:uploadFetcher + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; + + GTMSESSION_LOG_DEBUG(@"%@ restoring upload fetcher %@ for chunk fetcher %@", + [self class], uploadFetcher, fetcher); + } + return uploadFetchers; +} + +- (void)setUploadData:(NSData *)data { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadData != data) { + _uploadData = data; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSData *)uploadData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadData; + } +} + +- (void)setUploadFileHandle:(NSFileHandle *)fh { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileHandle != fh) { + _uploadFileHandle = fh; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSFileHandle *)uploadFileHandle { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadFileHandle; + } +} + +- (void)setUploadFileURL:(NSURL *)uploadURL { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileURL != uploadURL) { + _uploadFileURL = uploadURL; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSURL *)uploadFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadFileURL; + } +} + +- (void)setUploadFileLength:(int64_t)fullLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadFileLength = fullLength; + } +} + +- (void)setUploadDataLength:(int64_t)fullLength + provider:(GTMSessionUploadFetcherDataProvider)block { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadDataProvider = [block copy]; + _uploadFileLength = fullLength; + } + [self setupRequestHeaders]; +} + +- (GTMSessionUploadFetcherDataProvider)uploadDataProvider { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadDataProvider; + } +} + + +- (void)setUploadMIMEType:(NSString *)uploadMIMEType { + GTMSESSION_ASSERT_DEBUG(0, @"TODO: disallow setUploadMIMEType by making declaration readonly"); + // (and uploadMIMEType, chunksize, currentOffset) + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadMIMEType = uploadMIMEType; + } +} + +- (NSString *)uploadMIMEType { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadMIMEType; + } +} + +- (void)setChunkSize:(int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _chunkSize = chunkSize; + } +} + +- (int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _chunkSize; + } +} + +- (void)setupRequestHeaders { + GTMSessionCheckNotSynchronized(self); + +#if DEBUG + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + int hasData = (_uploadData != nil) ? 1 : 0; + int hasFileHandle = (_uploadFileHandle != nil) ? 1 : 0; + int hasFileURL = (_uploadFileURL != nil) ? 1 : 0; + int hasUploadDataProvider = (_uploadDataProvider != nil) ? 1 : 0; + int numberOfSources = hasData + hasFileHandle + hasFileURL + hasUploadDataProvider; + #pragma unused(numberOfSources) + GTMSESSION_ASSERT_DEBUG(numberOfSources == 1, + @"Need just one upload source (%d)", numberOfSources); + } // @synchronized(self) +#endif + + // Add our custom headers to the initial request indicating the data + // type and total size to be delivered later in the chunk requests. + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + + GTMSESSION_ASSERT_DEBUG((mutableRequest == nil) != (_uploadLocationURL == nil), + @"Request and location are mutually exclusive"); + if (!mutableRequest) return; + + NSNumber *lengthNum = @([self fullUploadLength]); + [mutableRequest setValue:@"resumable" + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadProtocol]; + [mutableRequest setValue:@"start" + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + [mutableRequest setValue:_uploadMIMEType + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentType]; + [mutableRequest setValue:lengthNum.stringValue + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentLength]; + + NSString *method = mutableRequest.HTTPMethod; + if (method == nil || [method caseInsensitiveCompare:@"GET"] == NSOrderedSame) { + [mutableRequest setHTTPMethod:@"POST"]; + } + + // Ensure the user agent header identifies this to the upload server as a + // GTMSessionUploadFetcher client. The /1 can be incremented in the unlikely circumstance + // we need to make a bug fix in the client that the server can recognize. + NSString *const kUserAgentStub = @"(GTMSUF/1)"; + NSString *userAgent = [mutableRequest valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent == nil + || [userAgent rangeOfString:kUserAgentStub].location == NSNotFound) { + if (userAgent.length == 0) { + userAgent = GTMFetcherStandardUserAgentString(nil); + } + userAgent = [userAgent stringByAppendingFormat:@" %@", kUserAgentStub]; + [mutableRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + [self setRequest:mutableRequest]; +} + +- (void)setLocationURL:(NSURL * GTM_NULLABLE_TYPE)location + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(chunkSize > 0, @"chunk size is zero"); + + // When resuming an upload, set the known upload target URL. + _uploadLocationURL = location; + + _uploadMIMEType = uploadMIMEType; + _chunkSize = chunkSize; + + // Indicate that we've not yet determined the file handle's length + _uploadFileLength = -1; + + // Indicate that we've not yet determined the upload fetcher status + _recentChunkStatusCode = -1; + + // If this is restarting an upload begun by another fetcher, + // the location is specified but the request is nil + _isRestartedUpload = (location != nil); + } // @synchronized(self) +} + +- (int64_t)fullUploadLength { + int64_t result; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadData) { + result = (int64_t)_uploadData.length; + } else { + if (_uploadFileLength == -1) { + if (_uploadFileHandle) { + // First time through, seek to end to determine file length + _uploadFileLength = (int64_t)[_uploadFileHandle seekToEndOfFile]; + } else if (_uploadDataProvider) { + // _uploadFileLength is set when the _uploadDataProvider is set. + GTMSESSION_ASSERT_DEBUG(_uploadFileLength >= 0, @"No uploadDataProvider length set"); + } else { + NSNumber *filesizeNum; + NSError *valueError; + if ([_uploadFileURL getResourceValue:&filesizeNum + forKey:NSURLFileSizeKey + error:&valueError]) { + _uploadFileLength = filesizeNum.longLongValue; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Cannot get file size: %@\n %@", + valueError, _uploadFileURL.path); + _uploadFileLength = 0; + } + } + } + result = _uploadFileLength; + } + } // @synchronized(self) + return result; +} + +// Make a subdata of the upload data. +- (void)generateChunkSubdataWithOffset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + GTMSessionUploadFetcherDataProvider uploadDataProvider = self.uploadDataProvider; + if (uploadDataProvider) { + uploadDataProvider(offset, length, response); + return; + } + + NSData *uploadData = self.uploadData; + if (uploadData) { + // NSData provided. + NSData *resultData; + if (offset == 0 && length == (int64_t)uploadData.length) { + resultData = uploadData; + } else { + int64_t dataLength = (int64_t)uploadData.length; + // Ensure our range is valid. b/18007814 + if (offset + length > dataLength) { + NSString *errorMessage = [NSString stringWithFormat: + @"Range invalid for upload data. offset: %lld\tlength: %lld\tdataLength: %lld", + offset, length, dataLength]; + GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage); + response(nil, [self uploadChunkUnavailableErrorWithDescription:errorMessage]); + return; + } + NSRange range = NSMakeRange((NSUInteger)offset, (NSUInteger)length); + resultData = [uploadData subdataWithRange:range]; + } + response(resultData, nil); + return; + } + NSURL *uploadFileURL = self.uploadFileURL; + if (uploadFileURL) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self generateChunkSubdataFromFileURL:uploadFileURL + offset:offset + length:length + response:response]; + }); + return; + } + GTMSESSION_ASSERT_DEBUG(_uploadFileHandle, @"Unexpectedly missing upload data package"); + NSFileHandle *uploadFileHandle = self.uploadFileHandle; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self generateChunkSubdataFromFileHandle:uploadFileHandle + offset:offset + length:length + response:response]; + }); +} + +- (void)generateChunkSubdataFromFileHandle:(NSFileHandle *)fileHandle + offset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + NSData *resultData; + NSError *error; + @try { + [fileHandle seekToFileOffset:(unsigned long long)offset]; + resultData = [fileHandle readDataOfLength:(NSUInteger)length]; + } + @catch (NSException *exception) { + GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileHandle failed to read, %@", exception); + error = [self uploadChunkUnavailableErrorWithDescription:exception.description]; + } + // The response always re-dispatches to the main thread, so we skip doing that here. + response(resultData, error); +} + +- (void)generateChunkSubdataFromFileURL:(NSURL *)fileURL + offset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + GTMSessionCheckNotSynchronized(self); + + NSData *resultData; + NSError *error; + int64_t fullUploadLength = [self fullUploadLength]; + NSData *mappedData = + [NSData dataWithContentsOfURL:fileURL + options:NSDataReadingMappedAlways + NSDataReadingUncached + error:&error]; + if (!mappedData) { + // We could not create an NSData by memory-mapping the file. +#if TARGET_IPHONE_SIMULATOR + // NSTemporaryDirectory() can differ in the simulator between app restarts, + // yet the contents for the new path remains unchanged, so try the latest temp path. + if ([error.domain isEqual:NSCocoaErrorDomain] && (error.code == NSFileReadNoSuchFileError)) { + NSString *filename = [fileURL lastPathComponent]; + NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + NSURL *newFileURL = [NSURL fileURLWithPath:filePath]; + if (![newFileURL isEqual:fileURL]) { + [self generateChunkSubdataFromFileURL:newFileURL + offset:offset + length:length + response:response]; + return; + } + } +#endif + + // If the file is just too large to create an NSData for, or if for some other reason we can't + // map it, create an NSFileHandle instead to read a subset into an NSData. +#if DEBUG + NSNumber *fileSizeNum; + BOOL hasFileSize = [fileURL getResourceValue:&fileSizeNum forKey:NSURLFileSizeKey error:NULL]; + GTMSESSION_LOG_DEBUG(@"Note: uploadFileURL is falling back to creating upload chunks by reading" + @" an NSFileHandle since uploadFileURL failed to map the upload file," + @" file size %@, %@", + hasFileSize ? fileSizeNum : @"unknown", error); +#endif + + NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:fileURL + error:&error]; + if (fileHandle != nil) { + [self generateChunkSubdataFromFileHandle:fileHandle + offset:offset + length:length + response:response]; + return; + } + GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileURL failed to read, %@", error); + // Fall through with the error. + } else { + // Successfully created an NSData by memory-mapping the file. + if (offset > 0 || length < fullUploadLength) { + NSRange range = NSMakeRange((NSUInteger)offset, (NSUInteger)length); + resultData = [mappedData subdataWithRange:range]; + } else { + resultData = mappedData; + } + } + // The response always re-dispatches to the main thread, so we skip re-dispatching here. + response(resultData, error); +} + +- (NSError *)uploadChunkUnavailableErrorWithDescription:(NSString *)description { + // The description in the userInfo is intended as a clue to programmers, not + // for client code to examine or rely on. + NSDictionary *userInfo = @{ @"description" : description }; + return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorUploadChunkUnavailable + userInfo:userInfo]; +} + +- (NSError *)prematureFailureErrorWithUserInfo:(NSDictionary *)userInfo { + // An error for if we get an unexpected status from the upload server or + // otherwise cannot continue. This is an issue beyond the upload protocol; + // there's no way the client can do anything useful except give up. + NSError *error = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:501 // Not implemented + userInfo:userInfo]; + return error; +} + ++ (GTMSessionUploadFetcherStatus)uploadStatusFromResponseHeaders:(NSDictionary *)responseHeaders { + NSString *statusString = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus]; + if ([statusString isEqual:@"active"]) { + return kStatusActive; + } + if ([statusString isEqual:@"final"]) { + return kStatusFinal; + } + if ([statusString isEqual:@"cancelled"]) { + return kStatusCancelled; + } + return kStatusUnknown; +} + +#pragma mark Method overrides affecting the initial fetch only + +- (void)setCompletionHandler:(GTMSessionFetcherCompletionHandler)handler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCompletionHandler = handler; + } +} + +- (void)setDelegateCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCallbackQueue = queue; + } +} + +- (dispatch_queue_t GTM_NULLABLE_TYPE)delegateCallbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateCallbackQueue; + } +} + +- (BOOL)isRestartedUpload { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isRestartedUpload; + } +} + +- (GTMSessionFetcher * GTM_NULLABLE_TYPE)chunkFetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _chunkFetcher; + } +} + +- (void)setChunkFetcher:(GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _chunkFetcher = fetcher; + } +} + +- (void)setFetcherInFlight:(GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _fetcherInFlight = fetcher; + } +} + +- (GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcherInFlight { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _fetcherInFlight; + } +} + +- (void)beginFetchWithCompletionHandler:(GTMSessionFetcherCompletionHandler)handler { + GTMSessionCheckNotSynchronized(self); + + [self setInitialBodyLength:[self bodyLength]]; + + // We'll hold onto the superclass's callback queue so we can invoke the handler + // even after the superclass has released the queue and its callback handler, as + // happens during auth failure. + [self setDelegateCallbackQueue:self.callbackQueue]; + self.completionHandler = handler; + + if ([self isRestartedUpload]) { + // When restarting an upload, we know the destination location for chunk fetches, + // but we need to query to find the initial offset. + if (![self isPaused]) { + [self sendQueryForUploadOffsetWithFetcherProperties:self.properties]; + } + return; + } + // We don't want to call into the client's completion block immediately + // after the finish of the initial connection (the delegate is called only + // when uploading finishes), so we substitute our own completion block to be + // called when the initial connection finishes + GTMSESSION_ASSERT_DEBUG(self.fetcherInFlight == nil, @"unexpected fetcher in flight: %@", + self.fetcherInFlight); + + self.fetcherInFlight = self; + [super beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + self.fetcherInFlight = nil; + // callback + + BOOL hasTestBlock = (self.testBlock != nil); + if (![self isRestartedUpload] && !hasTestBlock) { + if (error == nil) { + [self beginChunkFetches]; + } else { + if ([self retryTimer] == nil) { + [self invokeFinalCallbackWithData:nil + error:error + shouldInvalidateLocation:YES]; + } + } + } else { + // If there was no initial request, then this fetch is resuming some + // other uploadFetcher's initial request, and the superclass's connection + // is never used, so at this point we call the user's actual completion + // block. + if (!hasTestBlock) { + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + } else { + // There was a test block, so we won't do chunk fetches, but we simulate obtaining + // the data to be uploaded from the upload data provider block or the file handle, + // and then call back. + [self generateChunkSubdataWithOffset:0 + length:[self fullUploadLength] + response:^(NSData *generateData, NSError *generateError) { + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + }]; + } + } + }]; +} + +- (void)beginChunkFetches { + GTMSessionCheckNotSynchronized(self); + +#if DEBUG + // The initial response of the resumable upload protocol should have an + // empty body + // + // This assert typically happens because the upload create/edit link URL was + // not supplied with the request, and the server is thus expecting a non- + // resumable request/response. + if (self.downloadedData.length > 0) { + NSData *downloadedData = self.downloadedData; + NSString *str = [[NSString alloc] initWithData:downloadedData + encoding:NSUTF8StringEncoding]; + #pragma unused(str) + GTMSESSION_ASSERT_DEBUG(NO, @"unexpected response data (uploading to the wrong URL?)\n%@", str); + } +#endif + + // We need to get the upload URL from the location header to continue. + NSDictionary *responseHeaders = [self responseHeaders]; + + [self retrieveUploadChunkGranularityFromResponseHeaders:responseHeaders]; + + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown, + @"beginChunkFetches has unexpected upload status for headers %@", responseHeaders); + + BOOL isPrematureStop = (uploadStatus == kStatusFinal) || (uploadStatus == kStatusCancelled); + + NSString *uploadLocationURLStr = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadURL]; + BOOL hasUploadLocation = (uploadLocationURLStr.length > 0); + + if (isPrematureStop || !hasUploadLocation) { + GTMSESSION_ASSERT_DEBUG(NO, @"Premature failure: upload-status:\"%@\" location:%@", + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], uploadLocationURLStr); + // We cannot continue since we do not know the location to use + // as our upload destination. + NSDictionary *userInfo = nil; + NSData *downloadedData = self.downloadedData; + if (downloadedData.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : downloadedData }; + } + NSError *failureError = [self prematureFailureErrorWithUserInfo:userInfo]; + [self invokeFinalCallbackWithData:nil + error:failureError + shouldInvalidateLocation:YES]; + return; + } + + self.uploadLocationURL = [NSURL URLWithString:uploadLocationURLStr]; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherUploadLocationObtainedNotification + object:self]; + + // we've now sent all of the initial post body data, so we need to include + // its size in future progress indicator callbacks + [self setInitialBodySent:[self initialBodyLength]]; + + // just in case the user paused us during the initial fetch... + if (![self isPaused]) { + [self uploadNextChunkWithOffset:0]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + // Overrides the superclass. + [self invokeDelegateWithDidSendBytes:bytesSent + totalBytesSent:totalBytesSent + totalBytesExpectedToSend:totalBytesExpectedToSend + [self fullUploadLength]]; +} + +- (BOOL)shouldReleaseCallbacksUponCompletion { + // Overrides the superclass. + + // We don't want the superclass to release the delegate and callback + // blocks once the initial fetch has finished + // + // This is invoked for only successful completion of the connection; + // an error always will invoke and release the callbacks + return NO; +} + +- (void)invokeFinalCallbackWithData:(NSData *)data + error:(NSError *)error + shouldInvalidateLocation:(BOOL)shouldInvalidateLocation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (shouldInvalidateLocation) { + _uploadLocationURL = nil; + } + + dispatch_queue_t queue = _delegateCallbackQueue; + GTMSessionFetcherCompletionHandler handler = _delegateCompletionHandler; + if (queue && handler) { + [self invokeOnCallbackQueue:queue + afterUserStopped:NO + block:^{ + handler(data, error); + }]; + } + } // @synchronized(self) + + [self releaseUploadAndBaseCallbacks]; +} + +- (void)releaseUploadAndBaseCallbacks { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCallbackQueue = nil; + _delegateCompletionHandler = nil; + _uploadDataProvider = nil; + } + + // Release the base class's callbacks, too, if needed. + [self releaseCallbacks]; +} + +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks { + GTMSessionCheckNotSynchronized(self); + + // Clear _fetcherInFlight when stopped. Moved from stopFetching, since that's a public method, + // where this method does the work. Fixes issue clearing value when retryBlock included. + GTMSessionFetcher *fetcherInFlight = self.fetcherInFlight; + if (fetcherInFlight == self) { + self.fetcherInFlight = nil; + } + + [super stopFetchReleasingCallbacks:shouldReleaseCallbacks]; + + if (shouldReleaseCallbacks) { + [self releaseUploadAndBaseCallbacks]; + } +} + +#pragma mark Chunk fetching methods + +- (void)uploadNextChunkWithOffset:(int64_t)offset { + // use the properties in each chunk fetcher + NSDictionary *props = [self properties]; + + [self uploadNextChunkWithOffset:offset + fetcherProperties:props]; +} + +- (void)sendQueryForUploadOffsetWithFetcherProperties:(NSDictionary *)props { + GTMSessionFetcher *queryFetcher = [self uploadFetcherWithProperties:props + isQueryFetch:YES]; + queryFetcher.bodyData = [NSData data]; + + NSString *originalComment = self.comment; + [queryFetcher setCommentWithFormat:@"%@ (query offset)", + originalComment ? originalComment : @"upload"]; + + [queryFetcher setRequestValue:@"query" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + + self.fetcherInFlight = queryFetcher; + [queryFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(queryFetcher:finishedWithData:error:)]; +} + +- (void)queryFetcher:(GTMSessionFetcher *)queryFetcher + finishedWithData:(NSData *)data + error:(NSError *)error { + self.fetcherInFlight = nil; + + NSDictionary *responseHeaders = [queryFetcher responseHeaders]; + NSString *sizeReceivedHeader; + + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown || error != nil, + @"query fetcher completion has unexpected upload status for headers %@", responseHeaders); + + if (error == nil) { + sizeReceivedHeader = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadSizeReceived]; + + if (uploadStatus == kStatusCancelled || + (uploadStatus == kStatusActive && sizeReceivedHeader == nil)) { + NSDictionary *userInfo = nil; + if (data.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : data }; + } + error = [self prematureFailureErrorWithUserInfo:userInfo]; + } + } + + if (error == nil) { + int64_t offset = [sizeReceivedHeader longLongValue]; + int64_t fullUploadLength = [self fullUploadLength]; + if (offset >= fullUploadLength || uploadStatus == kStatusFinal) { + // Handle we're done + [self chunkFetcher:queryFetcher finishedWithData:data error:nil]; + } else { + [self retrieveUploadChunkGranularityFromResponseHeaders:responseHeaders]; + [self uploadNextChunkWithOffset:offset]; + } + } else { + // Handle query error + [self chunkFetcher:queryFetcher finishedWithData:data error:error]; + } +} + +- (void)sendCancelUploadWithFetcherProperties:(NSDictionary *)props { + GTMSessionFetcher *cancelFetcher = [self uploadFetcherWithProperties:props + isQueryFetch:YES]; + cancelFetcher.bodyData = [NSData data]; + + NSString *originalComment = self.comment; + [cancelFetcher setCommentWithFormat:@"%@ (cancel)", + originalComment ? originalComment : @"upload"]; + + [cancelFetcher setRequestValue:@"cancel" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + + self.fetcherInFlight = cancelFetcher; + [cancelFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + self.fetcherInFlight = nil; + if (error) { + GTMSESSION_LOG_DEBUG(@"cancelFetcher %@", error); + } + }]; +} + +- (void)uploadNextChunkWithOffset:(int64_t)offset + fetcherProperties:(NSDictionary *)props { + GTMSessionCheckNotSynchronized(self); + + // Example chunk headers: + // X-Goog-Upload-Command: upload, finalize + // X-Goog-Upload-Offset: 0 + // Content-Length: 2000000 + // Content-Type: image/jpeg + // + // {bytes 0-1999999} + + // The chunk upload URL requires no authentication header. + GTMSessionFetcher *chunkFetcher = [self uploadFetcherWithProperties:props + isQueryFetch:NO]; + [self attachSendProgressBlockToChunkFetcher:chunkFetcher]; + + BOOL isUploadingFileURL = (self.uploadFileURL != nil); + + // Upload another chunk, meeting server-required granularity. + int64_t chunkSize = self.chunkSize; + + int64_t fullUploadLength = [self fullUploadLength]; + + BOOL isUploadingFullFile = (offset == 0 && chunkSize >= fullUploadLength); + if (!isUploadingFileURL || !isUploadingFullFile) { + // We're not uploading the entire file and given the file URL. Since we'll be + // allocating a subdata block for a chunk, we need to bound it to something that + // won't blow the process's memory. + if (chunkSize > kGTMSessionUploadFetcherMaximumDemandBufferSize) { + chunkSize = kGTMSessionUploadFetcherMaximumDemandBufferSize; + } + } + + int64_t granularity = self.uploadGranularity; + if (granularity > 0) { + if (chunkSize < granularity) { + chunkSize = granularity; + } else { + chunkSize = chunkSize - (chunkSize % granularity); + } + } + + GTMSESSION_ASSERT_DEBUG(offset < fullUploadLength || fullUploadLength == 0, + @"offset %lld exceeds data length %lld", offset, fullUploadLength); + + if (granularity > 0) { + offset = offset - (offset % granularity); + } + + // If the chunk size is bigger than the remaining data, or else + // it's close enough in size to the remaining data that we'd rather + // avoid having a whole extra http fetch for the leftover bit, then make + // this chunk size exactly match the remaining data size + NSString *command; + int64_t thisChunkSize = chunkSize; + + BOOL isChunkTooBig = (thisChunkSize >= (fullUploadLength - offset)); + BOOL isChunkAlmostBigEnough = (fullUploadLength - offset - 2500 < thisChunkSize); + BOOL isFinalChunk = isChunkTooBig || isChunkAlmostBigEnough; + if (isFinalChunk) { + thisChunkSize = fullUploadLength - offset; + if (thisChunkSize > 0) { + command = @"upload, finalize"; + } else { + command = @"finalize"; + } + } else { + command = @"upload"; + } + NSString *lengthStr = @(thisChunkSize).stringValue; + NSString *offsetStr = @(offset).stringValue; + + [chunkFetcher setRequestValue:command forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + [chunkFetcher setRequestValue:lengthStr forHTTPHeaderField:@"Content-Length"]; + [chunkFetcher setRequestValue:offsetStr forHTTPHeaderField:kGTMSessionHeaderXGoogUploadOffset]; + + // Append the range of bytes in this chunk to the fetcher comment. + NSString *baseComment = self.comment; + [chunkFetcher setCommentWithFormat:@"%@ (%lld-%lld)", + baseComment ? baseComment : @"upload", offset, MAX(0, offset + thisChunkSize - 1)]; + + // The chunk size may have changed, so determine again if we're uploading the full file. + isUploadingFullFile = (offset == 0 && thisChunkSize >= fullUploadLength); + if (isUploadingFullFile && isUploadingFileURL) { + // The data is the full upload file URL. + chunkFetcher.bodyFileURL = self.uploadFileURL; + [self beginChunkFetcher:chunkFetcher + offset:offset]; + } else { + // Make an NSData for the subset for this upload chunk. + self.subdataGenerating = YES; + [self generateChunkSubdataWithOffset:offset + length:thisChunkSize + response:^(NSData *chunkData, NSError *chunkError) { + // The subdata methods may leave us on a background thread. + dispatch_async(dispatch_get_main_queue(), ^{ + self.subdataGenerating = NO; + if (chunkData == nil) { + NSError *responseError = chunkError; + if (!responseError) { + responseError = [self uploadChunkUnavailableErrorWithDescription:@"chunkData is nil"]; + } + [self invokeFinalCallbackWithData:nil + error:responseError + shouldInvalidateLocation:YES]; + return; + } + + BOOL didWriteFile = NO; + if (isUploadingFileURL) { + // Make a temporary file with the data subset. + NSString *tempName = + [NSString stringWithFormat:@"GTMUpload_temp_%@", [[NSUUID UUID] UUIDString]]; + NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:tempName]; + NSError *writeError; + didWriteFile = [chunkData writeToFile:tempPath + options:NSDataWritingAtomic + error:&writeError]; + if (didWriteFile) { + chunkFetcher.bodyFileURL = [NSURL fileURLWithPath:tempPath]; + } else { + GTMSESSION_LOG_DEBUG(@"writeToFile failed: %@\n%@", writeError, tempPath); + } + } + if (!didWriteFile) { + chunkFetcher.bodyData = [chunkData copy]; + } + [self beginChunkFetcher:chunkFetcher + offset:offset]; + }); + }]; + } +} + +- (void)beginChunkFetcher:(GTMSessionFetcher *)chunkFetcher + offset:(int64_t)offset { + + // Track the current offset for progress reporting + self.currentOffset = offset; + + // Hang on to the fetcher in case we need to cancel it. We set these before beginning the + // chunk fetch so the observers notified of chunk fetches can inspect the upload fetcher to + // match to the chunk. + self.chunkFetcher = chunkFetcher; + self.fetcherInFlight = chunkFetcher; + + // Update the last chunk request, including any request headers. + self.lastChunkRequest = chunkFetcher.request; + + [chunkFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; +} + +- (void)attachSendProgressBlockToChunkFetcher:(GTMSessionFetcher *)chunkFetcher { + chunkFetcher.sendProgressBlock = ^(int64_t bytesSent, int64_t totalBytesSent, + int64_t totalBytesExpectedToSend) { + // The total bytes expected include the initial body and the full chunked + // data, independent of how big this fetcher's chunk is. + int64_t initialBodySent = [self bodyLength]; // TODO(grobbins) use [self initialBodySent] + int64_t totalSent = initialBodySent + self.currentOffset + totalBytesSent; + int64_t totalExpected = initialBodySent + [self fullUploadLength]; + + [self invokeDelegateWithDidSendBytes:bytesSent + totalBytesSent:totalSent + totalBytesExpectedToSend:totalExpected]; + }; +} + +- (NSDictionary *)uploadSessionIdentifierMetadata { + NSMutableDictionary *metadata = [NSMutableDictionary dictionary]; + metadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] = @YES; + GTMSESSION_ASSERT_DEBUG(self.uploadFileURL, + @"Invalid upload fetcher to create session identifier for metadata"); + metadata[kGTMSessionIdentifierUploadFileURLMetadataKey] = [self.uploadFileURL absoluteString]; + metadata[kGTMSessionIdentifierUploadFileLengthMetadataKey] = @([self fullUploadLength]); + + if (self.uploadLocationURL) { + metadata[kGTMSessionIdentifierUploadLocationURLMetadataKey] = + [self.uploadLocationURL absoluteString]; + } + if (self.uploadMIMEType) { + metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey] = self.uploadMIMEType; + } + metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] = @(self.chunkSize); + metadata[kGTMSessionIdentifierUploadCurrentOffsetMetadataKey] = @(self.currentOffset); + return metadata; +} + +- (GTMSessionFetcher *)uploadFetcherWithProperties:(NSDictionary *)properties + isQueryFetch:(BOOL)isQueryFetch { + GTMSessionCheckNotSynchronized(self); + + // Common code to make a request for a query command or for a chunk upload. + NSURL *uploadLocationURL = self.uploadLocationURL; + NSMutableURLRequest *chunkRequest = [NSMutableURLRequest requestWithURL:uploadLocationURL]; + [chunkRequest setHTTPMethod:@"PUT"]; + + // copy the user-agent from the original connection + NSURLRequest *origRequest = self.request; + NSString *userAgent = [origRequest valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent.length > 0) { + [chunkRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + // To avoid timeouts when debugging, copy the timeout of the initial fetcher. + NSTimeInterval origTimeout = [origRequest timeoutInterval]; + [chunkRequest setTimeoutInterval:origTimeout]; + + // + // Make a new chunk fetcher. + // + GTMSessionFetcher *chunkFetcher = [GTMSessionFetcher fetcherWithRequest:chunkRequest]; + chunkFetcher.callbackQueue = self.callbackQueue; + chunkFetcher.sessionUserInfo = self.sessionUserInfo; + chunkFetcher.configurationBlock = self.configurationBlock; + chunkFetcher.allowedInsecureSchemes = self.allowedInsecureSchemes; + chunkFetcher.allowLocalhostRequest = self.allowLocalhostRequest; + chunkFetcher.allowInvalidServerCertificates = self.allowInvalidServerCertificates; + chunkFetcher.useUploadTask = !isQueryFetch; + + if (self.uploadFileURL && !isQueryFetch && self.useBackgroundSession) { + [chunkFetcher createSessionIdentifierWithMetadata:[self uploadSessionIdentifierMetadata]]; + } + + // Give the chunk fetcher the same properties as the previous chunk fetcher + chunkFetcher.properties = [properties mutableCopy]; + [chunkFetcher setProperty:[NSValue valueWithNonretainedObject:self] + forKey:kGTMSessionUploadFetcherChunkParentKey]; + + // copy other fetcher settings to the new fetcher + chunkFetcher.retryEnabled = self.retryEnabled; + chunkFetcher.maxRetryInterval = self.maxRetryInterval; + + if ([self isRetryEnabled]) { + // We interpose our own retry method both so we can change the request to ask the server to + // tell us where to resume the chunk. + chunkFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *chunkError, + GTMSessionFetcherRetryResponse response){ + void (^finish)(BOOL) = ^(BOOL shouldRetry){ + // We'll retry by sending an offset query. + if (shouldRetry) { + self.shouldInitiateOffsetQuery = !isQueryFetch; + + // We don't know what our actual offset is anymore, but the server will tell us. + self.currentOffset = 0; + } + // We don't actually want to retry this specific fetcher. + response(NO); + }; + + GTMSessionFetcherRetryBlock retryBlock = self.retryBlock; + if (retryBlock) { + // Ask the client, then call the finish block above. + retryBlock(suggestedWillRetry, chunkError, finish); + } else { + finish(suggestedWillRetry); + } + }; + } + + return chunkFetcher; +} + +- (void)chunkFetcher:(GTMSessionFetcher *)chunkFetcher + finishedWithData:(NSData *)data + error:(NSError *)error { + BOOL hasDestroyedOldChunkFetcher = NO; + self.fetcherInFlight = nil; + + NSDictionary *responseHeaders = [chunkFetcher responseHeaders]; + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown + || error != nil + || self.wasCreatedFromBackgroundSession, + @"chunk fetcher completion has kStatusUnknown upload status for headers %@ fetcher %@", + responseHeaders, self); + BOOL isUploadStatusStopped = (uploadStatus == kStatusFinal || uploadStatus == kStatusCancelled); + + // Check if the fetcher was actually querying. If it failed, do not retry, + // as it would enter an infinite retry loop. + NSString *uploadCommand = + chunkFetcher.request.allHTTPHeaderFields[kGTMSessionHeaderXGoogUploadCommand]; + BOOL isQueryFetch = [uploadCommand isEqual:@"query"]; + + int64_t previousContentLength = + [[chunkFetcher.request valueForHTTPHeaderField:@"Content-Length"] longLongValue]; + // The Content-Length header may not be present if the chunk fetcher was recreated from + // a background session. + BOOL hasKnownChunkSize = (previousContentLength > 0); + BOOL needsQuery = (!hasKnownChunkSize && !isUploadStatusStopped); + + if (error || (needsQuery && !isQueryFetch)) { + NSInteger status = error.code; + + // Status 4xx indicates a bad offset in the Google upload protocol. However, do not retry status + // 404 per spec, nor if the upload size appears to have been zero (since the server will just + // keep asking us to retry.) + if (self.shouldInitiateOffsetQuery || + (needsQuery && !isQueryFetch) || + ([error.domain isEqual:kGTMSessionFetcherStatusDomain] && + status >= 400 && status <= 499 && + status != 404 && + uploadStatus == kStatusActive && + previousContentLength > 0)) { + self.shouldInitiateOffsetQuery = NO; + [self destroyChunkFetcher]; + hasDestroyedOldChunkFetcher = YES; + [self sendQueryForUploadOffsetWithFetcherProperties:chunkFetcher.properties]; + } else { + // Some unexpected status has occurred; handle it as we would a regular + // object fetcher failure. + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:NO]; + } + } else { + // The chunk has uploaded successfully. + int64_t newOffset = self.currentOffset + previousContentLength; +#if DEBUG + // Verify that if we think all of the uploading data has been sent, the server responded with + // the "final" upload status. + BOOL hasUploadAllData = (newOffset == [self fullUploadLength]); + BOOL isFinalStatus = (uploadStatus == kStatusFinal); + #pragma unused(hasUploadAllData,isFinalStatus) + GTMSESSION_ASSERT_DEBUG(hasUploadAllData == isFinalStatus || !hasKnownChunkSize, + @"uploadStatus:%@ newOffset:%zd (%lld + %zd) fullUploadLength:%lld" + @" chunkFetcher:%@ requestHeaders:%@ responseHeaders:%@", + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], + newOffset, self.currentOffset, previousContentLength, + [self fullUploadLength], + chunkFetcher, chunkFetcher.request.allHTTPHeaderFields, + responseHeaders); +#endif + if (isUploadStatusStopped) { + // This was the last chunk. + if (error == nil && uploadStatus == kStatusCancelled) { + // Report cancelled status as an error. + NSDictionary *userInfo = nil; + if (data.length > 0) { + userInfo = @{ kGTMSessionFetcherStatusDataKey : data }; + } + data = nil; + error = [self prematureFailureErrorWithUserInfo:userInfo]; + } else { + // The upload is in final status. + // + // Take the chunk fetcher's data as the superclass data. + self.downloadedData = data; + self.statusCode = chunkFetcher.statusCode; + } + + // we're done + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + } else { + // Start the next chunk. + self.currentOffset = newOffset; + + // We want to destroy this chunk fetcher before creating the next one, but + // we want to pass on its properties + NSDictionary *props = [chunkFetcher properties]; + + // We no longer need to be able to cancel this chunkFetcher. Destroy it + // before we create a new chunk fetcher. + [self destroyChunkFetcher]; + hasDestroyedOldChunkFetcher = YES; + + [self uploadNextChunkWithOffset:newOffset + fetcherProperties:props]; + } + } + if (!hasDestroyedOldChunkFetcher) { + [self destroyChunkFetcher]; + } +} + +- (void)destroyChunkFetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_fetcherInFlight == _chunkFetcher) { + _fetcherInFlight = nil; + } + + [_chunkFetcher stopFetching]; + + NSURL *chunkFileURL = _chunkFetcher.bodyFileURL; + BOOL wasTemporaryUploadFile = ![chunkFileURL isEqual:_uploadFileURL]; + if (wasTemporaryUploadFile) { + NSError *error; + [[NSFileManager defaultManager] removeItemAtURL:chunkFileURL + error:&error]; + if (error) { + GTMSESSION_LOG_DEBUG(@"removingItemAtURL failed: %@\n%@", error, chunkFileURL); + } + } + + _recentChunkReponseHeaders = _chunkFetcher.responseHeaders; + + // To avoid retain cycles, remove all properties except the parent identifier. + _chunkFetcher.properties = + @{ kGTMSessionUploadFetcherChunkParentKey : [NSValue valueWithNonretainedObject:self] }; + + _chunkFetcher.retryBlock = nil; + _chunkFetcher.sendProgressBlock = nil; + _chunkFetcher = nil; + } // @synchronized(self) +} + +// This method calculates the proper values to pass to the client's send progress block. +// +// The actual total bytes sent include the initial body sent, plus the +// offset into the batched data prior to the current chunk fetcher + +- (void)invokeDelegateWithDidSendBytes:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpected { + GTMSessionCheckNotSynchronized(self); + + // Ensure the chunk fetcher survives the callback in case the user pauses the upload process. + __block GTMSessionFetcher *holdFetcher = self.chunkFetcher; + + [self invokeOnCallbackQueue:self.delegateCallbackQueue + afterUserStopped:NO + block:^{ + GTMSessionFetcherSendProgressBlock sendProgressBlock = self.sendProgressBlock; + if (sendProgressBlock) { + sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpected); + } + holdFetcher = nil; + }]; +} + +- (void)retrieveUploadChunkGranularityFromResponseHeaders:(NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + + // Standard granularity for Google uploads is 256K. + NSString *chunkGranularityHeader = + [responseHeaders objectForKey:@"X-Goog-Upload-Chunk-Granularity"]; + self.uploadGranularity = chunkGranularityHeader.longLongValue; +} + +#pragma mark - + +- (BOOL)isPaused { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isPaused; + } // @synchronized(self) +} + +- (void)pauseFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _isPaused = YES; + } // @synchronized(self) + + // Pausing just means stopping the current chunk from uploading; + // when we resume, we will send a query request to the server to + // figure out what bytes to resume sending. + // + // We won't try to cancel the initial data upload, but rather will check + // for being paused in beginChunkFetches. + [self destroyChunkFetcher]; +} + +- (void)resumeFetching { + BOOL wasPaused; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + wasPaused = _isPaused; + _isPaused = NO; + } // @synchronized(self) + + if (wasPaused) { + [self sendQueryForUploadOffsetWithFetcherProperties:self.properties]; + } +} + +- (void)stopFetching { + // Overrides the superclass + [self destroyChunkFetcher]; + + // If we think the server is waiting for more data, then tell it there won't be more. + if (self.uploadLocationURL) { + [self sendCancelUploadWithFetcherProperties:[self properties]]; + self.uploadLocationURL = nil; + } + + [super stopFetching]; +} + +#pragma mark - + +// Public properties. +@synthesize currentOffset = _currentOffset, + delegateCompletionHandler = _delegateCompletionHandler, + chunkFetcher = _chunkFetcher, + lastChunkRequest = _lastChunkRequest, + subdataGenerating = _subdataGenerating, + shouldInitiateOffsetQuery = _shouldInitiateOffsetQuery, + uploadGranularity = _uploadGranularity; + +// Internal properties. +@dynamic fetcherInFlight; +@dynamic activeFetcher; +@dynamic statusCode; +@dynamic delegateCallbackQueue; + ++ (void)removePointer:(void *)pointer fromPointerArray:(NSPointerArray *)pointerArray { + for (NSUInteger index = 0, count = pointerArray.count; index < count; ++index) { + void *pointerAtIndex = [pointerArray pointerAtIndex:index]; + if (pointerAtIndex == pointer) { + [pointerArray removePointerAtIndex:index]; + return; + } + } +} + +- (BOOL)useBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _useBackgroundSessionOnChunkFetchers; + } // @synchronized(self +} + +- (void)setUseBackgroundSession:(BOOL)useBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_useBackgroundSessionOnChunkFetchers != useBackgroundSession) { + _useBackgroundSessionOnChunkFetchers = useBackgroundSession; + NSPointerArray *uploadFetcherPointerArrayForBackgroundSessions = + [[self class] uploadFetcherPointerArrayForBackgroundSessions]; + if (_useBackgroundSessionOnChunkFetchers) { + [uploadFetcherPointerArrayForBackgroundSessions addPointer:(__bridge void *)self]; + } else { + [[self class] removePointer:(__bridge void *)self + fromPointerArray:uploadFetcherPointerArrayForBackgroundSessions]; + } + } + } // @synchronized(self +} + +- (BOOL)canFetchWithBackgroundSession { + // The initial upload fetcher is always a foreground session; the + // useBackgroundSession property will apply only to chunk fetchers, + // not to queries. + return NO; +} + +- (NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + // Overrides the superclass + + // If asked for the fetcher's response, use the most recent chunk fetcher's response, + // since the original request's response lacks useful information like the actual + // Content-Type. + NSDictionary *dict = self.chunkFetcher.responseHeaders; + if (dict) { + return dict; + } + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_recentChunkReponseHeaders) { + return _recentChunkReponseHeaders; + } + } // @synchronized(self + + // No chunk fetcher yet completed, so return whatever we have from the initial fetch. + return [super responseHeaders]; +} + +- (NSInteger)statusCodeUnsynchronized { + GTMSessionCheckSynchronized(self); + + if (_recentChunkStatusCode != -1) { + // Overrides the superclass to indicate status appropriate to the initial + // or latest chunk fetch + return _recentChunkStatusCode; + } else { + return [super statusCodeUnsynchronized]; + } +} + + +- (void)setStatusCode:(NSInteger)val { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _recentChunkStatusCode = val; + } +} + +- (int64_t)initialBodyLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _initialBodyLength; + } +} + +- (void)setInitialBodyLength:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _initialBodyLength = length; + } +} + +- (int64_t)initialBodySent { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _initialBodySent; + } +} + +- (void)setInitialBodySent:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _initialBodySent = length; + } +} + +- (NSURL *)uploadLocationURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadLocationURL; + } +} + +- (void)setUploadLocationURL:(NSURL *)locationURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadLocationURL = locationURL; + } +} + +- (GTMSessionFetcher *)activeFetcher { + GTMSessionFetcher *result = self.fetcherInFlight; + if (result) return result; + + return self; +} + +- (BOOL)isFetching { + // If there is an active chunk fetcher, then the upload fetcher is considered + // to still be fetching. + if (self.fetcherInFlight != nil) return YES; + + return [super isFetching]; +} + +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds { + NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + + while (self.fetcherInFlight || self.subdataGenerating) { + if ([timeoutDate timeIntervalSinceNow] < 0) return NO; + + if (self.subdataGenerating) { + // Allow time for subdata generation. + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:0.001]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + // Wait for any chunk or query fetchers that still have pending callbacks or + // notifications. + BOOL timedOut; + + if (self.fetcherInFlight == self) { + timedOut = ![super waitForCompletionWithTimeout:timeoutInSeconds]; + } else { + timedOut = ![self.fetcherInFlight waitForCompletionWithTimeout:timeoutInSeconds]; + } + if (timedOut) return NO; + } + } + return YES; +} + +@end + +@implementation GTMSessionFetcher (GTMSessionUploadFetcherMethods) + +- (GTMSessionUploadFetcher *)parentUploadFetcher { + NSValue *property = [self propertyForKey:kGTMSessionUploadFetcherChunkParentKey]; + if (!property) return nil; + + GTMSessionUploadFetcher *uploadFetcher = property.nonretainedObjectValue; + + GTMSESSION_ASSERT_DEBUG([uploadFetcher isKindOfClass:[GTMSessionUploadFetcher class]], + @"Unexpected parent upload fetcher class: %@", [uploadFetcher class]); + return uploadFetcher; +} + +@end diff --git a/Task Master/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugSelectorValidation.h b/Task Master/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugSelectorValidation.h new file mode 100644 index 0000000..2396524 --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugSelectorValidation.h @@ -0,0 +1,100 @@ +// +// GTMDebugSelectorValidation.h +// +// This file should only be included within an implimation file. In any +// function that takes an object and selector to invoke, you should call: +// +// GTMAssertSelectorNilOrImplementedWithArguments(obj, sel, @encode(arg1type), ..., NULL) +// or +// GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(obj, sel, @encode(returnType), @encode(arg1type), ..., NULL) +// +// This will then validate that the selector is defined and using the right +// type(s), this can help catch errors much earlier then waiting for the +// selector to actually fire (and in the case of error selectors, might never +// really be tested until in the field). +// +// Copyright 2007-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#if DEBUG + +#import +#import "GTMDefines.h" + +static void GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(id obj, SEL sel, const char *retType, ...) { + + // verify that the object's selector is implemented with the proper + // number and type of arguments + va_list argList; + va_start(argList, retType); + + if (obj && sel) { + // check that the selector is implemented + _GTMDevAssert([obj respondsToSelector:sel], + @"\"%@\" selector \"%@\" is unimplemented or misnamed", + NSStringFromClass([obj class]), + NSStringFromSelector(sel)); + + const char *expectedArgType; + NSUInteger argCount = 2; // skip self and _cmd + NSMethodSignature *sig = [obj methodSignatureForSelector:sel]; + + // check that each expected argument is present and of the correct type + while ((expectedArgType = va_arg(argList, const char*)) != 0) { + + if ([sig numberOfArguments] > argCount) { + const char *foundArgType = [sig getArgumentTypeAtIndex:argCount]; + + _GTMDevAssert(0 == strncmp(foundArgType, expectedArgType, strlen(expectedArgType)), + @"\"%@\" selector \"%@\" argument %u should be type %s", + NSStringFromClass([obj class]), + NSStringFromSelector(sel), + (uint32_t)(argCount - 2), + expectedArgType); + } + argCount++; + } + + // check that the proper number of arguments are present in the selector + _GTMDevAssert(argCount == [sig numberOfArguments], + @"\"%@\" selector \"%@\" should have %u arguments", + NSStringFromClass([obj class]), + NSStringFromSelector(sel), + (uint32_t)(argCount - 2)); + + // if asked, validate the return type + if (retType && (strcmp("gtm_skip_return_test", retType) != 0)) { + const char *foundRetType = [sig methodReturnType]; + _GTMDevAssert(0 == strncmp(foundRetType, retType, strlen(retType)), + @"\"%@\" selector \"%@\" return type should be type %s", + NSStringFromClass([obj class]), + NSStringFromSelector(sel), + retType); + } + } + + va_end(argList); +} + +#define GTMAssertSelectorNilOrImplementedWithArguments(obj, sel, ...) \ + GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments((obj), (sel), "gtm_skip_return_test", __VA_ARGS__) + +#else // DEBUG + +// make it go away if not debug +#define GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(obj, sel, retType, ...) do { } while (0) +#define GTMAssertSelectorNilOrImplementedWithArguments(obj, sel, ...) do { } while (0) + +#endif // DEBUG diff --git a/Task Master/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugThreadValidation.h b/Task Master/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugThreadValidation.h new file mode 100644 index 0000000..3f50f17 --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/DebugUtils/GTMDebugThreadValidation.h @@ -0,0 +1,44 @@ +// +// GTMDebugThreadValidation.h +// +// Copyright 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMDefines.h" +#import + +// GTMCheckCurrentQueue, GTMIsCurrentQueue +// +// GTMCheckCurrentQueue takes a target queue and uses _GTMDevAssert to +// report if that is not the currently executing queue. +// +// GTMIsCurrentQueue takes a target queue and returns true if the target queue +// is the currently executing dispatch queue. This can be passed to another +// assertion call in debug builds; it should never be used in release code. +// +// The dispatch queue must have a label. +#define GTMCheckCurrentQueue(targetQueue) \ + _GTMDevAssert(GTMIsCurrentQueue(targetQueue), \ + @"Current queue is %s (expected %s)", \ + _GTMQueueName(DISPATCH_CURRENT_QUEUE_LABEL), \ + _GTMQueueName(targetQueue)) + +#define GTMIsCurrentQueue(targetQueue) \ + (strcmp(_GTMQueueName(DISPATCH_CURRENT_QUEUE_LABEL), \ + _GTMQueueName(targetQueue)) == 0) + +#define _GTMQueueName(queue) \ + (strlen(dispatch_queue_get_label(queue)) > 0 ? \ + dispatch_queue_get_label(queue) : "unnamed") diff --git a/Task Master/Pods/GoogleToolboxForMac/DebugUtils/GTMMethodCheck.h b/Task Master/Pods/GoogleToolboxForMac/DebugUtils/GTMMethodCheck.h new file mode 100644 index 0000000..9fad81d --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/DebugUtils/GTMMethodCheck.h @@ -0,0 +1,69 @@ +// +// GTMMethodCheck.h +// +// Copyright 2006-2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import +#import +#import + +/// A macro for enforcing debug time checks to make sure all required methods are linked in +// +// When using categories, it can be very easy to forget to include the +// implementation of a category. +// Let's say you had a class foo that depended on method bar of class baz, and +// method bar was implemented as a member of a category. +// You could add the following code: +// +// GTM_METHOD_CHECK(baz, bar) +// +// and the code would check to make sure baz was implemented just before main +// was called. This works for both dynamic libraries, and executables. +// +// +// This is not compiled into release builds. + +#ifdef DEBUG + +// This is the "magic". +// A) we need a multi layer define here so that the preprocessor expands +// __LINE__ the way we want it. We need __LINE__ so that each of our +// GTM_METHOD_CHECKs generates a unique function name. +#define GTM_METHOD_CHECK(class, method) GTM_METHOD_CHECK_INNER(class, method, __LINE__) +#define GTM_METHOD_CHECK_INNER(class, method, line) \ + GTM_METHOD_CHECK_INNER_INNER(class, method, line) + +// B) define a function that is called at startup to check that |class| has an +// implementation for |method| (either a class method or an instance method). +#define GTM_METHOD_CHECK_INNER_INNER(class, method, line) \ +__attribute__ ((constructor, visibility("hidden"))) \ + static void xxGTMMethodCheckMethod ## class ## line () { \ + @autoreleasepool { \ + if (![class instancesRespondToSelector:@selector(method)] \ + && ![class respondsToSelector:@selector(method)]) { \ + fprintf(stderr, "%s:%d: error: We need method '%s' to be linked in for class '%s'\n", \ + __FILE__, line, #method, #class); \ + exit(EX_SOFTWARE); \ + } \ + } \ +} + +#else // DEBUG + +// Do nothing in release. +#define GTM_METHOD_CHECK(class, method) + +#endif // DEBUG diff --git a/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.h b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.h new file mode 100644 index 0000000..dceadc4 --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.h @@ -0,0 +1,199 @@ +// +// GTMNSData+zlib.h +// +// Copyright 2007-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import +#import "GTMDefines.h" + +/// Helpers for dealing w/ zlib inflate/deflate calls. +@interface NSData (GTMZLibAdditions) + +// NOTE: For 64bit, none of these apis handle input sizes >32bits, they will +// return nil when given such data. To handle data of that size you really +// should be streaming it rather then doing it all in memory. + +#pragma mark Gzip Compression + +/// Return an autoreleased NSData w/ the result of gzipping the bytes. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length; ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of gzipping the payload of |data|. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByGzippingData:(NSData *)data __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of gzipping the bytes using |level| compression level. +// +// |level| can be 1-9, any other values will be clipped to that range. ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of gzipping the payload of |data| using |level| compression level. ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error; + +#pragma mark Zlib "Stream" Compression + +// NOTE: deflate is *NOT* gzip. deflate is a "zlib" stream. pick which one +// you really want to create. (the inflate api will handle either) + +/// Return an autoreleased NSData w/ the result of deflating the bytes. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of deflating the payload of |data|. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of deflating the bytes using |level| compression level. +// +// |level| can be 1-9, any other values will be clipped to that range. ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of deflating the payload of |data| using |level| compression level. ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error; + +#pragma mark Uncompress of Gzip or Zlib + +/// Return an autoreleased NSData w/ the result of decompressing the bytes. +// +// The bytes to decompress can be zlib or gzip payloads. ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of decompressing the payload of |data|. +// +// The data to decompress can be zlib or gzip payloads. ++ (NSData *)gtm_dataByInflatingData:(NSData *)data __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByInflatingData:(NSData *)data + error:(NSError **)error; + +#pragma mark "Raw" Compression Support + +// NOTE: raw deflate is *NOT* gzip or deflate. it does not include a header +// of any form and should only be used within streams here an external crc/etc. +// is done to validate the data. The RawInflate apis can be used on data +// processed like this. + +/// Return an autoreleased NSData w/ the result of *raw* deflating the bytes. +// +// Uses the default compression level. +// *No* header is added to the resulting data. ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of *raw* deflating the payload of |data|. +// +// Uses the default compression level. +// *No* header is added to the resulting data. ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of *raw* deflating the bytes using |level| compression level. +// +// |level| can be 1-9, any other values will be clipped to that range. +// *No* header is added to the resulting data. ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of *raw* deflating the payload of |data| using |level| compression level. +// *No* header is added to the resulting data. ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data + compressionLevel:(int)level __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of *raw* decompressing the bytes. +// +// The data to decompress, it should *not* have any header (zlib nor gzip). ++ (NSData *)gtm_dataByRawInflatingBytes:(const void *)bytes + length:(NSUInteger)length __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawInflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error; + +/// Return an autoreleased NSData w/ the result of *raw* decompressing the payload of |data|. +// +// The data to decompress, it should *not* have any header (zlib nor gzip). ++ (NSData *)gtm_dataByRawInflatingData:(NSData *)data __attribute__((deprecated("Use error variant"))); ++ (NSData *)gtm_dataByRawInflatingData:(NSData *)data + error:(NSError **)error; + +@end + +FOUNDATION_EXPORT NSString *const GTMNSDataZlibErrorDomain; +FOUNDATION_EXPORT NSString *const GTMNSDataZlibErrorKey; // NSNumber +FOUNDATION_EXPORT NSString *const GTMNSDataZlibRemainingBytesKey; // NSNumber + +typedef NS_ENUM(NSInteger, GTMNSDataZlibError) { + GTMNSDataZlibErrorGreaterThan32BitsToCompress = 1024, + // An internal zlib error. + // GTMNSDataZlibErrorKey will contain the error value. + // NSLocalizedDescriptionKey may contain an error string from zlib. + // Look in zlib.h for list of errors. + GTMNSDataZlibErrorInternal, + // There was left over data in the buffer that was not used. + // GTMNSDataZlibRemainingBytesKey will contain number of remaining bytes. + GTMNSDataZlibErrorDataRemaining +}; diff --git a/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.m b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.m new file mode 100644 index 0000000..bf74b2d --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSData+zlib.m @@ -0,0 +1,531 @@ +// +// GTMNSData+zlib.m +// +// Copyright 2007-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMNSData+zlib.h" +#import +#import "GTMDefines.h" + +#define kChunkSize 1024 + +NSString *const GTMNSDataZlibErrorDomain = @"com.google.GTMNSDataZlibErrorDomain"; +NSString *const GTMNSDataZlibErrorKey = @"GTMNSDataZlibErrorKey"; +NSString *const GTMNSDataZlibRemainingBytesKey = @"GTMNSDataZlibRemainingBytesKey"; + +typedef enum { + CompressionModeZlib, + CompressionModeGzip, + CompressionModeRaw, +} CompressionMode; + +@interface NSData (GTMZlibAdditionsPrivate) ++ (NSData *)gtm_dataByCompressingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + mode:(CompressionMode)mode + error:(NSError **)error; ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length + isRawData:(BOOL)isRawData + error:(NSError **)error; +@end + +@implementation NSData (GTMZlibAdditionsPrivate) + ++ (NSData *)gtm_dataByCompressingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + mode:(CompressionMode)mode + error:(NSError **)error { + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + if (error) { + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorGreaterThan32BitsToCompress + userInfo:nil]; + } + return nil; + } +#endif + + if (level == Z_DEFAULT_COMPRESSION) { + // the default value is actually outside the range, so we have to let it + // through specifically. + } else if (level < Z_BEST_SPEED) { + level = Z_BEST_SPEED; + } else if (level > Z_BEST_COMPRESSION) { + level = Z_BEST_COMPRESSION; + } + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + int memLevel = 8; // the default + int windowBits = 15; // the default + switch (mode) { + case CompressionModeZlib: + // nothing to do + break; + + case CompressionModeGzip: + windowBits += 16; // enable gzip header instead of zlib header + break; + + case CompressionModeRaw: + windowBits *= -1; // Negative to mean no header. + break; + } + int retCode; + if ((retCode = deflateInit2(&strm, level, Z_DEFLATED, windowBits, + memLevel, Z_DEFAULT_STRATEGY)) != Z_OK) { + // COV_NF_START - no real way to force this in a unittest (we guard all args) + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GTMNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + // COV_NF_END + } + + // hint the size at 1/4 the input size + NSMutableData *result = [NSMutableData dataWithCapacity:(length/4)]; + unsigned char output[kChunkSize]; + + // setup the input + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char*)bytes; + + // loop to collect the data + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = deflate(&strm, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + // COV_NF_START - no real way to force this in a unittest + // (in inflate, we can feed bogus/truncated data to test, but an error + // here would be some internal issue w/in zlib, and there isn't any real + // way to test it) + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GTMNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorInternal + userInfo:userInfo]; + } + deflateEnd(&strm); + return nil; + // COV_NF_END + } + // collect what we got + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // if the loop exits, we used all input and the stream ended + _GTMDevAssert(strm.avail_in == 0, + @"thought we finished deflate w/o using all input, %u bytes left", + strm.avail_in); + _GTMDevAssert(retCode == Z_STREAM_END, + @"thought we finished deflate w/o getting a result of stream end, code %d", + retCode); + + // clean up + deflateEnd(&strm); + + return result; +} // gtm_dataByCompressingBytes:length:compressionLevel:useGzip: + ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length + isRawData:(BOOL)isRawData + error:(NSError **)error { + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + return nil; + } +#endif + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + // setup the input + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char*)bytes; + + int windowBits = 15; // 15 to enable any window size + if (isRawData) { + windowBits *= -1; // make it negative to signal no header. + } else { + windowBits += 32; // and +32 to enable zlib or gzip header detection. + } + + int retCode; + if ((retCode = inflateInit2(&strm, windowBits)) != Z_OK) { + // COV_NF_START - no real way to force this in a unittest (we guard all args) + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GTMNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + // COV_NF_END + } + + // hint the size at 4x the input size + NSMutableData *result = [NSMutableData dataWithCapacity:(length*4)]; + unsigned char output[kChunkSize]; + + // loop to collect the data + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = inflate(&strm, Z_NO_FLUSH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + if (error) { + NSMutableDictionary *userInfo = + [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GTMNSDataZlibErrorKey]; + if (strm.msg) { + NSString *message = [NSString stringWithUTF8String:strm.msg]; + if (message) { + [userInfo setObject:message forKey:NSLocalizedDescriptionKey]; + } + } + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorInternal + userInfo:userInfo]; + } + inflateEnd(&strm); + return nil; + } + // collect what we got + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // make sure there wasn't more data tacked onto the end of a valid compressed + // stream. + if (strm.avail_in != 0) { + if (error) { + NSDictionary *userInfo = + [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:strm.avail_in] + forKey:GTMNSDataZlibRemainingBytesKey]; + *error = [NSError errorWithDomain:GTMNSDataZlibErrorDomain + code:GTMNSDataZlibErrorDataRemaining + userInfo:userInfo]; + } + result = nil; + } + // the only way out of the loop was by hitting the end of the stream + _GTMDevAssert(retCode == Z_STREAM_END, + @"thought we finished inflate w/o getting a result of stream end, code %d", + retCode); + + // clean up + inflateEnd(&strm); + + return result; +} // gtm_dataByInflatingBytes:length:windowBits: + +@end + + +@implementation NSData (GTMZLibAdditions) + ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByGzippingBytes:bytes length:length error:NULL]; +} // gtm_dataByGzippingBytes:length: + ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error { + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeGzip + error:error]; +} // gtm_dataByGzippingBytes:length:error: + ++ (NSData *)gtm_dataByGzippingData:(NSData *)data { + return [self gtm_dataByGzippingData:data error:NULL]; +} // gtm_dataByGzippingData: + ++ (NSData *)gtm_dataByGzippingData:(NSData *)data error:(NSError **)error { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeGzip + error:error]; +} // gtm_dataByGzippingData:error: + ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level { + return [self gtm_dataByGzippingBytes:bytes + length:length + compressionLevel:level + error:NULL]; +} // gtm_dataByGzippingBytes:length:level: + ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error{ + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:level + mode:CompressionModeGzip + error:error]; +} // gtm_dataByGzippingBytes:length:level:error + ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + compressionLevel:(int)level { + return [self gtm_dataByGzippingData:data + compressionLevel:level + error:NULL]; +} // gtm_dataByGzippingData:level: + ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error{ + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:level + mode:CompressionModeGzip + error:error]; +} // gtm_dataByGzippingData:level:error + +#pragma mark - + ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByDeflatingBytes:bytes + length:length + error:NULL]; +} // gtm_dataByDeflatingBytes:length: + ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error{ + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeZlib + error:error]; +} // gtm_dataByDeflatingBytes:length:error + ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data { + return [self gtm_dataByDeflatingData:data error:NULL]; +} // gtm_dataByDeflatingData: + ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data error:(NSError **)error { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeZlib + error:error]; +} // gtm_dataByDeflatingData: + ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level { + return [self gtm_dataByDeflatingBytes:bytes + length:length + compressionLevel:level + error:NULL]; +} // gtm_dataByDeflatingBytes:length:level: + ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error { + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:level + mode:CompressionModeZlib + error:error]; +} // gtm_dataByDeflatingBytes:length:level:error: + ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + compressionLevel:(int)level { + return [self gtm_dataByDeflatingData:data + compressionLevel:level + error:NULL]; +} // gtm_dataByDeflatingData:level: + ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:level + mode:CompressionModeZlib + error:error]; +} // gtm_dataByDeflatingData:level:error: + +#pragma mark - + ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByInflatingBytes:bytes + length:length + error:NULL]; +} // gtm_dataByInflatingBytes:length: + ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error { + return [self gtm_dataByInflatingBytes:bytes + length:length + isRawData:NO + error:error]; +} // gtm_dataByInflatingBytes:length:error: + ++ (NSData *)gtm_dataByInflatingData:(NSData *)data { + return [self gtm_dataByInflatingData:data error:NULL]; +} // gtm_dataByInflatingData: + ++ (NSData *)gtm_dataByInflatingData:(NSData *)data + error:(NSError **)error { + return [self gtm_dataByInflatingBytes:[data bytes] + length:[data length] + isRawData:NO + error:error]; +} // gtm_dataByInflatingData: + +#pragma mark - + ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:NULL]; +} // gtm_dataByRawDeflatingBytes:length: + ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error { + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeRaw + error:error]; +} // gtm_dataByRawDeflatingBytes:length:error: + ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data { + return [self gtm_dataByRawDeflatingData:data error:NULL]; +} // gtm_dataByRawDeflatingData: + ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data error:(NSError **)error { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:Z_DEFAULT_COMPRESSION + mode:CompressionModeRaw + error:error]; +} // gtm_dataByRawDeflatingData:error: + ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level { + return [self gtm_dataByRawDeflatingBytes:bytes + length:length + compressionLevel:level + error:NULL]; +} // gtm_dataByRawDeflatingBytes:length:compressionLevel: + ++ (NSData *)gtm_dataByRawDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + error:(NSError **)error{ + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:level + mode:CompressionModeRaw + error:error]; +} // gtm_dataByRawDeflatingBytes:length:compressionLevel:error: + ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data + compressionLevel:(int)level { + return [self gtm_dataByRawDeflatingData:data + compressionLevel:level + error:NULL]; +} // gtm_dataByRawDeflatingData:compressionLevel: + ++ (NSData *)gtm_dataByRawDeflatingData:(NSData *)data + compressionLevel:(int)level + error:(NSError **)error { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:level + mode:CompressionModeRaw + error:error]; +} // gtm_dataByRawDeflatingData:compressionLevel:error: + ++ (NSData *)gtm_dataByRawInflatingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByInflatingBytes:bytes + length:length + error:NULL]; +} // gtm_dataByRawInflatingBytes:length: + ++ (NSData *)gtm_dataByRawInflatingBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **)error{ + return [self gtm_dataByInflatingBytes:bytes + length:length + isRawData:YES + error:error]; +} // gtm_dataByRawInflatingBytes:length:error: + ++ (NSData *)gtm_dataByRawInflatingData:(NSData *)data { + return [self gtm_dataByRawInflatingData:data + error:NULL]; +} // gtm_dataByRawInflatingData: + ++ (NSData *)gtm_dataByRawInflatingData:(NSData *)data + error:(NSError **)error { + return [self gtm_dataByInflatingBytes:[data bytes] + length:[data length] + isRawData:YES + error:error]; +} // gtm_dataByRawInflatingData:error: + +@end diff --git a/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.h b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.h new file mode 100644 index 0000000..b2f0564 --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.h @@ -0,0 +1,40 @@ +// +// GTMNSDictionary+URLArguments.h +// +// Copyright 2006-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import + +/// Utility for building a URL or POST argument string. +@interface NSDictionary (GTMNSDictionaryURLArgumentsAdditions) + +/// Returns a dictionary of the decoded key-value pairs in a http arguments +/// string of the form key1=value1&key2=value2&...&keyN=valueN. +/// Keys and values will be unescaped automatically. +/// Only the first value for a repeated key is returned. +/// +/// NOTE: Apps targeting iOS 8 or OS X 10.10 and later should use +/// NSURLComponents and NSURLQueryItem to create URLs with +/// query arguments instead of using these category methods. ++ (NSDictionary *)gtm_dictionaryWithHttpArgumentsString:(NSString *)argString; + +/// Gets a string representation of the dictionary in the form +/// key1=value1&key2=value2&...&keyN=valueN, suitable for use as either +/// URL arguments (after a '?') or POST body. Keys and values will be escaped +/// automatically, so should be unescaped in the dictionary. +- (NSString *)gtm_httpArgumentsString; + +@end diff --git a/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.m b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.m new file mode 100644 index 0000000..e9fa766 --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.m @@ -0,0 +1,77 @@ +// +// GTMNSDictionary+URLArguments.m +// +// Copyright 2006-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMNSDictionary+URLArguments.h" +#import "GTMNSString+URLArguments.h" +#import "GTMMethodCheck.h" +#import "GTMDefines.h" + + +// Export a nonsense symbol to suppress a libtool warning when this is linked alone in a static lib. +__attribute__((visibility("default"))) + char GTMNSDictionaryURLArgumentsExportToSuppressLibToolWarning = 0; + + +@implementation NSDictionary (GTMNSDictionaryURLArgumentsAdditions) + +GTM_METHOD_CHECK(NSString, gtm_stringByEscapingForURLArgument); +GTM_METHOD_CHECK(NSString, gtm_stringByUnescapingFromURLArgument); + ++ (NSDictionary *)gtm_dictionaryWithHttpArgumentsString:(NSString *)argString { + NSMutableDictionary* ret = [NSMutableDictionary dictionary]; + NSArray* components = [argString componentsSeparatedByString:@"&"]; + NSString* component; + // Use reverse order so that the first occurrence of a key replaces + // those subsequent. + for (component in [components reverseObjectEnumerator]) { + if ([component length] == 0) + continue; + NSRange pos = [component rangeOfString:@"="]; + NSString *key; + NSString *val; + if (pos.location == NSNotFound) { + key = [component gtm_stringByUnescapingFromURLArgument]; + val = @""; + } else { + key = [[component substringToIndex:pos.location] + gtm_stringByUnescapingFromURLArgument]; + val = [[component substringFromIndex:pos.location + pos.length] + gtm_stringByUnescapingFromURLArgument]; + } + // gtm_stringByUnescapingFromURLArgument returns nil on invalid UTF8 + // and NSMutableDictionary raises an exception when passed nil values. + if (!key) key = @""; + if (!val) val = @""; + [ret setObject:val forKey:key]; + } + return ret; +} + +- (NSString *)gtm_httpArgumentsString { + NSMutableArray* arguments = [NSMutableArray arrayWithCapacity:[self count]]; + NSString* key; + for (key in self) { + [arguments addObject:[NSString stringWithFormat:@"%@=%@", + [key gtm_stringByEscapingForURLArgument], + [[[self objectForKey:key] description] gtm_stringByEscapingForURLArgument]]]; + } + + return [arguments componentsJoinedByString:@"&"]; +} + +@end diff --git a/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.h b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.h new file mode 100644 index 0000000..b3a3e3e --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.h @@ -0,0 +1,45 @@ +// +// GTMNSString+URLArguments.h +// +// Copyright 2006-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import + +/// Utilities for encoding and decoding URL arguments. +@interface NSString (GTMNSStringURLArgumentsAdditions) + +/// Returns a string that is escaped properly to be a URL argument. +/// +/// This differs from stringByAddingPercentEscapesUsingEncoding: in that it +/// will escape all the reserved characters (per RFC 3986 +/// ) which +/// stringByAddingPercentEscapesUsingEncoding would leave. +/// +/// This will also escape '%', so this should not be used on a string that has +/// already been escaped unless double-escaping is the desired result. +/// +/// NOTE: Apps targeting iOS 8 or OS X 10.10 and later should use +/// NSURLComponents and NSURLQueryItem to create properly-escaped +/// URLs instead of using these category methods. +- (NSString*)gtm_stringByEscapingForURLArgument; + +/// Returns the unescaped version of a URL argument +/// +/// This has the same behavior as stringByReplacingPercentEscapesUsingEncoding:, +/// except that it will also convert '+' to space. +- (NSString*)gtm_stringByUnescapingFromURLArgument; + +@end diff --git a/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.m b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.m new file mode 100644 index 0000000..e785c5e --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.m @@ -0,0 +1,48 @@ +// +// GTMNSString+URLArguments.m +// +// Copyright 2006-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMNSString+URLArguments.h" + +@implementation NSString (GTMNSStringURLArgumentsAdditions) + +- (NSString *)gtm_stringByEscapingForURLArgument { + // Encode all the reserved characters, per RFC 3986 + // () + CFStringRef escaped = + CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)self, + NULL, + (CFStringRef)@"!*'();:@&=+$,/?%#[]", + kCFStringEncodingUTF8); +#if defined(__has_feature) && __has_feature(objc_arc) + return CFBridgingRelease(escaped); +#else + return [(NSString *)escaped autorelease]; +#endif +} + +- (NSString *)gtm_stringByUnescapingFromURLArgument { + NSMutableString *resultString = [NSMutableString stringWithString:self]; + [resultString replaceOccurrencesOfString:@"+" + withString:@" " + options:NSLiteralSearch + range:NSMakeRange(0, [resultString length])]; + return [resultString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; +} + +@end diff --git a/Task Master/Pods/GoogleToolboxForMac/GTMDefines.h b/Task Master/Pods/GoogleToolboxForMac/GTMDefines.h new file mode 100644 index 0000000..8ec88cc --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/GTMDefines.h @@ -0,0 +1,392 @@ +// +// GTMDefines.h +// +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +// ============================================================================ + +#include +#include + +#ifdef __OBJC__ +#include +#endif // __OBJC__ + +#if TARGET_OS_IPHONE +#include +#endif // TARGET_OS_IPHONE + +// ---------------------------------------------------------------------------- +// CPP symbols that can be overridden in a prefix to control how the toolbox +// is compiled. +// ---------------------------------------------------------------------------- + + +// By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and +// GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens +// when a validation fails. If you implement your own validators, you may want +// to control their internals using the same macros for consistency. +#ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT + #define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0 +#endif + +// Ensure __has_feature and __has_extension are safe to use. +// See http://clang-analyzer.llvm.org/annotations.html +#ifndef __has_feature // Optional. + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef __has_extension + #define __has_extension __has_feature // Compatibility with pre-3.0 compilers. +#endif + +// Give ourselves a consistent way to do inlines. Apple's macros even use +// a few different actual definitions, so we're based off of the foundation +// one. +#if !defined(GTM_INLINE) + #if (defined (__GNUC__) && (__GNUC__ == 4)) || defined (__clang__) + #define GTM_INLINE static __inline__ __attribute__((always_inline)) + #else + #define GTM_INLINE static __inline__ + #endif +#endif + +// Give ourselves a consistent way of doing externs that links up nicely +// when mixing objc and objc++ +#if !defined (GTM_EXTERN) + #if defined __cplusplus + #define GTM_EXTERN extern "C" + #define GTM_EXTERN_C_BEGIN extern "C" { + #define GTM_EXTERN_C_END } + #else + #define GTM_EXTERN extern + #define GTM_EXTERN_C_BEGIN + #define GTM_EXTERN_C_END + #endif +#endif + +// Give ourselves a consistent way of exporting things if we have visibility +// set to hidden. +#if !defined (GTM_EXPORT) + #define GTM_EXPORT __attribute__((visibility("default"))) +#endif + +// Give ourselves a consistent way of declaring something as unused. This +// doesn't use __unused because that is only supported in gcc 4.2 and greater. +#if !defined (GTM_UNUSED) +#define GTM_UNUSED(x) ((void)(x)) +#endif + +// _GTMDevLog & _GTMDevAssert +// +// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for +// developer level errors. This implementation simply macros to NSLog/NSAssert. +// It is not intended to be a general logging/reporting system. +// +// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert +// for a little more background on the usage of these macros. +// +// _GTMDevLog log some error/problem in debug builds +// _GTMDevAssert assert if condition isn't met w/in a method/function +// in all builds. +// +// To replace this system, just provide different macro definitions in your +// prefix header. Remember, any implementation you provide *must* be thread +// safe since this could be called by anything in what ever situtation it has +// been placed in. +// + +// We only define the simple macros if nothing else has defined this. +#ifndef _GTMDevLog + +#ifdef DEBUG + #define _GTMDevLog(...) NSLog(__VA_ARGS__) +#else + #define _GTMDevLog(...) do { } while (0) +#endif + +#endif // _GTMDevLog + +#ifndef _GTMDevAssert +// we directly invoke the NSAssert handler so we can pass on the varargs +// (NSAssert doesn't have a macro we can use that takes varargs) +#if !defined(NS_BLOCK_ASSERTIONS) + #define _GTMDevAssert(condition, ...) \ + do { \ + if (!(condition)) { \ + [[NSAssertionHandler currentHandler] \ + handleFailureInFunction:(NSString *) \ + [NSString stringWithUTF8String:__PRETTY_FUNCTION__] \ + file:(NSString *)[NSString stringWithUTF8String:__FILE__] \ + lineNumber:__LINE__ \ + description:__VA_ARGS__]; \ + } \ + } while(0) +#else // !defined(NS_BLOCK_ASSERTIONS) + #define _GTMDevAssert(condition, ...) do { } while (0) +#endif // !defined(NS_BLOCK_ASSERTIONS) + +#endif // _GTMDevAssert + +// _GTMCompileAssert +// +// Note: Software for current compilers should just use _Static_assert directly +// instead of this macro. +// +// _GTMCompileAssert is an assert that is meant to fire at compile time if you +// want to check things at compile instead of runtime. For example if you +// want to check that a wchar is 4 bytes instead of 2 you would use +// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X) +// Note that the second "arg" is not in quotes, and must be a valid processor +// symbol in it's own right (no spaces, punctuation etc). + +// Wrapping this in an #ifndef allows external groups to define their own +// compile time assert scheme. +#ifndef _GTMCompileAssert + #if __has_feature(c_static_assert) || __has_extension(c_static_assert) + #define _GTMCompileAssert(test, msg) _Static_assert((test), #msg) + #else + // Pre-Xcode 7 support. + // + // We got this technique from here: + // http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html + #define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg + #define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg) + #define _GTMCompileAssert(test, msg) \ + typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ] + #endif // __has_feature(c_static_assert) || __has_extension(c_static_assert) +#endif // _GTMCompileAssert + +// ---------------------------------------------------------------------------- +// CPP symbols defined based on the project settings so the GTM code has +// simple things to test against w/o scattering the knowledge of project +// setting through all the code. +// ---------------------------------------------------------------------------- + +// Provide a single constant CPP symbol that all of GTM uses for ifdefing +// iPhone code. +#if TARGET_OS_IPHONE // iPhone SDK + // For iPhone specific stuff + #define GTM_IPHONE_SDK 1 + #if TARGET_IPHONE_SIMULATOR + #define GTM_IPHONE_DEVICE 0 + #define GTM_IPHONE_SIMULATOR 1 + #else + #define GTM_IPHONE_DEVICE 1 + #define GTM_IPHONE_SIMULATOR 0 + #endif // TARGET_IPHONE_SIMULATOR + // By default, GTM has provided it's own unittesting support, define this + // to use the support provided by Xcode, especially for the Xcode4 support + // for unittesting. + #ifndef GTM_USING_XCTEST + #define GTM_USING_XCTEST 0 + #endif + #define GTM_MACOS_SDK 0 +#else + // For MacOS specific stuff + #define GTM_MACOS_SDK 1 + #define GTM_IPHONE_SDK 0 + #define GTM_IPHONE_SIMULATOR 0 + #define GTM_IPHONE_DEVICE 0 + #ifndef GTM_USING_XCTEST + #define GTM_USING_XCTEST 0 + #endif +#endif + +// Some of our own availability macros +#if GTM_MACOS_SDK +#define GTM_AVAILABLE_ONLY_ON_IPHONE UNAVAILABLE_ATTRIBUTE +#define GTM_AVAILABLE_ONLY_ON_MACOS +#else +#define GTM_AVAILABLE_ONLY_ON_IPHONE +#define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE +#endif + +// GC was dropped by Apple, define the old constant incase anyone still keys +// off of it. +#ifndef GTM_SUPPORT_GC + #define GTM_SUPPORT_GC 0 +#endif + +// Some support for advanced clang static analysis functionality +#ifndef NS_RETURNS_RETAINED + #if __has_feature(attribute_ns_returns_retained) + #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) + #else + #define NS_RETURNS_RETAINED + #endif +#endif + +#ifndef NS_RETURNS_NOT_RETAINED + #if __has_feature(attribute_ns_returns_not_retained) + #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) + #else + #define NS_RETURNS_NOT_RETAINED + #endif +#endif + +#ifndef CF_RETURNS_RETAINED + #if __has_feature(attribute_cf_returns_retained) + #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) + #else + #define CF_RETURNS_RETAINED + #endif +#endif + +#ifndef CF_RETURNS_NOT_RETAINED + #if __has_feature(attribute_cf_returns_not_retained) + #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) + #else + #define CF_RETURNS_NOT_RETAINED + #endif +#endif + +#ifndef NS_CONSUMED + #if __has_feature(attribute_ns_consumed) + #define NS_CONSUMED __attribute__((ns_consumed)) + #else + #define NS_CONSUMED + #endif +#endif + +#ifndef CF_CONSUMED + #if __has_feature(attribute_cf_consumed) + #define CF_CONSUMED __attribute__((cf_consumed)) + #else + #define CF_CONSUMED + #endif +#endif + +#ifndef NS_CONSUMES_SELF + #if __has_feature(attribute_ns_consumes_self) + #define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) + #else + #define NS_CONSUMES_SELF + #endif +#endif + +#ifndef GTM_NONNULL + #if defined(__has_attribute) + #if __has_attribute(nonnull) + #define GTM_NONNULL(x) __attribute__((nonnull x)) + #else + #define GTM_NONNULL(x) + #endif + #else + #define GTM_NONNULL(x) + #endif +#endif + +// Invalidates the initializer from which it's called. +#ifndef GTMInvalidateInitializer + #if __has_feature(objc_arc) + #define GTMInvalidateInitializer() \ + do { \ + [self class]; /* Avoid warning of dead store to |self|. */ \ + _GTMDevAssert(NO, @"Invalid initializer."); \ + return nil; \ + } while (0) + #else + #define GTMInvalidateInitializer() \ + do { \ + [self release]; \ + _GTMDevAssert(NO, @"Invalid initializer."); \ + return nil; \ + } while (0) + #endif +#endif + +#ifndef GTMCFAutorelease + // GTMCFAutorelease returns an id. In contrast, Apple's CFAutorelease returns + // a CFTypeRef. + #if __has_feature(objc_arc) + #define GTMCFAutorelease(x) CFBridgingRelease(x) + #else + #define GTMCFAutorelease(x) ([(id)x autorelease]) + #endif +#endif + +#ifdef __OBJC__ + + +// Macro to allow you to create NSStrings out of other macros. +// #define FOO foo +// NSString *fooString = GTM_NSSTRINGIFY(FOO); +#if !defined (GTM_NSSTRINGIFY) + #define GTM_NSSTRINGIFY_INNER(x) @#x + #define GTM_NSSTRINGIFY(x) GTM_NSSTRINGIFY_INNER(x) +#endif + +// Macro to allow fast enumeration when building for 10.5 or later, and +// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration +// does keys, so pick the right thing, nothing is done on the FastEnumeration +// side to be sure you're getting what you wanted. +#ifndef GTM_FOREACH_OBJECT + #if TARGET_OS_IPHONE || !(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) + #define GTM_FOREACH_ENUMEREE(element, enumeration) \ + for (element in enumeration) + #define GTM_FOREACH_OBJECT(element, collection) \ + for (element in collection) + #define GTM_FOREACH_KEY(element, collection) \ + for (element in collection) + #else + #define GTM_FOREACH_ENUMEREE(element, enumeration) \ + for (NSEnumerator *_ ## element ## _enum = enumeration; \ + (element = [_ ## element ## _enum nextObject]) != nil; ) + #define GTM_FOREACH_OBJECT(element, collection) \ + GTM_FOREACH_ENUMEREE(element, [collection objectEnumerator]) + #define GTM_FOREACH_KEY(element, collection) \ + GTM_FOREACH_ENUMEREE(element, [collection keyEnumerator]) + #endif +#endif + +// ============================================================================ + +// GTM_SEL_STRING is for specifying selector (usually property) names to KVC +// or KVO methods. +// In debug it will generate warnings for undeclared selectors if +// -Wunknown-selector is turned on. +// In release it will have no runtime overhead. +#ifndef GTM_SEL_STRING + #ifdef DEBUG + #define GTM_SEL_STRING(selName) NSStringFromSelector(@selector(selName)) + #else + #define GTM_SEL_STRING(selName) @#selName + #endif // DEBUG +#endif // GTM_SEL_STRING + +#ifndef GTM_WEAK +#if __has_feature(objc_arc_weak) + // With ARC enabled, __weak means a reference that isn't implicitly + // retained. __weak objects are accessed through runtime functions, so + // they are zeroed out, but this requires OS X 10.7+. + // At clang r251041+, ARC-style zeroing weak references even work in + // non-ARC mode. + #define GTM_WEAK __weak + #elif __has_feature(objc_arc) + // ARC, but targeting 10.6 or older, where zeroing weak references don't + // exist. + #define GTM_WEAK __unsafe_unretained + #else + // With manual reference counting, __weak used to be silently ignored. + // clang r251041 gives it the ARC semantics instead. This means they + // now require a deployment target of 10.7, while some clients of GTM + // still target 10.6. In these cases, expand to __unsafe_unretained instead + #define GTM_WEAK + #endif +#endif + +#endif // __OBJC__ diff --git a/Task Master/Pods/GoogleToolboxForMac/LICENSE b/Task Master/Pods/GoogleToolboxForMac/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Task Master/Pods/GoogleToolboxForMac/README.md b/Task Master/Pods/GoogleToolboxForMac/README.md new file mode 100644 index 0000000..710560a --- /dev/null +++ b/Task Master/Pods/GoogleToolboxForMac/README.md @@ -0,0 +1,15 @@ +# GTM: Google Toolbox for Mac # + +**Project site**
+**Discussion group** + +# Google Toolbox for Mac # + +A collection of source from different Google projects that may be of use to +developers working other iOS or OS X projects. + +If you find a problem/bug or want a new feature to be included in the Google +Toolbox for Mac, please join the +[discussion group](http://groups.google.com/group/google-toolbox-for-mac) +or submit an +[issue](https://github.com/google/google-toolbox-for-mac/issues). diff --git a/Task Master/Pods/Headers/Private/Firebase/Firebase.h b/Task Master/Pods/Headers/Private/Firebase/Firebase.h new file mode 120000 index 0000000..6d62033 --- /dev/null +++ b/Task Master/Pods/Headers/Private/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/Core/Sources/Firebase.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcher.h b/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcher.h new file mode 120000 index 0000000..7ed730f --- /dev/null +++ b/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcher.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcher.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherLogging.h b/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherLogging.h new file mode 120000 index 0000000..ada41e3 --- /dev/null +++ b/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherLogging.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcherLogging.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherService.h b/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherService.h new file mode 120000 index 0000000..1ef9cbb --- /dev/null +++ b/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionFetcherService.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcherService.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionUploadFetcher.h b/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionUploadFetcher.h new file mode 120000 index 0000000..cef7a0d --- /dev/null +++ b/Task Master/Pods/Headers/Private/GTMSessionFetcher/GTMSessionUploadFetcher.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionUploadFetcher.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugSelectorValidation.h b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugSelectorValidation.h new file mode 120000 index 0000000..521da72 --- /dev/null +++ b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugSelectorValidation.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/DebugUtils/GTMDebugSelectorValidation.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugThreadValidation.h b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugThreadValidation.h new file mode 120000 index 0000000..de29ea1 --- /dev/null +++ b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDebugThreadValidation.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/DebugUtils/GTMDebugThreadValidation.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDefines.h b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDefines.h new file mode 120000 index 0000000..5503110 --- /dev/null +++ b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMDefines.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/GTMDefines.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMMethodCheck.h b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMMethodCheck.h new file mode 120000 index 0000000..56dfa7e --- /dev/null +++ b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMMethodCheck.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/DebugUtils/GTMMethodCheck.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMNSData+zlib.h b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMNSData+zlib.h new file mode 120000 index 0000000..9e72419 --- /dev/null +++ b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMNSData+zlib.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/Foundation/GTMNSData+zlib.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMNSDictionary+URLArguments.h b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMNSDictionary+URLArguments.h new file mode 120000 index 0000000..b2ff829 --- /dev/null +++ b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMNSDictionary+URLArguments.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMNSString+URLArguments.h b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMNSString+URLArguments.h new file mode 120000 index 0000000..3b9b1a2 --- /dev/null +++ b/Task Master/Pods/Headers/Private/GoogleToolboxForMac/GTMNSString+URLArguments.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/Firebase/Firebase.h b/Task Master/Pods/Headers/Public/Firebase/Firebase.h new file mode 120000 index 0000000..6d62033 --- /dev/null +++ b/Task Master/Pods/Headers/Public/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/Core/Sources/Firebase.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics+AppDelegate.h b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics+AppDelegate.h new file mode 120000 index 0000000..1d9bd7e --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics+AppDelegate.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics.h b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics.h new file mode 120000 index 0000000..f8fc4fb --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalytics.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalyticsConfiguration.h b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalyticsConfiguration.h new file mode 120000 index 0000000..6773271 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRAnalyticsConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalyticsConfiguration.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRApp.h b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRApp.h new file mode 120000 index 0000000..97c9b35 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRApp.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRApp.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRConfiguration.h b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRConfiguration.h new file mode 120000 index 0000000..c34ddb8 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRConfiguration.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIREventNames.h b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIREventNames.h new file mode 120000 index 0000000..8924cc0 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIREventNames.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIREventNames.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIROptions.h b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIROptions.h new file mode 120000 index 0000000..a40119b --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIROptions.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIROptions.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRParameterNames.h b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRParameterNames.h new file mode 120000 index 0000000..6e37a6e --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRParameterNames.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRParameterNames.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRUserPropertyNames.h b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRUserPropertyNames.h new file mode 120000 index 0000000..4459d6b --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FIRUserPropertyNames.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FirebaseAnalytics.h b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FirebaseAnalytics.h new file mode 120000 index 0000000..2d48a7d --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAnalytics/FirebaseAnalytics/FirebaseAnalytics.h @@ -0,0 +1 @@ +../../../../FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuth.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuth.h new file mode 120000 index 0000000..35e20c5 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuth.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuth.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthCredential.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthCredential.h new file mode 120000 index 0000000..ed32f36 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthCredential.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthCredential.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthErrors.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthErrors.h new file mode 120000 index 0000000..e21f64e --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRAuthErrors.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRAuthErrors.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIREmailPasswordAuthProvider.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIREmailPasswordAuthProvider.h new file mode 120000 index 0000000..2dbd016 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIREmailPasswordAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIREmailPasswordAuthProvider.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRFacebookAuthProvider.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRFacebookAuthProvider.h new file mode 120000 index 0000000..8fbecbe --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRFacebookAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRFacebookAuthProvider.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGitHubAuthProvider.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGitHubAuthProvider.h new file mode 120000 index 0000000..dbb098a --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGitHubAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGitHubAuthProvider.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGoogleAuthProvider.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGoogleAuthProvider.h new file mode 120000 index 0000000..ad7189e --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRGoogleAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRGoogleAuthProvider.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRTwitterAuthProvider.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRTwitterAuthProvider.h new file mode 120000 index 0000000..30a19f2 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRTwitterAuthProvider.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRTwitterAuthProvider.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUser.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUser.h new file mode 120000 index 0000000..ecac892 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUser.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUser.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUserInfo.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUserInfo.h new file mode 120000 index 0000000..ef1617c --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FIRUserInfo.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FIRUserInfo.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuth.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuth.h new file mode 120000 index 0000000..e3b2676 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuth.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuth.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuthVersion.h b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuthVersion.h new file mode 120000 index 0000000..ee9f380 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseAuth/FirebaseAuth/FirebaseAuthVersion.h @@ -0,0 +1 @@ +../../../../FirebaseAuth/Frameworks/FirebaseAuth.framework/Headers/FirebaseAuthVersion.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRAnalyticsConfiguration.h b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRAnalyticsConfiguration.h new file mode 120000 index 0000000..31d68c3 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRAnalyticsConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRAnalyticsConfiguration.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRApp.h b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRApp.h new file mode 120000 index 0000000..90c263a --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRApp.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRApp.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRConfiguration.h b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRConfiguration.h new file mode 120000 index 0000000..6a732c0 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRConfiguration.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRConfiguration.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRLoggerLevel.h b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRLoggerLevel.h new file mode 120000 index 0000000..a216706 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIRLoggerLevel.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIRLoggerLevel.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIROptions.h b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIROptions.h new file mode 120000 index 0000000..5bd77eb --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FIROptions.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FIROptions.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FirebaseCore.h b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FirebaseCore.h new file mode 120000 index 0000000..96e9330 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseCore/FirebaseCore/FirebaseCore.h @@ -0,0 +1 @@ +../../../../FirebaseCore/Frameworks/FirebaseCore.framework/Headers/FirebaseCore.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataEventType.h b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataEventType.h new file mode 120000 index 0000000..ba0eb10 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataEventType.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataEventType.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataSnapshot.h b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataSnapshot.h new file mode 120000 index 0000000..635d198 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDataSnapshot.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDataSnapshot.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabase.h b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabase.h new file mode 120000 index 0000000..72f9038 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabase.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabase.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseQuery.h b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseQuery.h new file mode 120000 index 0000000..9ad7555 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseQuery.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseQuery.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseReference.h b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseReference.h new file mode 120000 index 0000000..b935ca6 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRDatabaseReference.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRDatabaseReference.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRMutableData.h b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRMutableData.h new file mode 120000 index 0000000..4efb3f2 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRMutableData.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRMutableData.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRServerValue.h b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRServerValue.h new file mode 120000 index 0000000..8632fa0 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRServerValue.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRServerValue.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRTransactionResult.h b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRTransactionResult.h new file mode 120000 index 0000000..c56d5c8 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FIRTransactionResult.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FIRTransactionResult.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FirebaseDatabase.h b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FirebaseDatabase.h new file mode 120000 index 0000000..4eefb9c --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseDatabase/FirebaseDatabase/FirebaseDatabase.h @@ -0,0 +1 @@ +../../../../FirebaseDatabase/Frameworks/FirebaseDatabase.framework/Headers/FirebaseDatabase.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FIRInstanceID.h b/Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FIRInstanceID.h new file mode 120000 index 0000000..62c92b0 --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FIRInstanceID.h @@ -0,0 +1 @@ +../../../../FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FIRInstanceID.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FirebaseInstanceID.h b/Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FirebaseInstanceID.h new file mode 120000 index 0000000..8925bdb --- /dev/null +++ b/Task Master/Pods/Headers/Public/FirebaseInstanceID/FirebaseInstanceID/FirebaseInstanceID.h @@ -0,0 +1 @@ +../../../../FirebaseInstanceID/Frameworks/FirebaseInstanceID.framework/Headers/FirebaseInstanceID.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.h b/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.h new file mode 120000 index 0000000..7ed730f --- /dev/null +++ b/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcher.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherLogging.h b/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherLogging.h new file mode 120000 index 0000000..ada41e3 --- /dev/null +++ b/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherLogging.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcherLogging.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherService.h b/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherService.h new file mode 120000 index 0000000..1ef9cbb --- /dev/null +++ b/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionFetcherService.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionFetcherService.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionUploadFetcher.h b/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionUploadFetcher.h new file mode 120000 index 0000000..cef7a0d --- /dev/null +++ b/Task Master/Pods/Headers/Public/GTMSessionFetcher/GTMSessionUploadFetcher.h @@ -0,0 +1 @@ +../../../GTMSessionFetcher/Source/GTMSessionUploadFetcher.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDebugSelectorValidation.h b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDebugSelectorValidation.h new file mode 120000 index 0000000..521da72 --- /dev/null +++ b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDebugSelectorValidation.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/DebugUtils/GTMDebugSelectorValidation.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDebugThreadValidation.h b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDebugThreadValidation.h new file mode 120000 index 0000000..de29ea1 --- /dev/null +++ b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDebugThreadValidation.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/DebugUtils/GTMDebugThreadValidation.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDefines.h b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDefines.h new file mode 120000 index 0000000..5503110 --- /dev/null +++ b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMDefines.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/GTMDefines.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMMethodCheck.h b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMMethodCheck.h new file mode 120000 index 0000000..56dfa7e --- /dev/null +++ b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMMethodCheck.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/DebugUtils/GTMMethodCheck.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMNSData+zlib.h b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMNSData+zlib.h new file mode 120000 index 0000000..9e72419 --- /dev/null +++ b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMNSData+zlib.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/Foundation/GTMNSData+zlib.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMNSDictionary+URLArguments.h b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMNSDictionary+URLArguments.h new file mode 120000 index 0000000..b2ff829 --- /dev/null +++ b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMNSDictionary+URLArguments.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/Foundation/GTMNSDictionary+URLArguments.h \ No newline at end of file diff --git a/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMNSString+URLArguments.h b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMNSString+URLArguments.h new file mode 120000 index 0000000..3b9b1a2 --- /dev/null +++ b/Task Master/Pods/Headers/Public/GoogleToolboxForMac/GTMNSString+URLArguments.h @@ -0,0 +1 @@ +../../../GoogleToolboxForMac/Foundation/GTMNSString+URLArguments.h \ No newline at end of file diff --git a/Task Master/Pods/Manifest.lock b/Task Master/Pods/Manifest.lock new file mode 100644 index 0000000..88a8631 --- /dev/null +++ b/Task Master/Pods/Manifest.lock @@ -0,0 +1,54 @@ +PODS: + - Firebase/Auth (3.16.0): + - Firebase/Core + - FirebaseAuth (= 3.1.1) + - Firebase/Core (3.16.0): + - FirebaseAnalytics (= 3.8.0) + - FirebaseCore (= 3.6.0) + - Firebase/Database (3.16.0): + - Firebase/Core + - FirebaseDatabase (= 3.1.2) + - FirebaseAnalytics (3.8.0): + - FirebaseCore (~> 3.6) + - FirebaseInstanceID (~> 1.0) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseAuth (3.1.1): + - FirebaseAnalytics (~> 3.7) + - GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1) + - GTMSessionFetcher/Core (~> 1.1) + - FirebaseCore (3.6.0): + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseDatabase (3.1.2): + - FirebaseAnalytics (~> 3.7) + - FirebaseInstanceID (1.0.10): + - FirebaseCore (~> 3.6) + - GoogleToolboxForMac/DebugUtils (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/Defines (2.1.1) + - GoogleToolboxForMac/NSData+zlib (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSDictionary+URLArguments (2.1.1): + - GoogleToolboxForMac/DebugUtils (= 2.1.1) + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (2.1.1) + - GTMSessionFetcher/Core (1.1.9) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Core + - Firebase/Database + +SPEC CHECKSUMS: + Firebase: 21bf4a89d3f01bfbe11adc3a5d934a4a3d3a5fd6 + FirebaseAnalytics: 920e46455f27b0a52a80907a6d9b73ee4bd1c635 + FirebaseAuth: cc8a1824170adbd351edb7f994490a3fb5c18be6 + FirebaseCore: 9691ee2ade70c098d7cf92440f4303f16d83ca75 + FirebaseDatabase: 05c96d7b43a7368dc91c07791adb49683e1738d1 + FirebaseInstanceID: b9eedd6846fb5e1f0f7279e1deaa7a7e4cf8392e + GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0 + GTMSessionFetcher: 5c046c76a1f859bc9c187e918f18e4fc7bb57b5e + +PODFILE CHECKSUM: 5dada07b8ffcd867f75f4115acd0e8c161a70c90 + +COCOAPODS: 1.2.1 diff --git a/Task Master/Pods/Pods.xcodeproj/project.pbxproj b/Task Master/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..4475fc2 --- /dev/null +++ b/Task Master/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,850 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0E6F2758E5743B053E54C51B0D236AF0 /* GTMSessionUploadFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 98F66488145FD3F532A107215A868B4C /* GTMSessionUploadFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1235AC549ED1B1EF40635602DCF8B4D5 /* GTMSessionFetcherLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 3377BF0710EAABFE6B0D1D2FC7AFD603 /* GTMSessionFetcherLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1B8714DF33ABD898CF49FAA1314DCF34 /* GTMSessionFetcherService.m in Sources */ = {isa = PBXBuildFile; fileRef = FD42D4FE60EC8139944392486999E88F /* GTMSessionFetcherService.m */; }; + 2089C7C2B78C35F067C3C93170D7F7B4 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C085E02FF89804F50ADDA04F5A586E94 /* Security.framework */; }; + 226B1BFF4E3FC473A1C88F2CFD77C9AF /* GTMDebugThreadValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = 16FAB65062FE9D2791D43873A90794D5 /* GTMDebugThreadValidation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 26BE741AD59EF185570AC9C853F44FAD /* GTMNSData+zlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CD4DC22744F41FEF11EEB8CB10E0007 /* GTMNSData+zlib.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3328D6AA0A6DD5371B63ECAD18718F3F /* GoogleToolboxForMac-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B4B87D80F6C1EBA9A3A85921DF1AD29 /* GoogleToolboxForMac-dummy.m */; }; + 476D901118FCE3506AF5ECEFC743403B /* GTMDebugSelectorValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = 233E0A3202A312BA2271BF50178E9C8C /* GTMDebugSelectorValidation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 49524DD7C80C2A517F6A1352B67A44E8 /* GTMNSString+URLArguments.m in Sources */ = {isa = PBXBuildFile; fileRef = 51669DDF21A5CDDF3E84C018A61CADBE /* GTMNSString+URLArguments.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 5E255A5B5203BE00C7B9E4D2E0D3BDC7 /* GTMMethodCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 95DECE4386E7AA2D8F377C3B417653C8 /* GTMMethodCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 67F79450D1729C70A35A3D4A58A88BB7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */; }; + 6C262944569C29D04DFA3C5F21494AAB /* GTMNSDictionary+URLArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = F34DEE8E03E3F74844FA62F23B053654 /* GTMNSDictionary+URLArguments.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9417B872ADCACCC4CFED22B51F5E05E0 /* GTMSessionFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 41623243289FEF60EAE87942A81775EF /* GTMSessionFetcher.m */; }; + 98C5F938C4C11CC1EB248AD794475E04 /* Pods-Task Master-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F3B24ED22504DFBA0A49537712904F6 /* Pods-Task Master-dummy.m */; }; + 9931FBF0D5CD16A87511F3EBD2302A5B /* GTMSessionFetcher-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D8F9EB8FDBBCE7E4E091A3E54A49C7D6 /* GTMSessionFetcher-dummy.m */; }; + 9EC3208101C0A4CE8E374B61F787355B /* GTMNSDictionary+URLArguments.m in Sources */ = {isa = PBXBuildFile; fileRef = 72360CB0553329CEEEEA01EA2FE50E5D /* GTMNSDictionary+URLArguments.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A46AF96BFE3E00583C3C2AB6C1322D7B /* GTMDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 3472068B1892D2F2A96A6D02F831D903 /* GTMDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B4B084A9C602985BE7858EA801AD4382 /* GTMSessionFetcherService.h in Headers */ = {isa = PBXBuildFile; fileRef = 2981E8356EBD64CEFFD1CD1AD8DBBEC8 /* GTMSessionFetcherService.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C9F3C20808CA9AD5C931B60A1D0FA461 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */; }; + CCD6DFBDC2C48307C8F478D690D4BD6A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */; }; + CF7E7B439D17C5FF57B2DBC7C03E10EF /* GTMSessionFetcherLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B8630F4C0DF774F600171FBCF2E7A31 /* GTMSessionFetcherLogging.m */; }; + E43766C39792FE24EFAF9291C5579176 /* GTMSessionUploadFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 71E94060769E8BF221554656591FF6B1 /* GTMSessionUploadFetcher.m */; }; + E84DEF53F8F01BAF747EB387654EC0AC /* GTMNSString+URLArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C7A741511BA88FDAE7A37F6017E52E7 /* GTMNSString+URLArguments.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E982A741CDD1A8CC804FC7F20E5C006F /* GTMSessionFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D99F88B88768ACBF0FA7CF05DC47611 /* GTMSessionFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EF7722D72FCA3A27E05EC9D4A716D5FD /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = CB6CD13971BD3EA8F35B148616C2A57D /* GTMNSData+zlib.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 5CC236650E5FD465A41D160E514F8E60 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 58E7450DB13C5ECCE92D3C0DF7CF0903; + remoteInfo = GoogleToolboxForMac; + }; + F8292744F9A4F7B0CC6D4F818AD9CA7A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = DE868725B18AE240E550C5515AE66BC4; + remoteInfo = GTMSessionFetcher; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 006786176BE95D0D239972D1E7693E79 /* Pods-Task Master-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Task Master-acknowledgements.plist"; sourceTree = ""; }; + 01429718C27A380964E42A42655048DF /* FirebaseInstanceID.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseInstanceID.framework; path = Frameworks/FirebaseInstanceID.framework; sourceTree = ""; }; + 05A7F88997BE7C68B81447E0C4AF1372 /* GoogleToolboxForMac.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleToolboxForMac.xcconfig; sourceTree = ""; }; + 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 15FC1941EF3F43CC7390243D68651DCD /* FirebaseCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseCore.framework; path = Frameworks/FirebaseCore.framework; sourceTree = ""; }; + 16FAB65062FE9D2791D43873A90794D5 /* GTMDebugThreadValidation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMDebugThreadValidation.h; path = DebugUtils/GTMDebugThreadValidation.h; sourceTree = ""; }; + 1CD4DC22744F41FEF11EEB8CB10E0007 /* GTMNSData+zlib.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GTMNSData+zlib.h"; path = "Foundation/GTMNSData+zlib.h"; sourceTree = ""; }; + 233E0A3202A312BA2271BF50178E9C8C /* GTMDebugSelectorValidation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMDebugSelectorValidation.h; path = DebugUtils/GTMDebugSelectorValidation.h; sourceTree = ""; }; + 2981E8356EBD64CEFFD1CD1AD8DBBEC8 /* GTMSessionFetcherService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherService.h; path = Source/GTMSessionFetcherService.h; sourceTree = ""; }; + 2E2928452C2DF1D6C544FAA3F58E1D48 /* libGTMSessionFetcher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libGTMSessionFetcher.a; path = libGTMSessionFetcher.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 306CEAB245E4106F94F053182FC27B59 /* FirebaseDatabase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseDatabase.framework; path = Frameworks/FirebaseDatabase.framework; sourceTree = ""; }; + 3377BF0710EAABFE6B0D1D2FC7AFD603 /* GTMSessionFetcherLogging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherLogging.h; path = Source/GTMSessionFetcherLogging.h; sourceTree = ""; }; + 3472068B1892D2F2A96A6D02F831D903 /* GTMDefines.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = GTMDefines.h; sourceTree = ""; }; + 3966403013FC02BF79A90DCCA4900984 /* Pods-Task Master.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Task Master.release.xcconfig"; sourceTree = ""; }; + 41623243289FEF60EAE87942A81775EF /* GTMSessionFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcher.m; path = Source/GTMSessionFetcher.m; sourceTree = ""; }; + 41BFEB07AB265B5818850BE386FEA53D /* FirebaseAnalytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseAnalytics.framework; path = Frameworks/FirebaseAnalytics.framework; sourceTree = ""; }; + 4D99F88B88768ACBF0FA7CF05DC47611 /* GTMSessionFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcher.h; path = Source/GTMSessionFetcher.h; sourceTree = ""; }; + 51669DDF21A5CDDF3E84C018A61CADBE /* GTMNSString+URLArguments.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GTMNSString+URLArguments.m"; path = "Foundation/GTMNSString+URLArguments.m"; sourceTree = ""; }; + 5B4B87D80F6C1EBA9A3A85921DF1AD29 /* GoogleToolboxForMac-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GoogleToolboxForMac-dummy.m"; sourceTree = ""; }; + 6A42CCEC85270D3AA8A425251F762CEF /* GTMSessionFetcher.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GTMSessionFetcher.xcconfig; sourceTree = ""; }; + 71E94060769E8BF221554656591FF6B1 /* GTMSessionUploadFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionUploadFetcher.m; path = Source/GTMSessionUploadFetcher.m; sourceTree = ""; }; + 72360CB0553329CEEEEA01EA2FE50E5D /* GTMNSDictionary+URLArguments.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GTMNSDictionary+URLArguments.m"; path = "Foundation/GTMNSDictionary+URLArguments.m"; sourceTree = ""; }; + 729772DADD32C2E0576A89CF11AC3B3E /* GoogleToolboxForMac-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GoogleToolboxForMac-prefix.pch"; sourceTree = ""; }; + 762FA705FCCD2B31C691DF1BD0594F3F /* Pods-Task Master-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Task Master-resources.sh"; sourceTree = ""; }; + 7B8630F4C0DF774F600171FBCF2E7A31 /* GTMSessionFetcherLogging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherLogging.m; path = Source/GTMSessionFetcherLogging.m; sourceTree = ""; }; + 7C7A741511BA88FDAE7A37F6017E52E7 /* GTMNSString+URLArguments.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GTMNSString+URLArguments.h"; path = "Foundation/GTMNSString+URLArguments.h"; sourceTree = ""; }; + 7F3B24ED22504DFBA0A49537712904F6 /* Pods-Task Master-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Task Master-dummy.m"; sourceTree = ""; }; + 7FCC08EAF84E1D055CD13F3836E8DDE4 /* Pods-Task Master-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Task Master-frameworks.sh"; sourceTree = ""; }; + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 95DECE4386E7AA2D8F377C3B417653C8 /* GTMMethodCheck.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMMethodCheck.h; path = DebugUtils/GTMMethodCheck.h; sourceTree = ""; }; + 98F66488145FD3F532A107215A868B4C /* GTMSessionUploadFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionUploadFetcher.h; path = Source/GTMSessionUploadFetcher.h; sourceTree = ""; }; + 9E0FEDCD4AB274B9139A253A6D518112 /* Pods-Task Master.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Task Master.debug.xcconfig"; sourceTree = ""; }; + A1D07A6EFA4EE579C07A60AD305FD47F /* Firebase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Firebase.h; path = Core/Sources/Firebase.h; sourceTree = ""; }; + C085E02FF89804F50ADDA04F5A586E94 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + C519B1E1782DBA1FF4D15FE520CF4A35 /* GTMSessionFetcher-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GTMSessionFetcher-prefix.pch"; sourceTree = ""; }; + CB6CD13971BD3EA8F35B148616C2A57D /* GTMNSData+zlib.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GTMNSData+zlib.m"; path = "Foundation/GTMNSData+zlib.m"; sourceTree = ""; }; + D18191A03A13815C433057AEFEA176F0 /* FirebaseAuth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FirebaseAuth.framework; path = Frameworks/FirebaseAuth.framework; sourceTree = ""; }; + D8F9EB8FDBBCE7E4E091A3E54A49C7D6 /* GTMSessionFetcher-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GTMSessionFetcher-dummy.m"; sourceTree = ""; }; + DCDB14E012A0F78243196D4BA948A24A /* libGoogleToolboxForMac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libGoogleToolboxForMac.a; path = libGoogleToolboxForMac.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F1CC7706AD2036332313B762C21FC86A /* Pods-Task Master-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Task Master-acknowledgements.markdown"; sourceTree = ""; }; + F34DEE8E03E3F74844FA62F23B053654 /* GTMNSDictionary+URLArguments.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GTMNSDictionary+URLArguments.h"; path = "Foundation/GTMNSDictionary+URLArguments.h"; sourceTree = ""; }; + F588AD05424983174F25B164ED8B782D /* libPods-Task Master.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libPods-Task Master.a"; path = "libPods-Task Master.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + FD42D4FE60EC8139944392486999E88F /* GTMSessionFetcherService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherService.m; path = Source/GTMSessionFetcherService.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7FC7E6D7E3148335DE0584C805D13772 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 67F79450D1729C70A35A3D4A58A88BB7 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D2BE8CE5663DF1EA1CF1CC5269C6067 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C9F3C20808CA9AD5C931B60A1D0FA461 /* Foundation.framework in Frameworks */, + 2089C7C2B78C35F067C3C93170D7F7B4 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E468DEE3816A9E9ED082166AC0F3EAAB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CCD6DFBDC2C48307C8F478D690D4BD6A /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 04EDBFA733238A8528C748FA2996DF02 /* FirebaseAnalytics */ = { + isa = PBXGroup; + children = ( + AF188A9850861DA424635D1EE7FAFBCA /* Frameworks */, + ); + name = FirebaseAnalytics; + path = FirebaseAnalytics; + sourceTree = ""; + }; + 06CDF80858197A2E120EF598FB8F6631 /* GoogleToolboxForMac */ = { + isa = PBXGroup; + children = ( + 888DBEDD006B88881DE74BBCE535E3EB /* DebugUtils */, + 39E7E2963A66BC3A5B3CC8110AE96008 /* Defines */, + 4602137C977615FD997FAEBC6B000BC9 /* NSData+zlib */, + 9F534E5B62E57B9A2FF3E007C0F94B7E /* NSDictionary+URLArguments */, + E4DDB595F9BAB65ED11A539EDB5EE529 /* NSString+URLArguments */, + 9088054B0A243CBF60D7CB432FA7D337 /* Support Files */, + ); + name = GoogleToolboxForMac; + path = GoogleToolboxForMac; + sourceTree = ""; + }; + 11DF9B270B3791EE068DD97A8A73F28A /* Support Files */ = { + isa = PBXGroup; + children = ( + 6A42CCEC85270D3AA8A425251F762CEF /* GTMSessionFetcher.xcconfig */, + D8F9EB8FDBBCE7E4E091A3E54A49C7D6 /* GTMSessionFetcher-dummy.m */, + C519B1E1782DBA1FF4D15FE520CF4A35 /* GTMSessionFetcher-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/GTMSessionFetcher"; + sourceTree = ""; + }; + 21AE49A2BD1638A73981AF95002D8B20 /* FirebaseDatabase */ = { + isa = PBXGroup; + children = ( + F91119FA42ADC8834926C316668B4959 /* Frameworks */, + ); + name = FirebaseDatabase; + path = FirebaseDatabase; + sourceTree = ""; + }; + 39E7E2963A66BC3A5B3CC8110AE96008 /* Defines */ = { + isa = PBXGroup; + children = ( + 3472068B1892D2F2A96A6D02F831D903 /* GTMDefines.h */, + ); + name = Defines; + sourceTree = ""; + }; + 3F655EF3F09E4676F524B208BB147068 /* Firebase */ = { + isa = PBXGroup; + children = ( + 977D589954AC2986C1DA6E30F631C3F6 /* Core */, + ); + name = Firebase; + path = Firebase; + sourceTree = ""; + }; + 433CD3331B6C3787F473C941B61FC68F /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4F990579C2E52276FD3C28227B49D60B /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + 4602137C977615FD997FAEBC6B000BC9 /* NSData+zlib */ = { + isa = PBXGroup; + children = ( + 1CD4DC22744F41FEF11EEB8CB10E0007 /* GTMNSData+zlib.h */, + CB6CD13971BD3EA8F35B148616C2A57D /* GTMNSData+zlib.m */, + ); + name = "NSData+zlib"; + sourceTree = ""; + }; + 4AAE49F71E8856578C4430191CC1ED3C /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + A111AF1E0E43326B0C6348C7298D6809 /* Pods-Task Master */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 4F990579C2E52276FD3C28227B49D60B /* iOS */ = { + isa = PBXGroup; + children = ( + 11C10A31CD5CFA3EFE266394471B152E /* Foundation.framework */, + C085E02FF89804F50ADDA04F5A586E94 /* Security.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 58C51D318451F31D95CF61E81761285D /* GTMSessionFetcher */ = { + isa = PBXGroup; + children = ( + 6180A8C059AF46F4798139E5A8BDA454 /* Core */, + 11DF9B270B3791EE068DD97A8A73F28A /* Support Files */, + ); + name = GTMSessionFetcher; + path = GTMSessionFetcher; + sourceTree = ""; + }; + 6180A8C059AF46F4798139E5A8BDA454 /* Core */ = { + isa = PBXGroup; + children = ( + 4D99F88B88768ACBF0FA7CF05DC47611 /* GTMSessionFetcher.h */, + 41623243289FEF60EAE87942A81775EF /* GTMSessionFetcher.m */, + 3377BF0710EAABFE6B0D1D2FC7AFD603 /* GTMSessionFetcherLogging.h */, + 7B8630F4C0DF774F600171FBCF2E7A31 /* GTMSessionFetcherLogging.m */, + 2981E8356EBD64CEFFD1CD1AD8DBBEC8 /* GTMSessionFetcherService.h */, + FD42D4FE60EC8139944392486999E88F /* GTMSessionFetcherService.m */, + 98F66488145FD3F532A107215A868B4C /* GTMSessionUploadFetcher.h */, + 71E94060769E8BF221554656591FF6B1 /* GTMSessionUploadFetcher.m */, + ); + name = Core; + sourceTree = ""; + }; + 6B74ACE89E2656BA4A5AD1C79C17CD7A /* FirebaseAuth */ = { + isa = PBXGroup; + children = ( + EB56BC83AECD86FC8FED0152F63AD2A9 /* Frameworks */, + ); + name = FirebaseAuth; + path = FirebaseAuth; + sourceTree = ""; + }; + 7976B93F1465642AAE6546AA0A456CBE /* Products */ = { + isa = PBXGroup; + children = ( + DCDB14E012A0F78243196D4BA948A24A /* libGoogleToolboxForMac.a */, + 2E2928452C2DF1D6C544FAA3F58E1D48 /* libGTMSessionFetcher.a */, + F588AD05424983174F25B164ED8B782D /* libPods-Task Master.a */, + ); + name = Products; + sourceTree = ""; + }; + 7DB346D0F39D3F0E887471402A8071AB = { + isa = PBXGroup; + children = ( + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */, + 433CD3331B6C3787F473C941B61FC68F /* Frameworks */, + E5D76B11EDE5735CB662AE0A758AC33D /* Pods */, + 7976B93F1465642AAE6546AA0A456CBE /* Products */, + 4AAE49F71E8856578C4430191CC1ED3C /* Targets Support Files */, + ); + sourceTree = ""; + }; + 888DBEDD006B88881DE74BBCE535E3EB /* DebugUtils */ = { + isa = PBXGroup; + children = ( + 233E0A3202A312BA2271BF50178E9C8C /* GTMDebugSelectorValidation.h */, + 16FAB65062FE9D2791D43873A90794D5 /* GTMDebugThreadValidation.h */, + 95DECE4386E7AA2D8F377C3B417653C8 /* GTMMethodCheck.h */, + ); + name = DebugUtils; + sourceTree = ""; + }; + 9088054B0A243CBF60D7CB432FA7D337 /* Support Files */ = { + isa = PBXGroup; + children = ( + 05A7F88997BE7C68B81447E0C4AF1372 /* GoogleToolboxForMac.xcconfig */, + 5B4B87D80F6C1EBA9A3A85921DF1AD29 /* GoogleToolboxForMac-dummy.m */, + 729772DADD32C2E0576A89CF11AC3B3E /* GoogleToolboxForMac-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/GoogleToolboxForMac"; + sourceTree = ""; + }; + 977D589954AC2986C1DA6E30F631C3F6 /* Core */ = { + isa = PBXGroup; + children = ( + A1D07A6EFA4EE579C07A60AD305FD47F /* Firebase.h */, + ); + name = Core; + sourceTree = ""; + }; + 9F534E5B62E57B9A2FF3E007C0F94B7E /* NSDictionary+URLArguments */ = { + isa = PBXGroup; + children = ( + F34DEE8E03E3F74844FA62F23B053654 /* GTMNSDictionary+URLArguments.h */, + 72360CB0553329CEEEEA01EA2FE50E5D /* GTMNSDictionary+URLArguments.m */, + ); + name = "NSDictionary+URLArguments"; + sourceTree = ""; + }; + A111AF1E0E43326B0C6348C7298D6809 /* Pods-Task Master */ = { + isa = PBXGroup; + children = ( + F1CC7706AD2036332313B762C21FC86A /* Pods-Task Master-acknowledgements.markdown */, + 006786176BE95D0D239972D1E7693E79 /* Pods-Task Master-acknowledgements.plist */, + 7F3B24ED22504DFBA0A49537712904F6 /* Pods-Task Master-dummy.m */, + 7FCC08EAF84E1D055CD13F3836E8DDE4 /* Pods-Task Master-frameworks.sh */, + 762FA705FCCD2B31C691DF1BD0594F3F /* Pods-Task Master-resources.sh */, + 9E0FEDCD4AB274B9139A253A6D518112 /* Pods-Task Master.debug.xcconfig */, + 3966403013FC02BF79A90DCCA4900984 /* Pods-Task Master.release.xcconfig */, + ); + name = "Pods-Task Master"; + path = "Target Support Files/Pods-Task Master"; + sourceTree = ""; + }; + AF188A9850861DA424635D1EE7FAFBCA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 41BFEB07AB265B5818850BE386FEA53D /* FirebaseAnalytics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + B50125EE8FF7840604CC60A8FA003802 /* FirebaseCore */ = { + isa = PBXGroup; + children = ( + F15C372593DA1BD68A682B254A53EAB4 /* Frameworks */, + ); + name = FirebaseCore; + path = FirebaseCore; + sourceTree = ""; + }; + E4DDB595F9BAB65ED11A539EDB5EE529 /* NSString+URLArguments */ = { + isa = PBXGroup; + children = ( + 7C7A741511BA88FDAE7A37F6017E52E7 /* GTMNSString+URLArguments.h */, + 51669DDF21A5CDDF3E84C018A61CADBE /* GTMNSString+URLArguments.m */, + ); + name = "NSString+URLArguments"; + sourceTree = ""; + }; + E5D76B11EDE5735CB662AE0A758AC33D /* Pods */ = { + isa = PBXGroup; + children = ( + 3F655EF3F09E4676F524B208BB147068 /* Firebase */, + 04EDBFA733238A8528C748FA2996DF02 /* FirebaseAnalytics */, + 6B74ACE89E2656BA4A5AD1C79C17CD7A /* FirebaseAuth */, + B50125EE8FF7840604CC60A8FA003802 /* FirebaseCore */, + 21AE49A2BD1638A73981AF95002D8B20 /* FirebaseDatabase */, + EC420F71251403C4D20481EB729717F5 /* FirebaseInstanceID */, + 06CDF80858197A2E120EF598FB8F6631 /* GoogleToolboxForMac */, + 58C51D318451F31D95CF61E81761285D /* GTMSessionFetcher */, + ); + name = Pods; + sourceTree = ""; + }; + EB56BC83AECD86FC8FED0152F63AD2A9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D18191A03A13815C433057AEFEA176F0 /* FirebaseAuth.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + EC420F71251403C4D20481EB729717F5 /* FirebaseInstanceID */ = { + isa = PBXGroup; + children = ( + F1527620709CCA623AC78EAA1D11C32A /* Frameworks */, + ); + name = FirebaseInstanceID; + path = FirebaseInstanceID; + sourceTree = ""; + }; + F1527620709CCA623AC78EAA1D11C32A /* Frameworks */ = { + isa = PBXGroup; + children = ( + 01429718C27A380964E42A42655048DF /* FirebaseInstanceID.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + F15C372593DA1BD68A682B254A53EAB4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 15FC1941EF3F43CC7390243D68651DCD /* FirebaseCore.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + F91119FA42ADC8834926C316668B4959 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 306CEAB245E4106F94F053182FC27B59 /* FirebaseDatabase.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 0CBA5A14986DAE7D6A473749221AA81F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 476D901118FCE3506AF5ECEFC743403B /* GTMDebugSelectorValidation.h in Headers */, + 226B1BFF4E3FC473A1C88F2CFD77C9AF /* GTMDebugThreadValidation.h in Headers */, + A46AF96BFE3E00583C3C2AB6C1322D7B /* GTMDefines.h in Headers */, + 5E255A5B5203BE00C7B9E4D2E0D3BDC7 /* GTMMethodCheck.h in Headers */, + 26BE741AD59EF185570AC9C853F44FAD /* GTMNSData+zlib.h in Headers */, + 6C262944569C29D04DFA3C5F21494AAB /* GTMNSDictionary+URLArguments.h in Headers */, + E84DEF53F8F01BAF747EB387654EC0AC /* GTMNSString+URLArguments.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A922FE66E6DEA4BD3090DCEB4580F34E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E982A741CDD1A8CC804FC7F20E5C006F /* GTMSessionFetcher.h in Headers */, + 1235AC549ED1B1EF40635602DCF8B4D5 /* GTMSessionFetcherLogging.h in Headers */, + B4B084A9C602985BE7858EA801AD4382 /* GTMSessionFetcherService.h in Headers */, + 0E6F2758E5743B053E54C51B0D236AF0 /* GTMSessionUploadFetcher.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 58E7450DB13C5ECCE92D3C0DF7CF0903 /* GoogleToolboxForMac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 26AE791F404F3732C3335D0EFE25E20A /* Build configuration list for PBXNativeTarget "GoogleToolboxForMac" */; + buildPhases = ( + F86A0216D6948A1D34655DBC29C561FC /* Sources */, + E468DEE3816A9E9ED082166AC0F3EAAB /* Frameworks */, + 0CBA5A14986DAE7D6A473749221AA81F /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GoogleToolboxForMac; + productName = GoogleToolboxForMac; + productReference = DCDB14E012A0F78243196D4BA948A24A /* libGoogleToolboxForMac.a */; + productType = "com.apple.product-type.library.static"; + }; + C44F9D7F542EE4E0C1B1843AF9785ECD /* Pods-Task Master */ = { + isa = PBXNativeTarget; + buildConfigurationList = DD42384FADA14C116A51AAFDFA2AC68F /* Build configuration list for PBXNativeTarget "Pods-Task Master" */; + buildPhases = ( + 34E8A10479E5D87698558C55946D8960 /* Sources */, + 7FC7E6D7E3148335DE0584C805D13772 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 633B223EE36F02D1970D5FB09A34CED0 /* PBXTargetDependency */, + A0DA7493AC88070F6A61B37DE0586240 /* PBXTargetDependency */, + ); + name = "Pods-Task Master"; + productName = "Pods-Task Master"; + productReference = F588AD05424983174F25B164ED8B782D /* libPods-Task Master.a */; + productType = "com.apple.product-type.library.static"; + }; + DE868725B18AE240E550C5515AE66BC4 /* GTMSessionFetcher */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4693C211CA1C7318A8B388F1C2D24725 /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */; + buildPhases = ( + 34191111C8E6A7E0C8B7499BA636A66A /* Sources */, + 8D2BE8CE5663DF1EA1CF1CC5269C6067 /* Frameworks */, + A922FE66E6DEA4BD3090DCEB4580F34E /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GTMSessionFetcher; + productName = GTMSessionFetcher; + productReference = 2E2928452C2DF1D6C544FAA3F58E1D48 /* libGTMSessionFetcher.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 0700; + }; + buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 7DB346D0F39D3F0E887471402A8071AB; + productRefGroup = 7976B93F1465642AAE6546AA0A456CBE /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 58E7450DB13C5ECCE92D3C0DF7CF0903 /* GoogleToolboxForMac */, + DE868725B18AE240E550C5515AE66BC4 /* GTMSessionFetcher */, + C44F9D7F542EE4E0C1B1843AF9785ECD /* Pods-Task Master */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 34191111C8E6A7E0C8B7499BA636A66A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9931FBF0D5CD16A87511F3EBD2302A5B /* GTMSessionFetcher-dummy.m in Sources */, + 9417B872ADCACCC4CFED22B51F5E05E0 /* GTMSessionFetcher.m in Sources */, + CF7E7B439D17C5FF57B2DBC7C03E10EF /* GTMSessionFetcherLogging.m in Sources */, + 1B8714DF33ABD898CF49FAA1314DCF34 /* GTMSessionFetcherService.m in Sources */, + E43766C39792FE24EFAF9291C5579176 /* GTMSessionUploadFetcher.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 34E8A10479E5D87698558C55946D8960 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 98C5F938C4C11CC1EB248AD794475E04 /* Pods-Task Master-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F86A0216D6948A1D34655DBC29C561FC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3328D6AA0A6DD5371B63ECAD18718F3F /* GoogleToolboxForMac-dummy.m in Sources */, + EF7722D72FCA3A27E05EC9D4A716D5FD /* GTMNSData+zlib.m in Sources */, + 9EC3208101C0A4CE8E374B61F787355B /* GTMNSDictionary+URLArguments.m in Sources */, + 49524DD7C80C2A517F6A1352B67A44E8 /* GTMNSString+URLArguments.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 633B223EE36F02D1970D5FB09A34CED0 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GTMSessionFetcher; + target = DE868725B18AE240E550C5515AE66BC4 /* GTMSessionFetcher */; + targetProxy = F8292744F9A4F7B0CC6D4F818AD9CA7A /* PBXContainerItemProxy */; + }; + A0DA7493AC88070F6A61B37DE0586240 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleToolboxForMac; + target = 58E7450DB13C5ECCE92D3C0DF7CF0903 /* GoogleToolboxForMac */; + targetProxy = 5CC236650E5FD465A41D160E514F8E60 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 163D87BE96A63549B0EACF1CC31A2E90 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + 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_OBJC_ROOT_CLASS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_REQUIRED = NO; + COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + ONLY_ACTIVE_ARCH = YES; + PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 1C4C51E0FB5471F2E95F17A5E250CF16 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3966403013FC02BF79A90DCCA4900984 /* Pods-Task Master.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MACH_O_TYPE = staticlib; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 2F5F5B61233D182FE923F37462D6E73B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 05A7F88997BE7C68B81447E0C4AF1372 /* GoogleToolboxForMac.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 3E15E1221F5F51D737D557DF33F26CE7 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 05A7F88997BE7C68B81447E0C4AF1372 /* GoogleToolboxForMac.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 6089EF5AAE5528CF09E8655B284A438E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6A42CCEC85270D3AA8A425251F762CEF /* GTMSessionFetcher.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 707B86CFB21B645E37109F39754D4051 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + 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_OBJC_ROOT_CLASS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_REQUIRED = NO; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 85750C6A2D9EFD780B5CD014850783CA /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6A42CCEC85270D3AA8A425251F762CEF /* GTMSessionFetcher.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + A7C0322D3FF9360E8DD8262388E2AE0C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9E0FEDCD4AB274B9139A253A6D518112 /* Pods-Task Master.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MACH_O_TYPE = staticlib; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 26AE791F404F3732C3335D0EFE25E20A /* Build configuration list for PBXNativeTarget "GoogleToolboxForMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3E15E1221F5F51D737D557DF33F26CE7 /* Debug */, + 2F5F5B61233D182FE923F37462D6E73B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 163D87BE96A63549B0EACF1CC31A2E90 /* Debug */, + 707B86CFB21B645E37109F39754D4051 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4693C211CA1C7318A8B388F1C2D24725 /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 85750C6A2D9EFD780B5CD014850783CA /* Debug */, + 6089EF5AAE5528CF09E8655B284A438E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DD42384FADA14C116A51AAFDFA2AC68F /* Build configuration list for PBXNativeTarget "Pods-Task Master" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A7C0322D3FF9360E8DD8262388E2AE0C /* Debug */, + 1C4C51E0FB5471F2E95F17A5E250CF16 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; +} diff --git a/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme b/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme new file mode 100644 index 0000000..8aa99fc --- /dev/null +++ b/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme b/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme new file mode 100644 index 0000000..43f1ae2 --- /dev/null +++ b/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/GoogleToolboxForMac.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Master.xcscheme b/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Master.xcscheme new file mode 100644 index 0000000..281de9b --- /dev/null +++ b/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Pods-Task Master.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist b/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..72b11a6 --- /dev/null +++ b/Task Master/Pods/Pods.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,42 @@ + + + + + SchemeUserState + + GTMSessionFetcher.xcscheme + + isShown + + + GoogleToolboxForMac.xcscheme + + isShown + + + Pods-Task Master.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + 58E7450DB13C5ECCE92D3C0DF7CF0903 + + primary + + + C44F9D7F542EE4E0C1B1843AF9785ECD + + primary + + + DE868725B18AE240E550C5515AE66BC4 + + primary + + + + + diff --git a/Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m b/Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m new file mode 100644 index 0000000..13d68b3 --- /dev/null +++ b/Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GTMSessionFetcher : NSObject +@end +@implementation PodsDummy_GTMSessionFetcher +@end diff --git a/Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch b/Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-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/Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig b/Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig new file mode 100644 index 0000000..88fb1dd --- /dev/null +++ b/Task Master/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = -framework "Security" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GTMSessionFetcher +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES diff --git a/Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-dummy.m b/Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-dummy.m new file mode 100644 index 0000000..9e35ec0 --- /dev/null +++ b/Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GoogleToolboxForMac : NSObject +@end +@implementation PodsDummy_GoogleToolboxForMac +@end diff --git a/Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch b/Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac-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/Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.xcconfig b/Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.xcconfig new file mode 100644 index 0000000..eae9e52 --- /dev/null +++ b/Task Master/Pods/Target Support Files/GoogleToolboxForMac/GoogleToolboxForMac.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/GoogleToolboxForMac" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = -l"z" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleToolboxForMac +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES diff --git a/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.markdown b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.markdown new file mode 100644 index 0000000..59d725a --- /dev/null +++ b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.markdown @@ -0,0 +1,439 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## Firebase + +Copyright 2017 Google + +## FirebaseAnalytics + +Copyright 2017 Google + +## FirebaseAuth + +Copyright 2017 Google + +## FirebaseCore + +Copyright 2017 Google + +## FirebaseDatabase + +Copyright 2017 Google + +## FirebaseInstanceID + +Copyright 2017 Google + +## GTMSessionFetcher + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## GoogleToolboxForMac + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Generated by CocoaPods - https://cocoapods.org diff --git a/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.plist b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.plist new file mode 100644 index 0000000..3a210a5 --- /dev/null +++ b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-acknowledgements.plist @@ -0,0 +1,513 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + Firebase + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseAnalytics + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseAuth + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseCore + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseDatabase + Type + PSGroupSpecifier + + + FooterText + Copyright 2017 Google + License + Copyright + Title + FirebaseInstanceID + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + GTMSessionFetcher + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + GoogleToolboxForMac + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-dummy.m b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-dummy.m new file mode 100644 index 0000000..d8a8d9b --- /dev/null +++ b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_Task_Master : NSObject +@end +@implementation PodsDummy_Pods_Task_Master +@end diff --git a/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh new file mode 100755 index 0000000..0f29f13 --- /dev/null +++ b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh @@ -0,0 +1,92 @@ +#!/bin/sh +set -e + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +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 dont' throw errors + echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync -av --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}" + 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 && exit ${PIPESTATUS[0]}) + 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 +} + +# 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_identitiy + 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 file + archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" + stripped="" + for arch in $archs; do + if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" || exit 1 + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi +} + +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh new file mode 100755 index 0000000..aed060f --- /dev/null +++ b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh @@ -0,0 +1,102 @@ +#!/bin/sh +set -e + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +case "${TARGETED_DEVICE_FAMILY}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + 3) + TARGET_DEVICE_ARGS="--target-device tv" + ;; + 4) + TARGET_DEVICE_ARGS="--target-device watch" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; +esac + +install_resource() +{ + if [[ "$1" = /* ]] ; then + RESOURCE_PATH="$1" + else + RESOURCE_PATH="${PODS_ROOT}/$1" + fi + if [[ ! -e "$RESOURCE_PATH" ]] ; then + cat << EOM +error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. +EOM + exit 1 + fi + case $RESOURCE_PATH in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.framework) + echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" + xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + *) + echo "$RESOURCE_PATH" + echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" + ;; + esac +} + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] +then + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "${PODS_ROOT}*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi diff --git a/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig new file mode 100644 index 0000000..5c8571b --- /dev/null +++ b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig @@ -0,0 +1,10 @@ +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/FirebaseAuth/Frameworks" "${PODS_ROOT}/FirebaseCore/Frameworks" "${PODS_ROOT}/FirebaseDatabase/Frameworks" "${PODS_ROOT}/FirebaseInstanceID/Frameworks" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) ${PODS_ROOT}/Firebase/Core/Sources $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher" "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Firebase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAuth" -isystem "${PODS_ROOT}/Headers/Public/FirebaseCore" -isystem "${PODS_ROOT}/Headers/Public/FirebaseDatabase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" -isystem "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" -isystem "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = $(inherited) -ObjC -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"c++" -l"icucore" -l"sqlite3" -l"z" -framework "CFNetwork" -framework "FirebaseAnalytics" -framework "FirebaseAuth" -framework "FirebaseCore" -framework "FirebaseDatabase" -framework "FirebaseInstanceID" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" +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 diff --git a/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig new file mode 100644 index 0000000..5c8571b --- /dev/null +++ b/Task Master/Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig @@ -0,0 +1,10 @@ +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/FirebaseAuth/Frameworks" "${PODS_ROOT}/FirebaseCore/Frameworks" "${PODS_ROOT}/FirebaseDatabase/Frameworks" "${PODS_ROOT}/FirebaseInstanceID/Frameworks" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) ${PODS_ROOT}/Firebase/Core/Sources $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" "${PODS_ROOT}/Headers/Public/FirebaseAuth" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseDatabase" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/GTMSessionFetcher" "$PODS_CONFIGURATION_BUILD_DIR/GoogleToolboxForMac" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Firebase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAnalytics" -isystem "${PODS_ROOT}/Headers/Public/FirebaseAuth" -isystem "${PODS_ROOT}/Headers/Public/FirebaseCore" -isystem "${PODS_ROOT}/Headers/Public/FirebaseDatabase" -isystem "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" -isystem "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" -isystem "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" +OTHER_LDFLAGS = $(inherited) -ObjC -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"c++" -l"icucore" -l"sqlite3" -l"z" -framework "CFNetwork" -framework "FirebaseAnalytics" -framework "FirebaseAuth" -framework "FirebaseCore" -framework "FirebaseDatabase" -framework "FirebaseInstanceID" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" +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 diff --git a/Task Master/Task Master.xcodeproj/project.pbxproj b/Task Master/Task Master.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a4d3b78 --- /dev/null +++ b/Task Master/Task Master.xcodeproj/project.pbxproj @@ -0,0 +1,680 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5F1A74751EB6A0AD00F45DE6 /* Alerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A746A1EB6A0AD00F45DE6 /* Alerts.swift */; }; + 5F1A74761EB6A0AD00F45DE6 /* OnBoardingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A746B1EB6A0AD00F45DE6 /* OnBoardingController.swift */; }; + 5F1A74771EB6A0AD00F45DE6 /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A746C1EB6A0AD00F45DE6 /* Task.swift */; }; + 5F1A74781EB6A0AD00F45DE6 /* TasksCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A746D1EB6A0AD00F45DE6 /* TasksCell.swift */; }; + 5F1A74791EB6A0AD00F45DE6 /* TasksTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A746E1EB6A0AD00F45DE6 /* TasksTable.swift */; }; + 5F1A747A1EB6A0AD00F45DE6 /* TaskView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A746F1EB6A0AD00F45DE6 /* TaskView.swift */; }; + 5F1A747B1EB6A0AD00F45DE6 /* UserViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A74701EB6A0AD00F45DE6 /* UserViews.swift */; }; + 5F1A747C1EB6A0AD00F45DE6 /* ViewControllers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A74711EB6A0AD00F45DE6 /* ViewControllers.swift */; }; + 5F1A747D1EB6A0AD00F45DE6 /* WelcomeScreenOne.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A74721EB6A0AD00F45DE6 /* WelcomeScreenOne.swift */; }; + 5F1A747E1EB6A0AD00F45DE6 /* WelcomeScreenThree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A74731EB6A0AD00F45DE6 /* WelcomeScreenThree.swift */; }; + 5F1A747F1EB6A0AD00F45DE6 /* WelcomeScreenTwo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1A74741EB6A0AD00F45DE6 /* WelcomeScreenTwo.swift */; }; + 5F1A74811EB6A38B00F45DE6 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5F1A74801EB6A38B00F45DE6 /* GoogleService-Info.plist */; }; + 5F88A9AA1EB69A9A0069EE0A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F88A9A91EB69A9A0069EE0A /* AppDelegate.swift */; }; + 5F88A9AF1EB69A9A0069EE0A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F88A9AD1EB69A9A0069EE0A /* Main.storyboard */; }; + 5F88A9B21EB69A9A0069EE0A /* Task_Master.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 5F88A9B01EB69A9A0069EE0A /* Task_Master.xcdatamodeld */; }; + 5F88A9B41EB69A9A0069EE0A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5F88A9B31EB69A9A0069EE0A /* Assets.xcassets */; }; + 5F88A9B71EB69A9A0069EE0A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F88A9B51EB69A9A0069EE0A /* LaunchScreen.storyboard */; }; + 5F88A9C21EB69A9A0069EE0A /* Task_MasterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F88A9C11EB69A9A0069EE0A /* Task_MasterTests.swift */; }; + 5F88A9CD1EB69A9A0069EE0A /* Task_MasterUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F88A9CC1EB69A9A0069EE0A /* Task_MasterUITests.swift */; }; + 69D51F73DD68CDAA256254B7 /* libPods-Task Master.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFA65F54703318AA09B28C5E /* libPods-Task Master.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 5F88A9BE1EB69A9A0069EE0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5F88A99E1EB69A990069EE0A /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5F88A9A51EB69A9A0069EE0A; + remoteInfo = "Task Master"; + }; + 5F88A9C91EB69A9A0069EE0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5F88A99E1EB69A990069EE0A /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5F88A9A51EB69A9A0069EE0A; + remoteInfo = "Task Master"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 2B11D727CB348DF742B752AE /* Pods-Task Master.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Task Master.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Task Master/Pods-Task Master.debug.xcconfig"; sourceTree = ""; }; + 5F1A74691EB6A0AD00F45DE6 /* BridgingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = ""; }; + 5F1A746A1EB6A0AD00F45DE6 /* Alerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Alerts.swift; sourceTree = ""; }; + 5F1A746B1EB6A0AD00F45DE6 /* OnBoardingController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnBoardingController.swift; sourceTree = ""; }; + 5F1A746C1EB6A0AD00F45DE6 /* Task.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Task.swift; sourceTree = ""; }; + 5F1A746D1EB6A0AD00F45DE6 /* TasksCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TasksCell.swift; sourceTree = ""; }; + 5F1A746E1EB6A0AD00F45DE6 /* TasksTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TasksTable.swift; sourceTree = ""; }; + 5F1A746F1EB6A0AD00F45DE6 /* TaskView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TaskView.swift; sourceTree = ""; }; + 5F1A74701EB6A0AD00F45DE6 /* UserViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserViews.swift; sourceTree = ""; }; + 5F1A74711EB6A0AD00F45DE6 /* ViewControllers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewControllers.swift; sourceTree = ""; }; + 5F1A74721EB6A0AD00F45DE6 /* WelcomeScreenOne.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeScreenOne.swift; sourceTree = ""; }; + 5F1A74731EB6A0AD00F45DE6 /* WelcomeScreenThree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeScreenThree.swift; sourceTree = ""; }; + 5F1A74741EB6A0AD00F45DE6 /* WelcomeScreenTwo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeScreenTwo.swift; sourceTree = ""; }; + 5F1A74801EB6A38B00F45DE6 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 5F88A9A61EB69A9A0069EE0A /* Task Master.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Task Master.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F88A9A91EB69A9A0069EE0A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 5F88A9AE1EB69A9A0069EE0A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5F88A9B11EB69A9A0069EE0A /* Task_Master.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Task_Master.xcdatamodel; sourceTree = ""; }; + 5F88A9B31EB69A9A0069EE0A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5F88A9B61EB69A9A0069EE0A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5F88A9B81EB69A9A0069EE0A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5F88A9BD1EB69A9A0069EE0A /* Task MasterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Task MasterTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F88A9C11EB69A9A0069EE0A /* Task_MasterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Task_MasterTests.swift; sourceTree = ""; }; + 5F88A9C31EB69A9A0069EE0A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5F88A9C81EB69A9A0069EE0A /* Task MasterUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Task MasterUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F88A9CC1EB69A9A0069EE0A /* Task_MasterUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Task_MasterUITests.swift; sourceTree = ""; }; + 5F88A9CE1EB69A9A0069EE0A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 982A7A363F80F47C6369C63E /* Pods-Task Master.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Task Master.release.xcconfig"; path = "Pods/Target Support Files/Pods-Task Master/Pods-Task Master.release.xcconfig"; sourceTree = ""; }; + BFA65F54703318AA09B28C5E /* libPods-Task Master.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Task Master.a"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5F88A9A31EB69A9A0069EE0A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 69D51F73DD68CDAA256254B7 /* libPods-Task Master.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F88A9BA1EB69A9A0069EE0A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F88A9C51EB69A9A0069EE0A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5F88A99D1EB69A990069EE0A = { + isa = PBXGroup; + children = ( + 5F88A9A81EB69A9A0069EE0A /* Task Master */, + 5F88A9C01EB69A9A0069EE0A /* Task MasterTests */, + 5F88A9CB1EB69A9A0069EE0A /* Task MasterUITests */, + 5F88A9A71EB69A9A0069EE0A /* Products */, + 70900A63B8EB85C202932793 /* Pods */, + 995740628E70EC81DC40A6B5 /* Frameworks */, + ); + sourceTree = ""; + }; + 5F88A9A71EB69A9A0069EE0A /* Products */ = { + isa = PBXGroup; + children = ( + 5F88A9A61EB69A9A0069EE0A /* Task Master.app */, + 5F88A9BD1EB69A9A0069EE0A /* Task MasterTests.xctest */, + 5F88A9C81EB69A9A0069EE0A /* Task MasterUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 5F88A9A81EB69A9A0069EE0A /* Task Master */ = { + isa = PBXGroup; + children = ( + 5F88A9A91EB69A9A0069EE0A /* AppDelegate.swift */, + 5F88A9AD1EB69A9A0069EE0A /* Main.storyboard */, + 5F88A9B31EB69A9A0069EE0A /* Assets.xcassets */, + 5F88A9B51EB69A9A0069EE0A /* LaunchScreen.storyboard */, + 5F1A74691EB6A0AD00F45DE6 /* BridgingHeader.h */, + 5F1A746A1EB6A0AD00F45DE6 /* Alerts.swift */, + 5F1A746B1EB6A0AD00F45DE6 /* OnBoardingController.swift */, + 5F1A746C1EB6A0AD00F45DE6 /* Task.swift */, + 5F1A74801EB6A38B00F45DE6 /* GoogleService-Info.plist */, + 5F1A746D1EB6A0AD00F45DE6 /* TasksCell.swift */, + 5F1A746E1EB6A0AD00F45DE6 /* TasksTable.swift */, + 5F1A746F1EB6A0AD00F45DE6 /* TaskView.swift */, + 5F1A74701EB6A0AD00F45DE6 /* UserViews.swift */, + 5F1A74711EB6A0AD00F45DE6 /* ViewControllers.swift */, + 5F1A74721EB6A0AD00F45DE6 /* WelcomeScreenOne.swift */, + 5F1A74731EB6A0AD00F45DE6 /* WelcomeScreenThree.swift */, + 5F1A74741EB6A0AD00F45DE6 /* WelcomeScreenTwo.swift */, + 5F88A9B81EB69A9A0069EE0A /* Info.plist */, + 5F88A9B01EB69A9A0069EE0A /* Task_Master.xcdatamodeld */, + ); + path = "Task Master"; + sourceTree = ""; + }; + 5F88A9C01EB69A9A0069EE0A /* Task MasterTests */ = { + isa = PBXGroup; + children = ( + 5F88A9C11EB69A9A0069EE0A /* Task_MasterTests.swift */, + 5F88A9C31EB69A9A0069EE0A /* Info.plist */, + ); + path = "Task MasterTests"; + sourceTree = ""; + }; + 5F88A9CB1EB69A9A0069EE0A /* Task MasterUITests */ = { + isa = PBXGroup; + children = ( + 5F88A9CC1EB69A9A0069EE0A /* Task_MasterUITests.swift */, + 5F88A9CE1EB69A9A0069EE0A /* Info.plist */, + ); + path = "Task MasterUITests"; + sourceTree = ""; + }; + 70900A63B8EB85C202932793 /* Pods */ = { + isa = PBXGroup; + children = ( + 2B11D727CB348DF742B752AE /* Pods-Task Master.debug.xcconfig */, + 982A7A363F80F47C6369C63E /* Pods-Task Master.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 995740628E70EC81DC40A6B5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + BFA65F54703318AA09B28C5E /* libPods-Task Master.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5F88A9A51EB69A9A0069EE0A /* Task Master */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F88A9D11EB69A9A0069EE0A /* Build configuration list for PBXNativeTarget "Task Master" */; + buildPhases = ( + 3DBC5137AFD97F2620268536 /* [CP] Check Pods Manifest.lock */, + 5F88A9A21EB69A9A0069EE0A /* Sources */, + 5F88A9A31EB69A9A0069EE0A /* Frameworks */, + 5F88A9A41EB69A9A0069EE0A /* Resources */, + 6257E5C88D9D7384E5659916 /* [CP] Embed Pods Frameworks */, + 45A11A56D15C27B1C2F59D43 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Task Master"; + productName = "Task Master"; + productReference = 5F88A9A61EB69A9A0069EE0A /* Task Master.app */; + productType = "com.apple.product-type.application"; + }; + 5F88A9BC1EB69A9A0069EE0A /* Task MasterTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F88A9D41EB69A9A0069EE0A /* Build configuration list for PBXNativeTarget "Task MasterTests" */; + buildPhases = ( + 5F88A9B91EB69A9A0069EE0A /* Sources */, + 5F88A9BA1EB69A9A0069EE0A /* Frameworks */, + 5F88A9BB1EB69A9A0069EE0A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5F88A9BF1EB69A9A0069EE0A /* PBXTargetDependency */, + ); + name = "Task MasterTests"; + productName = "Task MasterTests"; + productReference = 5F88A9BD1EB69A9A0069EE0A /* Task MasterTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 5F88A9C71EB69A9A0069EE0A /* Task MasterUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F88A9D71EB69A9A0069EE0A /* Build configuration list for PBXNativeTarget "Task MasterUITests" */; + buildPhases = ( + 5F88A9C41EB69A9A0069EE0A /* Sources */, + 5F88A9C51EB69A9A0069EE0A /* Frameworks */, + 5F88A9C61EB69A9A0069EE0A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5F88A9CA1EB69A9A0069EE0A /* PBXTargetDependency */, + ); + name = "Task MasterUITests"; + productName = "Task MasterUITests"; + productReference = 5F88A9C81EB69A9A0069EE0A /* Task MasterUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5F88A99E1EB69A990069EE0A /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 0830; + ORGANIZATIONNAME = "Alexander Davis"; + TargetAttributes = { + 5F88A9A51EB69A9A0069EE0A = { + CreatedOnToolsVersion = 8.3.2; + DevelopmentTeam = 28CC8SCVUN; + ProvisioningStyle = Automatic; + }; + 5F88A9BC1EB69A9A0069EE0A = { + CreatedOnToolsVersion = 8.3.2; + DevelopmentTeam = 28CC8SCVUN; + ProvisioningStyle = Automatic; + TestTargetID = 5F88A9A51EB69A9A0069EE0A; + }; + 5F88A9C71EB69A9A0069EE0A = { + CreatedOnToolsVersion = 8.3.2; + DevelopmentTeam = 28CC8SCVUN; + ProvisioningStyle = Automatic; + TestTargetID = 5F88A9A51EB69A9A0069EE0A; + }; + }; + }; + buildConfigurationList = 5F88A9A11EB69A990069EE0A /* Build configuration list for PBXProject "Task Master" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5F88A99D1EB69A990069EE0A; + productRefGroup = 5F88A9A71EB69A9A0069EE0A /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5F88A9A51EB69A9A0069EE0A /* Task Master */, + 5F88A9BC1EB69A9A0069EE0A /* Task MasterTests */, + 5F88A9C71EB69A9A0069EE0A /* Task MasterUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5F88A9A41EB69A9A0069EE0A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F88A9B71EB69A9A0069EE0A /* LaunchScreen.storyboard in Resources */, + 5F1A74811EB6A38B00F45DE6 /* GoogleService-Info.plist in Resources */, + 5F88A9B41EB69A9A0069EE0A /* Assets.xcassets in Resources */, + 5F88A9AF1EB69A9A0069EE0A /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F88A9BB1EB69A9A0069EE0A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F88A9C61EB69A9A0069EE0A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3DBC5137AFD97F2620268536 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 45A11A56D15C27B1C2F59D43 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 6257E5C88D9D7384E5659916 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Task Master/Pods-Task Master-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5F88A9A21EB69A9A0069EE0A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F1A74761EB6A0AD00F45DE6 /* OnBoardingController.swift in Sources */, + 5F88A9B21EB69A9A0069EE0A /* Task_Master.xcdatamodeld in Sources */, + 5F1A747C1EB6A0AD00F45DE6 /* ViewControllers.swift in Sources */, + 5F1A74781EB6A0AD00F45DE6 /* TasksCell.swift in Sources */, + 5F1A747F1EB6A0AD00F45DE6 /* WelcomeScreenTwo.swift in Sources */, + 5F1A74771EB6A0AD00F45DE6 /* Task.swift in Sources */, + 5F1A747B1EB6A0AD00F45DE6 /* UserViews.swift in Sources */, + 5F1A74751EB6A0AD00F45DE6 /* Alerts.swift in Sources */, + 5F1A747E1EB6A0AD00F45DE6 /* WelcomeScreenThree.swift in Sources */, + 5F1A747D1EB6A0AD00F45DE6 /* WelcomeScreenOne.swift in Sources */, + 5F1A74791EB6A0AD00F45DE6 /* TasksTable.swift in Sources */, + 5F88A9AA1EB69A9A0069EE0A /* AppDelegate.swift in Sources */, + 5F1A747A1EB6A0AD00F45DE6 /* TaskView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F88A9B91EB69A9A0069EE0A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F88A9C21EB69A9A0069EE0A /* Task_MasterTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F88A9C41EB69A9A0069EE0A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F88A9CD1EB69A9A0069EE0A /* Task_MasterUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 5F88A9BF1EB69A9A0069EE0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5F88A9A51EB69A9A0069EE0A /* Task Master */; + targetProxy = 5F88A9BE1EB69A9A0069EE0A /* PBXContainerItemProxy */; + }; + 5F88A9CA1EB69A9A0069EE0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5F88A9A51EB69A9A0069EE0A /* Task Master */; + targetProxy = 5F88A9C91EB69A9A0069EE0A /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 5F88A9AD1EB69A9A0069EE0A /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5F88A9AE1EB69A9A0069EE0A /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5F88A9B51EB69A9A0069EE0A /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5F88A9B61EB69A9A0069EE0A /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5F88A9CF1EB69A9A0069EE0A /* 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++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "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.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 5F88A9D01EB69A9A0069EE0A /* 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++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + 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.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5F88A9D21EB69A9A0069EE0A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2B11D727CB348DF742B752AE /* Pods-Task Master.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task Master/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-Master"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 5F88A9D31EB69A9A0069EE0A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 982A7A363F80F47C6369C63E /* Pods-Task Master.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task Master/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-Master"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 5F88A9D51EB69A9A0069EE0A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task MasterTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-MasterTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Task Master.app/Task Master"; + }; + name = Debug; + }; + 5F88A9D61EB69A9A0069EE0A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task MasterTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-MasterTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Task Master.app/Task Master"; + }; + name = Release; + }; + 5F88A9D81EB69A9A0069EE0A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task MasterUITests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-MasterUITests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_TARGET_NAME = "Task Master"; + }; + name = Debug; + }; + 5F88A9D91EB69A9A0069EE0A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + DEVELOPMENT_TEAM = 28CC8SCVUN; + INFOPLIST_FILE = "Task MasterUITests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "ADCMNetworks.Task-MasterUITests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_TARGET_NAME = "Task Master"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5F88A9A11EB69A990069EE0A /* Build configuration list for PBXProject "Task Master" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F88A9CF1EB69A9A0069EE0A /* Debug */, + 5F88A9D01EB69A9A0069EE0A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F88A9D11EB69A9A0069EE0A /* Build configuration list for PBXNativeTarget "Task Master" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F88A9D21EB69A9A0069EE0A /* Debug */, + 5F88A9D31EB69A9A0069EE0A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F88A9D41EB69A9A0069EE0A /* Build configuration list for PBXNativeTarget "Task MasterTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F88A9D51EB69A9A0069EE0A /* Debug */, + 5F88A9D61EB69A9A0069EE0A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F88A9D71EB69A9A0069EE0A /* Build configuration list for PBXNativeTarget "Task MasterUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F88A9D81EB69A9A0069EE0A /* Debug */, + 5F88A9D91EB69A9A0069EE0A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCVersionGroup section */ + 5F88A9B01EB69A9A0069EE0A /* Task_Master.xcdatamodeld */ = { + isa = XCVersionGroup; + children = ( + 5F88A9B11EB69A9A0069EE0A /* Task_Master.xcdatamodel */, + ); + currentVersion = 5F88A9B11EB69A9A0069EE0A /* Task_Master.xcdatamodel */; + path = Task_Master.xcdatamodeld; + sourceTree = ""; + versionGroupType = wrapper.xcdatamodel; + }; +/* End XCVersionGroup section */ + }; + rootObject = 5F88A99E1EB69A990069EE0A /* Project object */; +} diff --git a/Task Master/Task Master.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Task Master/Task Master.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..d44d66f --- /dev/null +++ b/Task Master/Task Master.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Task Master/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate b/Task Master/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..051384b Binary files /dev/null and b/Task Master/Task Master.xcodeproj/project.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Task Master.xcscheme b/Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Task Master.xcscheme new file mode 100644 index 0000000..eab2e55 --- /dev/null +++ b/Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/Task Master.xcscheme @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist b/Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..3a0ba4d --- /dev/null +++ b/Task Master/Task Master.xcodeproj/xcuserdata/alexanderdavis.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,32 @@ + + + + + SchemeUserState + + Task Master.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 5F88A9A51EB69A9A0069EE0A + + primary + + + 5F88A9BC1EB69A9A0069EE0A + + primary + + + 5F88A9C71EB69A9A0069EE0A + + primary + + + + + diff --git a/Task Master/Task Master.xcworkspace/contents.xcworkspacedata b/Task Master/Task Master.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..07cc9b5 --- /dev/null +++ b/Task Master/Task Master.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate b/Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..cdb5f8d Binary files /dev/null and b/Task Master/Task Master.xcworkspace/xcuserdata/alexanderdavis.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Task Master/Task Master/Alerts.swift b/Task Master/Task Master/Alerts.swift new file mode 100644 index 0000000..31505b6 --- /dev/null +++ b/Task Master/Task Master/Alerts.swift @@ -0,0 +1,24 @@ +// +// Alerts.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +extension UIAlertController { + + static func withError(error: NSError) -> UIAlertController { + let alert = UIAlertController(title: "Error", + message: error.localizedDescription, + preferredStyle: .alert) + + let cancelAction = UIAlertAction(title: "Ok", + style: .default) + alert.addAction(cancelAction) + return alert + } +} diff --git a/Task Master/Task Master/AppDelegate.swift b/Task Master/Task Master/AppDelegate.swift new file mode 100644 index 0000000..6e682f9 --- /dev/null +++ b/Task Master/Task Master/AppDelegate.swift @@ -0,0 +1,114 @@ +// +// AppDelegate.swift +// Task Master +// +// Created by Alexander Davis on 30/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import UIKit +import CoreData +import Firebase +import UserNotifications +import NotificationCenter +import FirebaseDatabase + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + + // Use Firebase library to configure APIs + FIRApp.configure() + FIRDatabase.database().persistenceEnabled = true + + //If User Is Signed In Direct to Main App Section + let currentUser = FIRAuth.auth()?.currentUser + let mainStoryboard = UIStoryboard(name: "Main", bundle: nil) + if currentUser != nil + { + self.window?.rootViewController = mainStoryboard.instantiateViewController(withIdentifier: "MainView") + } + else + { + self.window?.rootViewController = mainStoryboard.instantiateViewController(withIdentifier: "OnBoard") + } + + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + // Saves changes in the application's managed object context before the application terminates. + self.saveContext() + } + + // MARK: - Core Data stack + + lazy var persistentContainer: NSPersistentContainer = { + /* + The persistent container for the application. This implementation + creates and returns a container, having loaded the store for the + application to it. This property is optional since there are legitimate + error conditions that could cause the creation of the store to fail. + */ + let container = NSPersistentContainer(name: "Task_Master") + container.loadPersistentStores(completionHandler: { (storeDescription, error) in + if let error = error as NSError? { + // Replace this implementation with code to handle the error appropriately. + // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + + /* + Typical reasons for an error here include: + * The parent directory does not exist, cannot be created, or disallows writing. + * The persistent store is not accessible, due to permissions or data protection when the device is locked. + * The device is out of space. + * The store could not be migrated to the current model version. + Check the error message to determine what the actual problem was. + */ + fatalError("Unresolved error \(error), \(error.userInfo)") + } + }) + return container + }() + + // MARK: - Core Data Saving support + + func saveContext () { + let context = persistentContainer.viewContext + if context.hasChanges { + do { + try context.save() + } catch { + // Replace this implementation with code to handle the error appropriately. + // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + let nserror = error as NSError + fatalError("Unresolved error \(nserror), \(nserror.userInfo)") + } + } + } + +} + diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 0000000..d98c3c4 --- /dev/null +++ b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,152 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-App-57x57@1x.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-App-57x57@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50x50@1x.png", + "scale" : "1x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50x50@2x.png", + "scale" : "2x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-App-72x72@1x.png", + "scale" : "1x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-App-72x72@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..cb8c8dd Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..31a69a7 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..50bb01a Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..bdd7215 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..0f63d35 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..3ffb1d1 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..31a69a7 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..5f25168 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..5ccf3e8 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..8bf9ff2 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..290e064 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..5ccf3e8 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..2bd6152 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..f994c63 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..abe476f Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..ce5c7a6 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..49def24 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..e88b914 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png new file mode 100644 index 0000000..ce98871 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png new file mode 100644 index 0000000..0833776 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/Contents.json b/Task Master/Task Master/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Task Master/Task Master/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/Contents.json b/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/Contents.json new file mode 100755 index 0000000..c084b4d --- /dev/null +++ b/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "create_new-25.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "create_new-32.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "create_new-50.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-25.png b/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-25.png new file mode 100755 index 0000000..a5a31cc Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-25.png differ diff --git a/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-32.png b/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-32.png new file mode 100755 index 0000000..ceb4e8c Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-32.png differ diff --git a/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-50.png b/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-50.png new file mode 100755 index 0000000..01be1c0 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/create_new-50.imageset/create_new-50.png differ diff --git a/Task Master/Task Master/Assets.xcassets/first.imageset/Contents.json b/Task Master/Task Master/Assets.xcassets/first.imageset/Contents.json new file mode 100755 index 0000000..33a7451 --- /dev/null +++ b/Task Master/Task Master/Assets.xcassets/first.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "first.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Task Master/Task Master/Assets.xcassets/first.imageset/first.pdf b/Task Master/Task Master/Assets.xcassets/first.imageset/first.pdf new file mode 100755 index 0000000..47d911d Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/first.imageset/first.pdf differ diff --git a/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/Contents.json b/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/Contents.json new file mode 100644 index 0000000..43003d0 --- /dev/null +++ b/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "iTunesArtwork@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "iTunesArtwork@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "iTunesArtwork@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@1x.png b/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@1x.png new file mode 100644 index 0000000..5bb8a72 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@1x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@2x.png b/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@2x.png new file mode 100644 index 0000000..17c0cb6 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@3x.png b/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@3x.png new file mode 100644 index 0000000..510b9df Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/iTunesArtwork.imageset/iTunesArtwork@3x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/iTunesArtwork@1x.png b/Task Master/Task Master/Assets.xcassets/iTunesArtwork@1x.png new file mode 100644 index 0000000..5bb8a72 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/iTunesArtwork@1x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/iTunesArtwork@2x.png b/Task Master/Task Master/Assets.xcassets/iTunesArtwork@2x.png new file mode 100644 index 0000000..17c0cb6 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/iTunesArtwork@2x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/iTunesArtwork@3x.png b/Task Master/Task Master/Assets.xcassets/iTunesArtwork@3x.png new file mode 100644 index 0000000..510b9df Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/iTunesArtwork@3x.png differ diff --git a/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/Contents.json b/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/Contents.json new file mode 100755 index 0000000..58b2369 --- /dev/null +++ b/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "report_card-25.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "report_card-32.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "report_card-50.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-25.png b/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-25.png new file mode 100755 index 0000000..f18566e Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-25.png differ diff --git a/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-32.png b/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-32.png new file mode 100755 index 0000000..fdf21c7 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-32.png differ diff --git a/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-50.png b/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-50.png new file mode 100755 index 0000000..fe73ac5 Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/report_card-50.imageset/report_card-50.png differ diff --git a/Task Master/Task Master/Assets.xcassets/second.imageset/Contents.json b/Task Master/Task Master/Assets.xcassets/second.imageset/Contents.json new file mode 100755 index 0000000..03bd9c9 --- /dev/null +++ b/Task Master/Task Master/Assets.xcassets/second.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "second.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Task Master/Task Master/Assets.xcassets/second.imageset/second.pdf b/Task Master/Task Master/Assets.xcassets/second.imageset/second.pdf new file mode 100755 index 0000000..401614e Binary files /dev/null and b/Task Master/Task Master/Assets.xcassets/second.imageset/second.pdf differ diff --git a/Task Master/Task Master/Base.lproj/LaunchScreen.storyboard b/Task Master/Task Master/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..d19da7e --- /dev/null +++ b/Task Master/Task Master/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Task Master/Task Master/Base.lproj/Main.storyboard b/Task Master/Task Master/Base.lproj/Main.storyboard new file mode 100644 index 0000000..d36c58d --- /dev/null +++ b/Task Master/Task Master/Base.lproj/Main.storyboard @@ -0,0 +1,736 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Task Master/Task Master/BridgingHeader.h b/Task Master/Task Master/BridgingHeader.h new file mode 100644 index 0000000..fe8e802 --- /dev/null +++ b/Task Master/Task Master/BridgingHeader.h @@ -0,0 +1,15 @@ +// +// BridgingHeader.h +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +#ifndef BridgingHeader_h +#define BridgingHeader_h + + +#endif /* BridgingHeader_h */ + +#import diff --git a/Task Master/Task Master/GoogleService-Info.plist b/Task Master/Task Master/GoogleService-Info.plist new file mode 100644 index 0000000..9a46224 --- /dev/null +++ b/Task Master/Task Master/GoogleService-Info.plist @@ -0,0 +1,40 @@ + + + + + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 + CLIENT_ID + 423696983750-k57prfa7vk5bebm4nuvv4cfa78qthbfr.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.423696983750-k57prfa7vk5bebm4nuvv4cfa78qthbfr + API_KEY + AIzaSyDhHM39kcgnk5eVFOKq4pvCbiSSEGGQ0iQ + GCM_SENDER_ID + 423696983750 + PLIST_VERSION + 1 + BUNDLE_ID + ADCMNetworks.Task-Master + PROJECT_ID + taskmaster-20716 + STORAGE_BUCKET + taskmaster-20716.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:423696983750:ios:ee84cdaa017a58a7 + DATABASE_URL + https://taskmaster-20716.firebaseio.com + + \ No newline at end of file diff --git a/Task Master/Task Master/Info.plist b/Task Master/Task Master/Info.plist new file mode 100644 index 0000000..38e98af --- /dev/null +++ b/Task Master/Task Master/Info.plist @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Task Master/Task Master/OnBoardingController.swift b/Task Master/Task Master/OnBoardingController.swift new file mode 100644 index 0000000..14a7430 --- /dev/null +++ b/Task Master/Task Master/OnBoardingController.swift @@ -0,0 +1,83 @@ +// +// OnBoardingController.swift +// My Mind +// +// Created by Alexander Davis on 30/03/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class OnBoardingController : UIPageViewController { + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + + override func viewDidLoad() { + // Set the dataSource and delegate in code. + // I can't figure out how to do this in the Storyboard! + dataSource = self + delegate = self + // This is the starting point. Start with step zero. + setViewControllers([getPageOne()], direction: .forward, animated: false, completion: nil) + } + + func getPageOne() -> PageOne { + return storyboard!.instantiateViewController(withIdentifier: "WelcomeScreenOne") as! PageOne + } + + func getPageTwo() -> PageTwo { + return storyboard!.instantiateViewController(withIdentifier: "WelcomeScreenTwo") as! PageTwo + } + + func getPageThree() -> PageThree { + return storyboard!.instantiateViewController(withIdentifier: "WelcomeScreenThree") as! PageThree + } + +} + +// MARK: - UIPageViewControllerDataSource methods + +extension OnBoardingController : UIPageViewControllerDataSource { + + func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { + if viewController.isKind(of: PageTwo.self) { + // 2 -> 1 + return getPageTwo() + } else if viewController.isKind(of: PageTwo.self) { + // 1 -> 0 + return getPageOne() + } else { + // 0 -> end of the road + return nil + } + } + + func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { + if viewController.isKind(of: PageOne.self) { + // 0 -> 1 + return getPageTwo() + } else if viewController.isKind(of: PageTwo.self) { + // 1 -> 2 + return getPageThree() + } else { + // 2 -> end of the road + return nil + } + } + + + // This only gets called once, when setViewControllers is called + func presentationIndex(for pageViewController: UIPageViewController) -> Int { + return 0 + } + +} + +// MARK: - UIPageViewControllerDelegate methods + +extension OnBoardingController : UIPageViewControllerDelegate { + +} diff --git a/Task Master/Task Master/Task.swift b/Task Master/Task Master/Task.swift new file mode 100644 index 0000000..f388f9e --- /dev/null +++ b/Task Master/Task Master/Task.swift @@ -0,0 +1,55 @@ +// +// Task.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import Firebase + +/* Have keys as constants to prevent spelling errors + * and avoid confusion. eg. "title" can be found in + * ViewControllers too, so places can exist where the + * particular string is used for something else. + */ +let kTaskTitleKey = "title" +let kTaskCompletedKey = "completed" +let kTaskUserKey = "user" + +struct Task { + let title: String + let user: String + let firebaseReference: FIRDatabaseReference? + var completed: Bool + + /* Constructor for instantiating a new object in code. + */ + init(title: String, user: String, completed: Bool, id: String = "") { + self.title = title + self.user = user + self.completed = completed + self.firebaseReference = nil + } + + /* Constructor for instantiating an object received from Firebase. + */ + init(snapshot: FIRDataSnapshot) { + let snapshotValue = snapshot.value as! [String: Any] + self.title = snapshotValue[kTaskTitleKey] as! String + self.user = snapshotValue[kTaskUserKey] as! String + self.completed = snapshotValue[kTaskCompletedKey] as! Bool + self.firebaseReference = snapshot.ref + } + + /* Member to help updating values of an existing object. + */ + func toDictionary() -> Any { + return [ + kTaskTitleKey: self.title, + kTaskUserKey: self.user, + kTaskCompletedKey: self.completed + ] + } +} diff --git a/Task Master/Task Master/TaskView.swift b/Task Master/Task Master/TaskView.swift new file mode 100644 index 0000000..de44198 --- /dev/null +++ b/Task Master/Task Master/TaskView.swift @@ -0,0 +1,31 @@ +// +// TaskView.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class TaskViewController: UIViewController { + + var taskTitle: String? + var taskCompleted: Bool? + + @IBOutlet weak var titleField: UITextField! + @IBOutlet weak var completedSwitch: UISwitch! + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + self.titleField.text = self.taskTitle ?? "" + self.completedSwitch.setOn(taskCompleted ?? false, animated:false) + } + + func updateValues() { + self.taskTitle = self.titleField.text + self.taskCompleted = self.completedSwitch.isOn + } +} diff --git a/Task Master/Task Master/Task_Master.xcdatamodeld/.xccurrentversion b/Task Master/Task Master/Task_Master.xcdatamodeld/.xccurrentversion new file mode 100644 index 0000000..16ad39d --- /dev/null +++ b/Task Master/Task Master/Task_Master.xcdatamodeld/.xccurrentversion @@ -0,0 +1,8 @@ + + + + + _XCCurrentVersionName + Task_Master.xcdatamodel + + diff --git a/Task Master/Task Master/Task_Master.xcdatamodeld/Task_Master.xcdatamodel/contents b/Task Master/Task Master/Task_Master.xcdatamodeld/Task_Master.xcdatamodel/contents new file mode 100644 index 0000000..476e5b6 --- /dev/null +++ b/Task Master/Task Master/Task_Master.xcdatamodeld/Task_Master.xcdatamodel/contents @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Task Master/Task Master/TasksCell.swift b/Task Master/Task Master/TasksCell.swift new file mode 100644 index 0000000..e19d03e --- /dev/null +++ b/Task Master/Task Master/TasksCell.swift @@ -0,0 +1,16 @@ +// +// TasksCell.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class TasksTableViewCell: UITableViewCell { + + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var completedSwitch: UISwitch! +} diff --git a/Task Master/Task Master/TasksTable.swift b/Task Master/Task Master/TasksTable.swift new file mode 100644 index 0000000..a495a3d --- /dev/null +++ b/Task Master/Task Master/TasksTable.swift @@ -0,0 +1,155 @@ +// +// TasksTable.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import Firebase + +let kTasksListPath = "tasks-list" +let kTaskViewControllerSegueIdentifier = "TaskViewController" + +class TasksTableViewController: UITableViewController { + + let tasksReference = FIRDatabase.database().reference(withPath: kTasksListPath) + var tasks = [Task]() + var selectedTask: Task? = nil + weak var currentUser = FIRAuth.auth()?.currentUser + + override func viewDidLoad() { + super.viewDidLoad() + + /* Query tasks from firebase when this view controller is instantiated + */ + self.tasksReference.queryOrdered(byChild: kTaskCompletedKey).observe(.value, with: { snapshot in + + /* The callback block will be executed each and every time the value changes. + */ + var items: [Task] = [] + + for item in snapshot.children { + let task = Task(snapshot: item as! FIRDataSnapshot) + items.append(task) + } + + self.tasks = items + self.tableView.reloadData() + }) + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == kTaskViewControllerSegueIdentifier { + /* Pass along the selected task to the particular task view controller. + */ + if let taskViewController = segue.destination as? TaskViewController { + taskViewController.taskTitle = self.selectedTask?.title + taskViewController.taskCompleted = self.selectedTask?.completed + } + } + } + + @IBAction func prepareForUnwind(segue: UIStoryboardSegue) { + if let taskViewController = segue.source as? TaskViewController { + taskViewController.updateValues() + + if taskViewController.titleField.text == "" { + let alertController = UIAlertController(title: "Error", message: "Please enter a task name.", preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + }else{ + if let task = self.selectedTask { + /* This particular task was an existing one + it should be updated in Firebase. + */ + if let title = taskViewController.taskTitle, + let completed = taskViewController.taskCompleted, + let email = self.currentUser?.email { + + let taskFirebasePath = task.firebaseReference + taskFirebasePath?.updateChildValues([ + kTaskTitleKey: title, + kTaskUserKey: email, + kTaskCompletedKey: completed + ]) + } + } else { + /* This task is new, + it should be created in Firebase + */ + if let title = taskViewController.taskTitle, + let completed = taskViewController.taskCompleted, + let email = self.currentUser?.email { + + let task = Task(title: title, user: email, completed: completed) + let taskFirebasePath = self.tasksReference.ref.child(title.lowercased()) + taskFirebasePath.setValue(task.toDictionary()) + } + } + } + } + self.selectedTask = nil + } + + @IBAction func addTask() { + self.performSegue(withIdentifier: kTaskViewControllerSegueIdentifier, sender: self) + } + + // MARK: - Table view data source + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return self.tasks.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell", for: indexPath) + + if let c = cell as? TasksTableViewCell { + let task = self.tasks[indexPath.row] + c.titleLabel.text = task.title + c.completedSwitch.setOn(task.completed, animated: true) + } + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let task = self.tasks[indexPath.row] + + /* Keep a reference to the task that is currently edited. + */ + self.selectedTask = task + self.performSegue(withIdentifier: kTaskViewControllerSegueIdentifier, sender: self) + } + + override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + return true + } + + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + let task = self.tasks[indexPath.row] + /* Delete this task. + No tableview updates should be done here because a callback notification + will be provided. + */ + task.firebaseReference?.removeValue() + } + } + @IBAction func SignOut(_ sender: UIBarButtonItem) { + if FIRAuth.auth()?.currentUser != nil { + do { + try FIRAuth.auth()?.signOut() + let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "OnBoard") + present(vc, animated: true, completion: nil) + + } catch let error as NSError { + print(error.localizedDescription) + } + } + } +} diff --git a/Task Master/Task Master/UserViews.swift b/Task Master/Task Master/UserViews.swift new file mode 100644 index 0000000..a9220d0 --- /dev/null +++ b/Task Master/Task Master/UserViews.swift @@ -0,0 +1,168 @@ +// +// LoginView.swift +// My Mind +// +// Created by Alexander Davis on 31/03/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit +import Firebase +import FirebaseAuth + +class LoginView: UIViewController { + + @IBOutlet weak var Emailtbx: UITextField! + @IBOutlet weak var Passwordtbx: UITextField! + @IBAction func Loginbtn(_ sender: UIButton) { + if self.Emailtbx.text == "" || self.Passwordtbx.text == "" { + + //Alert to tell the user that there was an error because they didn't fill anything in the textfields because they didn't fill anything in + + let alertController = UIAlertController(title: "Error", message: "Please enter an email and password.", preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + + } else { + + FIRAuth.auth()?.signIn(withEmail: self.Emailtbx.text!, password: self.Passwordtbx.text!) { (user, error) in + + if error == nil { + + //Print into the console if successfully logged in + print("You have successfully logged in") + + //Go to the MainController if the login is sucessful + let alertController = UIAlertController(title: "Welcome", message: "You have successfully logged in", preferredStyle: .alert) + let vc = self.storyboard?.instantiateViewController(withIdentifier: "MainView") + let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in self.present(vc!, animated: true, completion: nil);}) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + + } else { + + //Tells the user that there is an error and then gets firebase to tell them the error + let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + } + } + } + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + } + +class SignUp : UIViewController { + + @IBOutlet weak var Emailtbx: UITextField! + @IBOutlet weak var Passwordtbx: UITextField! + @IBAction func createAccountbtn(_ sender: UIButton) { + if Emailtbx.text == "" { + let alertController = UIAlertController(title: "Error", message: "Please enter your email and password", preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) + alertController.addAction(defaultAction) + + present(alertController, animated: true, completion: nil) + + } else { + FIRAuth.auth()?.createUser(withEmail: Emailtbx.text!, password: Passwordtbx.text!) { (user, error) in + + if error == nil { + let alertController = UIAlertController(title: "Sign Up Complete", message: "You have Successfully Signed Up", preferredStyle: .alert) + let vc = self.storyboard?.instantiateViewController(withIdentifier: "Login") + let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in self.present(vc!, animated: true, completion: nil);}) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + + } else { + let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + } + } + } + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } +} + +class ForgotPass : UIViewController { + + @IBOutlet weak var Emailtbx: UITextField! + @IBAction func Resetbtn(_ sender: UIButton) { + if self.Emailtbx.text == "" { + let alertController = UIAlertController(title: "Oops!", message: "Please enter an email.", preferredStyle: .alert) + + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) + alertController.addAction(defaultAction) + + present(alertController, animated: true, completion: nil) + + } else { + FIRAuth.auth()?.sendPasswordReset(withEmail: self.Emailtbx.text!, completion: { (error) in + + var title = "" + var message = "" + + if error != nil { + title = "Error!" + message = (error?.localizedDescription)! + } else { + title = "Success!" + message = "Password reset email sent." + self.Emailtbx.text = "" + } + + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + + let vc = self.storyboard?.instantiateViewController(withIdentifier: "Login") + let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: { action in self.present(vc!, animated: true, completion: nil);}) + alertController.addAction(defaultAction) + + self.present(alertController, animated: true, completion: nil) + }) + } + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } +} + +class Logout : UIViewController { + + @IBAction func Logoutbtn(_ sender: UIButton) { + if FIRAuth.auth()?.currentUser != nil { + do { + try FIRAuth.auth()?.signOut() + let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "OnBoard") + present(vc, animated: true, completion: nil) + + } catch let error as NSError { + print(error.localizedDescription) + } + } + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } +} diff --git a/Task Master/Task Master/ViewControllers.swift b/Task Master/Task Master/ViewControllers.swift new file mode 100644 index 0000000..c3127dc --- /dev/null +++ b/Task Master/Task Master/ViewControllers.swift @@ -0,0 +1,88 @@ +// +// ViewController.swift +// Task Master +// +// Created by Alexander Davis on 14/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import UIKit + +import UIKit +import Firebase + +let kUserLoggedInSegueIdentifier = "userLoggedIn" + +class MainViewController: UIViewController { + + /* @IBOutlets create references so strings can be read from + the UITextFields + */ + @IBOutlet weak var emailField: UITextField! + @IBOutlet weak var passwordField: UITextField! + + /* Have a reference to the last signed in user to compare + changes + */ + weak var currentUser: FIRUser? + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + if let auth = FIRAuth.auth() { + + /* Add a state change listener to firebase + to get a notification if the user signed in. + */ + auth.addStateDidChangeListener({ (auth, user) in + if user != nil && user != self.currentUser { + self.currentUser = user + self.performSegue(withIdentifier: kUserLoggedInSegueIdentifier, + sender: self) + } + }) + } + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + if let auth = FIRAuth.auth() { + /* Following the balance principle in iOS, + Stop listening to user state changes while not on screen. + */ + auth.removeStateDidChangeListener(self) + } + } + + @IBAction func login() { + if let email = self.emailField.text, + let password = self.passwordField.text, + let auth = FIRAuth.auth() { + + /* If both email and password fields are not empty, + call firebase signin + */ + auth.signIn(withEmail: email, + password: password) + } + } + + @IBAction func register() { + if let email = self.emailField.text, + let password = self.passwordField.text, + let auth = FIRAuth.auth() { + /* Note: creating a user automatically signs in. + */ + auth.createUser(withEmail: email, + password: password) { user, error in + if error != nil { + self.present(UIAlertController.withError(error: error! as NSError), + animated: true, + completion: nil) + } + } + } + } + + +} diff --git a/Task Master/Task Master/WelcomeScreenOne.swift b/Task Master/Task Master/WelcomeScreenOne.swift new file mode 100644 index 0000000..ae853e4 --- /dev/null +++ b/Task Master/Task Master/WelcomeScreenOne.swift @@ -0,0 +1,18 @@ +// +// WelcomeScreenOne.swift +// My Mind +// +// Created by Alexander Davis on 30/03/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class PageOne : UIViewController { + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + +} diff --git a/Task Master/Task Master/WelcomeScreenThree.swift b/Task Master/Task Master/WelcomeScreenThree.swift new file mode 100644 index 0000000..502dbfb --- /dev/null +++ b/Task Master/Task Master/WelcomeScreenThree.swift @@ -0,0 +1,18 @@ +// +// WelcomeScreenThree.swift +// My Mind +// +// Created by Alexander Davis on 30/03/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class PageThree : UIViewController { + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + +} diff --git a/Task Master/Task Master/WelcomeScreenTwo.swift b/Task Master/Task Master/WelcomeScreenTwo.swift new file mode 100644 index 0000000..29edc23 --- /dev/null +++ b/Task Master/Task Master/WelcomeScreenTwo.swift @@ -0,0 +1,18 @@ +// +// WelcomeScreenTwo.swift +// My Mind +// +// Created by Alexander Davis on 30/03/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import Foundation +import UIKit + +class PageTwo : UIViewController { + + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + +} diff --git a/Task Master/Task MasterTests/Info.plist b/Task Master/Task MasterTests/Info.plist new file mode 100644 index 0000000..6c6c23c --- /dev/null +++ b/Task Master/Task MasterTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Task Master/Task MasterTests/Task_MasterTests.swift b/Task Master/Task MasterTests/Task_MasterTests.swift new file mode 100644 index 0000000..e4e8913 --- /dev/null +++ b/Task Master/Task MasterTests/Task_MasterTests.swift @@ -0,0 +1,36 @@ +// +// Task_MasterTests.swift +// Task MasterTests +// +// Created by Alexander Davis on 30/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import XCTest +@testable import Task_Master + +class Task_MasterTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/Task Master/Task MasterUITests/Info.plist b/Task Master/Task MasterUITests/Info.plist new file mode 100644 index 0000000..6c6c23c --- /dev/null +++ b/Task Master/Task MasterUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Task Master/Task MasterUITests/Task_MasterUITests.swift b/Task Master/Task MasterUITests/Task_MasterUITests.swift new file mode 100644 index 0000000..be7dc90 --- /dev/null +++ b/Task Master/Task MasterUITests/Task_MasterUITests.swift @@ -0,0 +1,36 @@ +// +// Task_MasterUITests.swift +// Task MasterUITests +// +// Created by Alexander Davis on 30/04/2017. +// Copyright © 2017 Alexander Davis. All rights reserved. +// + +import XCTest + +class Task_MasterUITests: XCTestCase { + + override func setUp() { + super.setUp() + + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. + XCUIApplication().launch() + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + +} diff --git a/TaskMasterParse Security Key.pem b/TaskMasterParse Security Key.pem deleted file mode 100644 index a562cab..0000000 --- a/TaskMasterParse Security Key.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAi0Sn88eusTdujP3ahJ9p+2EaAYp5Knm+NfKZolTQ9u4JaXzR7ZvohGXJ/Rrz -soX0RwxI6lr/wpTtOGSxijvysM0c542Yg0ntGOkeYHpYyU4Je2DGFjhe+gg8neaYx8deX4FovoYS -s9iq/VGrleNCiBND0SCKQixy9kyN/u4SOMj7gT2dzFv9usN5cVzyWBPhl+QjO+8Tfvo0e59LtUAt -xLXZ4SoLurhuFyynTBz9Ra8HyfAK93KpLg0lGASEnrhm1btdIpUXDBE+/ifXx2YuSxpRoBCoj5Nx -75kk90dnwBOfk/VQgxFQv/RVwGzFE5AtHeIc8iSBREim0laGv374PwIDAQABAoIBAD03PXf7cr80 -9WQGBXI8PDKh2POKcX4JK2G9NGjVTVDtCrgShJgj6s2fjGyz1yDGnrxIGxjgTQGzwp4CLMPtW9z5 -G9ZwN/SlnxFPDuorfTFnGuXfgNKtjpnq2vIxNUDDUqk6UddFSZ1CBM76giiNT2ZOyYV3/y3dKd83 -gUboUJwim+s3auIuwl6ptWTVGuByD47DSK5wkUb99V13jASt1KfR2sKMC1xetoFsrRcpIkrJuoAV -DLtLylSxPaPRMAyXRRGmHkHMYxv/RGmiZ8phvejyDiKOnplbyzitW6XKAeqOqKnKicxLrxk5IHtf -YWFni/KAE7JjBbIgabzQocUabjECgYEA3D/1rMdGxTxyRhs4bBP+3/Z3jD9h9ttOYS3DiOVYKjzI -LuUWbkEe54QpDyijnI+Um2C01UIgOzeoDWN1XanNCA2j9TTRUso3T701bmcLGPS1EnCwv0SoJRDR -cCOcrjz/ciRrCK0vmcYZeUzivYvvtVhIvo2d+3CN46z3iIkZGfcCgYEAod+qjDijUs2jsg5y8Yzv -nq/yTfCol5dVld3MLaDsayvN1JtGdPl4XtKdX+MUMsbK1NTxQ9XKGf8SeEAOQp+BmDMRdiqCOAxC -z+b2Ji+LjtAeCWfw3IE9f1MsX1FB2JoHM24kpZC2Rd3VQ97iGV4L5XpmPdqvmLN/FImZ6CYrQfkC -gYBVSoN15Dm4uZ67HWFtIRUrX8ON0SG7udOReGpnQgExYhZXaqmUCq3QE/LehutM/qEaxolgqFnY -9MWkYaaand3jR3z9wPVqrRpcS7Y8SbUXdfQE7xTTDOBccjXYykGri72UUxwL4R003G0S9z47DszG -GikZebf7Hewkhd/ZxNWuowKBgDj8pO34gocEHjzxGUYwd6tGBeeqca/sdxTroJXvsUuJgEz43TUR -Hm9DdmPrbZDyqzWCQe2/tgaw5a+v3VVXEiii0eLn1DAnIN5QURfgZSFB41EsZn86gIvynAxybtvy -XdadUAl5iLHQBuR98ts7YLTJAnWEJ416o6J3TteLmG8BAoGBAMpIFKcdQ7QndhyMxXZDj6SkUNgU -LL8RW59irFsqHxQTh/U2oZpTjtAybWGED0Z6h81US8AvBEDYua6EczxEYsYvMHPZn4xIVBnDP7NU -1i+CZ3WXgBNfLLOmskOrNHjkZcuVuWN1yij+EUOXrXcZpACnOV/5okHeQId6WCwI4AkT ------END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/_config.yml b/_config.yml deleted file mode 100644 index c741881..0000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-slate \ No newline at end of file