summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/ios/Pods/GoogleUtilities
diff options
context:
space:
mode:
Diffstat (limited to 'StoneIsland/platforms/ios/Pods/GoogleUtilities')
-rwxr-xr-xStoneIsland/platforms/ios/Pods/GoogleUtilities/Frameworks/frameworks/GoogleUtilities.framework/GoogleUtilitiesbin2567216 -> 0 bytes
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m1021
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h55
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Private/GULAppDelegateSwizzler.h111
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Private/GULApplication.h50
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h56
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m154
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m103
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h47
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULHeartbeatDateStorage.h49
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULKeychainStorage.h79
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULKeychainUtils.h61
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULSecureCoding.h36
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m192
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m113
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m252
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULObjectSwizzler+Internal.h21
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULObjectSwizzler.m164
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULSwizzledObject.m88
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/Private/GULObjectSwizzler.h123
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/Private/GULSwizzledObject.h44
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/LICENSE247
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m221
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Private/GULLogger.h163
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GULLoggerLevel.h37
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m153
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Private/GULOriginalIMPConvenienceMacros.h207
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Private/GULSwizzler.h71
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m207
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Private/GULNSDataInternal.h22
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GULNSData+zlib.h49
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m101
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m389
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m40
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m762
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULMutableDictionary.h46
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetwork.h87
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkConstants.h79
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkLoggerProtocol.h51
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkMessageCode.h47
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkURLSession.h62
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h47
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m263
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Private/GULReachabilityChecker.h79
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Private/GULReachabilityMessageCode.h29
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/GULSceneDelegateSwizzler.m438
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h48
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/Private/GULSceneDelegateSwizzler.h73
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m213
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Private/GULUserDefaults.h110
-rw-r--r--StoneIsland/platforms/ios/Pods/GoogleUtilities/README.md300
51 files changed, 7460 insertions, 0 deletions
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/Frameworks/frameworks/GoogleUtilities.framework/GoogleUtilities b/StoneIsland/platforms/ios/Pods/GoogleUtilities/Frameworks/frameworks/GoogleUtilities.framework/GoogleUtilities
deleted file mode 100755
index 0fd17b65..00000000
--- a/StoneIsland/platforms/ios/Pods/GoogleUtilities/Frameworks/frameworks/GoogleUtilities.framework/GoogleUtilities
+++ /dev/null
Binary files differ
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m
new file mode 100644
index 00000000..ca551aca
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m
@@ -0,0 +1,1021 @@
+// Copyright 2018 Google LLC
+//
+// 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 <TargetConditionals.h>
+
+#import "GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h"
+#import "GoogleUtilities/AppDelegateSwizzler/Private/GULAppDelegateSwizzler.h"
+#import "GoogleUtilities/Common/GULLoggerCodes.h"
+#import "GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h"
+#import "GoogleUtilities/Logger/Private/GULLogger.h"
+#import "GoogleUtilities/Network/Private/GULMutableDictionary.h"
+
+#import <objc/runtime.h>
+
+// Implementations need to be typed before calling the implementation directly to cast the
+// arguments and the return types correctly. Otherwise, it will crash the app.
+typedef BOOL (*GULRealOpenURLSourceApplicationAnnotationIMP)(
+ id, SEL, GULApplication *, NSURL *, NSString *, id);
+
+typedef BOOL (*GULRealOpenURLOptionsIMP)(
+ id, SEL, GULApplication *, NSURL *, NSDictionary<NSString *, id> *);
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wstrict-prototypes"
+typedef void (*GULRealHandleEventsForBackgroundURLSessionIMP)(
+ id, SEL, GULApplication *, NSString *, void (^)());
+#pragma clang diagnostic pop
+
+typedef BOOL (*GULRealContinueUserActivityIMP)(
+ id, SEL, GULApplication *, NSUserActivity *, void (^)(NSArray *restorableObjects));
+
+typedef void (*GULRealDidRegisterForRemoteNotificationsIMP)(id, SEL, GULApplication *, NSData *);
+
+typedef void (*GULRealDidFailToRegisterForRemoteNotificationsIMP)(id,
+ SEL,
+ GULApplication *,
+ NSError *);
+
+typedef void (*GULRealDidReceiveRemoteNotificationIMP)(id, SEL, GULApplication *, NSDictionary *);
+
+#if !TARGET_OS_WATCH && !TARGET_OS_OSX
+typedef void (*GULRealDidReceiveRemoteNotificationWithCompletionIMP)(
+ id, SEL, GULApplication *, NSDictionary *, void (^)(UIBackgroundFetchResult));
+#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX
+
+typedef void (^GULAppDelegateInterceptorCallback)(id<GULApplicationDelegate>);
+
+// The strings below are the keys for associated objects.
+static char const *const kGULRealIMPBySelectorKey = "GUL_realIMPBySelector";
+static char const *const kGULRealClassKey = "GUL_realClass";
+
+static NSString *const kGULAppDelegateKeyPath = @"delegate";
+
+static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/AppDelegateSwizzler]";
+
+// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change
+// we disable App Delegate proxying when either of these two flags are set to NO.
+
+/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */
+static NSString *const kGULFirebaseAppDelegateProxyEnabledPlistKey =
+ @"FirebaseAppDelegateProxyEnabled";
+
+/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying.
+ */
+static NSString *const kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey =
+ @"GoogleUtilitiesAppDelegateProxyEnabled";
+
+/** The prefix of the App Delegate. */
+static NSString *const kGULAppDelegatePrefix = @"GUL_";
+
+/** The original instance of App Delegate. */
+static id<GULApplicationDelegate> gOriginalAppDelegate;
+
+/** The original App Delegate class */
+static Class gOriginalAppDelegateClass;
+
+/** The subclass of the original App Delegate. */
+static Class gAppDelegateSubclass;
+
+/** Remote notification methods selectors
+ *
+ * We have to opt out of referencing APNS related App Delegate methods directly to prevent
+ * an Apple review warning email about missing Push Notification Entitlement
+ * (like here: https://github.com/firebase/firebase-ios-sdk/issues/2807). From our experience, the
+ * warning is triggered when any of the symbols is present in the application sent to review, even
+ * if the code is never executed. Because GULAppDelegateSwizzler may be used by applications that
+ * are not using APNS we have to refer to the methods indirectly using selector constructed from
+ * string.
+ *
+ * NOTE: None of the methods is proxied unless it is explicitly requested by calling the method
+ * +[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods]
+ */
+static NSString *const kGULDidRegisterForRemoteNotificationsSEL =
+ @"application:didRegisterForRemoteNotificationsWithDeviceToken:";
+static NSString *const kGULDidFailToRegisterForRemoteNotificationsSEL =
+ @"application:didFailToRegisterForRemoteNotificationsWithError:";
+static NSString *const kGULDidReceiveRemoteNotificationSEL =
+ @"application:didReceiveRemoteNotification:";
+static NSString *const kGULDidReceiveRemoteNotificationWithCompletionSEL =
+ @"application:didReceiveRemoteNotification:fetchCompletionHandler:";
+
+/**
+ * This class is necessary to store the delegates in an NSArray without retaining them.
+ * [NSValue valueWithNonRetainedObject] also provides this functionality, but does not provide a
+ * zeroing pointer. This will cause EXC_BAD_ACCESS when trying to access the object after it is
+ * dealloced. Instead, this container stores a weak, zeroing reference to the object, which
+ * automatically is set to nil by the runtime when the object is dealloced.
+ */
+@interface GULZeroingWeakContainer : NSObject
+
+/** Stores a weak object. */
+@property(nonatomic, weak) id object;
+
+@end
+
+@implementation GULZeroingWeakContainer
+@end
+
+@interface GULAppDelegateObserver : NSObject
+@end
+
+@implementation GULAppDelegateObserver {
+ BOOL _isObserving;
+}
+
++ (GULAppDelegateObserver *)sharedInstance {
+ static GULAppDelegateObserver *instance;
+ static dispatch_once_t once;
+ dispatch_once(&once, ^{
+ instance = [[GULAppDelegateObserver alloc] init];
+ });
+ return instance;
+}
+
+- (void)observeUIApplication {
+ if (_isObserving) {
+ return;
+ }
+ [[GULAppDelegateSwizzler sharedApplication]
+ addObserver:self
+ forKeyPath:kGULAppDelegateKeyPath
+ options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
+ context:nil];
+ _isObserving = YES;
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath
+ ofObject:(id)object
+ change:(NSDictionary *)change
+ context:(void *)context {
+ if ([keyPath isEqual:kGULAppDelegateKeyPath]) {
+ id newValue = change[NSKeyValueChangeNewKey];
+ id oldValue = change[NSKeyValueChangeOldKey];
+ if ([newValue isEqual:oldValue]) {
+ return;
+ }
+ // Free the stored app delegate instance because it has been changed to a different instance to
+ // avoid keeping it alive forever.
+ if ([oldValue isEqual:gOriginalAppDelegate]) {
+ gOriginalAppDelegate = nil;
+ // Remove the observer. Parse it to NSObject to avoid warning.
+ [[GULAppDelegateSwizzler sharedApplication] removeObserver:self
+ forKeyPath:kGULAppDelegateKeyPath];
+ _isObserving = NO;
+ }
+ }
+}
+
+@end
+
+@implementation GULAppDelegateSwizzler
+
+static dispatch_once_t sProxyAppDelegateOnceToken;
+static dispatch_once_t sProxyAppDelegateRemoteNotificationOnceToken;
+
+#pragma mark - Public methods
+
++ (BOOL)isAppDelegateProxyEnabled {
+ NSDictionary *infoDictionary = [NSBundle mainBundle].infoDictionary;
+
+ id isFirebaseProxyEnabledPlistValue = infoDictionary[kGULFirebaseAppDelegateProxyEnabledPlistKey];
+ id isGoogleProxyEnabledPlistValue =
+ infoDictionary[kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey];
+
+ // Enabled by default.
+ BOOL isFirebaseAppDelegateProxyEnabled = YES;
+ BOOL isGoogleUtilitiesAppDelegateProxyEnabled = YES;
+
+ if ([isFirebaseProxyEnabledPlistValue isKindOfClass:[NSNumber class]]) {
+ isFirebaseAppDelegateProxyEnabled = [isFirebaseProxyEnabledPlistValue boolValue];
+ }
+
+ if ([isGoogleProxyEnabledPlistValue isKindOfClass:[NSNumber class]]) {
+ isGoogleUtilitiesAppDelegateProxyEnabled = [isGoogleProxyEnabledPlistValue boolValue];
+ }
+
+ // Only deactivate the proxy if it is explicitly disabled by app developers using either one of
+ // the plist flags.
+ return isFirebaseAppDelegateProxyEnabled && isGoogleUtilitiesAppDelegateProxyEnabled;
+}
+
++ (GULAppDelegateInterceptorID)registerAppDelegateInterceptor:
+ (id<GULApplicationDelegate>)interceptor {
+ NSAssert(interceptor, @"AppDelegateProxy cannot add nil interceptor");
+ NSAssert([interceptor conformsToProtocol:@protocol(GULApplicationDelegate)],
+ @"AppDelegateProxy interceptor does not conform to UIApplicationDelegate");
+
+ if (!interceptor) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling000],
+ @"AppDelegateProxy cannot add nil interceptor.");
+ return nil;
+ }
+ if (![interceptor conformsToProtocol:@protocol(GULApplicationDelegate)]) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling001],
+ @"AppDelegateProxy interceptor does not conform to UIApplicationDelegate");
+ return nil;
+ }
+
+ // The ID should be the same given the same interceptor object.
+ NSString *interceptorID = [NSString stringWithFormat:@"%@%p", kGULAppDelegatePrefix, interceptor];
+ if (!interceptorID.length) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling002],
+ @"AppDelegateProxy cannot create Interceptor ID.");
+ return nil;
+ }
+ GULZeroingWeakContainer *weakObject = [[GULZeroingWeakContainer alloc] init];
+ weakObject.object = interceptor;
+ [GULAppDelegateSwizzler interceptors][interceptorID] = weakObject;
+ return interceptorID;
+}
+
++ (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID {
+ NSAssert(interceptorID, @"AppDelegateProxy cannot unregister nil interceptor ID.");
+ NSAssert(((NSString *)interceptorID).length != 0,
+ @"AppDelegateProxy cannot unregister empty interceptor ID.");
+
+ if (!interceptorID) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling003],
+ @"AppDelegateProxy cannot unregister empty interceptor ID.");
+ return;
+ }
+
+ GULZeroingWeakContainer *weakContainer = [GULAppDelegateSwizzler interceptors][interceptorID];
+ if (!weakContainer.object) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling004],
+ @"AppDelegateProxy cannot unregister interceptor that was not registered. "
+ "Interceptor ID %@",
+ interceptorID);
+ return;
+ }
+
+ [[GULAppDelegateSwizzler interceptors] removeObjectForKey:interceptorID];
+}
+
++ (void)proxyOriginalDelegate {
+ if ([GULAppEnvironmentUtil isAppExtension]) {
+ return;
+ }
+
+ dispatch_once(&sProxyAppDelegateOnceToken, ^{
+ id<GULApplicationDelegate> originalDelegate =
+ [GULAppDelegateSwizzler sharedApplication].delegate;
+ [GULAppDelegateSwizzler proxyAppDelegate:originalDelegate];
+ });
+}
+
++ (void)proxyOriginalDelegateIncludingAPNSMethods {
+ if ([GULAppEnvironmentUtil isAppExtension]) {
+ return;
+ }
+
+ [self proxyOriginalDelegate];
+
+ dispatch_once(&sProxyAppDelegateRemoteNotificationOnceToken, ^{
+ id<GULApplicationDelegate> appDelegate = [GULAppDelegateSwizzler sharedApplication].delegate;
+
+ NSMutableDictionary *realImplementationsBySelector =
+ [objc_getAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey) mutableCopy];
+
+ [self proxyRemoteNotificationsMethodsWithAppDelegateSubClass:gAppDelegateSubclass
+ realClass:gOriginalAppDelegateClass
+ appDelegate:appDelegate
+ realImplementationsBySelector:realImplementationsBySelector];
+
+ objc_setAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey,
+ [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN);
+ [self reassignAppDelegate];
+ });
+}
+
+#pragma mark - Create proxy
+
++ (GULApplication *)sharedApplication {
+ if ([GULAppEnvironmentUtil isAppExtension]) {
+ return nil;
+ }
+ id sharedApplication = nil;
+ Class uiApplicationClass = NSClassFromString(kGULApplicationClassName);
+ if (uiApplicationClass &&
+ [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) {
+ sharedApplication = [uiApplicationClass sharedApplication];
+ }
+ return sharedApplication;
+}
+
+#pragma mark - Override default methods
+
+/** Creates a new subclass of the class of the given object and sets the isa value of the given
+ * object to the new subclass. Additionally this copies methods to that new subclass that allow us
+ * to intercept UIApplicationDelegate methods. This is better known as isa swizzling.
+ *
+ * @param appDelegate The object to which you want to isa swizzle. This has to conform to the
+ * UIApplicationDelegate subclass.
+ * @return Returns the new subclass.
+ */
++ (nullable Class)createSubclassWithObject:(id<GULApplicationDelegate>)appDelegate {
+ Class realClass = [appDelegate class];
+
+ // Create GUL_<RealAppDelegate>_<UUID>
+ NSString *classNameWithPrefix =
+ [kGULAppDelegatePrefix stringByAppendingString:NSStringFromClass(realClass)];
+ NSString *newClassName =
+ [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString];
+
+ if (NSClassFromString(newClassName)) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling005],
+ @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: "
+ @"%@, subclass: %@",
+ NSStringFromClass(realClass), newClassName);
+ return nil;
+ }
+
+ // Register the new class as subclass of the real one. Do not allocate more than the real class
+ // size.
+ Class appDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0);
+ if (appDelegateSubClass == Nil) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling006],
+ @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: "
+ @"%@, subclass: Nil",
+ NSStringFromClass(realClass));
+ return nil;
+ }
+
+ NSMutableDictionary<NSString *, NSValue *> *realImplementationsBySelector =
+ [[NSMutableDictionary alloc] init];
+
+ // For application:continueUserActivity:restorationHandler:
+ SEL continueUserActivitySEL = @selector(application:continueUserActivity:restorationHandler:);
+ [self proxyDestinationSelector:continueUserActivitySEL
+ implementationsFromSourceSelector:continueUserActivitySEL
+ fromClass:[GULAppDelegateSwizzler class]
+ toClass:appDelegateSubClass
+ realClass:realClass
+ storeDestinationImplementationTo:realImplementationsBySelector];
+
+#if TARGET_OS_IOS || TARGET_OS_TV
+ // Add the following methods from GULAppDelegate class, and store the real implementation so it
+ // can forward to the real one.
+ // For application:openURL:options:
+ SEL applicationOpenURLOptionsSEL = @selector(application:openURL:options:);
+ if ([appDelegate respondsToSelector:applicationOpenURLOptionsSEL]) {
+ // Only add the application:openURL:options: method if the original AppDelegate implements it.
+ // This fixes a bug if an app only implements application:openURL:sourceApplication:annotation:
+ // (if we add the `options` method, iOS sees that one exists and does not call the
+ // `sourceApplication` method, which in this case is the only one the app implements).
+
+ [self proxyDestinationSelector:applicationOpenURLOptionsSEL
+ implementationsFromSourceSelector:applicationOpenURLOptionsSEL
+ fromClass:[GULAppDelegateSwizzler class]
+ toClass:appDelegateSubClass
+ realClass:realClass
+ storeDestinationImplementationTo:realImplementationsBySelector];
+ }
+
+ // For application:handleEventsForBackgroundURLSession:completionHandler:
+ SEL handleEventsForBackgroundURLSessionSEL = @selector(application:
+ handleEventsForBackgroundURLSession:completionHandler:);
+ [self proxyDestinationSelector:handleEventsForBackgroundURLSessionSEL
+ implementationsFromSourceSelector:handleEventsForBackgroundURLSessionSEL
+ fromClass:[GULAppDelegateSwizzler class]
+ toClass:appDelegateSubClass
+ realClass:realClass
+ storeDestinationImplementationTo:realImplementationsBySelector];
+#endif // TARGET_OS_IOS || TARGET_OS_TV
+
+#if TARGET_OS_IOS
+ // For application:openURL:sourceApplication:annotation:
+ SEL openURLSourceApplicationAnnotationSEL = @selector(application:
+ openURL:sourceApplication:annotation:);
+
+ [self proxyDestinationSelector:openURLSourceApplicationAnnotationSEL
+ implementationsFromSourceSelector:openURLSourceApplicationAnnotationSEL
+ fromClass:[GULAppDelegateSwizzler class]
+ toClass:appDelegateSubClass
+ realClass:realClass
+ storeDestinationImplementationTo:realImplementationsBySelector];
+#endif // TARGET_OS_IOS
+
+ // Override the description too so the custom class name will not show up.
+ [GULAppDelegateSwizzler addInstanceMethodWithDestinationSelector:@selector(description)
+ withImplementationFromSourceSelector:@selector(fakeDescription)
+ fromClass:[self class]
+ toClass:appDelegateSubClass];
+
+ // Store original implementations to a fake property of the original delegate.
+ objc_setAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey,
+ [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ objc_setAssociatedObject(appDelegate, &kGULRealClassKey, realClass,
+ OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+
+ // The subclass size has to be exactly the same size with the original class size. The subclass
+ // cannot have more ivars/properties than its superclass since it will cause an offset in memory
+ // that can lead to overwriting the isa of an object in the next frame.
+ if (class_getInstanceSize(realClass) != class_getInstanceSize(appDelegateSubClass)) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling007],
+ @"Cannot create subclass of App Delegate, because the created subclass is not the "
+ @"same size. %@",
+ NSStringFromClass(realClass));
+ NSAssert(NO, @"Classes must be the same size to swizzle isa");
+ return nil;
+ }
+
+ // Make the newly created class to be the subclass of the real App Delegate class.
+ objc_registerClassPair(appDelegateSubClass);
+ if (object_setClass(appDelegate, appDelegateSubClass)) {
+ GULLogDebug(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling008],
+ @"Successfully created App Delegate Proxy automatically. To disable the "
+ @"proxy, set the flag %@ to NO (Boolean) in the Info.plist",
+ [GULAppDelegateSwizzler correctAppDelegateProxyKey]);
+ }
+
+ return appDelegateSubClass;
+}
+
++ (void)proxyRemoteNotificationsMethodsWithAppDelegateSubClass:(Class)appDelegateSubClass
+ realClass:(Class)realClass
+ appDelegate:(id)appDelegate
+ realImplementationsBySelector:
+ (NSMutableDictionary *)realImplementationsBySelector {
+ if (realClass == nil || appDelegateSubClass == nil || appDelegate == nil ||
+ realImplementationsBySelector == nil) {
+ // The App Delegate has not been swizzled.
+ return;
+ }
+
+ // For application:didRegisterForRemoteNotificationsWithDeviceToken:
+ SEL didRegisterForRemoteNotificationsSEL =
+ NSSelectorFromString(kGULDidRegisterForRemoteNotificationsSEL);
+ SEL didRegisterForRemoteNotificationsDonorSEL = @selector(application:
+ donor_didRegisterForRemoteNotificationsWithDeviceToken:);
+
+ [self proxyDestinationSelector:didRegisterForRemoteNotificationsSEL
+ implementationsFromSourceSelector:didRegisterForRemoteNotificationsDonorSEL
+ fromClass:[GULAppDelegateSwizzler class]
+ toClass:appDelegateSubClass
+ realClass:realClass
+ storeDestinationImplementationTo:realImplementationsBySelector];
+
+ // For application:didFailToRegisterForRemoteNotificationsWithError:
+ SEL didFailToRegisterForRemoteNotificationsSEL =
+ NSSelectorFromString(kGULDidFailToRegisterForRemoteNotificationsSEL);
+ SEL didFailToRegisterForRemoteNotificationsDonorSEL = @selector(application:
+ donor_didFailToRegisterForRemoteNotificationsWithError:);
+
+ [self proxyDestinationSelector:didFailToRegisterForRemoteNotificationsSEL
+ implementationsFromSourceSelector:didFailToRegisterForRemoteNotificationsDonorSEL
+ fromClass:[GULAppDelegateSwizzler class]
+ toClass:appDelegateSubClass
+ realClass:realClass
+ storeDestinationImplementationTo:realImplementationsBySelector];
+
+ // For application:didReceiveRemoteNotification:
+ SEL didReceiveRemoteNotificationSEL = NSSelectorFromString(kGULDidReceiveRemoteNotificationSEL);
+ SEL didReceiveRemoteNotificationDonotSEL = @selector(application:
+ donor_didReceiveRemoteNotification:);
+
+ [self proxyDestinationSelector:didReceiveRemoteNotificationSEL
+ implementationsFromSourceSelector:didReceiveRemoteNotificationDonotSEL
+ fromClass:[GULAppDelegateSwizzler class]
+ toClass:appDelegateSubClass
+ realClass:realClass
+ storeDestinationImplementationTo:realImplementationsBySelector];
+
+ // For application:didReceiveRemoteNotification:fetchCompletionHandler:
+#if !TARGET_OS_WATCH && !TARGET_OS_OSX
+ SEL didReceiveRemoteNotificationWithCompletionSEL =
+ NSSelectorFromString(kGULDidReceiveRemoteNotificationWithCompletionSEL);
+ SEL didReceiveRemoteNotificationWithCompletionDonorSEL =
+ @selector(application:donor_didReceiveRemoteNotification:fetchCompletionHandler:);
+ if ([appDelegate respondsToSelector:didReceiveRemoteNotificationWithCompletionSEL]) {
+ // Only add the application:didReceiveRemoteNotification:fetchCompletionHandler: method if
+ // the original AppDelegate implements it.
+ // This fixes a bug if an app only implements application:didReceiveRemoteNotification:
+ // (if we add the method with completion, iOS sees that one exists and does not call
+ // the method without the completion, which in this case is the only one the app implements).
+
+ [self proxyDestinationSelector:didReceiveRemoteNotificationWithCompletionSEL
+ implementationsFromSourceSelector:didReceiveRemoteNotificationWithCompletionDonorSEL
+ fromClass:[GULAppDelegateSwizzler class]
+ toClass:appDelegateSubClass
+ realClass:realClass
+ storeDestinationImplementationTo:realImplementationsBySelector];
+ }
+#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX
+}
+
+/// We have to do this to invalidate the cache that caches the original respondsToSelector of
+/// openURL handlers. Without this, it won't call the default implementations because the system
+/// checks and caches them.
+/// Register KVO only once. Otherwise, the observing method will be called as many times as
+/// being registered.
++ (void)reassignAppDelegate {
+#if !TARGET_OS_WATCH
+ id<GULApplicationDelegate> delegate = [self sharedApplication].delegate;
+ [self sharedApplication].delegate = nil;
+ [self sharedApplication].delegate = delegate;
+ gOriginalAppDelegate = delegate;
+ [[GULAppDelegateObserver sharedInstance] observeUIApplication];
+#endif
+}
+
+#pragma mark - Helper methods
+
++ (GULMutableDictionary *)interceptors {
+ static dispatch_once_t onceToken;
+ static GULMutableDictionary *sInterceptors;
+ dispatch_once(&onceToken, ^{
+ sInterceptors = [[GULMutableDictionary alloc] init];
+ });
+ return sInterceptors;
+}
+
++ (nullable NSValue *)originalImplementationForSelector:(SEL)selector object:(id)object {
+ NSDictionary *realImplementationBySelector =
+ objc_getAssociatedObject(object, &kGULRealIMPBySelectorKey);
+ return realImplementationBySelector[NSStringFromSelector(selector)];
+}
+
++ (void)proxyDestinationSelector:(SEL)destinationSelector
+ implementationsFromSourceSelector:(SEL)sourceSelector
+ fromClass:(Class)sourceClass
+ toClass:(Class)destinationClass
+ realClass:(Class)realClass
+ storeDestinationImplementationTo:
+ (NSMutableDictionary<NSString *, NSValue *> *)destinationImplementationsBySelector {
+ [self addInstanceMethodWithDestinationSelector:destinationSelector
+ withImplementationFromSourceSelector:sourceSelector
+ fromClass:sourceClass
+ toClass:destinationClass];
+ IMP sourceImplementation =
+ [GULAppDelegateSwizzler implementationOfMethodSelector:destinationSelector
+ fromClass:realClass];
+ NSValue *sourceImplementationPointer = [NSValue valueWithPointer:sourceImplementation];
+
+ NSString *destinationSelectorString = NSStringFromSelector(destinationSelector);
+ destinationImplementationsBySelector[destinationSelectorString] = sourceImplementationPointer;
+}
+
+/** Copies a method identified by the methodSelector from one class to the other. After this method
+ * is called, performing [toClassInstance methodSelector] will be similar to calling
+ * [fromClassInstance methodSelector]. This method does nothing if toClass already has a method
+ * identified by methodSelector.
+ *
+ * @param methodSelector The SEL that identifies both the method on the fromClass as well as the
+ * one on the toClass.
+ * @param fromClass The class from which a method is sourced.
+ * @param toClass The class to which the method is added. If the class already has a method with
+ * the same selector, this has no effect.
+ */
++ (void)addInstanceMethodWithSelector:(SEL)methodSelector
+ fromClass:(Class)fromClass
+ toClass:(Class)toClass {
+ [self addInstanceMethodWithDestinationSelector:methodSelector
+ withImplementationFromSourceSelector:methodSelector
+ fromClass:fromClass
+ toClass:toClass];
+}
+
+/** Copies a method identified by the sourceSelector from the fromClass as a method for the
+ * destinationSelector on the toClass. After this method is called, performing
+ * [toClassInstance destinationSelector] will be similar to calling
+ * [fromClassInstance sourceSelector]. This method does nothing if toClass already has a method
+ * identified by destinationSelector.
+ *
+ * @param destinationSelector The SEL that identifies the method on the toClass.
+ * @param sourceSelector The SEL that identifies the method on the fromClass.
+ * @param fromClass The class from which a method is sourced.
+ * @param toClass The class to which the method is added. If the class already has a method with
+ * the same selector, this has no effect.
+ */
++ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector
+ withImplementationFromSourceSelector:(SEL)sourceSelector
+ fromClass:(Class)fromClass
+ toClass:(Class)toClass {
+ Method method = class_getInstanceMethod(fromClass, sourceSelector);
+ IMP methodIMP = method_getImplementation(method);
+ const char *types = method_getTypeEncoding(method);
+ if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) {
+ GULLogWarning(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling009],
+ @"Cannot copy method to destination selector %@ as it already exists",
+ NSStringFromSelector(destinationSelector));
+ }
+}
+
+/** Gets the IMP of the instance method on the class identified by the selector.
+ *
+ * @param selector The selector of which the IMP is to be fetched.
+ * @param aClass The class from which the IMP is to be fetched.
+ * @return The IMP of the instance method identified by selector and aClass.
+ */
++ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass {
+ Method aMethod = class_getInstanceMethod(aClass, selector);
+ return method_getImplementation(aMethod);
+}
+
+/** Enumerates through all the interceptors and if they respond to a given selector, executes a
+ * GULAppDelegateInterceptorCallback with the interceptor.
+ *
+ * @param methodSelector The SEL to check if an interceptor responds to.
+ * @param callback the GULAppDelegateInterceptorCallback.
+ */
++ (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector
+ callback:(GULAppDelegateInterceptorCallback)callback {
+ if (!callback) {
+ return;
+ }
+
+ NSDictionary *interceptors = [GULAppDelegateSwizzler interceptors].dictionary;
+ [interceptors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
+ GULZeroingWeakContainer *interceptorContainer = obj;
+ id interceptor = interceptorContainer.object;
+ if (!interceptor) {
+ GULLogWarning(
+ kGULLoggerSwizzler, NO,
+ [NSString
+ stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling010],
+ @"AppDelegateProxy cannot find interceptor with ID %@. Removing the interceptor.", key);
+ [[GULAppDelegateSwizzler interceptors] removeObjectForKey:key];
+ return;
+ }
+ if ([interceptor respondsToSelector:methodSelector]) {
+ callback(interceptor);
+ }
+ }];
+}
+
+// The methods below are donor methods which are added to the dynamic subclass of the App Delegate.
+// They are called within the scope of the real App Delegate so |self| does not refer to the
+// GULAppDelegateSwizzler instance but the real App Delegate instance.
+
+#pragma mark - [Donor Methods] Overridden instance description method
+
+- (NSString *)fakeDescription {
+ Class realClass = objc_getAssociatedObject(self, &kGULRealClassKey);
+ return [NSString stringWithFormat:@"<%@: %p>", realClass, self];
+}
+
+#pragma mark - [Donor Methods] URL overridden handler methods
+#if TARGET_OS_IOS || TARGET_OS_TV
+
+- (BOOL)application:(GULApplication *)application
+ openURL:(NSURL *)url
+ options:(NSDictionary<NSString *, id> *)options {
+ SEL methodSelector = @selector(application:openURL:options:);
+ // Call the real implementation if the real App Delegate has any.
+ NSValue *openURLIMPPointer =
+ [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self];
+ GULRealOpenURLOptionsIMP openURLOptionsIMP = [openURLIMPPointer pointerValue];
+
+ __block BOOL returnedValue = NO;
+
+// This is needed to for the library to be warning free on iOS versions < 9.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+ [GULAppDelegateSwizzler
+ notifyInterceptorsWithMethodSelector:methodSelector
+ callback:^(id<GULApplicationDelegate> interceptor) {
+ returnedValue |= [interceptor application:application
+ openURL:url
+ options:options];
+ }];
+#pragma clang diagnostic pop
+ if (openURLOptionsIMP) {
+ returnedValue |= openURLOptionsIMP(self, methodSelector, application, url, options);
+ }
+ return returnedValue;
+}
+
+#endif // TARGET_OS_IOS || TARGET_OS_TV
+
+#if TARGET_OS_IOS
+
+- (BOOL)application:(GULApplication *)application
+ openURL:(NSURL *)url
+ sourceApplication:(NSString *)sourceApplication
+ annotation:(id)annotation {
+ SEL methodSelector = @selector(application:openURL:sourceApplication:annotation:);
+
+ // Call the real implementation if the real App Delegate has any.
+ NSValue *openURLSourceAppAnnotationIMPPointer =
+ [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self];
+ GULRealOpenURLSourceApplicationAnnotationIMP openURLSourceApplicationAnnotationIMP =
+ [openURLSourceAppAnnotationIMPPointer pointerValue];
+
+ __block BOOL returnedValue = NO;
+ [GULAppDelegateSwizzler
+ notifyInterceptorsWithMethodSelector:methodSelector
+ callback:^(id<GULApplicationDelegate> interceptor) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ returnedValue |= [interceptor application:application
+ openURL:url
+ sourceApplication:sourceApplication
+ annotation:annotation];
+#pragma clang diagnostic pop
+ }];
+ if (openURLSourceApplicationAnnotationIMP) {
+ returnedValue |= openURLSourceApplicationAnnotationIMP(self, methodSelector, application, url,
+ sourceApplication, annotation);
+ }
+ return returnedValue;
+}
+
+#endif // TARGET_OS_IOS
+
+#pragma mark - [Donor Methods] Network overridden handler methods
+
+#if TARGET_OS_IOS || TARGET_OS_TV
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wstrict-prototypes"
+- (void)application:(GULApplication *)application
+ handleEventsForBackgroundURLSession:(NSString *)identifier
+ completionHandler:(void (^)())completionHandler API_AVAILABLE(ios(7.0)) {
+#pragma clang diagnostic pop
+ SEL methodSelector = @selector(application:
+ handleEventsForBackgroundURLSession:completionHandler:);
+ NSValue *handleBackgroundSessionPointer =
+ [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self];
+ GULRealHandleEventsForBackgroundURLSessionIMP handleBackgroundSessionIMP =
+ [handleBackgroundSessionPointer pointerValue];
+
+ // Notify interceptors.
+ [GULAppDelegateSwizzler
+ notifyInterceptorsWithMethodSelector:methodSelector
+ callback:^(id<GULApplicationDelegate> interceptor) {
+ [interceptor application:application
+ handleEventsForBackgroundURLSession:identifier
+ completionHandler:completionHandler];
+ }];
+ // Call the real implementation if the real App Delegate has any.
+ if (handleBackgroundSessionIMP) {
+ handleBackgroundSessionIMP(self, methodSelector, application, identifier, completionHandler);
+ }
+}
+
+#endif // TARGET_OS_IOS || TARGET_OS_TV
+
+#pragma mark - [Donor Methods] User Activities overridden handler methods
+
+- (BOOL)application:(GULApplication *)application
+ continueUserActivity:(NSUserActivity *)userActivity
+ restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
+ SEL methodSelector = @selector(application:continueUserActivity:restorationHandler:);
+ NSValue *continueUserActivityIMPPointer =
+ [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self];
+ GULRealContinueUserActivityIMP continueUserActivityIMP =
+ continueUserActivityIMPPointer.pointerValue;
+
+ __block BOOL returnedValue = NO;
+#if !TARGET_OS_WATCH
+ [GULAppDelegateSwizzler
+ notifyInterceptorsWithMethodSelector:methodSelector
+ callback:^(id<GULApplicationDelegate> interceptor) {
+ returnedValue |= [interceptor application:application
+ continueUserActivity:userActivity
+ restorationHandler:restorationHandler];
+ }];
+#endif
+ // Call the real implementation if the real App Delegate has any.
+ if (continueUserActivityIMP) {
+ returnedValue |= continueUserActivityIMP(self, methodSelector, application, userActivity,
+ restorationHandler);
+ }
+ return returnedValue;
+}
+
+#pragma mark - [Donor Methods] Remote Notifications
+
+- (void)application:(GULApplication *)application
+ donor_didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
+ SEL methodSelector = NSSelectorFromString(kGULDidRegisterForRemoteNotificationsSEL);
+
+ NSValue *didRegisterForRemoteNotificationsIMPPointer =
+ [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self];
+ GULRealDidRegisterForRemoteNotificationsIMP didRegisterForRemoteNotificationsIMP =
+ [didRegisterForRemoteNotificationsIMPPointer pointerValue];
+
+ // Notify interceptors.
+ [GULAppDelegateSwizzler
+ notifyInterceptorsWithMethodSelector:methodSelector
+ callback:^(id<GULApplicationDelegate> interceptor) {
+ NSInvocation *invocation = [GULAppDelegateSwizzler
+ appDelegateInvocationForSelector:methodSelector];
+ [invocation setTarget:interceptor];
+ [invocation setSelector:methodSelector];
+ [invocation setArgument:(void *)(&application) atIndex:2];
+ [invocation setArgument:(void *)(&deviceToken) atIndex:3];
+ [invocation invoke];
+ }];
+ // Call the real implementation if the real App Delegate has any.
+ if (didRegisterForRemoteNotificationsIMP) {
+ didRegisterForRemoteNotificationsIMP(self, methodSelector, application, deviceToken);
+ }
+}
+
+- (void)application:(GULApplication *)application
+ donor_didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
+ SEL methodSelector = NSSelectorFromString(kGULDidFailToRegisterForRemoteNotificationsSEL);
+ NSValue *didFailToRegisterForRemoteNotificationsIMPPointer =
+ [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self];
+ GULRealDidFailToRegisterForRemoteNotificationsIMP didFailToRegisterForRemoteNotificationsIMP =
+ [didFailToRegisterForRemoteNotificationsIMPPointer pointerValue];
+
+ // Notify interceptors.
+ [GULAppDelegateSwizzler
+ notifyInterceptorsWithMethodSelector:methodSelector
+ callback:^(id<GULApplicationDelegate> interceptor) {
+ NSInvocation *invocation = [GULAppDelegateSwizzler
+ appDelegateInvocationForSelector:methodSelector];
+ [invocation setTarget:interceptor];
+ [invocation setSelector:methodSelector];
+ [invocation setArgument:(void *)(&application) atIndex:2];
+ [invocation setArgument:(void *)(&error) atIndex:3];
+ [invocation invoke];
+ }];
+ // Call the real implementation if the real App Delegate has any.
+ if (didFailToRegisterForRemoteNotificationsIMP) {
+ didFailToRegisterForRemoteNotificationsIMP(self, methodSelector, application, error);
+ }
+}
+
+#if !TARGET_OS_WATCH && !TARGET_OS_OSX
+- (void)application:(GULApplication *)application
+ donor_didReceiveRemoteNotification:(NSDictionary *)userInfo
+ fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
+ SEL methodSelector = NSSelectorFromString(kGULDidReceiveRemoteNotificationWithCompletionSEL);
+ NSValue *didReceiveRemoteNotificationWithCompletionIMPPointer =
+ [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self];
+ GULRealDidReceiveRemoteNotificationWithCompletionIMP
+ didReceiveRemoteNotificationWithCompletionIMP =
+ [didReceiveRemoteNotificationWithCompletionIMPPointer pointerValue];
+
+ // Notify interceptors.
+ [GULAppDelegateSwizzler
+ notifyInterceptorsWithMethodSelector:methodSelector
+ callback:^(id<GULApplicationDelegate> interceptor) {
+ NSInvocation *invocation = [GULAppDelegateSwizzler
+ appDelegateInvocationForSelector:methodSelector];
+ [invocation setTarget:interceptor];
+ [invocation setSelector:methodSelector];
+ [invocation setArgument:(void *)(&application) atIndex:2];
+ [invocation setArgument:(void *)(&userInfo) atIndex:3];
+ [invocation setArgument:(void *)(&completionHandler) atIndex:4];
+ [invocation invoke];
+ }];
+ // Call the real implementation if the real App Delegate has any.
+ if (didReceiveRemoteNotificationWithCompletionIMP) {
+ didReceiveRemoteNotificationWithCompletionIMP(self, methodSelector, application, userInfo,
+ completionHandler);
+ }
+}
+#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX
+
+- (void)application:(GULApplication *)application
+ donor_didReceiveRemoteNotification:(NSDictionary *)userInfo {
+ SEL methodSelector = NSSelectorFromString(kGULDidReceiveRemoteNotificationSEL);
+ NSValue *didReceiveRemoteNotificationIMPPointer =
+ [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self];
+ GULRealDidReceiveRemoteNotificationIMP didReceiveRemoteNotificationIMP =
+ [didReceiveRemoteNotificationIMPPointer pointerValue];
+
+ // Notify interceptors.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ [GULAppDelegateSwizzler
+ notifyInterceptorsWithMethodSelector:methodSelector
+ callback:^(id<GULApplicationDelegate> interceptor) {
+ NSInvocation *invocation = [GULAppDelegateSwizzler
+ appDelegateInvocationForSelector:methodSelector];
+ [invocation setTarget:interceptor];
+ [invocation setSelector:methodSelector];
+ [invocation setArgument:(void *)(&application) atIndex:2];
+ [invocation setArgument:(void *)(&userInfo) atIndex:3];
+ [invocation invoke];
+ }];
+#pragma clang diagnostic pop
+ // Call the real implementation if the real App Delegate has any.
+ if (didReceiveRemoteNotificationIMP) {
+ didReceiveRemoteNotificationIMP(self, methodSelector, application, userInfo);
+ }
+}
+
++ (nullable NSInvocation *)appDelegateInvocationForSelector:(SEL)selector {
+ struct objc_method_description methodDescription =
+ protocol_getMethodDescription(@protocol(GULApplicationDelegate), selector, NO, YES);
+ if (methodDescription.types == NULL) {
+ return nil;
+ }
+
+ NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:methodDescription.types];
+ return [NSInvocation invocationWithMethodSignature:signature];
+}
+
++ (void)proxyAppDelegate:(id<GULApplicationDelegate>)appDelegate {
+ if (![appDelegate conformsToProtocol:@protocol(GULApplicationDelegate)]) {
+ GULLogNotice(
+ kGULLoggerSwizzler, NO,
+ [NSString
+ stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate],
+ @"App Delegate does not conform to UIApplicationDelegate protocol. %@",
+ [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]);
+ return;
+ }
+
+ id<GULApplicationDelegate> originalDelegate = appDelegate;
+ // Do not create a subclass if it is not enabled.
+ if (![GULAppDelegateSwizzler isAppDelegateProxyEnabled]) {
+ GULLogNotice(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling011],
+ @"App Delegate Proxy is disabled. %@",
+ [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]);
+ return;
+ }
+ // Do not accept nil delegate.
+ if (!originalDelegate) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling012],
+ @"Cannot create App Delegate Proxy because App Delegate instance is nil. %@",
+ [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]);
+ return;
+ }
+
+ @try {
+ gOriginalAppDelegateClass = [originalDelegate class];
+ gAppDelegateSubclass = [self createSubclassWithObject:originalDelegate];
+ [self reassignAppDelegate];
+ } @catch (NSException *exception) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeAppDelegateSwizzling013],
+ @"Cannot create App Delegate Proxy. %@",
+ [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]);
+ return;
+ }
+}
+
+#pragma mark - Methods to print correct debug logs
+
++ (NSString *)correctAppDelegateProxyKey {
+ return NSClassFromString(@"FIRCore") ? kGULFirebaseAppDelegateProxyEnabledPlistKey
+ : kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey;
+}
+
++ (NSString *)correctAlternativeWhenAppDelegateProxyNotCreated {
+ return NSClassFromString(@"FIRCore")
+ ? @"To log deep link campaigns manually, call the methods in "
+ @"FIRAnalytics+AppDelegate.h."
+ : @"";
+}
+
+#pragma mark - Private Methods for Testing
+
++ (void)clearInterceptors {
+ [[self interceptors] removeAllObjects];
+}
+
++ (void)resetProxyOriginalDelegateOnceToken {
+ sProxyAppDelegateOnceToken = 0;
+ sProxyAppDelegateRemoteNotificationOnceToken = 0;
+}
+
++ (id<GULApplicationDelegate>)originalDelegate {
+ return gOriginalAppDelegate;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h
new file mode 100644
index 00000000..eb3abb1e
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * 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 <Foundation/Foundation.h>
+#import "GoogleUtilities/AppDelegateSwizzler/Private/GULAppDelegateSwizzler.h"
+#import "GoogleUtilities/Network/Private/GULMutableDictionary.h"
+
+@class GULApplication;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GULAppDelegateSwizzler ()
+
+/** ISA Swizzles the given appDelegate as the original app delegate would be.
+ *
+ * @param appDelegate The object that needs to be isa swizzled. This should conform to the
+ * application delegate protocol.
+ */
++ (void)proxyAppDelegate:(id<GULApplicationDelegate>)appDelegate;
+
+/** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer.
+ *
+ * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is
+ * the interceptorID.
+ */
++ (GULMutableDictionary *)interceptors;
+
+/** Deletes all the registered interceptors. */
++ (void)clearInterceptors;
+
+/** Resets the token that prevents the app delegate proxy from being isa swizzled multiple times. */
++ (void)resetProxyOriginalDelegateOnceToken;
+
+/** Returns the original app delegate that was proxied.
+ *
+ * @return The original app delegate instance that was proxied.
+ */
++ (id<GULApplicationDelegate>)originalDelegate;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Private/GULAppDelegateSwizzler.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Private/GULAppDelegateSwizzler.h
new file mode 100644
index 00000000..b15925f4
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Private/GULAppDelegateSwizzler.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * 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 <Foundation/Foundation.h>
+
+#if SWIFT_PACKAGE
+#import "GoogleUtilities/AppDelegateSwizzler/Private/GULApplication.h"
+#else
+#import <GoogleUtilities/GULApplication.h>
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NSString *const GULAppDelegateInterceptorID;
+
+/** This class contains methods that isa swizzle the app delegate. */
+@interface GULAppDelegateSwizzler : NSProxy
+
+/** Registers an app delegate interceptor whose methods will be invoked as they're invoked on the
+ * original app delegate.
+ *
+ * @param interceptor An instance of a class that conforms to the application delegate protocol.
+ * The interceptor is NOT retained.
+ * @return A unique GULAppDelegateInterceptorID if interceptor was successfully registered; nil
+ * if it fails.
+ */
++ (nullable GULAppDelegateInterceptorID)registerAppDelegateInterceptor:
+ (id<GULApplicationDelegate>)interceptor;
+
+/** Unregisters an interceptor with the given ID if it exists.
+ *
+ * @param interceptorID The object that was generated when the interceptor was registered.
+ */
++ (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID;
+
+/** This method ensures that the original app delegate has been proxied. Call this before
+ * registering your interceptor. This method is safe to call multiple times (but it only proxies
+ * the app delegate once).
+ *
+ * This method doesn't proxy APNS related methods:
+ * @code
+ * - application:didRegisterForRemoteNotificationsWithDeviceToken:
+ * - application:didFailToRegisterForRemoteNotificationsWithError:
+ * - application:didReceiveRemoteNotification:fetchCompletionHandler:
+ * - application:didReceiveRemoteNotification:
+ * @endcode
+ *
+ * To proxy these methods use +[GULAppDelegateSwizzler
+ * proxyOriginalDelegateIncludingAPNSMethods]. The methods have to be proxied separately to
+ * avoid potential warnings from Apple review about missing Push Notification Entitlement (e.g.
+ * https://github.com/firebase/firebase-ios-sdk/issues/2807)
+ *
+ * The method has no effect for extensions.
+ *
+ * @see proxyOriginalDelegateIncludingAPNSMethods
+ */
++ (void)proxyOriginalDelegate;
+
+/** This method ensures that the original app delegate has been proxied including APNS related
+ * methods. Call this before registering your interceptor. This method is safe to call multiple
+ * times (but it only proxies the app delegate once) or
+ * after +[GULAppDelegateSwizzler proxyOriginalDelegate]
+ *
+ * This method calls +[GULAppDelegateSwizzler proxyOriginalDelegate] under the hood.
+ * After calling this method the following App Delegate methods will be proxied in addition to
+ * the methods proxied by proxyOriginalDelegate:
+ * @code
+ * - application:didRegisterForRemoteNotificationsWithDeviceToken:
+ * - application:didFailToRegisterForRemoteNotificationsWithError:
+ * - application:didReceiveRemoteNotification:fetchCompletionHandler:
+ * - application:didReceiveRemoteNotification:
+ * @endcode
+ *
+ * The method has no effect for extensions.
+ *
+ * @see proxyOriginalDelegate
+ */
++ (void)proxyOriginalDelegateIncludingAPNSMethods;
+
+/** Indicates whether app delegate proxy is explicitly disabled or enabled. Enabled by default.
+ *
+ * @return YES if AppDelegateProxy is Enabled, NO otherwise.
+ */
++ (BOOL)isAppDelegateProxyEnabled;
+
+/** Returns the current sharedApplication.
+ *
+ * @return the current application instance if in an app, or nil if in extension or if it doesn't
+ * exist.
+ */
++ (nullable GULApplication *)sharedApplication;
+
+/** Do not initialize this class. */
+- (instancetype)init NS_UNAVAILABLE;
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Private/GULApplication.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Private/GULApplication.h
new file mode 100644
index 00000000..80672124
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Private/GULApplication.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * 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 <Foundation/Foundation.h>
+
+#if TARGET_OS_IOS || TARGET_OS_TV
+
+#import <UIKit/UIKit.h>
+
+#define GULApplication UIApplication
+#define GULApplicationDelegate UIApplicationDelegate
+#define GULUserActivityRestoring UIUserActivityRestoring
+
+static NSString *const kGULApplicationClassName = @"UIApplication";
+
+#elif TARGET_OS_OSX
+
+#import <AppKit/AppKit.h>
+
+#define GULApplication NSApplication
+#define GULApplicationDelegate NSApplicationDelegate
+#define GULUserActivityRestoring NSUserActivityRestoring
+
+static NSString *const kGULApplicationClassName = @"NSApplication";
+
+#elif TARGET_OS_WATCH
+
+#import <WatchKit/WatchKit.h>
+
+// We match the according watchOS API but swizzling should not work in watch
+#define GULApplication WKExtension
+#define GULApplicationDelegate WKExtensionDelegate
+#define GULUserActivityRestoring NSUserActivityRestoring
+
+static NSString *const kGULApplicationClassName = @"WKExtension";
+
+#endif
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h
new file mode 100644
index 00000000..053ce843
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * 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 <Foundation/Foundation.h>
+
+typedef NS_ENUM(NSInteger, GULSwizzlerMessageCode) {
+ // App Delegate Swizzling.
+ kGULSwizzlerMessageCodeAppDelegateSwizzling000 = 1000, // I-SWZ001000
+ kGULSwizzlerMessageCodeAppDelegateSwizzling001 = 1001, // I-SWZ001001
+ kGULSwizzlerMessageCodeAppDelegateSwizzling002 = 1002, // I-SWZ001002
+ kGULSwizzlerMessageCodeAppDelegateSwizzling003 = 1003, // I-SWZ001003
+ kGULSwizzlerMessageCodeAppDelegateSwizzling004 = 1004, // I-SWZ001004
+ kGULSwizzlerMessageCodeAppDelegateSwizzling005 = 1005, // I-SWZ001005
+ kGULSwizzlerMessageCodeAppDelegateSwizzling006 = 1006, // I-SWZ001006
+ kGULSwizzlerMessageCodeAppDelegateSwizzling007 = 1007, // I-SWZ001007
+ kGULSwizzlerMessageCodeAppDelegateSwizzling008 = 1008, // I-SWZ001008
+ kGULSwizzlerMessageCodeAppDelegateSwizzling009 = 1009, // I-SWZ001009
+ kGULSwizzlerMessageCodeAppDelegateSwizzling010 = 1010, // I-SWZ001010
+ kGULSwizzlerMessageCodeAppDelegateSwizzling011 = 1011, // I-SWZ001011
+ kGULSwizzlerMessageCodeAppDelegateSwizzling012 = 1012, // I-SWZ001012
+ kGULSwizzlerMessageCodeAppDelegateSwizzling013 = 1013, // I-SWZ001013
+ kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate = 1014, // I-SWZ001014
+
+ // Scene Delegate Swizzling.
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling000 = 1100, // I-SWZ001100
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling001 = 1101, // I-SWZ001101
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling002 = 1102, // I-SWZ001102
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling003 = 1103, // I-SWZ001103
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling004 = 1104, // I-SWZ001104
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling005 = 1105, // I-SWZ001105
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling006 = 1106, // I-SWZ001106
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling007 = 1107, // I-SWZ001107
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling008 = 1108, // I-SWZ001108
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling009 = 1109, // I-SWZ001109
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling010 = 1110, // I-SWZ001110
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling011 = 1111, // I-SWZ001111
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling012 = 1112, // I-SWZ001112
+ kGULSwizzlerMessageCodeSceneDelegateSwizzling013 = 1113, // I-SWZ001113
+ kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate = 1114, // I-SWZ001114
+
+ // Method Swizzling.
+ kGULSwizzlerMessageCodeMethodSwizzling000 = 2000, // I-SWZ002000
+};
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m
new file mode 100644
index 00000000..b49dbf32
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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 "GoogleUtilities/Environment/Private/GULHeartbeatDateStorage.h"
+#import "GoogleUtilities/Environment/Private/GULSecureCoding.h"
+
+@interface GULHeartbeatDateStorage ()
+/** The storage to store the date of the last sent heartbeat. */
+@property(nonatomic, readonly) NSFileCoordinator *fileCoordinator;
+/** The name of the file that stores heartbeat information. */
+@property(nonatomic, readonly) NSString *fileName;
+@end
+
+@implementation GULHeartbeatDateStorage
+
+@synthesize fileURL = _fileURL;
+
+- (instancetype)initWithFileName:(NSString *)fileName {
+ if (fileName == nil) {
+ return nil;
+ }
+
+ self = [super init];
+ if (self) {
+ _fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
+ _fileName = fileName;
+ }
+ return self;
+}
+
+/** Lazy getter for fileURL
+ * @return fileURL where heartbeat information is stored.
+ */
+- (NSURL *)fileURL {
+ if (!_fileURL) {
+ NSURL *directoryURL = [[self class] directoryPathURL];
+ [[self class] checkAndCreateDirectory:directoryURL fileCoordinator:_fileCoordinator];
+ _fileURL = [directoryURL URLByAppendingPathComponent:_fileName];
+ }
+ return _fileURL;
+}
+
+/** Returns the URL path of the Application Support folder.
+ * @return the URL path of Application Support.
+ */
++ (NSURL *)directoryPathURL {
+ NSArray<NSString *> *paths =
+ NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
+ NSArray<NSString *> *components = @[ paths.lastObject, @"Google/FIRApp" ];
+ NSString *directoryString = [NSString pathWithComponents:components];
+ NSURL *directoryURL = [NSURL fileURLWithPath:directoryString];
+ return directoryURL;
+}
+
+/** Checks and creates a directory for the directory specified by the
+ * directory url
+ * @param directoryPathURL The path to the directory which needs to be created.
+ * @param fileCoordinator The fileCoordinator object to coordinate writes to the directory.
+ */
++ (void)checkAndCreateDirectory:(NSURL *)directoryPathURL
+ fileCoordinator:(NSFileCoordinator *)fileCoordinator {
+ NSError *fileCoordinatorError = nil;
+ [fileCoordinator
+ coordinateWritingItemAtURL:directoryPathURL
+ options:0
+ error:&fileCoordinatorError
+ byAccessor:^(NSURL *writingDirectoryURL) {
+ NSError *error;
+ if (![writingDirectoryURL checkResourceIsReachableAndReturnError:&error]) {
+ // If fail creating the Application Support directory, log warning.
+ NSError *error;
+ [[NSFileManager defaultManager] createDirectoryAtURL:writingDirectoryURL
+ withIntermediateDirectories:YES
+ attributes:nil
+ error:&error];
+ }
+ }];
+}
+
+- (nullable NSMutableDictionary *)heartbeatDictionaryWithFileURL:(NSURL *)readingFileURL {
+ NSError *error;
+ NSMutableDictionary *dict;
+ NSData *objectData = [NSData dataWithContentsOfURL:readingFileURL options:0 error:&error];
+ if (objectData == nil || error != nil) {
+ dict = [NSMutableDictionary dictionary];
+ } else {
+ dict = [GULSecureCoding
+ unarchivedObjectOfClasses:[NSSet setWithArray:@[ NSDictionary.class, NSDate.class ]]
+ fromData:objectData
+ error:&error];
+ if (dict == nil || error != nil) {
+ dict = [NSMutableDictionary dictionary];
+ }
+ }
+ return dict;
+}
+
+- (nullable NSDate *)heartbeatDateForTag:(NSString *)tag {
+ __block NSMutableDictionary *dict;
+ NSError *error;
+ [self.fileCoordinator coordinateReadingItemAtURL:self.fileURL
+ options:0
+ error:&error
+ byAccessor:^(NSURL *readingURL) {
+ dict = [self heartbeatDictionaryWithFileURL:readingURL];
+ }];
+ return dict[tag];
+}
+
+- (BOOL)setHearbeatDate:(NSDate *)date forTag:(NSString *)tag {
+ NSError *error;
+ __block BOOL isSuccess = false;
+ [self.fileCoordinator coordinateReadingItemAtURL:self.fileURL
+ options:0
+ writingItemAtURL:self.fileURL
+ options:0
+ error:&error
+ byAccessor:^(NSURL *readingURL, NSURL *writingURL) {
+ NSMutableDictionary *dictionary =
+ [self heartbeatDictionaryWithFileURL:readingURL];
+ dictionary[tag] = date;
+ NSError *error;
+ isSuccess = [self writeDictionary:dictionary
+ forWritingURL:writingURL
+ error:&error];
+ }];
+ return isSuccess;
+}
+
+- (BOOL)writeDictionary:(NSMutableDictionary *)dictionary
+ forWritingURL:(NSURL *)writingFileURL
+ error:(NSError **)outError {
+ NSData *data = [GULSecureCoding archivedDataWithRootObject:dictionary error:outError];
+ if (*outError != nil) {
+ return false;
+ } else {
+ return [data writeToURL:writingFileURL atomically:YES];
+ }
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m
new file mode 100644
index 00000000..91c4495f
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m
@@ -0,0 +1,103 @@
+// Copyright 2019 Google
+//
+// 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 "GoogleUtilities/Environment/Private/GULSecureCoding.h"
+
+NSString *const kGULSecureCodingError = @"GULSecureCodingError";
+
+@implementation GULSecureCoding
+
++ (nullable id)unarchivedObjectOfClasses:(NSSet<Class> *)classes
+ fromData:(NSData *)data
+ error:(NSError **)outError {
+ id object;
+#if __has_builtin(__builtin_available)
+ if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
+ object = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:data error:outError];
+ } else
+#endif // __has_builtin(__builtin_available)
+ {
+ @try {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
+#pragma clang diagnostic pop
+ unarchiver.requiresSecureCoding = YES;
+
+ object = [unarchiver decodeObjectOfClasses:classes forKey:NSKeyedArchiveRootObjectKey];
+ } @catch (NSException *exception) {
+ if (outError) {
+ *outError = [self archivingErrorWithException:exception];
+ }
+ }
+
+ if (object == nil && outError && *outError == nil) {
+ NSString *failureReason = @"NSKeyedUnarchiver failed to unarchive data.";
+ *outError = [NSError errorWithDomain:kGULSecureCodingError
+ code:-1
+ userInfo:@{NSLocalizedFailureReasonErrorKey : failureReason}];
+ }
+ }
+
+ return object;
+}
+
++ (nullable id)unarchivedObjectOfClass:(Class)class
+ fromData:(NSData *)data
+ error:(NSError **)outError {
+ return [self unarchivedObjectOfClasses:[NSSet setWithObject:class] fromData:data error:outError];
+}
+
++ (nullable NSData *)archivedDataWithRootObject:(id<NSCoding>)object error:(NSError **)outError {
+ NSData *archiveData;
+#if __has_builtin(__builtin_available)
+ if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
+ archiveData = [NSKeyedArchiver archivedDataWithRootObject:object
+ requiringSecureCoding:YES
+ error:outError];
+ } else
+#endif // __has_builtin(__builtin_available)
+ {
+ @try {
+ NSMutableData *data = [NSMutableData data];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
+#pragma clang diagnostic pop
+ archiver.requiresSecureCoding = YES;
+
+ [archiver encodeObject:object forKey:NSKeyedArchiveRootObjectKey];
+ [archiver finishEncoding];
+
+ archiveData = [data copy];
+ } @catch (NSException *exception) {
+ if (outError) {
+ *outError = [self archivingErrorWithException:exception];
+ }
+ }
+ }
+
+ return archiveData;
+}
+
++ (NSError *)archivingErrorWithException:(NSException *)exception {
+ NSString *failureReason = [NSString
+ stringWithFormat:@"NSKeyedArchiver exception with name: %@, reason: %@, userInfo: %@",
+ exception.name, exception.reason, exception.userInfo];
+ NSDictionary *errorUserInfo = @{NSLocalizedFailureReasonErrorKey : failureReason};
+
+ return [NSError errorWithDomain:kGULSecureCodingError code:-1 userInfo:errorUserInfo];
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h
new file mode 100644
index 00000000..2fb16226
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+@interface GULAppEnvironmentUtil : NSObject
+
+/// Indicates whether the app is from Apple Store or not. Returns NO if the app is on simulator,
+/// development environment or sideloaded.
++ (BOOL)isFromAppStore;
+
+/// Indicates whether the app is a Testflight app. Returns YES if the app has sandbox receipt.
+/// Returns NO otherwise.
++ (BOOL)isAppStoreReceiptSandbox;
+
+/// Indicates whether the app is on simulator or not at runtime depending on the device
+/// architecture.
++ (BOOL)isSimulator;
+
+/// The current device model. Returns an empty string if device model cannot be retrieved.
++ (NSString *)deviceModel;
+
+/// The current operating system version. Returns an empty string if the system version cannot be
+/// retrieved.
++ (NSString *)systemVersion;
+
+/// Indicates whether it is running inside an extension or an app.
++ (BOOL)isAppExtension;
+
+/// @return Returns @YES when is run on iOS version greater or equal to 7.0
++ (BOOL)isIOS7OrHigher DEPRECATED_MSG_ATTRIBUTE(
+ "Always `YES` because only iOS 8 and higher supported. The method will be removed.");
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULHeartbeatDateStorage.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULHeartbeatDateStorage.h
new file mode 100644
index 00000000..9432dfc0
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULHeartbeatDateStorage.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Stores either a date or a dictionary to a specified file.
+@interface GULHeartbeatDateStorage : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@property(nonatomic, readonly) NSURL *fileURL;
+
+/**
+ * Default initializer.
+ * @param fileName The name of the file to store the date information.
+ * exist, it will be created if needed.
+ */
+- (instancetype)initWithFileName:(NSString *)fileName;
+
+/**
+ * Reads the date from the specified file for the given tag.
+ * @return Returns date if exists, otherwise `nil`.
+ */
+- (nullable NSDate *)heartbeatDateForTag:(NSString *)tag;
+
+/**
+ * Saves the date for the specified tag in the specified file.
+ * @return YES on success, NO otherwise.
+ */
+- (BOOL)setHearbeatDate:(NSDate *)date forTag:(NSString *)tag;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULKeychainStorage.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULKeychainStorage.h
new file mode 100644
index 00000000..dc01a836
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULKeychainStorage.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+@class FBLPromise<ValueType>;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// The class provides a convenient abstraction on top of the iOS Keychain API to save data.
+@interface GULKeychainStorage : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Initializes the keychain storage with Keychain Service name.
+ * @param service A Keychain Service name that will be used to store and retrieve objects. See also
+ * `kSecAttrService`.
+ */
+- (instancetype)initWithService:(NSString *)service;
+
+/**
+ * Get an object by key.
+ * @param key The key.
+ * @param objectClass The expected object class required by `NSSecureCoding`.
+ * @param accessGroup The Keychain Access Group.
+ *
+ * @return Returns a promise. It is resolved with an object stored by key if exists. It is resolved
+ * with `nil` when the object not found. It fails on a Keychain error.
+ */
+- (FBLPromise<id<NSSecureCoding>> *)getObjectForKey:(NSString *)key
+ objectClass:(Class)objectClass
+ accessGroup:(nullable NSString *)accessGroup;
+
+/**
+ * Saves the given object by the given key.
+ * @param object The object to store.
+ * @param key The key to store the object. If there is an existing object by the key, it will be
+ * overridden.
+ * @param accessGroup The Keychain Access Group.
+ *
+ * @return Returns which is resolved with `[NSNull null]` on success.
+ */
+- (FBLPromise<NSNull *> *)setObject:(id<NSSecureCoding>)object
+ forKey:(NSString *)key
+ accessGroup:(nullable NSString *)accessGroup;
+
+/**
+ * Removes the object by the given key.
+ * @param key The key to store the object. If there is an existing object by the key, it will be
+ * overridden.
+ * @param accessGroup The Keychain Access Group.
+ *
+ * @return Returns which is resolved with `[NSNull null]` on success.
+ */
+- (FBLPromise<NSNull *> *)removeObjectForKey:(NSString *)key
+ accessGroup:(nullable NSString *)accessGroup;
+
+#if TARGET_OS_OSX
+/// If not `nil`, then only this keychain will be used to save and read data (see
+/// `kSecMatchSearchList` and `kSecUseKeychain`. It is mostly intended to be used by unit tests.
+@property(nonatomic, nullable) SecKeychainRef keychainRef;
+#endif // TARGET_OSX
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULKeychainUtils.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULKeychainUtils.h
new file mode 100644
index 00000000..de4bef2f
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULKeychainUtils.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+FOUNDATION_EXPORT NSString *const kGULKeychainUtilsErrorDomain;
+
+/// Helper functions to access Keychain.
+@interface GULKeychainUtils : NSObject
+
+/** Fetches a keychain item data matching to the provided query.
+ * @param query A dictionary with Keychain query parameters. See docs for `SecItemCopyMatching` for
+ * details.
+ * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be
+ * assigned with an error if there is.
+ * @returns Data for the first Keychain Item matching the provided query or `nil` if there is not
+ * such an item (`outError` will be `nil` in this case) or an error occurred.
+ */
++ (nullable NSData *)getItemWithQuery:(NSDictionary *)query
+ error:(NSError *_Nullable *_Nullable)outError;
+
+/** Stores data to a Keychain Item matching to the provided query. An existing Keychain Item
+ * matching the query parameters will be updated or a new will be created.
+ * @param item A Keychain Item data to store.
+ * @param query A dictionary with Keychain query parameters. See docs for `SecItemAdd` and
+ * `SecItemUpdate` for details.
+ * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be
+ * assigned with an error if there is.
+ * @returns `YES` when data was successfully stored, `NO` otherwise.
+ */
++ (BOOL)setItem:(NSData *)item
+ withQuery:(NSDictionary *)query
+ error:(NSError *_Nullable *_Nullable)outError;
+
+/** Removes a Keychain Item matching to the provided query.
+ * @param query A dictionary with Keychain query parameters. See docs for `SecItemDelete` for
+ * details.
+ * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be
+ * assigned with an error if there is.
+ * @returns `YES` if the item was removed successfully or doesn't exist, `NO` otherwise.
+ */
++ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULSecureCoding.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULSecureCoding.h
new file mode 100644
index 00000000..8484b395
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Private/GULSecureCoding.h
@@ -0,0 +1,36 @@
+// Copyright 2019 Google
+//
+// 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 <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** The class wraps `NSKeyedArchiver` and `NSKeyedUnarchiver` API to provide a unified secure coding
+ * methods for iOS versions before and after 11.
+ */
+@interface GULSecureCoding : NSObject
+
++ (nullable id)unarchivedObjectOfClasses:(NSSet<Class> *)classes
+ fromData:(NSData *)data
+ error:(NSError **)outError;
+
++ (nullable id)unarchivedObjectOfClass:(Class)class
+ fromData:(NSData *)data
+ error:(NSError **)outError;
+
++ (nullable NSData *)archivedDataWithRootObject:(id<NSCoding>)object error:(NSError **)outError;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m
new file mode 100644
index 00000000..b6ef0cbd
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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 "GoogleUtilities/Environment/Private/GULKeychainStorage.h"
+#import <Security/Security.h>
+
+#if __has_include(<FBLPromises/FBLPromises.h>)
+#import <FBLPromises/FBLPromises.h>
+#else
+#import "FBLPromises.h"
+#endif
+
+#import "GoogleUtilities/Environment/Private/GULKeychainUtils.h"
+#import "GoogleUtilities/Environment/Private/GULSecureCoding.h"
+
+@interface GULKeychainStorage ()
+@property(nonatomic, readonly) dispatch_queue_t keychainQueue;
+@property(nonatomic, readonly) dispatch_queue_t inMemoryCacheQueue;
+@property(nonatomic, readonly) NSString *service;
+@property(nonatomic, readonly) NSCache<NSString *, id<NSSecureCoding>> *inMemoryCache;
+@end
+
+@implementation GULKeychainStorage
+
+- (instancetype)initWithService:(NSString *)service {
+ NSCache *cache = [[NSCache alloc] init];
+ // Cache up to 5 installations.
+ cache.countLimit = 5;
+ return [self initWithService:service cache:cache];
+}
+
+- (instancetype)initWithService:(NSString *)service cache:(NSCache *)cache {
+ self = [super init];
+ if (self) {
+ _keychainQueue =
+ dispatch_queue_create("com.gul.KeychainStorage.Keychain", DISPATCH_QUEUE_SERIAL);
+ _inMemoryCacheQueue =
+ dispatch_queue_create("com.gul.KeychainStorage.InMemoryCache", DISPATCH_QUEUE_SERIAL);
+ _service = [service copy];
+ _inMemoryCache = cache;
+ }
+ return self;
+}
+
+#pragma mark - Public
+
+- (FBLPromise<id<NSSecureCoding>> *)getObjectForKey:(NSString *)key
+ objectClass:(Class)objectClass
+ accessGroup:(nullable NSString *)accessGroup {
+ return [FBLPromise onQueue:self.inMemoryCacheQueue
+ do:^id _Nullable {
+ // Return cached object or fail otherwise.
+ id object = [self.inMemoryCache objectForKey:key];
+ return object
+ ?: [[NSError alloc]
+ initWithDomain:FBLPromiseErrorDomain
+ code:FBLPromiseErrorCodeValidationFailure
+ userInfo:nil];
+ }]
+ .recover(^id _Nullable(NSError *error) {
+ // Look for the object in the keychain.
+ return [self getObjectFromKeychainForKey:key
+ objectClass:objectClass
+ accessGroup:accessGroup];
+ });
+}
+
+- (FBLPromise<NSNull *> *)setObject:(id<NSSecureCoding>)object
+ forKey:(NSString *)key
+ accessGroup:(nullable NSString *)accessGroup {
+ return [FBLPromise onQueue:self.inMemoryCacheQueue
+ do:^id _Nullable {
+ // Save to the in-memory cache first.
+ [self.inMemoryCache setObject:object forKey:[key copy]];
+ return [NSNull null];
+ }]
+ .thenOn(self.keychainQueue, ^id(id result) {
+ // Then store the object to the keychain.
+ NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup];
+ NSError *error;
+ NSData *encodedObject = [GULSecureCoding archivedDataWithRootObject:object error:&error];
+ if (!encodedObject) {
+ return error;
+ }
+
+ if (![GULKeychainUtils setItem:encodedObject withQuery:query error:&error]) {
+ return error;
+ }
+
+ return [NSNull null];
+ });
+}
+
+- (FBLPromise<NSNull *> *)removeObjectForKey:(NSString *)key
+ accessGroup:(nullable NSString *)accessGroup {
+ return [FBLPromise onQueue:self.inMemoryCacheQueue
+ do:^id _Nullable {
+ [self.inMemoryCache removeObjectForKey:key];
+ return nil;
+ }]
+ .thenOn(self.keychainQueue, ^id(id result) {
+ NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup];
+
+ NSError *error;
+ if (![GULKeychainUtils removeItemWithQuery:query error:&error]) {
+ return error;
+ }
+
+ return [NSNull null];
+ });
+}
+
+#pragma mark - Private
+
+- (FBLPromise<id<NSSecureCoding>> *)getObjectFromKeychainForKey:(NSString *)key
+ objectClass:(Class)objectClass
+ accessGroup:(nullable NSString *)accessGroup {
+ // Look for the object in the keychain.
+ return [FBLPromise
+ onQueue:self.keychainQueue
+ do:^id {
+ NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup];
+ NSError *error;
+ NSData *encodedObject = [GULKeychainUtils getItemWithQuery:query error:&error];
+
+ if (error) {
+ return error;
+ }
+ if (!encodedObject) {
+ return nil;
+ }
+ id object = [GULSecureCoding unarchivedObjectOfClass:objectClass
+ fromData:encodedObject
+ error:&error];
+ if (error) {
+ return error;
+ }
+
+ return object;
+ }]
+ .thenOn(self.inMemoryCacheQueue,
+ ^id<NSSecureCoding> _Nullable(id<NSSecureCoding> _Nullable object) {
+ // Save object to the in-memory cache if exists and return the object.
+ if (object) {
+ [self.inMemoryCache setObject:object forKey:[key copy]];
+ }
+ return object;
+ });
+}
+
+- (void)resetInMemoryCache {
+ [self.inMemoryCache removeAllObjects];
+}
+
+#pragma mark - Keychain
+
+- (NSMutableDictionary<NSString *, id> *)keychainQueryWithKey:(NSString *)key
+ accessGroup:(nullable NSString *)accessGroup {
+ NSMutableDictionary<NSString *, id> *query = [NSMutableDictionary dictionary];
+
+ query[(__bridge NSString *)kSecClass] = (__bridge NSString *)kSecClassGenericPassword;
+ query[(__bridge NSString *)kSecAttrService] = self.service;
+ query[(__bridge NSString *)kSecAttrAccount] = key;
+
+ if (accessGroup) {
+ query[(__bridge NSString *)kSecAttrAccessGroup] = accessGroup;
+ }
+
+#if TARGET_OS_OSX
+ if (self.keychainRef) {
+ query[(__bridge NSString *)kSecUseKeychain] = (__bridge id)(self.keychainRef);
+ query[(__bridge NSString *)kSecMatchSearchList] = @[ (__bridge id)(self.keychainRef) ];
+ }
+#endif // TARGET_OSX
+
+ return query;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m
new file mode 100644
index 00000000..ba8731a5
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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 "GoogleUtilities/Environment/Private/GULKeychainUtils.h"
+
+NSString *const kGULKeychainUtilsErrorDomain = @"com.gul.keychain.ErrorDomain";
+
+@implementation GULKeychainUtils
+
++ (nullable NSData *)getItemWithQuery:(NSDictionary *)query
+ error:(NSError *_Nullable *_Nullable)outError {
+ NSMutableDictionary *mutableQuery = [query mutableCopy];
+
+ mutableQuery[(__bridge id)kSecReturnData] = @YES;
+ mutableQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
+
+ CFDataRef result = NULL;
+ OSStatus status =
+ SecItemCopyMatching((__bridge CFDictionaryRef)mutableQuery, (CFTypeRef *)&result);
+
+ if (status == errSecSuccess && result != NULL) {
+ if (outError) {
+ *outError = nil;
+ }
+
+ return (__bridge_transfer NSData *)result;
+ }
+
+ if (status == errSecItemNotFound) {
+ if (outError) {
+ *outError = nil;
+ }
+ } else {
+ if (outError) {
+ *outError = [self keychainErrorWithFunction:@"SecItemCopyMatching" status:status];
+ }
+ }
+ return nil;
+}
+
++ (BOOL)setItem:(NSData *)item
+ withQuery:(NSDictionary *)query
+ error:(NSError *_Nullable *_Nullable)outError {
+ NSData *existingItem = [self getItemWithQuery:query error:outError];
+ if (outError && *outError) {
+ return NO;
+ }
+
+ NSMutableDictionary *mutableQuery = [query mutableCopy];
+ mutableQuery[(__bridge id)kSecAttrAccessible] =
+ (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
+
+ OSStatus status;
+ if (!existingItem) {
+ mutableQuery[(__bridge id)kSecValueData] = item;
+ status = SecItemAdd((__bridge CFDictionaryRef)mutableQuery, NULL);
+ } else {
+ NSDictionary *attributes = @{(__bridge id)kSecValueData : item};
+ status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes);
+ }
+
+ if (status == noErr) {
+ if (outError) {
+ *outError = nil;
+ }
+ return YES;
+ }
+
+ NSString *function = existingItem ? @"SecItemUpdate" : @"SecItemAdd";
+ if (outError) {
+ *outError = [self keychainErrorWithFunction:function status:status];
+ }
+ return NO;
+}
+
++ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError {
+ OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
+
+ if (status == noErr || status == errSecItemNotFound) {
+ if (outError) {
+ *outError = nil;
+ }
+ return YES;
+ }
+
+ if (outError) {
+ *outError = [self keychainErrorWithFunction:@"SecItemDelete" status:status];
+ }
+ return NO;
+}
+
+#pragma mark - Errors
+
++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status {
+ NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status];
+ NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey : failureReason};
+ return [NSError errorWithDomain:kGULKeychainUtilsErrorDomain code:0 userInfo:userInfo];
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m
new file mode 100644
index 00000000..924b642a
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m
@@ -0,0 +1,252 @@
+// Copyright 2017 Google
+//
+// 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 "GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h"
+
+#import <Foundation/Foundation.h>
+#import <dlfcn.h>
+#import <mach-o/dyld.h>
+#import <sys/utsname.h>
+
+#if TARGET_OS_IOS
+#import <UIKit/UIKit.h>
+#endif
+
+/// The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from
+/// the iPhoneOS or Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just
+/// provide the definitions here.
+#if TARGET_OS_SIMULATOR && !defined(LC_ENCRYPTION_INFO)
+#define LC_ENCRYPTION_INFO 0x21
+struct encryption_info_command {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ uint32_t cryptoff;
+ uint32_t cryptsize;
+ uint32_t cryptid;
+};
+#endif
+
+@implementation GULAppEnvironmentUtil
+
+/// A key for the Info.plist to enable or disable checking if the App Store is running in a sandbox.
+/// This will affect your data integrity when using Firebase Analytics, as it will disable some
+/// necessary checks.
+static NSString *const kFIRAppStoreReceiptURLCheckEnabledKey =
+ @"FirebaseAppStoreReceiptURLCheckEnabled";
+
+/// The file name of the sandbox receipt. This is available on iOS >= 8.0
+static NSString *const kFIRAIdentitySandboxReceiptFileName = @"sandboxReceipt";
+
+/// The following copyright from Landon J. Fuller applies to the isAppEncrypted function.
+///
+/// Copyright (c) 2017 Landon J. Fuller <landon@landonf.org>
+/// 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.
+///
+/// Comment from <a href="http://iphonedevwiki.net/index.php/Crack_prevention">iPhone Dev Wiki
+/// Crack Prevention</a>:
+/// App Store binaries are signed by both their developer and Apple. This encrypts the binary so
+/// that decryption keys are needed in order to make the binary readable. When iOS executes the
+/// binary, the decryption keys are used to decrypt the binary into a readable state where it is
+/// then loaded into memory and executed. iOS can tell the encryption status of a binary via the
+/// cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is a non-zero
+/// value then the binary is encrypted.
+///
+/// 'Cracking' works by letting the kernel decrypt the binary then siphoning the decrypted data into
+/// a new binary file, resigning, and repackaging. This will only work on jailbroken devices as
+/// codesignature validation has been removed. Resigning takes place because while the codesignature
+/// doesn't have to be valid thanks to the jailbreak, it does have to be in place unless you have
+/// AppSync or similar to disable codesignature checks.
+///
+/// More information at <a href="http://landonf.org/2009/02/index.html">Landon Fuller's blog</a>
+static BOOL IsAppEncrypted() {
+ const struct mach_header *executableHeader = NULL;
+ for (uint32_t i = 0; i < _dyld_image_count(); i++) {
+ const struct mach_header *header = _dyld_get_image_header(i);
+ if (header && header->filetype == MH_EXECUTE) {
+ executableHeader = header;
+ break;
+ }
+ }
+
+ if (!executableHeader) {
+ return NO;
+ }
+
+ BOOL is64bit = (executableHeader->magic == MH_MAGIC_64);
+ uintptr_t cursor = (uintptr_t)executableHeader +
+ (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header));
+ const struct segment_command *segmentCommand = NULL;
+ uint32_t i = 0;
+
+ while (i++ < executableHeader->ncmds) {
+ segmentCommand = (struct segment_command *)cursor;
+
+ if (!segmentCommand) {
+ continue;
+ }
+
+ if ((!is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO) ||
+ (is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO_64)) {
+ if (is64bit) {
+ struct encryption_info_command_64 *cryptCmd =
+ (struct encryption_info_command_64 *)segmentCommand;
+ return cryptCmd && cryptCmd->cryptid != 0;
+ } else {
+ struct encryption_info_command *cryptCmd = (struct encryption_info_command *)segmentCommand;
+ return cryptCmd && cryptCmd->cryptid != 0;
+ }
+ }
+ cursor += segmentCommand->cmdsize;
+ }
+
+ return NO;
+}
+
+static BOOL HasSCInfoFolder() {
+#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
+ NSString *bundlePath = [NSBundle mainBundle].bundlePath;
+ NSString *scInfoPath = [bundlePath stringByAppendingPathComponent:@"SC_Info"];
+ return [[NSFileManager defaultManager] fileExistsAtPath:scInfoPath];
+#elif TARGET_OS_OSX
+ return NO;
+#endif
+}
+
+static BOOL HasEmbeddedMobileProvision() {
+#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
+ return [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"].length > 0;
+#elif TARGET_OS_OSX
+ return NO;
+#endif
+}
+
++ (BOOL)isFromAppStore {
+ static dispatch_once_t isEncryptedOnce;
+ static BOOL isEncrypted = NO;
+
+ dispatch_once(&isEncryptedOnce, ^{
+ isEncrypted = IsAppEncrypted();
+ });
+
+ if ([GULAppEnvironmentUtil isSimulator]) {
+ return NO;
+ }
+
+ // If an app contain the sandboxReceipt file, it means its coming from TestFlight
+ // This must be checked before the SCInfo Folder check below since TestFlight apps may
+ // also have an SCInfo folder.
+ if ([GULAppEnvironmentUtil isAppStoreReceiptSandbox]) {
+ return NO;
+ }
+
+ if (HasSCInfoFolder()) {
+ // When iTunes downloads a .ipa, it also gets a customized .sinf file which is added to the
+ // main SC_Info directory.
+ return YES;
+ }
+
+ // For iOS >= 8.0, iTunesMetadata.plist is moved outside of the sandbox. Any attempt to read
+ // the iTunesMetadata.plist outside of the sandbox will be rejected by Apple.
+ // If the app does not contain the embedded.mobileprovision which is stripped out by Apple when
+ // the app is submitted to store, then it is highly likely that it is from Apple Store.
+ return isEncrypted && !HasEmbeddedMobileProvision();
+}
+
++ (BOOL)isAppStoreReceiptSandbox {
+ // Since checking the App Store's receipt URL can be memory intensive, check the option in the
+ // Info.plist if developers opted out of this check.
+ id enableSandboxCheck =
+ [[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRAppStoreReceiptURLCheckEnabledKey];
+ if (enableSandboxCheck && [enableSandboxCheck isKindOfClass:[NSNumber class]] &&
+ ![enableSandboxCheck boolValue]) {
+ return NO;
+ }
+
+ NSURL *appStoreReceiptURL = [NSBundle mainBundle].appStoreReceiptURL;
+ NSString *appStoreReceiptFileName = appStoreReceiptURL.lastPathComponent;
+ return [appStoreReceiptFileName isEqualToString:kFIRAIdentitySandboxReceiptFileName];
+}
+
++ (BOOL)isSimulator {
+#if TARGET_OS_SIMULATOR
+ return YES;
+#elif TARGET_OS_MACCATALYST
+ return NO;
+#elif TARGET_OS_IOS || TARGET_OS_TV
+ NSString *platform = [GULAppEnvironmentUtil deviceModel];
+ return [platform isEqual:@"x86_64"] || [platform isEqual:@"i386"];
+#elif TARGET_OS_OSX
+ return NO;
+#endif
+ return NO;
+}
+
++ (NSString *)deviceModel {
+ static dispatch_once_t once;
+ static NSString *deviceModel;
+
+ dispatch_once(&once, ^{
+ struct utsname systemInfo;
+ if (uname(&systemInfo) == 0) {
+ deviceModel = [NSString stringWithUTF8String:systemInfo.machine];
+ }
+ });
+ return deviceModel;
+}
+
++ (NSString *)systemVersion {
+#if TARGET_OS_IOS
+ return [UIDevice currentDevice].systemVersion;
+#elif TARGET_OS_OSX || TARGET_OS_TV || TARGET_OS_WATCH
+ // Assemble the systemVersion, excluding the patch version if it's 0.
+ NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion;
+ NSMutableString *versionString = [[NSMutableString alloc]
+ initWithFormat:@"%ld.%ld", (long)osVersion.majorVersion, (long)osVersion.minorVersion];
+ if (osVersion.patchVersion != 0) {
+ [versionString appendFormat:@".%ld", (long)osVersion.patchVersion];
+ }
+ return versionString;
+#endif
+}
+
++ (BOOL)isAppExtension {
+#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
+ // Documented by <a href="https://goo.gl/RRB2Up">Apple</a>
+ BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"];
+ return appExtension;
+#elif TARGET_OS_OSX
+ return NO;
+#endif
+}
+
++ (BOOL)isIOS7OrHigher {
+ return YES;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULObjectSwizzler+Internal.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULObjectSwizzler+Internal.h
new file mode 100644
index 00000000..db13d6cf
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULObjectSwizzler+Internal.h
@@ -0,0 +1,21 @@
+// Copyright 2019 Google LLC
+//
+// 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 "GoogleUtilities/ISASwizzler/Private/GULObjectSwizzler.h"
+
+@interface GULObjectSwizzler (Internal)
+
+- (void)swizzledObjectHasBeenDeallocatedWithGeneratedSubclass:(BOOL)isInstanceOfGeneratedSubclass;
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULObjectSwizzler.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULObjectSwizzler.m
new file mode 100644
index 00000000..d59cdc1c
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULObjectSwizzler.m
@@ -0,0 +1,164 @@
+// Copyright 2018 Google LLC
+//
+// 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 "GoogleUtilities/ISASwizzler/Private/GULObjectSwizzler.h"
+
+#import <objc/runtime.h>
+
+#import "GoogleUtilities/ISASwizzler/Private/GULSwizzledObject.h"
+
+@implementation GULObjectSwizzler {
+ // The swizzled object.
+ __weak id _swizzledObject;
+
+ // The original class of the object.
+ Class _originalClass;
+
+ // The dynamically generated subclass of _originalClass.
+ Class _generatedClass;
+}
+
+#pragma mark - Class methods
+
++ (void)setAssociatedObject:(id)object
+ key:(NSString *)key
+ value:(nullable id)value
+ association:(GUL_ASSOCIATION)association {
+ objc_AssociationPolicy resolvedAssociation;
+ switch (association) {
+ case GUL_ASSOCIATION_ASSIGN:
+ resolvedAssociation = OBJC_ASSOCIATION_ASSIGN;
+ break;
+
+ case GUL_ASSOCIATION_RETAIN_NONATOMIC:
+ resolvedAssociation = OBJC_ASSOCIATION_RETAIN_NONATOMIC;
+ break;
+
+ case GUL_ASSOCIATION_COPY_NONATOMIC:
+ resolvedAssociation = OBJC_ASSOCIATION_COPY_NONATOMIC;
+ break;
+
+ case GUL_ASSOCIATION_RETAIN:
+ resolvedAssociation = OBJC_ASSOCIATION_RETAIN;
+ break;
+
+ case GUL_ASSOCIATION_COPY:
+ resolvedAssociation = OBJC_ASSOCIATION_COPY;
+ break;
+
+ default:
+ break;
+ }
+ objc_setAssociatedObject(object, key.UTF8String, value, resolvedAssociation);
+}
+
++ (nullable id)getAssociatedObject:(id)object key:(NSString *)key {
+ return objc_getAssociatedObject(object, key.UTF8String);
+}
+
+#pragma mark - Instance methods
+
+/** Instantiates an instance of this class.
+ *
+ * @param object The object to swizzle.
+ * @return An instance of this class.
+ */
+- (instancetype)initWithObject:(id)object {
+ self = [super init];
+ if (self) {
+ __strong id swizzledObject = object;
+ if (swizzledObject) {
+ _swizzledObject = swizzledObject;
+ _originalClass = object_getClass(object);
+ NSString *newClassName = [NSString stringWithFormat:@"fir_%@_%@", [[NSUUID UUID] UUIDString],
+ NSStringFromClass(_originalClass)];
+ _generatedClass = objc_allocateClassPair(_originalClass, newClassName.UTF8String, 0);
+ NSAssert(_generatedClass, @"Wasn't able to allocate the class pair.");
+ } else {
+ return nil;
+ }
+ }
+ return self;
+}
+
+- (void)copySelector:(SEL)selector fromClass:(Class)aClass isClassSelector:(BOOL)isClassSelector {
+ NSAssert(_generatedClass, @"This object has already been unswizzled.");
+ Method method = isClassSelector ? class_getClassMethod(aClass, selector)
+ : class_getInstanceMethod(aClass, selector);
+ Class targetClass = isClassSelector ? object_getClass(_generatedClass) : _generatedClass;
+ IMP implementation = method_getImplementation(method);
+ const char *typeEncoding = method_getTypeEncoding(method);
+ BOOL success __unused = class_addMethod(targetClass, selector, implementation, typeEncoding);
+ NSAssert(success, @"Unable to add selector %@ to class %@", NSStringFromSelector(selector),
+ NSStringFromClass(targetClass));
+}
+
+- (void)setAssociatedObjectWithKey:(NSString *)key
+ value:(id)value
+ association:(GUL_ASSOCIATION)association {
+ __strong id swizzledObject = _swizzledObject;
+ if (swizzledObject) {
+ [[self class] setAssociatedObject:swizzledObject key:key value:value association:association];
+ }
+}
+
+- (nullable id)getAssociatedObjectForKey:(NSString *)key {
+ __strong id swizzledObject = _swizzledObject;
+ if (swizzledObject) {
+ return [[self class] getAssociatedObject:swizzledObject key:key];
+ }
+ return nil;
+}
+
+- (void)swizzle {
+ __strong id swizzledObject = _swizzledObject;
+ if (swizzledObject) {
+ [GULObjectSwizzler setAssociatedObject:swizzledObject
+ key:kSwizzlerAssociatedObjectKey
+ value:self
+ association:GUL_ASSOCIATION_RETAIN_NONATOMIC];
+
+ [GULSwizzledObject copyDonorSelectorsUsingObjectSwizzler:self];
+
+ NSAssert(_originalClass == object_getClass(swizzledObject),
+ @"The original class is not the reported class now.");
+ NSAssert(class_getInstanceSize(_originalClass) == class_getInstanceSize(_generatedClass),
+ @"The instance size of the generated class must be equal to the original class.");
+ objc_registerClassPair(_generatedClass);
+ Class doubleCheckOriginalClass __unused = object_setClass(_swizzledObject, _generatedClass);
+ NSAssert(_originalClass == doubleCheckOriginalClass,
+ @"The original class must be the same as the class returned by object_setClass");
+ } else {
+ NSAssert(NO, @"You can't swizzle a nil object");
+ }
+}
+
+- (void)swizzledObjectHasBeenDeallocatedWithGeneratedSubclass:(BOOL)isInstanceOfGeneratedSubclass {
+ // If the swizzled object had a different class, it most likely indicates that the object was
+ // ISA swizzled one more time. In this case it is not safe to dispose the generated class. We
+ // will have to keep it to prevent a crash.
+
+ // TODO: Consider adding a flag that can be set by the host application to dispose the class pair
+ // unconditionally. It may be used by apps that use ISA Swizzling themself and are confident in
+ // disposing their subclasses.
+ if (isInstanceOfGeneratedSubclass) {
+ objc_disposeClassPair(_generatedClass);
+ }
+}
+
+- (BOOL)isSwizzlingProxyObject {
+ return [_swizzledObject isProxy];
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULSwizzledObject.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULSwizzledObject.m
new file mode 100644
index 00000000..e11ea5db
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/GULSwizzledObject.m
@@ -0,0 +1,88 @@
+// Copyright 2018 Google LLC
+//
+// 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 <objc/runtime.h>
+
+#import "GoogleUtilities/ISASwizzler/GULObjectSwizzler+Internal.h"
+#import "GoogleUtilities/ISASwizzler/Private/GULSwizzledObject.h"
+
+NSString *kSwizzlerAssociatedObjectKey = @"gul_objectSwizzler";
+
+@interface GULSwizzledObject ()
+
+@end
+
+@implementation GULSwizzledObject
+
++ (void)copyDonorSelectorsUsingObjectSwizzler:(GULObjectSwizzler *)objectSwizzler {
+ [objectSwizzler copySelector:@selector(gul_objectSwizzler) fromClass:self isClassSelector:NO];
+ [objectSwizzler copySelector:@selector(gul_class) fromClass:self isClassSelector:NO];
+ [objectSwizzler copySelector:@selector(dealloc) fromClass:self isClassSelector:NO];
+
+ // This is needed because NSProxy objects usually override -[NSObjectProtocol respondsToSelector:]
+ // and ask this question to the underlying object. Since we don't swizzle the underlying object
+ // but swizzle the proxy, when someone calls -[NSObjectProtocol respondsToSelector:] on the proxy,
+ // the answer ends up being NO even if we added new methods to the subclass through ISA Swizzling.
+ // To solve that, we override -[NSObjectProtocol respondsToSelector:] in such a way that takes
+ // into account the fact that we've added new methods.
+ if ([objectSwizzler isSwizzlingProxyObject]) {
+ [objectSwizzler copySelector:@selector(respondsToSelector:) fromClass:self isClassSelector:NO];
+ }
+}
+
+- (instancetype)init {
+ NSAssert(NO, @"Do not instantiate this class, it's only a donor class");
+ return nil;
+}
+
+- (GULObjectSwizzler *)gul_objectSwizzler {
+ return [GULObjectSwizzler getAssociatedObject:self key:kSwizzlerAssociatedObjectKey];
+}
+
+#pragma mark - Donor methods
+
+- (Class)gul_class {
+ return [[self gul_objectSwizzler] generatedClass];
+}
+
+// Only added to a class when we detect it is a proxy.
+- (BOOL)respondsToSelector:(SEL)aSelector {
+ Class gulClass = [[self gul_objectSwizzler] generatedClass];
+ return [gulClass instancesRespondToSelector:aSelector] || [super respondsToSelector:aSelector];
+}
+
+- (void)dealloc {
+ // We need to make sure the swizzler is deallocated after the swizzled object to do the clean up
+ // only when the swizzled object is not used.
+ GULObjectSwizzler *swizzler = nil;
+ BOOL isInstanceOfGeneratedClass = NO;
+
+ @autoreleasepool {
+ Class generatedClass = [self gul_class];
+ isInstanceOfGeneratedClass = object_getClass(self) == generatedClass;
+
+ swizzler = [[self gul_objectSwizzler] retain];
+ [GULObjectSwizzler setAssociatedObject:self
+ key:kSwizzlerAssociatedObjectKey
+ value:nil
+ association:GUL_ASSOCIATION_RETAIN_NONATOMIC];
+ }
+
+ [super dealloc];
+
+ [swizzler swizzledObjectHasBeenDeallocatedWithGeneratedSubclass:isInstanceOfGeneratedClass];
+ [swizzler release];
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/Private/GULObjectSwizzler.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/Private/GULObjectSwizzler.h
new file mode 100644
index 00000000..b0a692a3
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/Private/GULObjectSwizzler.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * 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 <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Enums that map to their OBJC-prefixed counterparts. */
+typedef OBJC_ENUM(uintptr_t, GUL_ASSOCIATION){
+
+ // Is a weak association.
+ GUL_ASSOCIATION_ASSIGN,
+
+ // Is a nonatomic strong association.
+ GUL_ASSOCIATION_RETAIN_NONATOMIC,
+
+ // Is a nonatomic copy association.
+ GUL_ASSOCIATION_COPY_NONATOMIC,
+
+ // Is an atomic strong association.
+ GUL_ASSOCIATION_RETAIN,
+
+ // Is an atomic copy association.
+ GUL_ASSOCIATION_COPY};
+
+/** This class handles swizzling a specific instance of a class by generating a
+ * dynamic subclass and installing selectors and properties onto the dynamic
+ * subclass. Then, the instance's class is set to the dynamic subclass. There
+ * should be a 1:1 ratio of object swizzlers to swizzled instances.
+ */
+@interface GULObjectSwizzler : NSObject
+
+/** The subclass that is generated. */
+@property(nullable, nonatomic, readonly) Class generatedClass;
+
+/** Sets an associated object in the runtime. This mechanism can be used to
+ * simulate adding properties.
+ *
+ * @param object The object that will be queried for the associated object.
+ * @param key The key of the associated object.
+ * @param value The value to associate to the swizzled object.
+ * @param association The mechanism to use when associating the objects.
+ */
++ (void)setAssociatedObject:(id)object
+ key:(NSString *)key
+ value:(nullable id)value
+ association:(GUL_ASSOCIATION)association;
+
+/** Gets an associated object in the runtime. This mechanism can be used to
+ * simulate adding properties.
+ *
+ * @param object The object that will be queried for the associated object.
+ * @param key The key of the associated object.
+ */
++ (nullable id)getAssociatedObject:(id)object key:(NSString *)key;
+
+/** Please use the designated initializer. */
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Instantiates an object swizzler using an object it will operate on.
+ * Generates a new class pair.
+ *
+ * @note There is no need to store this object. After calling -swizzle, this
+ * object can be found by calling -gul_objectSwizzler
+ *
+ * @param object The object to be swizzled.
+ * @return An instance of this class.
+ */
+- (instancetype)initWithObject:(id)object NS_DESIGNATED_INITIALIZER;
+
+/** Sets an associated object in the runtime. This mechanism can be used to
+ * simulate adding properties.
+ *
+ * @param key The key of the associated object.
+ * @param value The value to associate to the swizzled object.
+ * @param association The mechanism to use when associating the objects.
+ */
+- (void)setAssociatedObjectWithKey:(NSString *)key
+ value:(id)value
+ association:(GUL_ASSOCIATION)association;
+
+/** Gets an associated object in the runtime. This mechanism can be used to
+ * simulate adding properties.
+ *
+ * @param key The key of the associated object.
+ */
+- (nullable id)getAssociatedObjectForKey:(NSString *)key;
+
+/** Copies a selector from an existing class onto the generated dynamic subclass
+ * that this object will adopt. This mechanism can be used to add methods to
+ * specific instances of a class.
+ *
+ * @note Should not be called after calling -swizzle.
+ * @param selector The selector to add to the instance.
+ * @param aClass The class supplying an implementation of the method.
+ * @param isClassSelector A BOOL specifying whether the selector is a class or
+ * instance selector.
+ */
+- (void)copySelector:(SEL)selector fromClass:(Class)aClass isClassSelector:(BOOL)isClassSelector;
+
+/** Swizzles the object, changing its class to the generated class. Registers
+ * the class pair. */
+- (void)swizzle;
+
+/** @return The value of -[objectBeingSwizzled isProxy] */
+- (BOOL)isSwizzlingProxyObject;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/Private/GULSwizzledObject.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/Private/GULSwizzledObject.h
new file mode 100644
index 00000000..314ceecd
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/ISASwizzler/Private/GULSwizzledObject.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * 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 <Foundation/Foundation.h>
+
+@class GULObjectSwizzler;
+
+FOUNDATION_EXPORT NSString *kSwizzlerAssociatedObjectKey;
+
+/** This class exists as a method donor. These methods will be added to all objects that are
+ * swizzled by the object swizzler. This class should not be instantiated.
+ */
+@interface GULSwizzledObject : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Copies the methods below to the swizzled object.
+ *
+ * @param objectSwizzler The swizzler to use when adding the methods below.
+ */
++ (void)copyDonorSelectorsUsingObjectSwizzler:(GULObjectSwizzler *)objectSwizzler;
+
+#pragma mark - Donor methods.
+
+/** @return The generated subclass. Used in respondsToSelector: calls. */
+- (Class)gul_class;
+
+/** @return The object swizzler that manages this object. */
+- (GULObjectSwizzler *)gul_objectSwizzler;
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/LICENSE b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/LICENSE
new file mode 100644
index 00000000..30a8f725
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/LICENSE
@@ -0,0 +1,247 @@
+
+ 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.
+
+================================================================================
+
+The following copyright from Landon J. Fuller applies to the isAppEncrypted
+function in Environment/third_party/GULAppEnvironmentUtil.m.
+
+Copyright (c) 2017 Landon J. Fuller <landon@landonf.org>
+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.
+
+Comment from
+<a href="http://iphonedevwiki.net/index.php/Crack_prevention">iPhone Dev Wiki
+Crack Prevention</a>: App Store binaries are signed by both their developer
+and Apple. This encrypts the binary so that decryption keys are needed in order
+to make the binary readable. When iOS executes the binary, the decryption keys
+are used to decrypt the binary into a readable state where it is then loaded
+into memory and executed. iOS can tell the encryption status of a binary via the
+cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is
+a non-zero value then the binary is encrypted.
+
+'Cracking' works by letting the kernel decrypt the binary then siphoning the
+decrypted data into a new binary file, resigning, and repackaging. This will
+only work on jailbroken devices as codesignature validation has been removed.
+Resigning takes place because while the codesignature doesn't have to be valid
+thanks to the jailbreak, it does have to be in place unless you have AppSync or
+similar to disable codesignature checks.
+
+More information at <a href="http://landonf.org/2009/02/index.html">Landon
+Fuller's blog</a>
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m
new file mode 100644
index 00000000..7ad44050
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m
@@ -0,0 +1,221 @@
+// Copyright 2018 Google
+//
+// 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 SWIFT_PACKAGE
+// Need to import the public header here, since the module won't exist yet.
+// Restructure the GULLogger headers for Firebase 7.
+#import "GoogleUtilities/Logger/Public/GULLoggerLevel.h"
+#endif
+
+#import "GoogleUtilities/Logger/Private/GULLogger.h"
+
+#include <asl.h>
+
+#import "GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h"
+#import "GoogleUtilities/Logger/Public/GULLoggerLevel.h"
+
+/// ASL client facility name used by GULLogger.
+const char *kGULLoggerASLClientFacilityName = "com.google.utilities.logger";
+
+static dispatch_once_t sGULLoggerOnceToken;
+
+static aslclient sGULLoggerClient;
+
+static dispatch_queue_t sGULClientQueue;
+
+static BOOL sGULLoggerDebugMode;
+
+static GULLoggerLevel sGULLoggerMaximumLevel;
+
+// Allow clients to register a version to include in the log.
+static const char *sVersion = "";
+
+static GULLoggerService kGULLoggerLogger = @"[GULLogger]";
+
+#ifdef DEBUG
+/// The regex pattern for the message code.
+static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$";
+static NSRegularExpression *sMessageCodeRegex;
+#endif
+
+void GULLoggerInitializeASL(void) {
+ dispatch_once(&sGULLoggerOnceToken, ^{
+ NSInteger majorOSVersion = [[GULAppEnvironmentUtil systemVersion] integerValue];
+ uint32_t aslOptions = ASL_OPT_STDERR;
+#if TARGET_OS_SIMULATOR
+ // The iOS 11 simulator doesn't need the ASL_OPT_STDERR flag.
+ if (majorOSVersion >= 11) {
+ aslOptions = 0;
+ }
+#else
+ // Devices running iOS 10 or higher don't need the ASL_OPT_STDERR flag.
+ if (majorOSVersion >= 10) {
+ aslOptions = 0;
+ }
+#endif // TARGET_OS_SIMULATOR
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations" // asl is deprecated
+ // Initialize the ASL client handle.
+ sGULLoggerClient = asl_open(NULL, kGULLoggerASLClientFacilityName, aslOptions);
+ sGULLoggerMaximumLevel = GULLoggerLevelNotice;
+
+ // Set the filter used by system/device log. Initialize in default mode.
+ asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE));
+
+ sGULClientQueue = dispatch_queue_create("GULLoggingClientQueue", DISPATCH_QUEUE_SERIAL);
+ dispatch_set_target_queue(sGULClientQueue,
+ dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
+#ifdef DEBUG
+ sMessageCodeRegex = [NSRegularExpression regularExpressionWithPattern:kMessageCodePattern
+ options:0
+ error:NULL];
+#endif
+ });
+}
+
+void GULLoggerEnableSTDERR(void) {
+ asl_add_log_file(sGULLoggerClient, STDERR_FILENO);
+}
+
+void GULLoggerForceDebug(void) {
+ // We should enable debug mode if we're not running from App Store.
+ if (![GULAppEnvironmentUtil isFromAppStore]) {
+ sGULLoggerDebugMode = YES;
+ GULSetLoggerLevel(GULLoggerLevelDebug);
+ }
+}
+
+__attribute__((no_sanitize("thread"))) void GULSetLoggerLevel(GULLoggerLevel loggerLevel) {
+ if (loggerLevel < GULLoggerLevelMin || loggerLevel > GULLoggerLevelMax) {
+ GULLogError(kGULLoggerLogger, NO, @"I-COR000023", @"Invalid logger level, %ld",
+ (long)loggerLevel);
+ return;
+ }
+ GULLoggerInitializeASL();
+ // We should not raise the logger level if we are running from App Store.
+ if (loggerLevel >= GULLoggerLevelNotice && [GULAppEnvironmentUtil isFromAppStore]) {
+ return;
+ }
+
+ sGULLoggerMaximumLevel = loggerLevel;
+ dispatch_async(sGULClientQueue, ^{
+ asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(loggerLevel));
+ });
+}
+
+/**
+ * Check if the level is high enough to be loggable.
+ */
+__attribute__((no_sanitize("thread"))) BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel) {
+ GULLoggerInitializeASL();
+ if (sGULLoggerDebugMode) {
+ return YES;
+ }
+ return (BOOL)(loggerLevel <= sGULLoggerMaximumLevel);
+}
+
+#ifdef DEBUG
+void GULResetLogger() {
+ sGULLoggerOnceToken = 0;
+ sGULLoggerDebugMode = NO;
+}
+
+aslclient getGULLoggerClient() {
+ return sGULLoggerClient;
+}
+
+dispatch_queue_t getGULClientQueue() {
+ return sGULClientQueue;
+}
+
+BOOL getGULLoggerDebugMode() {
+ return sGULLoggerDebugMode;
+}
+#endif
+
+void GULLoggerRegisterVersion(const char *version) {
+ sVersion = version;
+}
+
+void GULLogBasic(GULLoggerLevel level,
+ GULLoggerService service,
+ BOOL forceLog,
+ NSString *messageCode,
+ NSString *message,
+ va_list args_ptr) {
+ GULLoggerInitializeASL();
+ if (!(level <= sGULLoggerMaximumLevel || sGULLoggerDebugMode || forceLog)) {
+ return;
+ }
+
+#ifdef DEBUG
+ NSCAssert(messageCode.length == 11, @"Incorrect message code length.");
+ NSRange messageCodeRange = NSMakeRange(0, messageCode.length);
+ NSUInteger numberOfMatches = [sMessageCodeRegex numberOfMatchesInString:messageCode
+ options:0
+ range:messageCodeRange];
+ NSCAssert(numberOfMatches == 1, @"Incorrect message code format.");
+#endif
+ NSString *logMsg;
+ if (args_ptr == NULL) {
+ logMsg = message;
+ } else {
+ logMsg = [[NSString alloc] initWithFormat:message arguments:args_ptr];
+ }
+ logMsg = [NSString stringWithFormat:@"%s - %@[%@] %@", sVersion, service, messageCode, logMsg];
+ dispatch_async(sGULClientQueue, ^{
+ asl_log(sGULLoggerClient, NULL, (int)level, "%s", logMsg.UTF8String);
+ });
+}
+#pragma clang diagnostic pop
+
+/**
+ * Generates the logging functions using macros.
+ *
+ * Calling GULLogError({service}, @"I-XYZ000001", @"Configure %@ failed.", @"blah") shows:
+ * yyyy-mm-dd hh:mm:ss.SSS sender[PID] <Error> [{service}][I-XYZ000001] Configure blah failed.
+ * Calling GULLogDebug({service}, @"I-XYZ000001", @"Configure succeed.") shows:
+ * yyyy-mm-dd hh:mm:ss.SSS sender[PID] <Debug> [{service}][I-XYZ000001] Configure succeed.
+ */
+#define GUL_LOGGING_FUNCTION(level) \
+ void GULLog##level(GULLoggerService service, BOOL force, NSString *messageCode, \
+ NSString *message, ...) { \
+ va_list args_ptr; \
+ va_start(args_ptr, message); \
+ GULLogBasic(GULLoggerLevel##level, service, force, messageCode, message, args_ptr); \
+ va_end(args_ptr); \
+ }
+
+GUL_LOGGING_FUNCTION(Error)
+GUL_LOGGING_FUNCTION(Warning)
+GUL_LOGGING_FUNCTION(Notice)
+GUL_LOGGING_FUNCTION(Info)
+GUL_LOGGING_FUNCTION(Debug)
+
+#undef GUL_MAKE_LOGGER
+
+#pragma mark - GULLoggerWrapper
+
+@implementation GULLoggerWrapper
+
++ (void)logWithLevel:(GULLoggerLevel)level
+ withService:(GULLoggerService)service
+ withCode:(NSString *)messageCode
+ withMessage:(NSString *)message
+ withArgs:(va_list)args {
+ GULLogBasic(level, service, NO, messageCode, message, args);
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Private/GULLogger.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Private/GULLogger.h
new file mode 100644
index 00000000..1146ee23
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Private/GULLogger.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+#if SWIFT_PACKAGE
+@import GoogleUtilities_Logger;
+#else
+#import <GoogleUtilities/GULLoggerLevel.h>
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * The services used in the logger.
+ */
+typedef NSString *const GULLoggerService;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * Initialize GULLogger.
+ */
+extern void GULLoggerInitializeASL(void);
+
+/**
+ * Override log level to Debug.
+ */
+void GULLoggerForceDebug(void);
+
+/**
+ * Turn on logging to STDERR.
+ */
+extern void GULLoggerEnableSTDERR(void);
+
+/**
+ * Changes the default logging level of GULLoggerLevelNotice to a user-specified level.
+ * The default level cannot be set above GULLoggerLevelNotice if the app is running from App Store.
+ * (required) log level (one of the GULLoggerLevel enum values).
+ */
+extern void GULSetLoggerLevel(GULLoggerLevel loggerLevel);
+
+/**
+ * Checks if the specified logger level is loggable given the current settings.
+ * (required) log level (one of the GULLoggerLevel enum values).
+ */
+extern BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel);
+
+/**
+ * Register version to include in logs.
+ * (required) version
+ */
+extern void GULLoggerRegisterVersion(const char *version);
+
+/**
+ * Logs a message to the Xcode console and the device log. If running from AppStore, will
+ * not log any messages with a level higher than GULLoggerLevelNotice to avoid log spamming.
+ * (required) log level (one of the GULLoggerLevel enum values).
+ * (required) service name of type GULLoggerService.
+ * (required) message code starting with "I-" which means iOS, followed by a capitalized
+ * three-character service identifier and a six digit integer message ID that is unique
+ * within the service.
+ * An example of the message code is @"I-COR000001".
+ * (required) message string which can be a format string.
+ * (optional) variable arguments list obtained from calling va_start, used when message is a format
+ * string.
+ */
+extern void GULLogBasic(GULLoggerLevel level,
+ GULLoggerService service,
+ BOOL forceLog,
+ NSString *messageCode,
+ NSString *message,
+// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable
+// See: http://stackoverflow.com/q/29095469
+#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX
+ va_list args_ptr
+#else
+ va_list _Nullable args_ptr
+#endif
+);
+
+/**
+ * The following functions accept the following parameters in order:
+ * (required) service name of type GULLoggerService.
+ * (required) message code starting from "I-" which means iOS, followed by a capitalized
+ * three-character service identifier and a six digit integer message ID that is unique
+ * within the service.
+ * An example of the message code is @"I-COR000001".
+ * See go/firebase-log-proposal for details.
+ * (required) message string which can be a format string.
+ * (optional) the list of arguments to substitute into the format string.
+ * Example usage:
+ * GULLogError(kGULLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name);
+ */
+extern void GULLogError(GULLoggerService service,
+ BOOL force,
+ NSString *messageCode,
+ NSString *message,
+ ...) NS_FORMAT_FUNCTION(4, 5);
+extern void GULLogWarning(GULLoggerService service,
+ BOOL force,
+ NSString *messageCode,
+ NSString *message,
+ ...) NS_FORMAT_FUNCTION(4, 5);
+extern void GULLogNotice(GULLoggerService service,
+ BOOL force,
+ NSString *messageCode,
+ NSString *message,
+ ...) NS_FORMAT_FUNCTION(4, 5);
+extern void GULLogInfo(GULLoggerService service,
+ BOOL force,
+ NSString *messageCode,
+ NSString *message,
+ ...) NS_FORMAT_FUNCTION(4, 5);
+extern void GULLogDebug(GULLoggerService service,
+ BOOL force,
+ NSString *messageCode,
+ NSString *message,
+ ...) NS_FORMAT_FUNCTION(4, 5);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+@interface GULLoggerWrapper : NSObject
+
+/**
+ * Objective-C wrapper for GULLogBasic to allow weak linking to GULLogger
+ * (required) log level (one of the GULLoggerLevel enum values).
+ * (required) service name of type GULLoggerService.
+ * (required) message code starting with "I-" which means iOS, followed by a capitalized
+ * three-character service identifier and a six digit integer message ID that is unique
+ * within the service.
+ * An example of the message code is @"I-COR000001".
+ * (required) message string which can be a format string.
+ * (optional) variable arguments list obtained from calling va_start, used when message is a format
+ * string.
+ */
+
++ (void)logWithLevel:(GULLoggerLevel)level
+ withService:(GULLoggerService)service
+ withCode:(NSString *)messageCode
+ withMessage:(NSString *)message
+ withArgs:(va_list)args;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GULLoggerLevel.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GULLoggerLevel.h
new file mode 100644
index 00000000..f0ee435b
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GULLoggerLevel.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+/**
+ * The log levels used by internal logging.
+ */
+typedef NS_ENUM(NSInteger, GULLoggerLevel) {
+ /** Error level, matches ASL_LEVEL_ERR. */
+ GULLoggerLevelError = 3,
+ /** Warning level, matches ASL_LEVEL_WARNING. */
+ GULLoggerLevelWarning = 4,
+ /** Notice level, matches ASL_LEVEL_NOTICE. */
+ GULLoggerLevelNotice = 5,
+ /** Info level, matches ASL_LEVEL_INFO. */
+ GULLoggerLevelInfo = 6,
+ /** Debug level, matches ASL_LEVEL_DEBUG. */
+ GULLoggerLevelDebug = 7,
+ /** Minimum log level. */
+ GULLoggerLevelMin = GULLoggerLevelError,
+ /** Maximum log level. */
+ GULLoggerLevelMax = GULLoggerLevelDebug
+} NS_SWIFT_NAME(GoogleLoggerLevel);
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m
new file mode 100644
index 00000000..040da268
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m
@@ -0,0 +1,153 @@
+// Copyright 2018 Google LLC
+//
+// 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 "GoogleUtilities/MethodSwizzler/Private/GULSwizzler.h"
+
+#import <objc/runtime.h>
+
+#ifdef DEBUG
+#import "GoogleUtilities/Common/GULLoggerCodes.h"
+#import "GoogleUtilities/Logger/Private/GULLogger.h"
+
+static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/MethodSwizzler]";
+#endif
+
+dispatch_queue_t GetGULSwizzlingQueue(void) {
+ static dispatch_queue_t queue;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ queue = dispatch_queue_create("com.google.GULSwizzler", DISPATCH_QUEUE_SERIAL);
+ });
+ return queue;
+}
+
+@implementation GULSwizzler
+
++ (void)swizzleClass:(Class)aClass
+ selector:(SEL)selector
+ isClassSelector:(BOOL)isClassSelector
+ withBlock:(nullable id)block {
+ dispatch_sync(GetGULSwizzlingQueue(), ^{
+ NSAssert(selector, @"The selector cannot be NULL");
+ NSAssert(aClass, @"The class cannot be Nil");
+ Class resolvedClass = aClass;
+ Method method = nil;
+ if (isClassSelector) {
+ method = class_getClassMethod(aClass, selector);
+ resolvedClass = object_getClass(aClass);
+ } else {
+ method = class_getInstanceMethod(aClass, selector);
+ }
+ NSAssert(method, @"You're attempting to swizzle a method that doesn't exist. (%@, %@)",
+ NSStringFromClass(resolvedClass), NSStringFromSelector(selector));
+ IMP newImp = imp_implementationWithBlock(block);
+#ifdef DEBUG
+ IMP currentImp = class_getMethodImplementation(resolvedClass, selector);
+ Class class = NSClassFromString(@"GULSwizzlingCache");
+ if (class) {
+ SEL cacheSelector = NSSelectorFromString(@"cacheCurrentIMP:forNewIMP:forClass:withSelector:");
+ NSMethodSignature *methodSignature = [class methodSignatureForSelector:cacheSelector];
+ if (methodSignature != nil) {
+ NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature];
+ [inv setSelector:cacheSelector];
+ [inv setTarget:class];
+ [inv setArgument:&(currentImp) atIndex:2];
+ [inv setArgument:&(newImp) atIndex:3];
+ [inv setArgument:&(resolvedClass) atIndex:4];
+ [inv setArgument:(void *_Nonnull) & (selector) atIndex:5];
+ [inv invoke];
+ }
+ }
+#endif
+
+ const char *typeEncoding = method_getTypeEncoding(method);
+ __unused IMP originalImpOfClass =
+ class_replaceMethod(resolvedClass, selector, newImp, typeEncoding);
+
+#ifdef DEBUG
+ // If !originalImpOfClass, then the IMP came from a superclass.
+ if (originalImpOfClass) {
+ SEL selector = NSSelectorFromString(@"originalIMPOfCurrentIMP:");
+ NSMethodSignature *methodSignature = [class methodSignatureForSelector:selector];
+ if (methodSignature != nil) {
+ NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature];
+ [inv setSelector:selector];
+ [inv setTarget:class];
+ [inv setArgument:&(currentImp) atIndex:2];
+ [inv invoke];
+ IMP testOriginal;
+ [inv getReturnValue:&testOriginal];
+ if (originalImpOfClass != testOriginal) {
+ GULLogWarning(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeMethodSwizzling000],
+ @"Swizzling class: %@ SEL:%@ after it has been previously been swizzled.",
+ NSStringFromClass(resolvedClass), NSStringFromSelector(selector));
+ }
+ }
+ }
+#endif
+ });
+}
+
++ (nullable IMP)currentImplementationForClass:(Class)aClass
+ selector:(SEL)selector
+ isClassSelector:(BOOL)isClassSelector {
+ NSAssert(selector, @"The selector cannot be NULL");
+ NSAssert(aClass, @"The class cannot be Nil");
+ if (selector == NULL || aClass == nil) {
+ return nil;
+ }
+ __block IMP currentIMP = nil;
+ dispatch_sync(GetGULSwizzlingQueue(), ^{
+ Method method = nil;
+ if (isClassSelector) {
+ method = class_getClassMethod(aClass, selector);
+ } else {
+ method = class_getInstanceMethod(aClass, selector);
+ }
+ NSAssert(method, @"The Method for this class/selector combo doesn't exist (%@, %@).",
+ NSStringFromClass(aClass), NSStringFromSelector(selector));
+ if (method == nil) {
+ return;
+ }
+ currentIMP = method_getImplementation(method);
+ NSAssert(currentIMP, @"The IMP for this class/selector combo doesn't exist (%@, %@).",
+ NSStringFromClass(aClass), NSStringFromSelector(selector));
+ });
+ return currentIMP;
+}
+
++ (BOOL)selector:(SEL)selector existsInClass:(Class)aClass isClassSelector:(BOOL)isClassSelector {
+ Method method = isClassSelector ? class_getClassMethod(aClass, selector)
+ : class_getInstanceMethod(aClass, selector);
+ return method != nil;
+}
+
++ (NSArray<id> *)ivarObjectsForObject:(id)object {
+ NSMutableArray *array = [NSMutableArray array];
+ unsigned int count;
+ Ivar *vars = class_copyIvarList([object class], &count);
+ for (NSUInteger i = 0; i < count; i++) {
+ const char *typeEncoding = ivar_getTypeEncoding(vars[i]);
+ // Check to see if the ivar is an object.
+ if (strncmp(typeEncoding, "@", 1) == 0) {
+ id ivarObject = object_getIvar(object, vars[i]);
+ [array addObject:ivarObject];
+ }
+ }
+ free(vars);
+ return array;
+}
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Private/GULOriginalIMPConvenienceMacros.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Private/GULOriginalIMPConvenienceMacros.h
new file mode 100644
index 00000000..a33262af
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Private/GULOriginalIMPConvenienceMacros.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * 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.
+ */
+
+/**
+ * GULOriginalIMPConvenienceMacros.h
+ *
+ * This header contains convenience macros for invoking the original IMP of a swizzled method.
+ */
+
+/**
+ * Invokes original IMP when the original selector takes no arguments.
+ *
+ * @param __receivingObject The object on which the IMP is invoked.
+ * @param __swizzledSEL The selector used for swizzling.
+ * @param __returnType The return type of the original implementation.
+ * @param __originalIMP The original IMP.
+ */
+#define GUL_INVOKE_ORIGINAL_IMP0(__receivingObject, __swizzledSEL, __returnType, __originalIMP) \
+ ((__returnType(*)(id, SEL))__originalIMP)(__receivingObject, __swizzledSEL)
+
+/**
+ * Invokes original IMP when the original selector takes 1 argument.
+ *
+ * @param __receivingObject The object on which the IMP is invoked.
+ * @param __swizzledSEL The selector used for swizzling.
+ * @param __returnType The return type of the original implementation.
+ * @param __originalIMP The original IMP.
+ * @param __arg1 The first argument.
+ */
+#define GUL_INVOKE_ORIGINAL_IMP1(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \
+ __arg1) \
+ ((__returnType(*)(id, SEL, __typeof__(__arg1)))__originalIMP)(__receivingObject, __swizzledSEL, \
+ __arg1)
+
+/**
+ * Invokes original IMP when the original selector takes 2 arguments.
+ *
+ * @param __receivingObject The object on which the IMP is invoked.
+ * @param __swizzledSEL The selector used for swizzling.
+ * @param __returnType The return type of the original implementation.
+ * @param __originalIMP The original IMP.
+ * @param __arg1 The first argument.
+ * @param __arg2 The second argument.
+ */
+#define GUL_INVOKE_ORIGINAL_IMP2(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \
+ __arg1, __arg2) \
+ ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2)))__originalIMP)( \
+ __receivingObject, __swizzledSEL, __arg1, __arg2)
+
+/**
+ * Invokes original IMP when the original selector takes 3 arguments.
+ *
+ * @param __receivingObject The object on which the IMP is invoked.
+ * @param __swizzledSEL The selector used for swizzling.
+ * @param __returnType The return type of the original implementation.
+ * @param __originalIMP The original IMP.
+ * @param __arg1 The first argument.
+ * @param __arg2 The second argument.
+ * @param __arg3 The third argument.
+ */
+#define GUL_INVOKE_ORIGINAL_IMP3(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \
+ __arg1, __arg2, __arg3) \
+ ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), \
+ __typeof__(__arg3)))__originalIMP)(__receivingObject, __swizzledSEL, __arg1, \
+ __arg2, __arg3)
+
+/**
+ * Invokes original IMP when the original selector takes 4 arguments.
+ *
+ * @param __receivingObject The object on which the IMP is invoked.
+ * @param __swizzledSEL The selector used for swizzling.
+ * @param __returnType The return type of the original implementation.
+ * @param __originalIMP The original IMP.
+ * @param __arg1 The first argument.
+ * @param __arg2 The second argument.
+ * @param __arg3 The third argument.
+ * @param __arg4 The fourth argument.
+ */
+#define GUL_INVOKE_ORIGINAL_IMP4(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \
+ __arg1, __arg2, __arg3, __arg4) \
+ ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \
+ __typeof__(__arg4)))__originalIMP)(__receivingObject, __swizzledSEL, __arg1, \
+ __arg2, __arg3, __arg4)
+
+/**
+ * Invokes original IMP when the original selector takes 5 arguments.
+ *
+ * @param __receivingObject The object on which the IMP is invoked.
+ * @param __swizzledSEL The selector used for swizzling.
+ * @param __returnType The return type of the original implementation.
+ * @param __originalIMP The original IMP.
+ * @param __arg1 The first argument.
+ * @param __arg2 The second argument.
+ * @param __arg3 The third argument.
+ * @param __arg4 The fourth argument.
+ * @param __arg5 The fifth argument.
+ */
+#define GUL_INVOKE_ORIGINAL_IMP5(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \
+ __arg1, __arg2, __arg3, __arg4, __arg5) \
+ ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \
+ __typeof__(__arg4), __typeof__(__arg5)))__originalIMP)( \
+ __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5)
+
+/**
+ * Invokes original IMP when the original selector takes 6 arguments.
+ *
+ * @param __receivingObject The object on which the IMP is invoked.
+ * @param __swizzledSEL The selector used for swizzling.
+ * @param __returnType The return type of the original implementation.
+ * @param __originalIMP The original IMP.
+ * @param __arg1 The first argument.
+ * @param __arg2 The second argument.
+ * @param __arg3 The third argument.
+ * @param __arg4 The fourth argument.
+ * @param __arg5 The fifth argument.
+ * @param __arg6 The sixth argument.
+ */
+#define GUL_INVOKE_ORIGINAL_IMP6(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \
+ __arg1, __arg2, __arg3, __arg4, __arg5, __arg6) \
+ ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \
+ __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6)))__originalIMP)( \
+ __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6)
+
+/**
+ * Invokes original IMP when the original selector takes 7 arguments.
+ *
+ * @param __receivingObject The object on which the IMP is invoked.
+ * @param __swizzledSEL The selector used for swizzling.
+ * @param __returnType The return type of the original implementation.
+ * @param __originalIMP The original IMP.
+ * @param __arg1 The first argument.
+ * @param __arg2 The second argument.
+ * @param __arg3 The third argument.
+ * @param __arg4 The fourth argument.
+ * @param __arg5 The fifth argument.
+ * @param __arg6 The sixth argument.
+ * @param __arg7 The seventh argument.
+ */
+#define GUL_INVOKE_ORIGINAL_IMP7(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \
+ __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7) \
+ ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \
+ __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6), \
+ __typeof__(__arg7)))__originalIMP)( \
+ __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7)
+
+/**
+ * Invokes original IMP when the original selector takes 8 arguments.
+ *
+ * @param __receivingObject The object on which the IMP is invoked.
+ * @param __swizzledSEL The selector used for swizzling.
+ * @param __returnType The return type of the original implementation.
+ * @param __originalIMP The original IMP.
+ * @param __arg1 The first argument.
+ * @param __arg2 The second argument.
+ * @param __arg3 The third argument.
+ * @param __arg4 The fourth argument.
+ * @param __arg5 The fifth argument.
+ * @param __arg6 The sixth argument.
+ * @param __arg7 The seventh argument.
+ * @param __arg8 The eighth argument.
+ */
+#define GUL_INVOKE_ORIGINAL_IMP8(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \
+ __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, __arg8) \
+ ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \
+ __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6), \
+ __typeof__(__arg7), __typeof__(__arg8)))__originalIMP)( \
+ __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, \
+ __arg8)
+
+/**
+ * Invokes original IMP when the original selector takes 9 arguments.
+ *
+ * @param __receivingObject The object on which the IMP is invoked.
+ * @param __swizzledSEL The selector used for swizzling.
+ * @param __returnType The return type of the original implementation.
+ * @param __originalIMP The original IMP.
+ * @param __arg1 The first argument.
+ * @param __arg2 The second argument.
+ * @param __arg3 The third argument.
+ * @param __arg4 The fourth argument.
+ * @param __arg5 The fifth argument.
+ * @param __arg6 The sixth argument.
+ * @param __arg7 The seventh argument.
+ * @param __arg8 The eighth argument.
+ * @param __arg9 The ninth argument.
+ */
+#define GUL_INVOKE_ORIGINAL_IMP9(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \
+ __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, __arg8, \
+ __arg9) \
+ ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \
+ __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6), \
+ __typeof__(__arg7), __typeof__(__arg8), __typeof__(__arg9)))__originalIMP)( \
+ __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, \
+ __arg8, __arg9)
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Private/GULSwizzler.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Private/GULSwizzler.h
new file mode 100644
index 00000000..26949c88
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Private/GULSwizzler.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * 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 <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** This class handles the runtime manipulation necessary to instrument selectors. It stores the
+ * classes and selectors that have been swizzled, and runs all operations on its own queue.
+ */
+@interface GULSwizzler : NSObject
+
+/** Manipulates the Objective-C runtime to replace the original IMP with the supplied block.
+ *
+ * @param aClass The class to swizzle.
+ * @param selector The selector of the class to swizzle.
+ * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector.
+ * @param block The block that replaces the original IMP.
+ */
++ (void)swizzleClass:(Class)aClass
+ selector:(SEL)selector
+ isClassSelector:(BOOL)isClassSelector
+ withBlock:(nullable id)block;
+
+/** Returns the current IMP for the given class and selector.
+ *
+ * @param aClass The class to use.
+ * @param selector The selector to find the implementation of.
+ * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector.
+ * @return The implementation of the selector in the runtime.
+ */
++ (nullable IMP)currentImplementationForClass:(Class)aClass
+ selector:(SEL)selector
+ isClassSelector:(BOOL)isClassSelector;
+
+/** Checks the runtime to see if a selector exists on a class. If a property is declared as
+ * @dynamic, we have a reverse swizzling situation, where the implementation of a method exists
+ * only in concrete subclasses, and NOT in the superclass. We can detect that situation using
+ * this helper method. Similarly, we can detect situations where a class doesn't implement a
+ * protocol method.
+ *
+ * @param selector The selector to check for.
+ * @param aClass The class to check.
+ * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector.
+ * @return YES if the method was found in this selector/class combination, NO otherwise.
+ */
++ (BOOL)selector:(SEL)selector existsInClass:(Class)aClass isClassSelector:(BOOL)isClassSelector;
+
+/** Returns a list of all Objective-C (and not primitive) ivars contained by the given object.
+ *
+ * @param object The object whose ivars will be iterated.
+ * @return The list of ivar objects.
+ */
++ (NSArray<id> *)ivarObjectsForObject:(id)object;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m
new file mode 100644
index 00000000..5eb638d6
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m
@@ -0,0 +1,207 @@
+// Copyright 2018 Google
+//
+// 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 "GoogleUtilities/NSData+zlib/Public/GULNSData+zlib.h"
+
+#import <zlib.h>
+
+#define kChunkSize 1024
+#define Z_DEFAULT_COMPRESSION (-1)
+
+NSString *const GULNSDataZlibErrorDomain = @"com.google.GULNSDataZlibErrorDomain";
+NSString *const GULNSDataZlibErrorKey = @"GULNSDataZlibErrorKey";
+NSString *const GULNSDataZlibRemainingBytesKey = @"GULNSDataZlibRemainingBytesKey";
+
+@implementation NSData (GULGzip)
+
++ (NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error {
+ const void *bytes = [data bytes];
+ NSUInteger length = [data length];
+ 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
+ windowBits += 32; // and +32 to enable zlib or gzip header detection.
+
+ int retCode;
+ if ((retCode = inflateInit2(&strm, windowBits)) != Z_OK) {
+ if (error) {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode]
+ forKey:GULNSDataZlibErrorKey];
+ *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain
+ code:GULNSDataZlibErrorInternal
+ userInfo:userInfo];
+ }
+ return nil;
+ }
+
+ // 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:GULNSDataZlibErrorKey];
+ if (strm.msg) {
+ NSString *message = [NSString stringWithUTF8String:strm.msg];
+ if (message) {
+ [userInfo setObject:message forKey:NSLocalizedDescriptionKey];
+ }
+ }
+ *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain
+ code:GULNSDataZlibErrorInternal
+ 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:GULNSDataZlibRemainingBytesKey];
+ *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain
+ code:GULNSDataZlibErrorDataRemaining
+ userInfo:userInfo];
+ }
+ result = nil;
+ }
+ // The only way out of the loop was by hitting the end of the stream.
+ NSAssert(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;
+}
+
++ (NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error {
+ const void *bytes = [data bytes];
+ NSUInteger length = [data length];
+
+ int level = Z_DEFAULT_COMPRESSION;
+ 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:GULNSDataZlibErrorDomain
+ code:GULNSDataZlibErrorGreaterThan32BitsToCompress
+ userInfo:nil];
+ }
+ return nil;
+ }
+#endif
+
+ z_stream strm;
+ bzero(&strm, sizeof(z_stream));
+
+ int memLevel = 8; // Default.
+ int windowBits = 15 + 16; // Enable gzip header instead of zlib header.
+
+ int retCode;
+ if ((retCode = deflateInit2(&strm, level, Z_DEFLATED, windowBits, memLevel,
+ Z_DEFAULT_STRATEGY)) != Z_OK) {
+ if (error) {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode]
+ forKey:GULNSDataZlibErrorKey];
+ *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain
+ code:GULNSDataZlibErrorInternal
+ userInfo:userInfo];
+ }
+ return nil;
+ }
+
+ // 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;
+
+ // 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)) {
+ if (error) {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode]
+ forKey:GULNSDataZlibErrorKey];
+ *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain
+ code:GULNSDataZlibErrorInternal
+ userInfo:userInfo];
+ }
+ deflateEnd(&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);
+
+ // If the loop exits, it used all input and the stream ended.
+ NSAssert(strm.avail_in == 0,
+ @"Should have finished deflating without using all input, %u bytes left", strm.avail_in);
+ NSAssert(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;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Private/GULNSDataInternal.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Private/GULNSDataInternal.h
new file mode 100644
index 00000000..903589d5
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Private/GULNSDataInternal.h
@@ -0,0 +1,22 @@
+// Copyright 2020 Google LLC
+//
+// 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.
+
+// An umbrella header, for any other libraries in this repo to access Firebase Public and Private
+// headers. Any package manager complexity should be handled here.
+
+#if SWIFT_PACKAGE
+@import GoogleUtilities_NSData;
+#else
+#import <GoogleUtilities/GULNSData+zlib.h>
+#endif
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GULNSData+zlib.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GULNSData+zlib.h
new file mode 100644
index 00000000..36f94a70
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GULNSData+zlib.h
@@ -0,0 +1,49 @@
+// Copyright 2018 Google
+//
+// 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 <Foundation/Foundation.h>
+
+/// This is a copy of Google Toolbox for Mac library to avoid creating an extra framework.
+
+// 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.
+
+@interface NSData (GULGzip)
+
+/// Returns an data as the result of decompressing the payload of |data|.The data to decompress must
+/// be a gzipped payloads.
++ (NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error;
+
+/// Returns an compressed data with the result of gzipping the payload of |data|. Uses the default
+/// compression level.
++ (NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error;
+
+FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorDomain;
+FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorKey; // NSNumber
+FOUNDATION_EXPORT NSString *const GULNSDataZlibRemainingBytesKey; // NSNumber
+
+typedef NS_ENUM(NSInteger, GULNSDataZlibError) {
+ GULNSDataZlibErrorGreaterThan32BitsToCompress = 1024,
+ // An internal zlib error.
+ // GULNSDataZlibErrorKey will contain the error value.
+ // NSLocalizedDescriptionKey may contain an error string from zlib.
+ // Look in zlib.h for list of errors.
+ GULNSDataZlibErrorInternal,
+ // There was left over data in the buffer that was not used.
+ // GULNSDataZlibRemainingBytesKey will contain number of remaining bytes.
+ GULNSDataZlibErrorDataRemaining
+};
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m
new file mode 100644
index 00000000..43896601
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m
@@ -0,0 +1,101 @@
+// Copyright 2017 Google
+//
+// 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 "GoogleUtilities/Network/Private/GULMutableDictionary.h"
+
+@implementation GULMutableDictionary {
+ /// The mutable dictionary.
+ NSMutableDictionary *_objects;
+
+ /// Serial synchronization queue. All reads should use dispatch_sync, while writes use
+ /// dispatch_async.
+ dispatch_queue_t _queue;
+}
+
+- (instancetype)init {
+ self = [super init];
+
+ if (self) {
+ _objects = [[NSMutableDictionary alloc] init];
+ _queue = dispatch_queue_create("GULMutableDictionary", DISPATCH_QUEUE_SERIAL);
+ }
+
+ return self;
+}
+
+- (NSString *)description {
+ __block NSString *description;
+ dispatch_sync(_queue, ^{
+ description = self->_objects.description;
+ });
+ return description;
+}
+
+- (id)objectForKey:(id)key {
+ __block id object;
+ dispatch_sync(_queue, ^{
+ object = [self->_objects objectForKey:key];
+ });
+ return object;
+}
+
+- (void)setObject:(id)object forKey:(id<NSCopying>)key {
+ dispatch_async(_queue, ^{
+ [self->_objects setObject:object forKey:key];
+ });
+}
+
+- (void)removeObjectForKey:(id)key {
+ dispatch_async(_queue, ^{
+ [self->_objects removeObjectForKey:key];
+ });
+}
+
+- (void)removeAllObjects {
+ dispatch_async(_queue, ^{
+ [self->_objects removeAllObjects];
+ });
+}
+
+- (NSUInteger)count {
+ __block NSUInteger count;
+ dispatch_sync(_queue, ^{
+ count = self->_objects.count;
+ });
+ return count;
+}
+
+- (id)objectForKeyedSubscript:(id<NSCopying>)key {
+ __block id object;
+ dispatch_sync(_queue, ^{
+ object = self->_objects[key];
+ });
+ return object;
+}
+
+- (void)setObject:(id)obj forKeyedSubscript:(id<NSCopying>)key {
+ dispatch_async(_queue, ^{
+ self->_objects[key] = obj;
+ });
+}
+
+- (NSDictionary *)dictionary {
+ __block NSDictionary *dictionary;
+ dispatch_sync(_queue, ^{
+ dictionary = [self->_objects copy];
+ });
+ return dictionary;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m
new file mode 100644
index 00000000..5b7d7e37
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m
@@ -0,0 +1,389 @@
+// Copyright 2017 Google
+//
+// 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 "GoogleUtilities/Network/Private/GULNetwork.h"
+#import "GoogleUtilities/Network/Private/GULNetworkMessageCode.h"
+
+#import "GoogleUtilities/Logger/Private/GULLogger.h"
+#import "GoogleUtilities/NSData+zlib/Private/GULNSDataInternal.h"
+#import "GoogleUtilities/Network/Private/GULMutableDictionary.h"
+#import "GoogleUtilities/Network/Private/GULNetworkConstants.h"
+#import "GoogleUtilities/Reachability/Private/GULReachabilityChecker.h"
+
+/// Constant string for request header Content-Encoding.
+static NSString *const kGULNetworkContentCompressionKey = @"Content-Encoding";
+
+/// Constant string for request header Content-Encoding value.
+static NSString *const kGULNetworkContentCompressionValue = @"gzip";
+
+/// Constant string for request header Content-Length.
+static NSString *const kGULNetworkContentLengthKey = @"Content-Length";
+
+/// Constant string for request header Content-Type.
+static NSString *const kGULNetworkContentTypeKey = @"Content-Type";
+
+/// Constant string for request header Content-Type value.
+static NSString *const kGULNetworkContentTypeValue = @"application/x-www-form-urlencoded";
+
+/// Constant string for GET request method.
+static NSString *const kGULNetworkGETRequestMethod = @"GET";
+
+/// Constant string for POST request method.
+static NSString *const kGULNetworkPOSTRequestMethod = @"POST";
+
+/// Default constant string as a prefix for network logger.
+static NSString *const kGULNetworkLogTag = @"Google/Utilities/Network";
+
+@interface GULNetwork () <GULReachabilityDelegate, GULNetworkLoggerDelegate>
+@end
+
+@implementation GULNetwork {
+ /// Network reachability.
+ GULReachabilityChecker *_reachability;
+
+ /// The dictionary of requests by session IDs { NSString : id }.
+ GULMutableDictionary *_requests;
+}
+
+- (instancetype)init {
+ return [self initWithReachabilityHost:kGULNetworkReachabilityHost];
+}
+
+- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost {
+ self = [super init];
+ if (self) {
+ // Setup reachability.
+ _reachability = [[GULReachabilityChecker alloc] initWithReachabilityDelegate:self
+ withHost:reachabilityHost];
+ if (![_reachability start]) {
+ return nil;
+ }
+
+ _requests = [[GULMutableDictionary alloc] init];
+ _timeoutInterval = kGULNetworkTimeOutInterval;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ _reachability.reachabilityDelegate = nil;
+ [_reachability stop];
+}
+
+#pragma mark - External Methods
+
++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID
+ completionHandler:(GULNetworkSystemCompletionHandler)completionHandler {
+ [GULNetworkURLSession handleEventsForBackgroundURLSessionID:sessionID
+ completionHandler:completionHandler];
+}
+
+- (NSString *)postURL:(NSURL *)url
+ payload:(NSData *)payload
+ queue:(dispatch_queue_t)queue
+ usingBackgroundSession:(BOOL)usingBackgroundSession
+ completionHandler:(GULNetworkCompletionHandler)handler {
+ if (!url.absoluteString.length) {
+ [self handleErrorWithCode:GULErrorCodeNetworkInvalidURL queue:queue withHandler:handler];
+ return nil;
+ }
+
+ NSTimeInterval timeOutInterval = _timeoutInterval ?: kGULNetworkTimeOutInterval;
+
+ NSMutableURLRequest *request =
+ [[NSMutableURLRequest alloc] initWithURL:url
+ cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+ timeoutInterval:timeOutInterval];
+
+ if (!request) {
+ [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation
+ queue:queue
+ withHandler:handler];
+ return nil;
+ }
+
+ NSError *compressError = nil;
+ NSData *compressedData = [NSData gul_dataByGzippingData:payload error:&compressError];
+ if (!compressedData || compressError) {
+ if (compressError || payload.length > 0) {
+ // If the payload is not empty but it fails to compress the payload, something has been wrong.
+ [self handleErrorWithCode:GULErrorCodeNetworkPayloadCompression
+ queue:queue
+ withHandler:handler];
+ return nil;
+ }
+ compressedData = [[NSData alloc] init];
+ }
+
+ NSString *postLength = @(compressedData.length).stringValue;
+
+ // Set up the request with the compressed data.
+ [request setValue:postLength forHTTPHeaderField:kGULNetworkContentLengthKey];
+ request.HTTPBody = compressedData;
+ request.HTTPMethod = kGULNetworkPOSTRequestMethod;
+ [request setValue:kGULNetworkContentTypeValue forHTTPHeaderField:kGULNetworkContentTypeKey];
+ [request setValue:kGULNetworkContentCompressionValue
+ forHTTPHeaderField:kGULNetworkContentCompressionKey];
+
+ GULNetworkURLSession *fetcher = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:self];
+ fetcher.backgroundNetworkEnabled = usingBackgroundSession;
+
+ __weak GULNetwork *weakSelf = self;
+ NSString *requestID = [fetcher
+ sessionIDFromAsyncPOSTRequest:request
+ completionHandler:^(NSHTTPURLResponse *response, NSData *data,
+ NSString *sessionID, NSError *error) {
+ GULNetwork *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue();
+ dispatch_async(queueToDispatch, ^{
+ if (sessionID.length) {
+ [strongSelf->_requests removeObjectForKey:sessionID];
+ }
+ if (handler) {
+ handler(response, data, error);
+ }
+ });
+ }];
+ if (!requestID) {
+ [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation
+ queue:queue
+ withHandler:handler];
+ return nil;
+ }
+
+ [self GULNetwork_logWithLevel:kGULNetworkLogLevelDebug
+ messageCode:kGULNetworkMessageCodeNetwork000
+ message:@"Uploading data. Host"
+ context:url];
+ _requests[requestID] = fetcher;
+ return requestID;
+}
+
+- (NSString *)getURL:(NSURL *)url
+ headers:(NSDictionary *)headers
+ queue:(dispatch_queue_t)queue
+ usingBackgroundSession:(BOOL)usingBackgroundSession
+ completionHandler:(GULNetworkCompletionHandler)handler {
+ if (!url.absoluteString.length) {
+ [self handleErrorWithCode:GULErrorCodeNetworkInvalidURL queue:queue withHandler:handler];
+ return nil;
+ }
+
+ NSTimeInterval timeOutInterval = _timeoutInterval ?: kGULNetworkTimeOutInterval;
+ NSMutableURLRequest *request =
+ [[NSMutableURLRequest alloc] initWithURL:url
+ cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+ timeoutInterval:timeOutInterval];
+
+ if (!request) {
+ [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation
+ queue:queue
+ withHandler:handler];
+ return nil;
+ }
+
+ request.HTTPMethod = kGULNetworkGETRequestMethod;
+ request.allHTTPHeaderFields = headers;
+
+ GULNetworkURLSession *fetcher = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:self];
+ fetcher.backgroundNetworkEnabled = usingBackgroundSession;
+
+ __weak GULNetwork *weakSelf = self;
+ NSString *requestID = [fetcher
+ sessionIDFromAsyncGETRequest:request
+ completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSString *sessionID,
+ NSError *error) {
+ GULNetwork *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue();
+ dispatch_async(queueToDispatch, ^{
+ if (sessionID.length) {
+ [strongSelf->_requests removeObjectForKey:sessionID];
+ }
+ if (handler) {
+ handler(response, data, error);
+ }
+ });
+ }];
+
+ if (!requestID) {
+ [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation
+ queue:queue
+ withHandler:handler];
+ return nil;
+ }
+
+ [self GULNetwork_logWithLevel:kGULNetworkLogLevelDebug
+ messageCode:kGULNetworkMessageCodeNetwork001
+ message:@"Downloading data. Host"
+ context:url];
+ _requests[requestID] = fetcher;
+ return requestID;
+}
+
+- (BOOL)hasUploadInProgress {
+ return _requests.count > 0;
+}
+
+#pragma mark - Network Reachability
+
+/// Tells reachability delegate to call reachabilityDidChangeToStatus: to notify the network
+/// reachability has changed.
+- (void)reachability:(GULReachabilityChecker *)reachability
+ statusChanged:(GULReachabilityStatus)status {
+ _networkConnected = (status == kGULReachabilityViaCellular || status == kGULReachabilityViaWifi);
+ [_reachabilityDelegate reachabilityDidChange];
+}
+
+#pragma mark - Network logger delegate
+
+- (void)setLoggerDelegate:(id<GULNetworkLoggerDelegate>)loggerDelegate {
+ // Explicitly check whether the delegate responds to the methods because conformsToProtocol does
+ // not work correctly even though the delegate does respond to the methods.
+ if (!loggerDelegate ||
+ ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel:
+ messageCode:message:contexts:)] ||
+ ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel:
+ messageCode:message:context:)] ||
+ ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel:
+ messageCode:message:)]) {
+ GULLogError(kGULLoggerNetwork, NO,
+ [NSString stringWithFormat:@"I-NET%06ld", (long)kGULNetworkMessageCodeNetwork002],
+ @"Cannot set the network logger delegate: delegate does not conform to the network "
+ "logger protocol.");
+ return;
+ }
+ _loggerDelegate = loggerDelegate;
+}
+
+#pragma mark - Private methods
+
+/// Handles network error and calls completion handler with the error.
+- (void)handleErrorWithCode:(NSInteger)code
+ queue:(dispatch_queue_t)queue
+ withHandler:(GULNetworkCompletionHandler)handler {
+ NSDictionary *userInfo = @{kGULNetworkErrorContext : @"Failed to create network request"};
+ NSError *error = [[NSError alloc] initWithDomain:kGULNetworkErrorDomain
+ code:code
+ userInfo:userInfo];
+ [self GULNetwork_logWithLevel:kGULNetworkLogLevelWarning
+ messageCode:kGULNetworkMessageCodeNetwork002
+ message:@"Failed to create network request. Code, error"
+ contexts:@[ @(code), error ]];
+ if (handler) {
+ dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue();
+ dispatch_async(queueToDispatch, ^{
+ handler(nil, nil, error);
+ });
+ }
+}
+
+#pragma mark - Network logger
+
+- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel
+ messageCode:(GULNetworkMessageCode)messageCode
+ message:(NSString *)message
+ contexts:(NSArray *)contexts {
+ // Let the delegate log the message if there is a valid logger delegate. Otherwise, just log
+ // errors/warnings/info messages to the console log.
+ if (_loggerDelegate) {
+ [_loggerDelegate GULNetwork_logWithLevel:logLevel
+ messageCode:messageCode
+ message:message
+ contexts:contexts];
+ return;
+ }
+ if (_isDebugModeEnabled || logLevel == kGULNetworkLogLevelError ||
+ logLevel == kGULNetworkLogLevelWarning || logLevel == kGULNetworkLogLevelInfo) {
+ NSString *formattedMessage = GULStringWithLogMessage(message, logLevel, contexts);
+ NSLog(@"%@", formattedMessage);
+ GULLogBasic((GULLoggerLevel)logLevel, kGULLoggerNetwork, NO,
+ [NSString stringWithFormat:@"I-NET%06ld", (long)messageCode], formattedMessage,
+ NULL);
+ }
+}
+
+- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel
+ messageCode:(GULNetworkMessageCode)messageCode
+ message:(NSString *)message
+ context:(id)context {
+ if (_loggerDelegate) {
+ [_loggerDelegate GULNetwork_logWithLevel:logLevel
+ messageCode:messageCode
+ message:message
+ context:context];
+ return;
+ }
+ NSArray *contexts = context ? @[ context ] : @[];
+ [self GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:contexts];
+}
+
+- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel
+ messageCode:(GULNetworkMessageCode)messageCode
+ message:(NSString *)message {
+ if (_loggerDelegate) {
+ [_loggerDelegate GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message];
+ return;
+ }
+ [self GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:@[]];
+}
+
+/// Returns a string for the given log level (e.g. kGULNetworkLogLevelError -> @"ERROR").
+static NSString *GULLogLevelDescriptionFromLogLevel(GULNetworkLogLevel logLevel) {
+ static NSDictionary *levelNames = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ levelNames = @{
+ @(kGULNetworkLogLevelError) : @"ERROR",
+ @(kGULNetworkLogLevelWarning) : @"WARNING",
+ @(kGULNetworkLogLevelInfo) : @"INFO",
+ @(kGULNetworkLogLevelDebug) : @"DEBUG"
+ };
+ });
+ return levelNames[@(logLevel)];
+}
+
+/// Returns a formatted string to be used for console logging.
+static NSString *GULStringWithLogMessage(NSString *message,
+ GULNetworkLogLevel logLevel,
+ NSArray *contexts) {
+ if (!message) {
+ message = @"(Message was nil)";
+ } else if (!message.length) {
+ message = @"(Message was empty)";
+ }
+ NSMutableString *result = [[NSMutableString alloc]
+ initWithFormat:@"<%@/%@> %@", kGULNetworkLogTag, GULLogLevelDescriptionFromLogLevel(logLevel),
+ message];
+
+ if (!contexts.count) {
+ return result;
+ }
+
+ NSMutableArray *formattedContexts = [[NSMutableArray alloc] init];
+ for (id item in contexts) {
+ [formattedContexts addObject:(item != [NSNull null] ? item : @"(nil)")];
+ }
+
+ [result appendString:@": "];
+ [result appendString:[formattedContexts componentsJoinedByString:@", "]];
+ return result;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m
new file mode 100644
index 00000000..dea8dbd5
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m
@@ -0,0 +1,40 @@
+// Copyright 2017 Google
+//
+// 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 "GoogleUtilities/Network/Private/GULNetworkConstants.h"
+
+#import <Foundation/Foundation.h>
+
+NSString *const kGULNetworkBackgroundSessionConfigIDPrefix = @"com.gul.network.background-upload";
+NSString *const kGULNetworkApplicationSupportSubdirectory = @"GUL/Network";
+NSString *const kGULNetworkTempDirectoryName = @"GULNetworkTemporaryDirectory";
+const NSTimeInterval kGULNetworkTempFolderExpireTime = 60 * 60; // 1 hour
+const NSTimeInterval kGULNetworkTimeOutInterval = 60; // 1 minute.
+NSString *const kGULNetworkReachabilityHost = @"app-measurement.com";
+NSString *const kGULNetworkErrorContext = @"Context";
+
+const int kGULNetworkHTTPStatusOK = 200;
+const int kGULNetworkHTTPStatusNoContent = 204;
+const int kGULNetworkHTTPStatusCodeMultipleChoices = 300;
+const int kGULNetworkHTTPStatusCodeMovedPermanently = 301;
+const int kGULNetworkHTTPStatusCodeFound = 302;
+const int kGULNetworkHTTPStatusCodeNotModified = 304;
+const int kGULNetworkHTTPStatusCodeMovedTemporarily = 307;
+const int kGULNetworkHTTPStatusCodeNotFound = 404;
+const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic = 429;
+const int kGULNetworkHTTPStatusCodeUnavailable = 503;
+
+NSString *const kGULNetworkErrorDomain = @"com.gul.network.ErrorDomain";
+
+GULLoggerService kGULLoggerNetwork = @"[GULNetwork]";
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m
new file mode 100644
index 00000000..6cece046
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m
@@ -0,0 +1,762 @@
+// Copyright 2017 Google
+//
+// 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 <Foundation/Foundation.h>
+
+#import "GoogleUtilities/Network/Private/GULNetworkURLSession.h"
+
+#import "GoogleUtilities/Logger/Private/GULLogger.h"
+#import "GoogleUtilities/Network/Private/GULMutableDictionary.h"
+#import "GoogleUtilities/Network/Private/GULNetworkConstants.h"
+#import "GoogleUtilities/Network/Private/GULNetworkMessageCode.h"
+
+@interface GULNetworkURLSession () <NSURLSessionDelegate,
+ NSURLSessionDataDelegate,
+ NSURLSessionDownloadDelegate,
+ NSURLSessionTaskDelegate>
+@end
+
+@implementation GULNetworkURLSession {
+ /// The handler to be called when the request completes or error has occurs.
+ GULNetworkURLSessionCompletionHandler _completionHandler;
+
+ /// Session ID generated randomly with a fixed prefix.
+ NSString *_sessionID;
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+ /// The session configuration. NSURLSessionConfiguration' is only available on iOS 7.0 or newer.
+ NSURLSessionConfiguration *_sessionConfig;
+
+ /// The current NSURLSession.
+ NSURLSession *__weak _Nullable _URLSession;
+#pragma clang diagnostic pop
+
+ /// The path to the directory where all temporary files are stored before uploading.
+ NSURL *_networkDirectoryURL;
+
+ /// The downloaded data from fetching.
+ NSData *_downloadedData;
+
+ /// The path to the temporary file which stores the uploading data.
+ NSURL *_uploadingFileURL;
+
+ /// The current request.
+ NSURLRequest *_request;
+}
+
+#pragma mark - Init
+
+- (instancetype)initWithNetworkLoggerDelegate:(id<GULNetworkLoggerDelegate>)networkLoggerDelegate {
+ self = [super init];
+ if (self) {
+ // Create URL to the directory where all temporary files to upload have to be stored.
+ NSArray *paths =
+ NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
+ NSString *applicationSupportDirectory = paths.firstObject;
+ NSArray *tempPathComponents = @[
+ applicationSupportDirectory, kGULNetworkApplicationSupportSubdirectory,
+ kGULNetworkTempDirectoryName
+ ];
+ _networkDirectoryURL = [NSURL fileURLWithPathComponents:tempPathComponents];
+ _sessionID = [NSString stringWithFormat:@"%@-%@", kGULNetworkBackgroundSessionConfigIDPrefix,
+ [[NSUUID UUID] UUIDString]];
+ _loggerDelegate = networkLoggerDelegate;
+ }
+ return self;
+}
+
+#pragma mark - External Methods
+
+#pragma mark - To be called from AppDelegate
+
++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID
+ completionHandler:
+ (GULNetworkSystemCompletionHandler)systemCompletionHandler {
+ // The session may not be Analytics background. Ignore those that do not have the prefix.
+ if (![sessionID hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) {
+ return;
+ }
+ GULNetworkURLSession *fetcher = [self fetcherWithSessionIdentifier:sessionID];
+ if (fetcher != nil) {
+ [fetcher addSystemCompletionHandler:systemCompletionHandler forSession:sessionID];
+ } else {
+ GULLogError(kGULLoggerNetwork, NO,
+ [NSString stringWithFormat:@"I-NET%06ld", (long)kGULNetworkMessageCodeNetwork003],
+ @"Failed to retrieve background session with ID %@ after app is relaunched.",
+ sessionID);
+ }
+}
+
+#pragma mark - External Methods
+
+/// Sends an async POST request using NSURLSession for iOS >= 7.0, and returns an ID of the
+/// connection.
+- (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request
+ completionHandler:(GULNetworkURLSessionCompletionHandler)handler
+ API_AVAILABLE(ios(7.0)) {
+ // NSURLSessionUploadTask does not work with NSData in the background.
+ // To avoid this issue, write the data to a temporary file to upload it.
+ // Make a temporary file with the data subset.
+ _uploadingFileURL = [self temporaryFilePathWithSessionID:_sessionID];
+ NSError *writeError;
+ NSURLSessionUploadTask *postRequestTask;
+ NSURLSession *session;
+ BOOL didWriteFile = NO;
+
+ // Clean up the entire temp folder to avoid temp files that remain in case the previous session
+ // crashed and did not clean up.
+ [self maybeRemoveTempFilesAtURL:_networkDirectoryURL
+ expiringTime:kGULNetworkTempFolderExpireTime];
+
+ // If there is no background network enabled, no need to write to file. This will allow default
+ // network session which runs on the foreground.
+ if (_backgroundNetworkEnabled && [self ensureTemporaryDirectoryExists]) {
+ didWriteFile = [request.HTTPBody writeToFile:_uploadingFileURL.path
+ options:NSDataWritingAtomic
+ error:&writeError];
+
+ if (writeError) {
+ [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError
+ messageCode:kGULNetworkMessageCodeURLSession000
+ message:@"Failed to write request data to file"
+ context:writeError];
+ }
+ }
+
+ if (didWriteFile) {
+ // Exclude this file from backing up to iTunes. There are conflicting reports that excluding
+ // directory from backing up does not exclude files of that directory from backing up.
+ [self excludeFromBackupForURL:_uploadingFileURL];
+
+ _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID];
+ [self populateSessionConfig:_sessionConfig withRequest:request];
+ session = [NSURLSession sessionWithConfiguration:_sessionConfig
+ delegate:self
+ delegateQueue:[NSOperationQueue mainQueue]];
+ postRequestTask = [session uploadTaskWithRequest:request fromFile:_uploadingFileURL];
+ } else {
+ // If we cannot write to file, just send it in the foreground.
+ _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
+ [self populateSessionConfig:_sessionConfig withRequest:request];
+ session = [NSURLSession sessionWithConfiguration:_sessionConfig
+ delegate:self
+ delegateQueue:[NSOperationQueue mainQueue]];
+ postRequestTask = [session uploadTaskWithRequest:request fromData:request.HTTPBody];
+ }
+
+ if (!session || !postRequestTask) {
+ NSError *error = [[NSError alloc]
+ initWithDomain:kGULNetworkErrorDomain
+ code:GULErrorCodeNetworkRequestCreation
+ userInfo:@{kGULNetworkErrorContext : @"Cannot create network session"}];
+ [self callCompletionHandler:handler withResponse:nil data:nil error:error];
+ return nil;
+ }
+
+ _URLSession = session;
+
+ // Save the session into memory.
+ [[self class] setSessionInFetcherMap:self forSessionID:_sessionID];
+
+ _request = [request copy];
+
+ // Store completion handler because background session does not accept handler block but custom
+ // delegate.
+ _completionHandler = [handler copy];
+ [postRequestTask resume];
+
+ return _sessionID;
+}
+
+/// Sends an async GET request using NSURLSession for iOS >= 7.0, and returns an ID of the session.
+- (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request
+ completionHandler:(GULNetworkURLSessionCompletionHandler)handler
+ API_AVAILABLE(ios(7.0)) {
+ if (_backgroundNetworkEnabled) {
+ _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID];
+ } else {
+ _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
+ }
+
+ [self populateSessionConfig:_sessionConfig withRequest:request];
+
+ // Do not cache the GET request.
+ _sessionConfig.URLCache = nil;
+
+ NSURLSession *session = [NSURLSession sessionWithConfiguration:_sessionConfig
+ delegate:self
+ delegateQueue:[NSOperationQueue mainQueue]];
+ NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];
+
+ if (!session || !downloadTask) {
+ NSError *error = [[NSError alloc]
+ initWithDomain:kGULNetworkErrorDomain
+ code:GULErrorCodeNetworkRequestCreation
+ userInfo:@{kGULNetworkErrorContext : @"Cannot create network session"}];
+ [self callCompletionHandler:handler withResponse:nil data:nil error:error];
+ return nil;
+ }
+
+ _URLSession = session;
+
+ // Save the session into memory.
+ [[self class] setSessionInFetcherMap:self forSessionID:_sessionID];
+
+ _request = [request copy];
+
+ _completionHandler = [handler copy];
+ [downloadTask resume];
+
+ return _sessionID;
+}
+
+#pragma mark - NSURLSessionDataDelegate
+
+/// Called by the NSURLSession when the data task has received some of the expected data.
+/// Once the session is completed, URLSession:task:didCompleteWithError will be called and the
+/// completion handler will be called with the downloaded data.
+- (void)URLSession:(NSURLSession *)session
+ dataTask:(NSURLSessionDataTask *)dataTask
+ didReceiveData:(NSData *)data {
+ @synchronized(self) {
+ NSMutableData *mutableData = [[NSMutableData alloc] init];
+ if (_downloadedData) {
+ mutableData = _downloadedData.mutableCopy;
+ }
+ [mutableData appendData:data];
+ _downloadedData = mutableData;
+ }
+}
+
+#pragma mark - NSURLSessionTaskDelegate
+
+/// Called by the NSURLSession once the download task is completed. The file is saved in the
+/// provided URL so we need to read the data and store into _downloadedData. Once the session is
+/// completed, URLSession:task:didCompleteWithError will be called and the completion handler will
+/// be called with the downloaded data.
+- (void)URLSession:(NSURLSession *)session
+ downloadTask:(NSURLSessionDownloadTask *)task
+ didFinishDownloadingToURL:(NSURL *)url API_AVAILABLE(ios(7.0)) {
+ if (!url.path) {
+ [_loggerDelegate
+ GULNetwork_logWithLevel:kGULNetworkLogLevelError
+ messageCode:kGULNetworkMessageCodeURLSession001
+ message:@"Unable to read downloaded data from empty temp path"];
+ _downloadedData = nil;
+ return;
+ }
+
+ NSError *error;
+ _downloadedData = [NSData dataWithContentsOfFile:url.path options:0 error:&error];
+
+ if (error) {
+ [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError
+ messageCode:kGULNetworkMessageCodeURLSession002
+ message:@"Cannot read the content of downloaded data"
+ context:error];
+ _downloadedData = nil;
+ }
+}
+
+#if TARGET_OS_IOS || TARGET_OS_TV
+- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
+ API_AVAILABLE(ios(7.0)) {
+ [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug
+ messageCode:kGULNetworkMessageCodeURLSession003
+ message:@"Background session finished"
+ context:session.configuration.identifier];
+ [self callSystemCompletionHandler:session.configuration.identifier];
+}
+#endif
+
+- (void)URLSession:(NSURLSession *)session
+ task:(NSURLSessionTask *)task
+ didCompleteWithError:(NSError *)error API_AVAILABLE(ios(7.0)) {
+ // Avoid any chance of recursive behavior leading to it being used repeatedly.
+ GULNetworkURLSessionCompletionHandler handler = _completionHandler;
+ _completionHandler = nil;
+
+ if (task.response) {
+ // The following assertion should always be true for HTTP requests, see https://goo.gl/gVLxT7.
+ NSAssert([task.response isKindOfClass:[NSHTTPURLResponse class]], @"URL response must be HTTP");
+
+ // The server responded so ignore the error created by the system.
+ error = nil;
+ } else if (!error) {
+ error = [[NSError alloc]
+ initWithDomain:kGULNetworkErrorDomain
+ code:GULErrorCodeNetworkInvalidResponse
+ userInfo:@{kGULNetworkErrorContext : @"Network Error: Empty network response"}];
+ }
+
+ [self callCompletionHandler:handler
+ withResponse:(NSHTTPURLResponse *)task.response
+ data:_downloadedData
+ error:error];
+
+ // Remove the temp file to avoid trashing devices with lots of temp files.
+ [self removeTempItemAtURL:_uploadingFileURL];
+
+ // Try to clean up stale files again.
+ [self maybeRemoveTempFilesAtURL:_networkDirectoryURL
+ expiringTime:kGULNetworkTempFolderExpireTime];
+
+ // This is called without checking the sessionID here since non-background sessions
+ // won't have an ID.
+ [session finishTasksAndInvalidate];
+
+ // Explicitly remove the session so it won't be reused. The weak map table should
+ // remove the session on deallocation, but dealloc may not happen immediately after
+ // calling `finishTasksAndInvalidate`.
+ NSString *sessionID = session.configuration.identifier;
+ [[self class] setSessionInFetcherMap:nil forSessionID:sessionID];
+}
+
+- (void)URLSession:(NSURLSession *)session
+ task:(NSURLSessionTask *)task
+ didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
+ completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,
+ NSURLCredential *credential))completionHandler
+ API_AVAILABLE(ios(7.0)) {
+ // The handling is modeled after GTMSessionFetcher.
+ if ([challenge.protectionSpace.authenticationMethod
+ isEqualToString:NSURLAuthenticationMethodServerTrust]) {
+ SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
+ if (serverTrust == NULL) {
+ [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug
+ messageCode:kGULNetworkMessageCodeURLSession004
+ message:@"Received empty server trust for host. Host"
+ context:_request.URL];
+ completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
+ return;
+ }
+ NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
+ if (!credential) {
+ [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelWarning
+ messageCode:kGULNetworkMessageCodeURLSession005
+ message:@"Unable to verify server identity. Host"
+ context:_request.URL];
+ completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
+ return;
+ }
+
+ [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug
+ messageCode:kGULNetworkMessageCodeURLSession006
+ message:@"Received SSL challenge for host. Host"
+ context:_request.URL];
+
+ void (^callback)(BOOL) = ^(BOOL allow) {
+ if (allow) {
+ completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
+ } else {
+ [self->_loggerDelegate
+ GULNetwork_logWithLevel:kGULNetworkLogLevelDebug
+ messageCode:kGULNetworkMessageCodeURLSession007
+ message:@"Cancelling authentication challenge for host. Host"
+ context:self->_request.URL];
+ completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
+ }
+ };
+
+ // 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/
+ dispatch_queue_t evaluateBackgroundQueue =
+ dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ dispatch_async(evaluateBackgroundQueue, ^{
+ SecTrustResultType trustEval = kSecTrustResultInvalid;
+ BOOL shouldAllow;
+ OSStatus trustError;
+
+ @synchronized([GULNetworkURLSession class]) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ trustError = SecTrustEvaluate(serverTrust, &trustEval);
+#pragma clang dianostic pop
+ }
+
+ if (trustError != errSecSuccess) {
+ [self->_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError
+ messageCode:kGULNetworkMessageCodeURLSession008
+ message:@"Cannot evaluate server trust. Error, host"
+ contexts:@[ @(trustError), self->_request.URL ]];
+ 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
+ shouldAllow =
+ (trustEval == kSecTrustResultUnspecified || trustEval == kSecTrustResultProceed);
+ }
+
+ // Call the call back with the permission.
+ callback(shouldAllow);
+
+ CFRelease(serverTrust);
+ });
+ return;
+ }
+
+ // Default handling for other Auth Challenges.
+ completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
+}
+
+#pragma mark - Internal Methods
+
+/// Stores system completion handler with session ID as key.
+- (void)addSystemCompletionHandler:(GULNetworkSystemCompletionHandler)handler
+ forSession:(NSString *)identifier {
+ if (!handler) {
+ [_loggerDelegate
+ GULNetwork_logWithLevel:kGULNetworkLogLevelError
+ messageCode:kGULNetworkMessageCodeURLSession009
+ message:@"Cannot store nil system completion handler in network"];
+ return;
+ }
+
+ if (!identifier.length) {
+ [_loggerDelegate
+ GULNetwork_logWithLevel:kGULNetworkLogLevelError
+ messageCode:kGULNetworkMessageCodeURLSession010
+ message:@"Cannot store system completion handler with empty network "
+ "session identifier"];
+ return;
+ }
+
+ GULMutableDictionary *systemCompletionHandlers =
+ [[self class] sessionIDToSystemCompletionHandlerDictionary];
+ if (systemCompletionHandlers[identifier]) {
+ [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelWarning
+ messageCode:kGULNetworkMessageCodeURLSession011
+ message:@"Got multiple system handlers for a single session ID"
+ context:identifier];
+ }
+
+ systemCompletionHandlers[identifier] = handler;
+}
+
+/// Calls the system provided completion handler with the session ID stored in the dictionary.
+/// The handler will be removed from the dictionary after being called.
+- (void)callSystemCompletionHandler:(NSString *)identifier {
+ GULMutableDictionary *systemCompletionHandlers =
+ [[self class] sessionIDToSystemCompletionHandlerDictionary];
+ GULNetworkSystemCompletionHandler handler = [systemCompletionHandlers objectForKey:identifier];
+
+ if (handler) {
+ [systemCompletionHandlers removeObjectForKey:identifier];
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler();
+ });
+ }
+}
+
+/// Sets or updates the session ID of this session.
+- (void)setSessionID:(NSString *)sessionID {
+ _sessionID = [sessionID copy];
+}
+
+/// Creates a background session configuration with the session ID using the supported method.
+- (NSURLSessionConfiguration *)backgroundSessionConfigWithSessionID:(NSString *)sessionID
+ API_AVAILABLE(ios(7.0)) {
+#if (TARGET_OS_OSX && defined(MAC_OS_X_VERSION_10_10) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) || \
+ TARGET_OS_TV || \
+ (TARGET_OS_IOS && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0)
+
+ // iOS 8/10.10 builds require the new backgroundSessionConfiguration method name.
+ return [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionID];
+
+#elif (TARGET_OS_OSX && defined(MAC_OS_X_VERSION_10_10) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10) || \
+ (TARGET_OS_IOS && 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+.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+ return [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionID];
+#pragma clang diagnostic pop
+ } else {
+ // Running on iOS 7/OS X 10.9.
+ return [NSURLSessionConfiguration backgroundSessionConfiguration:sessionID];
+ }
+
+#else
+ // Building with an SDK earlier than iOS 8/OS X 10.10.
+ return [NSURLSessionConfiguration backgroundSessionConfiguration:sessionID];
+#endif
+}
+
+- (void)maybeRemoveTempFilesAtURL:(NSURL *)folderURL expiringTime:(NSTimeInterval)staleTime {
+ if (!folderURL.absoluteString.length) {
+ return;
+ }
+
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSError *error = nil;
+
+ NSArray *properties = @[ NSURLCreationDateKey ];
+ NSArray *directoryContent =
+ [fileManager contentsOfDirectoryAtURL:folderURL
+ includingPropertiesForKeys:properties
+ options:NSDirectoryEnumerationSkipsSubdirectoryDescendants
+ error:&error];
+ if (error && error.code != NSFileReadNoSuchFileError) {
+ [_loggerDelegate
+ GULNetwork_logWithLevel:kGULNetworkLogLevelDebug
+ messageCode:kGULNetworkMessageCodeURLSession012
+ message:@"Cannot get files from the temporary network folder. Error"
+ context:error];
+ return;
+ }
+
+ if (!directoryContent.count) {
+ return;
+ }
+
+ NSTimeInterval now = [NSDate date].timeIntervalSince1970;
+ for (NSURL *tempFile in directoryContent) {
+ NSDate *creationDate;
+ BOOL getCreationDate = [tempFile getResourceValue:&creationDate
+ forKey:NSURLCreationDateKey
+ error:NULL];
+ if (!getCreationDate) {
+ continue;
+ }
+ NSTimeInterval creationTimeInterval = creationDate.timeIntervalSince1970;
+ if (fabs(now - creationTimeInterval) > staleTime) {
+ [self removeTempItemAtURL:tempFile];
+ }
+ }
+}
+
+/// Removes the temporary file written to disk for sending the request. It has to be cleaned up
+/// after the session is done.
+- (void)removeTempItemAtURL:(NSURL *)fileURL {
+ if (!fileURL.absoluteString.length) {
+ return;
+ }
+
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSError *error = nil;
+
+ if (![fileManager removeItemAtURL:fileURL error:&error] && error.code != NSFileNoSuchFileError) {
+ [_loggerDelegate
+ GULNetwork_logWithLevel:kGULNetworkLogLevelError
+ messageCode:kGULNetworkMessageCodeURLSession013
+ message:@"Failed to remove temporary uploading data file. Error"
+ context:error.localizedDescription];
+ }
+}
+
+/// Gets the fetcher with the session ID.
++ (instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier {
+ GULNetworkURLSession *session = [self sessionFromFetcherMapForSessionID:sessionIdentifier];
+ if (!session && [sessionIdentifier hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) {
+ session = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:nil];
+ [session setSessionID:sessionIdentifier];
+ [self setSessionInFetcherMap:session forSessionID:sessionIdentifier];
+ }
+ return session;
+}
+
+/// Returns a map of the fetcher by session ID. Creates a map if it is not created.
+/// When reading and writing from/to the session map, don't use this method directly.
+/// To avoid thread safety issues, use one of the helper methods at the bottom of the
+/// file: setSessionInFetcherMap:forSessionID:, sessionFromFetcherMapForSessionID:
++ (NSMapTable<NSString *, GULNetworkURLSession *> *)sessionIDToFetcherMap {
+ static NSMapTable *sessionIDToFetcherMap;
+
+ static dispatch_once_t sessionMapOnceToken;
+ dispatch_once(&sessionMapOnceToken, ^{
+ sessionIDToFetcherMap = [NSMapTable strongToWeakObjectsMapTable];
+ });
+ return sessionIDToFetcherMap;
+}
+
++ (NSLock *)sessionIDToFetcherMapReadWriteLock {
+ static NSLock *lock;
+
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ lock = [[NSLock alloc] init];
+ });
+ return lock;
+}
+
+/// Returns a map of system provided completion handler by session ID. Creates a map if it is not
+/// created.
++ (GULMutableDictionary *)sessionIDToSystemCompletionHandlerDictionary {
+ static GULMutableDictionary *systemCompletionHandlers;
+
+ static dispatch_once_t systemCompletionHandlerOnceToken;
+ dispatch_once(&systemCompletionHandlerOnceToken, ^{
+ systemCompletionHandlers = [[GULMutableDictionary alloc] init];
+ });
+ return systemCompletionHandlers;
+}
+
+- (NSURL *)temporaryFilePathWithSessionID:(NSString *)sessionID {
+ NSString *tempName = [NSString stringWithFormat:@"GULUpload_temp_%@", sessionID];
+ return [_networkDirectoryURL URLByAppendingPathComponent:tempName];
+}
+
+/// Makes sure that the directory to store temp files exists. If not, tries to create it and returns
+/// YES. If there is anything wrong, returns NO.
+- (BOOL)ensureTemporaryDirectoryExists {
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSError *error = nil;
+
+ // Create a temporary directory if it does not exist or was deleted.
+ if ([_networkDirectoryURL checkResourceIsReachableAndReturnError:&error]) {
+ return YES;
+ }
+
+ if (error && error.code != NSFileReadNoSuchFileError) {
+ [_loggerDelegate
+ GULNetwork_logWithLevel:kGULNetworkLogLevelWarning
+ messageCode:kGULNetworkMessageCodeURLSession014
+ message:@"Error while trying to access Network temp folder. Error"
+ context:error];
+ }
+
+ NSError *writeError = nil;
+
+ [fileManager createDirectoryAtURL:_networkDirectoryURL
+ withIntermediateDirectories:YES
+ attributes:nil
+ error:&writeError];
+ if (writeError) {
+ [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError
+ messageCode:kGULNetworkMessageCodeURLSession015
+ message:@"Cannot create temporary directory. Error"
+ context:writeError];
+ return NO;
+ }
+
+ // Set the iCloud exclusion attribute on the Documents URL.
+ [self excludeFromBackupForURL:_networkDirectoryURL];
+
+ return YES;
+}
+
+- (void)excludeFromBackupForURL:(NSURL *)url {
+ if (!url.path) {
+ return;
+ }
+
+ // Set the iCloud exclusion attribute on the Documents URL.
+ NSError *preventBackupError = nil;
+ [url setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&preventBackupError];
+ if (preventBackupError) {
+ [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError
+ messageCode:kGULNetworkMessageCodeURLSession016
+ message:@"Cannot exclude temporary folder from iTunes backup"];
+ }
+}
+
+- (void)URLSession:(NSURLSession *)session
+ task:(NSURLSessionTask *)task
+ willPerformHTTPRedirection:(NSHTTPURLResponse *)response
+ newRequest:(NSURLRequest *)request
+ completionHandler:(void (^)(NSURLRequest *))completionHandler API_AVAILABLE(ios(7.0)) {
+ NSArray *nonAllowedRedirectionCodes = @[
+ @(kGULNetworkHTTPStatusCodeFound), @(kGULNetworkHTTPStatusCodeMovedPermanently),
+ @(kGULNetworkHTTPStatusCodeMovedTemporarily), @(kGULNetworkHTTPStatusCodeMultipleChoices)
+ ];
+
+ // Allow those not in the non allowed list to be followed.
+ if (![nonAllowedRedirectionCodes containsObject:@(response.statusCode)]) {
+ completionHandler(request);
+ return;
+ }
+
+ // Do not allow redirection if the response code is in the non-allowed list.
+ NSURLRequest *newRequest = request;
+
+ if (response) {
+ newRequest = nil;
+ }
+
+ completionHandler(newRequest);
+}
+
+#pragma mark - Helper Methods
+
++ (void)setSessionInFetcherMap:(GULNetworkURLSession *)session forSessionID:(NSString *)sessionID {
+ [[self sessionIDToFetcherMapReadWriteLock] lock];
+ GULNetworkURLSession *existingSession =
+ [[[self class] sessionIDToFetcherMap] objectForKey:sessionID];
+ if (existingSession) {
+ if (session) {
+ NSString *message = [NSString stringWithFormat:@"Discarding session: %@", existingSession];
+ [existingSession->_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelInfo
+ messageCode:kGULNetworkMessageCodeURLSession019
+ message:message];
+ }
+ [existingSession->_URLSession finishTasksAndInvalidate];
+ }
+ if (session) {
+ [[[self class] sessionIDToFetcherMap] setObject:session forKey:sessionID];
+ } else {
+ [[[self class] sessionIDToFetcherMap] removeObjectForKey:sessionID];
+ }
+ [[self sessionIDToFetcherMapReadWriteLock] unlock];
+}
+
++ (nullable GULNetworkURLSession *)sessionFromFetcherMapForSessionID:(NSString *)sessionID {
+ [[self sessionIDToFetcherMapReadWriteLock] lock];
+ GULNetworkURLSession *session = [[[self class] sessionIDToFetcherMap] objectForKey:sessionID];
+ [[self sessionIDToFetcherMapReadWriteLock] unlock];
+ return session;
+}
+
+- (void)callCompletionHandler:(GULNetworkURLSessionCompletionHandler)handler
+ withResponse:(NSHTTPURLResponse *)response
+ data:(NSData *)data
+ error:(NSError *)error {
+ if (error) {
+ [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError
+ messageCode:kGULNetworkMessageCodeURLSession017
+ message:@"Encounter network error. Code, error"
+ contexts:@[ @(error.code), error ]];
+ }
+
+ if (handler) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler(response, data, self->_sessionID, error);
+ });
+ }
+}
+
+// Always use the request parameters even if the default session configuration is more restrictive.
+- (void)populateSessionConfig:(NSURLSessionConfiguration *)sessionConfig
+ withRequest:(NSURLRequest *)request API_AVAILABLE(ios(7.0)) {
+ sessionConfig.HTTPAdditionalHeaders = request.allHTTPHeaderFields;
+ sessionConfig.timeoutIntervalForRequest = request.timeoutInterval;
+ sessionConfig.timeoutIntervalForResource = request.timeoutInterval;
+ sessionConfig.requestCachePolicy = request.cachePolicy;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULMutableDictionary.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULMutableDictionary.h
new file mode 100644
index 00000000..a8cc45b4
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULMutableDictionary.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+/// A mutable dictionary that provides atomic accessor and mutators.
+@interface GULMutableDictionary : NSObject
+
+/// Returns an object given a key in the dictionary or nil if not found.
+- (id)objectForKey:(id)key;
+
+/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary.
+- (void)setObject:(id)object forKey:(id<NSCopying>)key;
+
+/// Removes the object given its session ID from the dictionary.
+- (void)removeObjectForKey:(id)key;
+
+/// Removes all objects.
+- (void)removeAllObjects;
+
+/// Returns the number of current objects in the dictionary.
+- (NSUInteger)count;
+
+/// Returns an object given a key in the dictionary or nil if not found.
+- (id)objectForKeyedSubscript:(id<NSCopying>)key;
+
+/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary.
+- (void)setObject:(id)obj forKeyedSubscript:(id<NSCopying>)key;
+
+/// Returns the immutable dictionary.
+- (NSDictionary *)dictionary;
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetwork.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetwork.h
new file mode 100644
index 00000000..646cb440
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetwork.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+#import "GoogleUtilities/Network/Private/GULNetworkConstants.h"
+#import "GoogleUtilities/Network/Private/GULNetworkLoggerProtocol.h"
+#import "GoogleUtilities/Network/Private/GULNetworkURLSession.h"
+
+/// Delegate protocol for GULNetwork events.
+@protocol GULNetworkReachabilityDelegate
+
+/// Tells the delegate to handle events when the network reachability changes to connected or not
+/// connected.
+- (void)reachabilityDidChange;
+
+@end
+
+/// The Network component that provides network status and handles network requests and responses.
+/// This is not thread safe.
+///
+/// NOTE:
+/// User must add FIRAnalytics handleEventsForBackgroundURLSessionID:completionHandler to the
+/// AppDelegate application:handleEventsForBackgroundURLSession:completionHandler:
+@interface GULNetwork : NSObject
+
+/// Indicates if network connectivity is available.
+@property(nonatomic, readonly, getter=isNetworkConnected) BOOL networkConnected;
+
+/// Indicates if there are any uploads in progress.
+@property(nonatomic, readonly, getter=hasUploadInProgress) BOOL uploadInProgress;
+
+/// An optional delegate that can be used in the event when network reachability changes.
+@property(nonatomic, weak) id<GULNetworkReachabilityDelegate> reachabilityDelegate;
+
+/// An optional delegate that can be used to log messages, warnings or errors that occur in the
+/// network operations.
+@property(nonatomic, weak) id<GULNetworkLoggerDelegate> loggerDelegate;
+
+/// Indicates whether the logger should display debug messages.
+@property(nonatomic, assign) BOOL isDebugModeEnabled;
+
+/// The time interval in seconds for the network request to timeout.
+@property(nonatomic, assign) NSTimeInterval timeoutInterval;
+
+/// Initializes with the default reachability host.
+- (instancetype)init;
+
+/// Initializes with a custom reachability host.
+- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost;
+
+/// Handles events when background session with the given ID has finished.
++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID
+ completionHandler:(GULNetworkSystemCompletionHandler)completionHandler;
+
+/// Compresses and sends a POST request with the provided data to the URL. The session will be
+/// background session if usingBackgroundSession is YES. Otherwise, the POST session is default
+/// session. Returns a session ID or nil if an error occurs.
+- (NSString *)postURL:(NSURL *)url
+ payload:(NSData *)payload
+ queue:(dispatch_queue_t)queue
+ usingBackgroundSession:(BOOL)usingBackgroundSession
+ completionHandler:(GULNetworkCompletionHandler)handler;
+
+/// Sends a GET request with the provided data to the URL. The session will be background session
+/// if usingBackgroundSession is YES. Otherwise, the GET session is default session. Returns a
+/// session ID or nil if an error occurs.
+- (NSString *)getURL:(NSURL *)url
+ headers:(NSDictionary *)headers
+ queue:(dispatch_queue_t)queue
+ usingBackgroundSession:(BOOL)usingBackgroundSession
+ completionHandler:(GULNetworkCompletionHandler)handler;
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkConstants.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkConstants.h
new file mode 100644
index 00000000..c73965f9
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkConstants.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 Google
+ *
+ * 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 <Foundation/Foundation.h>
+#import "GoogleUtilities/Logger/Private/GULLogger.h"
+
+/// Error codes in Firebase Network error domain.
+/// Note: these error codes should never change. It would make it harder to decode the errors if
+/// we inadvertently altered any of these codes in a future SDK version.
+typedef NS_ENUM(NSInteger, GULNetworkErrorCode) {
+ /// Unknown error.
+ GULNetworkErrorCodeUnknown = 0,
+ /// Error occurs when the request URL is invalid.
+ GULErrorCodeNetworkInvalidURL = 1,
+ /// Error occurs when request cannot be constructed.
+ GULErrorCodeNetworkRequestCreation = 2,
+ /// Error occurs when payload cannot be compressed.
+ GULErrorCodeNetworkPayloadCompression = 3,
+ /// Error occurs when session task cannot be created.
+ GULErrorCodeNetworkSessionTaskCreation = 4,
+ /// Error occurs when there is no response.
+ GULErrorCodeNetworkInvalidResponse = 5
+};
+
+#pragma mark - Network constants
+
+/// The prefix of the ID of the background session.
+extern NSString *const kGULNetworkBackgroundSessionConfigIDPrefix;
+
+/// The sub directory to store the files of data that is being uploaded in the background.
+extern NSString *const kGULNetworkApplicationSupportSubdirectory;
+
+/// Name of the temporary directory that stores files for background uploading.
+extern NSString *const kGULNetworkTempDirectoryName;
+
+/// The period when the temporary uploading file can stay.
+extern const NSTimeInterval kGULNetworkTempFolderExpireTime;
+
+/// The default network request timeout interval.
+extern const NSTimeInterval kGULNetworkTimeOutInterval;
+
+/// The host to check the reachability of the network.
+extern NSString *const kGULNetworkReachabilityHost;
+
+/// The key to get the error context of the UserInfo.
+extern NSString *const kGULNetworkErrorContext;
+
+#pragma mark - Network Status Code
+
+extern const int kGULNetworkHTTPStatusOK;
+extern const int kGULNetworkHTTPStatusNoContent;
+extern const int kGULNetworkHTTPStatusCodeMultipleChoices;
+extern const int kGULNetworkHTTPStatusCodeMovedPermanently;
+extern const int kGULNetworkHTTPStatusCodeFound;
+extern const int kGULNetworkHTTPStatusCodeNotModified;
+extern const int kGULNetworkHTTPStatusCodeMovedTemporarily;
+extern const int kGULNetworkHTTPStatusCodeNotFound;
+extern const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic;
+extern const int kGULNetworkHTTPStatusCodeUnavailable;
+
+#pragma mark - Error Domain
+
+extern NSString *const kGULNetworkErrorDomain;
+
+/// The logger service for GULNetwork.
+extern GULLoggerService kGULLoggerNetwork;
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkLoggerProtocol.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkLoggerProtocol.h
new file mode 100644
index 00000000..b713e4a8
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkLoggerProtocol.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+#import "GoogleUtilities/Logger/Private/GULLogger.h"
+
+#import "GoogleUtilities/Network/Private/GULNetworkMessageCode.h"
+
+/// The log levels used by GULNetworkLogger.
+typedef NS_ENUM(NSInteger, GULNetworkLogLevel) {
+ kGULNetworkLogLevelError = GULLoggerLevelError,
+ kGULNetworkLogLevelWarning = GULLoggerLevelWarning,
+ kGULNetworkLogLevelInfo = GULLoggerLevelInfo,
+ kGULNetworkLogLevelDebug = GULLoggerLevelDebug,
+};
+
+@protocol GULNetworkLoggerDelegate <NSObject>
+
+@required
+/// Tells the delegate to log a message with an array of contexts and the log level.
+- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel
+ messageCode:(GULNetworkMessageCode)messageCode
+ message:(NSString *)message
+ contexts:(NSArray *)contexts;
+
+/// Tells the delegate to log a message with a context and the log level.
+- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel
+ messageCode:(GULNetworkMessageCode)messageCode
+ message:(NSString *)message
+ context:(id)context;
+
+/// Tells the delegate to log a message with the log level.
+- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel
+ messageCode:(GULNetworkMessageCode)messageCode
+ message:(NSString *)message;
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkMessageCode.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkMessageCode.h
new file mode 100644
index 00000000..507bc5a5
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkMessageCode.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum.
+typedef NS_ENUM(NSInteger, GULNetworkMessageCode) {
+ // GULNetwork.m
+ kGULNetworkMessageCodeNetwork000 = 900000, // I-NET900000
+ kGULNetworkMessageCodeNetwork001 = 900001, // I-NET900001
+ kGULNetworkMessageCodeNetwork002 = 900002, // I-NET900002
+ kGULNetworkMessageCodeNetwork003 = 900003, // I-NET900003
+ // GULNetworkURLSession.m
+ kGULNetworkMessageCodeURLSession000 = 901000, // I-NET901000
+ kGULNetworkMessageCodeURLSession001 = 901001, // I-NET901001
+ kGULNetworkMessageCodeURLSession002 = 901002, // I-NET901002
+ kGULNetworkMessageCodeURLSession003 = 901003, // I-NET901003
+ kGULNetworkMessageCodeURLSession004 = 901004, // I-NET901004
+ kGULNetworkMessageCodeURLSession005 = 901005, // I-NET901005
+ kGULNetworkMessageCodeURLSession006 = 901006, // I-NET901006
+ kGULNetworkMessageCodeURLSession007 = 901007, // I-NET901007
+ kGULNetworkMessageCodeURLSession008 = 901008, // I-NET901008
+ kGULNetworkMessageCodeURLSession009 = 901009, // I-NET901009
+ kGULNetworkMessageCodeURLSession010 = 901010, // I-NET901010
+ kGULNetworkMessageCodeURLSession011 = 901011, // I-NET901011
+ kGULNetworkMessageCodeURLSession012 = 901012, // I-NET901012
+ kGULNetworkMessageCodeURLSession013 = 901013, // I-NET901013
+ kGULNetworkMessageCodeURLSession014 = 901014, // I-NET901014
+ kGULNetworkMessageCodeURLSession015 = 901015, // I-NET901015
+ kGULNetworkMessageCodeURLSession016 = 901016, // I-NET901016
+ kGULNetworkMessageCodeURLSession017 = 901017, // I-NET901017
+ kGULNetworkMessageCodeURLSession018 = 901018, // I-NET901018
+ kGULNetworkMessageCodeURLSession019 = 901019, // I-NET901019
+};
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkURLSession.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkURLSession.h
new file mode 100644
index 00000000..b4fa9709
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Private/GULNetworkURLSession.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+#import "GoogleUtilities/Network/Private/GULNetworkLoggerProtocol.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef void (^GULNetworkCompletionHandler)(NSHTTPURLResponse *_Nullable response,
+ NSData *_Nullable data,
+ NSError *_Nullable error);
+typedef void (^GULNetworkURLSessionCompletionHandler)(NSHTTPURLResponse *_Nullable response,
+ NSData *_Nullable data,
+ NSString *sessionID,
+ NSError *_Nullable error);
+typedef void (^GULNetworkSystemCompletionHandler)(void);
+
+/// The protocol that uses NSURLSession for iOS >= 7.0 to handle requests and responses.
+@interface GULNetworkURLSession : NSObject
+
+/// Indicates whether the background network is enabled. Default value is NO.
+@property(nonatomic, getter=isBackgroundNetworkEnabled) BOOL backgroundNetworkEnabled;
+
+/// The logger delegate to log message, errors or warnings that occur during the network operations.
+@property(nonatomic, weak, nullable) id<GULNetworkLoggerDelegate> loggerDelegate;
+
+/// Calls the system provided completion handler after the background session is finished.
++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID
+ completionHandler:(GULNetworkSystemCompletionHandler)completionHandler;
+
+/// Initializes with logger delegate.
+- (instancetype)initWithNetworkLoggerDelegate:
+ (nullable id<GULNetworkLoggerDelegate>)networkLoggerDelegate NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/// Sends an asynchronous POST request and calls the provided completion handler when the request
+/// completes or when errors occur, and returns an ID of the session/connection.
+- (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request
+ completionHandler:(GULNetworkURLSessionCompletionHandler)handler;
+
+/// Sends an asynchronous GET request and calls the provided completion handler when the request
+/// completes or when errors occur, and returns an ID of the session.
+- (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request
+ completionHandler:(GULNetworkURLSessionCompletionHandler)handler;
+
+NS_ASSUME_NONNULL_END
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h
new file mode 100644
index 00000000..5a54e442
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 Google
+ *
+ * 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 "GoogleUtilities/Reachability/Private/GULReachabilityChecker.h"
+#if !TARGET_OS_WATCH
+typedef SCNetworkReachabilityRef (*GULReachabilityCreateWithNameFn)(CFAllocatorRef allocator,
+ const char *host);
+
+typedef Boolean (*GULReachabilitySetCallbackFn)(SCNetworkReachabilityRef target,
+ SCNetworkReachabilityCallBack callback,
+ SCNetworkReachabilityContext *context);
+typedef Boolean (*GULReachabilityScheduleWithRunLoopFn)(SCNetworkReachabilityRef target,
+ CFRunLoopRef runLoop,
+ CFStringRef runLoopMode);
+typedef Boolean (*GULReachabilityUnscheduleFromRunLoopFn)(SCNetworkReachabilityRef target,
+ CFRunLoopRef runLoop,
+ CFStringRef runLoopMode);
+
+typedef void (*GULReachabilityReleaseFn)(CFTypeRef cf);
+
+struct GULReachabilityApi {
+ GULReachabilityCreateWithNameFn createWithNameFn;
+ GULReachabilitySetCallbackFn setCallbackFn;
+ GULReachabilityScheduleWithRunLoopFn scheduleWithRunLoopFn;
+ GULReachabilityUnscheduleFromRunLoopFn unscheduleFromRunLoopFn;
+ GULReachabilityReleaseFn releaseFn;
+};
+#endif
+@interface GULReachabilityChecker (Internal)
+
+- (const struct GULReachabilityApi *)reachabilityApi;
+- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi;
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m
new file mode 100644
index 00000000..8cbe609d
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m
@@ -0,0 +1,263 @@
+// Copyright 2017 Google
+//
+// 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 <Foundation/Foundation.h>
+
+#import "GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h"
+#import "GoogleUtilities/Reachability/Private/GULReachabilityChecker.h"
+#import "GoogleUtilities/Reachability/Private/GULReachabilityMessageCode.h"
+
+#import "GoogleUtilities/Logger/Private/GULLogger.h"
+#import "GoogleUtilities/Reachability/Private/GULReachabilityChecker.h"
+
+static GULLoggerService kGULLoggerReachability = @"[GULReachability]";
+#if !TARGET_OS_WATCH
+static void ReachabilityCallback(SCNetworkReachabilityRef reachability,
+ SCNetworkReachabilityFlags flags,
+ void *info);
+
+static const struct GULReachabilityApi kGULDefaultReachabilityApi = {
+ SCNetworkReachabilityCreateWithName,
+ SCNetworkReachabilitySetCallback,
+ SCNetworkReachabilityScheduleWithRunLoop,
+ SCNetworkReachabilityUnscheduleFromRunLoop,
+ CFRelease,
+};
+
+static NSString *const kGULReachabilityUnknownStatus = @"Unknown";
+static NSString *const kGULReachabilityConnectedStatus = @"Connected";
+static NSString *const kGULReachabilityDisconnectedStatus = @"Disconnected";
+#endif
+@interface GULReachabilityChecker ()
+
+@property(nonatomic, assign) const struct GULReachabilityApi *reachabilityApi;
+@property(nonatomic, assign) GULReachabilityStatus reachabilityStatus;
+@property(nonatomic, copy) NSString *host;
+#if !TARGET_OS_WATCH
+@property(nonatomic, assign) SCNetworkReachabilityRef reachability;
+#endif
+
+@end
+
+@implementation GULReachabilityChecker
+
+@synthesize reachabilityApi = reachabilityApi_;
+#if !TARGET_OS_WATCH
+@synthesize reachability = reachability_;
+#endif
+
+- (const struct GULReachabilityApi *)reachabilityApi {
+ return reachabilityApi_;
+}
+
+- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi {
+#if !TARGET_OS_WATCH
+ if (reachability_) {
+ GULLogError(kGULLoggerReachability, NO,
+ [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode000],
+ @"Cannot change reachability API while reachability is running. "
+ @"Call stop first.");
+ return;
+ }
+ reachabilityApi_ = reachabilityApi;
+#endif
+}
+
+@synthesize reachabilityStatus = reachabilityStatus_;
+@synthesize host = host_;
+@synthesize reachabilityDelegate = reachabilityDelegate_;
+
+- (BOOL)isActive {
+#if !TARGET_OS_WATCH
+ return reachability_ != nil;
+#else
+ return NO;
+#endif
+}
+
+- (void)setReachabilityDelegate:(id<GULReachabilityDelegate>)reachabilityDelegate {
+ if (reachabilityDelegate &&
+ (![(NSObject *)reachabilityDelegate conformsToProtocol:@protocol(GULReachabilityDelegate)])) {
+ GULLogError(kGULLoggerReachability, NO,
+ [NSString stringWithFormat:@"I-NET%06ld", (long)kGULReachabilityMessageCode005],
+ @"Reachability delegate doesn't conform to Reachability protocol.");
+ return;
+ }
+ reachabilityDelegate_ = reachabilityDelegate;
+}
+
+- (instancetype)initWithReachabilityDelegate:(id<GULReachabilityDelegate>)reachabilityDelegate
+ withHost:(NSString *)host {
+ self = [super init];
+
+ if (!host || !host.length) {
+ GULLogError(kGULLoggerReachability, NO,
+ [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode001],
+ @"Invalid host specified");
+ return nil;
+ }
+ if (self) {
+#if !TARGET_OS_WATCH
+ [self setReachabilityDelegate:reachabilityDelegate];
+ reachabilityApi_ = &kGULDefaultReachabilityApi;
+ reachabilityStatus_ = kGULReachabilityUnknown;
+ host_ = [host copy];
+ reachability_ = nil;
+#endif
+ }
+ return self;
+}
+
+- (void)dealloc {
+ reachabilityDelegate_ = nil;
+ [self stop];
+}
+
+- (BOOL)start {
+#if TARGET_OS_WATCH
+ return NO;
+#else
+
+ if (!reachability_) {
+ reachability_ = reachabilityApi_->createWithNameFn(kCFAllocatorDefault, [host_ UTF8String]);
+ if (!reachability_) {
+ return NO;
+ }
+ SCNetworkReachabilityContext context = {
+ 0, /* version */
+ (__bridge void *)(self), /* info (passed as last parameter to reachability callback) */
+ NULL, /* retain */
+ NULL, /* release */
+ NULL /* copyDescription */
+ };
+ if (!reachabilityApi_->setCallbackFn(reachability_, ReachabilityCallback, &context) ||
+ !reachabilityApi_->scheduleWithRunLoopFn(reachability_, CFRunLoopGetMain(),
+ kCFRunLoopCommonModes)) {
+ reachabilityApi_->releaseFn(reachability_);
+ reachability_ = nil;
+
+ GULLogError(kGULLoggerReachability, NO,
+ [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode002],
+ @"Failed to start reachability handle");
+ return NO;
+ }
+ }
+ GULLogDebug(kGULLoggerReachability, NO,
+ [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode003],
+ @"Monitoring the network status");
+ return YES;
+#endif
+}
+
+- (void)stop {
+#if !TARGET_OS_WATCH
+ if (reachability_) {
+ reachabilityStatus_ = kGULReachabilityUnknown;
+ reachabilityApi_->unscheduleFromRunLoopFn(reachability_, CFRunLoopGetMain(),
+ kCFRunLoopCommonModes);
+ reachabilityApi_->releaseFn(reachability_);
+ reachability_ = nil;
+ }
+#endif
+}
+
+#if !TARGET_OS_WATCH
+- (GULReachabilityStatus)statusForFlags:(SCNetworkReachabilityFlags)flags {
+ GULReachabilityStatus status = kGULReachabilityNotReachable;
+ // If the Reachable flag is not set, we definitely don't have connectivity.
+ if (flags & kSCNetworkReachabilityFlagsReachable) {
+ // Reachable flag is set. Check further flags.
+ if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired)) {
+// Connection required flag is not set, so we have connectivity.
+#if TARGET_OS_IOS || TARGET_OS_TV
+ status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular
+ : kGULReachabilityViaWifi;
+#elif TARGET_OS_OSX
+ status = kGULReachabilityViaWifi;
+#endif
+ } else if ((flags & (kSCNetworkReachabilityFlagsConnectionOnDemand |
+ kSCNetworkReachabilityFlagsConnectionOnTraffic)) &&
+ !(flags & kSCNetworkReachabilityFlagsInterventionRequired)) {
+// If the connection on demand or connection on traffic flag is set, and user intervention
+// is not required, we have connectivity.
+#if TARGET_OS_IOS || TARGET_OS_TV
+ status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular
+ : kGULReachabilityViaWifi;
+#elif TARGET_OS_OSX
+ status = kGULReachabilityViaWifi;
+#endif
+ }
+ }
+ return status;
+}
+
+- (void)reachabilityFlagsChanged:(SCNetworkReachabilityFlags)flags {
+ GULReachabilityStatus status = [self statusForFlags:flags];
+ if (reachabilityStatus_ != status) {
+ NSString *reachabilityStatusString;
+ if (status == kGULReachabilityUnknown) {
+ reachabilityStatusString = kGULReachabilityUnknownStatus;
+ } else {
+ reachabilityStatusString = (status == kGULReachabilityNotReachable)
+ ? kGULReachabilityDisconnectedStatus
+ : kGULReachabilityConnectedStatus;
+ }
+
+ GULLogDebug(kGULLoggerReachability, NO,
+ [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode004],
+ @"Network status has changed. Code:%@, status:%@", @(status),
+ reachabilityStatusString);
+ reachabilityStatus_ = status;
+ [reachabilityDelegate_ reachability:self statusChanged:reachabilityStatus_];
+ }
+}
+
+#endif
+@end
+
+#if !TARGET_OS_WATCH
+static void ReachabilityCallback(SCNetworkReachabilityRef reachability,
+ SCNetworkReachabilityFlags flags,
+ void *info) {
+ GULReachabilityChecker *checker = (__bridge GULReachabilityChecker *)info;
+ [checker reachabilityFlagsChanged:flags];
+}
+#endif
+
+// This function used to be at the top of the file, but it was moved here
+// as a workaround for a suspected compiler bug. When compiled in Release mode
+// and run on an iOS device with WiFi disabled, the reachability code crashed
+// when calling SCNetworkReachabilityScheduleWithRunLoop, or shortly thereafter.
+// After unsuccessfully trying to diagnose the cause of the crash, it was
+// discovered that moving this function to the end of the file magically fixed
+// the crash. If you are going to edit this file, exercise caution and make sure
+// to test thoroughly with an iOS device under various network conditions.
+const NSString *GULReachabilityStatusString(GULReachabilityStatus status) {
+ switch (status) {
+ case kGULReachabilityUnknown:
+ return @"Reachability Unknown";
+
+ case kGULReachabilityNotReachable:
+ return @"Not reachable";
+
+ case kGULReachabilityViaWifi:
+ return @"Reachable via Wifi";
+
+ case kGULReachabilityViaCellular:
+ return @"Reachable via Cellular Data";
+
+ default:
+ return [NSString stringWithFormat:@"Invalid reachability status %d", (int)status];
+ }
+}
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Private/GULReachabilityChecker.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Private/GULReachabilityChecker.h
new file mode 100644
index 00000000..0c70c055
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Private/GULReachabilityChecker.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 Google
+ *
+ * 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 <Foundation/Foundation.h>
+#if !TARGET_OS_WATCH
+#import <SystemConfiguration/SystemConfiguration.h>
+#endif
+
+/// Reachability Status
+typedef enum {
+ kGULReachabilityUnknown, ///< Have not yet checked or been notified whether host is reachable.
+ kGULReachabilityNotReachable, ///< Host is not reachable.
+ kGULReachabilityViaWifi, ///< Host is reachable via Wifi.
+ kGULReachabilityViaCellular, ///< Host is reachable via cellular.
+} GULReachabilityStatus;
+
+const NSString *GULReachabilityStatusString(GULReachabilityStatus status);
+
+@class GULReachabilityChecker;
+
+/// Google Analytics iOS Reachability Checker.
+@protocol GULReachabilityDelegate
+@required
+/// Called when network status has changed.
+- (void)reachability:(GULReachabilityChecker *)reachability
+ statusChanged:(GULReachabilityStatus)status;
+@end
+
+/// Google Analytics iOS Network Status Checker.
+@interface GULReachabilityChecker : NSObject
+
+/// The last known reachability status, or GULReachabilityStatusUnknown if the
+/// checker is not active.
+@property(nonatomic, readonly) GULReachabilityStatus reachabilityStatus;
+/// The host to which reachability status is to be checked.
+@property(nonatomic, copy, readonly) NSString *host;
+/// The delegate to be notified of reachability status changes.
+@property(nonatomic, weak) id<GULReachabilityDelegate> reachabilityDelegate;
+/// `YES` if the reachability checker is active, `NO` otherwise.
+@property(nonatomic, readonly) BOOL isActive;
+
+/// Initialize the reachability checker. Note that you must call start to begin checking for and
+/// receiving notifications about network status changes.
+///
+/// @param reachabilityDelegate The delegate to be notified when reachability status to host
+/// changes.
+///
+/// @param host The name of the host.
+///
+- (instancetype)initWithReachabilityDelegate:(id<GULReachabilityDelegate>)reachabilityDelegate
+ withHost:(NSString *)host;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/// Start checking for reachability to the specified host. This has no effect if the status
+/// checker is already checking for connectivity.
+///
+/// @return `YES` if initiating status checking was successful or the status checking has already
+/// been initiated, `NO` otherwise.
+- (BOOL)start;
+
+/// Stop checking for reachability to the specified host. This has no effect if the status
+/// checker is not checking for connectivity.
+- (void)stop;
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Private/GULReachabilityMessageCode.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Private/GULReachabilityMessageCode.h
new file mode 100644
index 00000000..373e0af4
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Private/GULReachabilityMessageCode.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017 Google
+ *
+ * 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 <Foundation/Foundation.h>
+
+// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum.
+typedef NS_ENUM(NSInteger, GULReachabilityMessageCode) {
+ // GULReachabilityChecker.m
+ kGULReachabilityMessageCode000 = 902000, // I-NET902000
+ kGULReachabilityMessageCode001 = 902001, // I-NET902001
+ kGULReachabilityMessageCode002 = 902002, // I-NET902002
+ kGULReachabilityMessageCode003 = 902003, // I-NET902003
+ kGULReachabilityMessageCode004 = 902004, // I-NET902004
+ kGULReachabilityMessageCode005 = 902005, // I-NET902005
+ kGULReachabilityMessageCode006 = 902006, // I-NET902006
+};
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/GULSceneDelegateSwizzler.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/GULSceneDelegateSwizzler.m
new file mode 100644
index 00000000..134caa98
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/GULSceneDelegateSwizzler.m
@@ -0,0 +1,438 @@
+// Copyright 2019 Google LLC
+//
+// 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 <TargetConditionals.h>
+
+#import "GoogleUtilities/AppDelegateSwizzler/Private/GULAppDelegateSwizzler.h"
+#import "GoogleUtilities/Common/GULLoggerCodes.h"
+#import "GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h"
+#import "GoogleUtilities/Logger/Private/GULLogger.h"
+#import "GoogleUtilities/Network/Private/GULMutableDictionary.h"
+#import "GoogleUtilities/SceneDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h"
+#import "GoogleUtilities/SceneDelegateSwizzler/Private/GULSceneDelegateSwizzler.h"
+
+#import <objc/runtime.h>
+
+#if UISCENE_SUPPORTED
+API_AVAILABLE(ios(13.0), tvos(13.0))
+typedef void (*GULOpenURLContextsIMP)(id, SEL, UIScene *, NSSet<UIOpenURLContext *> *);
+
+API_AVAILABLE(ios(13.0), tvos(13.0))
+typedef void (^GULSceneDelegateInterceptorCallback)(id<UISceneDelegate>);
+
+// The strings below are the keys for associated objects.
+static char const *const kGULRealIMPBySelectorKey = "GUL_realIMPBySelector";
+static char const *const kGULRealClassKey = "GUL_realClass";
+#endif // UISCENE_SUPPORTED
+
+static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/SceneDelegateSwizzler]";
+
+// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change
+// we disable App Delegate proxying when either of these two flags are set to NO.
+
+/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */
+static NSString *const kGULFirebaseSceneDelegateProxyEnabledPlistKey =
+ @"FirebaseAppDelegateProxyEnabled";
+
+/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying.
+ */
+static NSString *const kGULGoogleUtilitiesSceneDelegateProxyEnabledPlistKey =
+ @"GoogleUtilitiesAppDelegateProxyEnabled";
+
+/** The prefix of the Scene Delegate. */
+static NSString *const kGULSceneDelegatePrefix = @"GUL_";
+
+/**
+ * This class is necessary to store the delegates in an NSArray without retaining them.
+ * [NSValue valueWithNonRetainedObject] also provides this functionality, but does not provide a
+ * zeroing pointer. This will cause EXC_BAD_ACCESS when trying to access the object after it is
+ * dealloced. Instead, this container stores a weak, zeroing reference to the object, which
+ * automatically is set to nil by the runtime when the object is dealloced.
+ */
+@interface GULSceneZeroingWeakContainer : NSObject
+
+/** Stores a weak object. */
+@property(nonatomic, weak) id object;
+
+@end
+
+@implementation GULSceneZeroingWeakContainer
+@end
+
+@implementation GULSceneDelegateSwizzler
+
+#pragma mark - Public methods
+
++ (BOOL)isSceneDelegateProxyEnabled {
+ return [GULAppDelegateSwizzler isAppDelegateProxyEnabled];
+}
+
++ (void)proxyOriginalSceneDelegate {
+#if UISCENE_SUPPORTED
+ if ([GULAppEnvironmentUtil isAppExtension]) {
+ return;
+ }
+
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ if (@available(iOS 13.0, tvOS 13.0, *)) {
+ if (![GULSceneDelegateSwizzler isSceneDelegateProxyEnabled]) {
+ return;
+ }
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(handleSceneWillConnectToNotification:)
+ name:UISceneWillConnectNotification
+ object:nil];
+ }
+ });
+#endif // UISCENE_SUPPORTED
+}
+
+#if UISCENE_SUPPORTED
++ (GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor:(id<UISceneDelegate>)interceptor {
+ NSAssert(interceptor, @"SceneDelegateProxy cannot add nil interceptor");
+ NSAssert([interceptor conformsToProtocol:@protocol(UISceneDelegate)],
+ @"SceneDelegateProxy interceptor does not conform to UIApplicationDelegate");
+
+ if (!interceptor) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling000],
+ @"SceneDelegateProxy cannot add nil interceptor.");
+ return nil;
+ }
+ if (![interceptor conformsToProtocol:@protocol(UISceneDelegate)]) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling001],
+ @"SceneDelegateProxy interceptor does not conform to UIApplicationDelegate");
+ return nil;
+ }
+
+ // The ID should be the same given the same interceptor object.
+ NSString *interceptorID =
+ [NSString stringWithFormat:@"%@%p", kGULSceneDelegatePrefix, interceptor];
+ if (!interceptorID.length) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling002],
+ @"SceneDelegateProxy cannot create Interceptor ID.");
+ return nil;
+ }
+ GULSceneZeroingWeakContainer *weakObject = [[GULSceneZeroingWeakContainer alloc] init];
+ weakObject.object = interceptor;
+ [GULSceneDelegateSwizzler interceptors][interceptorID] = weakObject;
+ return interceptorID;
+}
+
++ (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID {
+ NSAssert(interceptorID, @"SceneDelegateProxy cannot unregister nil interceptor ID.");
+ NSAssert(((NSString *)interceptorID).length != 0,
+ @"SceneDelegateProxy cannot unregister empty interceptor ID.");
+
+ if (!interceptorID) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling003],
+ @"SceneDelegateProxy cannot unregister empty interceptor ID.");
+ return;
+ }
+
+ GULSceneZeroingWeakContainer *weakContainer =
+ [GULSceneDelegateSwizzler interceptors][interceptorID];
+ if (!weakContainer.object) {
+ GULLogError(kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling004],
+ @"SceneDelegateProxy cannot unregister interceptor that was not registered. "
+ "Interceptor ID %@",
+ interceptorID);
+ return;
+ }
+
+ [[GULSceneDelegateSwizzler interceptors] removeObjectForKey:interceptorID];
+}
+
+#pragma mark - Helper methods
+
++ (GULMutableDictionary *)interceptors {
+ static dispatch_once_t onceToken;
+ static GULMutableDictionary *sInterceptors;
+ dispatch_once(&onceToken, ^{
+ sInterceptors = [[GULMutableDictionary alloc] init];
+ });
+ return sInterceptors;
+}
+
++ (void)clearInterceptors {
+ [[self interceptors] removeAllObjects];
+}
+
++ (nullable NSValue *)originalImplementationForSelector:(SEL)selector object:(id)object {
+ NSDictionary *realImplementationBySelector =
+ objc_getAssociatedObject(object, &kGULRealIMPBySelectorKey);
+ return realImplementationBySelector[NSStringFromSelector(selector)];
+}
+
++ (void)proxyDestinationSelector:(SEL)destinationSelector
+ implementationsFromSourceSelector:(SEL)sourceSelector
+ fromClass:(Class)sourceClass
+ toClass:(Class)destinationClass
+ realClass:(Class)realClass
+ storeDestinationImplementationTo:
+ (NSMutableDictionary<NSString *, NSValue *> *)destinationImplementationsBySelector {
+ [self addInstanceMethodWithDestinationSelector:destinationSelector
+ withImplementationFromSourceSelector:sourceSelector
+ fromClass:sourceClass
+ toClass:destinationClass];
+ IMP sourceImplementation =
+ [GULSceneDelegateSwizzler implementationOfMethodSelector:destinationSelector
+ fromClass:realClass];
+ NSValue *sourceImplementationPointer = [NSValue valueWithPointer:sourceImplementation];
+
+ NSString *destinationSelectorString = NSStringFromSelector(destinationSelector);
+ destinationImplementationsBySelector[destinationSelectorString] = sourceImplementationPointer;
+}
+
+/** Copies a method identified by the methodSelector from one class to the other. After this method
+ * is called, performing [toClassInstance methodSelector] will be similar to calling
+ * [fromClassInstance methodSelector]. This method does nothing if toClass already has a method
+ * identified by methodSelector.
+ *
+ * @param methodSelector The SEL that identifies both the method on the fromClass as well as the
+ * one on the toClass.
+ * @param fromClass The class from which a method is sourced.
+ * @param toClass The class to which the method is added. If the class already has a method with
+ * the same selector, this has no effect.
+ */
++ (void)addInstanceMethodWithSelector:(SEL)methodSelector
+ fromClass:(Class)fromClass
+ toClass:(Class)toClass {
+ [self addInstanceMethodWithDestinationSelector:methodSelector
+ withImplementationFromSourceSelector:methodSelector
+ fromClass:fromClass
+ toClass:toClass];
+}
+
+/** Copies a method identified by the sourceSelector from the fromClass as a method for the
+ * destinationSelector on the toClass. After this method is called, performing
+ * [toClassInstance destinationSelector] will be similar to calling
+ * [fromClassInstance sourceSelector]. This method does nothing if toClass already has a method
+ * identified by destinationSelector.
+ *
+ * @param destinationSelector The SEL that identifies the method on the toClass.
+ * @param sourceSelector The SEL that identifies the method on the fromClass.
+ * @param fromClass The class from which a method is sourced.
+ * @param toClass The class to which the method is added. If the class already has a method with
+ * the same selector, this has no effect.
+ */
++ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector
+ withImplementationFromSourceSelector:(SEL)sourceSelector
+ fromClass:(Class)fromClass
+ toClass:(Class)toClass {
+ Method method = class_getInstanceMethod(fromClass, sourceSelector);
+ IMP methodIMP = method_getImplementation(method);
+ const char *types = method_getTypeEncoding(method);
+ if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) {
+ GULLogWarning(
+ kGULLoggerSwizzler, NO,
+ [NSString
+ stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling009],
+ @"Cannot copy method to destination selector %@ as it already exists",
+ NSStringFromSelector(destinationSelector));
+ }
+}
+
+/** Gets the IMP of the instance method on the class identified by the selector.
+ *
+ * @param selector The selector of which the IMP is to be fetched.
+ * @param aClass The class from which the IMP is to be fetched.
+ * @return The IMP of the instance method identified by selector and aClass.
+ */
++ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass {
+ Method aMethod = class_getInstanceMethod(aClass, selector);
+ return method_getImplementation(aMethod);
+}
+
+/** Enumerates through all the interceptors and if they respond to a given selector, executes a
+ * GULSceneDelegateInterceptorCallback with the interceptor.
+ *
+ * @param methodSelector The SEL to check if an interceptor responds to.
+ * @param callback the GULSceneDelegateInterceptorCallback.
+ */
++ (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector
+ callback:(GULSceneDelegateInterceptorCallback)callback
+ API_AVAILABLE(ios(13.0)) {
+ if (!callback) {
+ return;
+ }
+
+ NSDictionary *interceptors = [GULSceneDelegateSwizzler interceptors].dictionary;
+ [interceptors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
+ GULSceneZeroingWeakContainer *interceptorContainer = obj;
+ id interceptor = interceptorContainer.object;
+ if (!interceptor) {
+ GULLogWarning(
+ kGULLoggerSwizzler, NO,
+ [NSString stringWithFormat:@"I-SWZ%06ld",
+ (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling010],
+ @"SceneDelegateProxy cannot find interceptor with ID %@. Removing the interceptor.", key);
+ [[GULSceneDelegateSwizzler interceptors] removeObjectForKey:key];
+ return;
+ }
+ if ([interceptor respondsToSelector:methodSelector]) {
+ callback(interceptor);
+ }
+ }];
+}
+
++ (void)handleSceneWillConnectToNotification:(NSNotification *)notification {
+ if (@available(iOS 13.0, tvOS 13.0, *)) {
+ if ([notification.object isKindOfClass:[UIScene class]]) {
+ UIScene *scene = (UIScene *)notification.object;
+ [GULSceneDelegateSwizzler proxySceneDelegateIfNeeded:scene];
+ }
+ }
+}
+
+#pragma mark - [Donor Methods] UISceneDelegate URL handler
+
+- (void)scene:(UIScene *)scene
+ openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts API_AVAILABLE(ios(13.0), tvos(13.0)) {
+ if (@available(iOS 13.0, tvOS 13.0, *)) {
+ SEL methodSelector = @selector(scene:openURLContexts:);
+ // Call the real implementation if the real Scene Delegate has any.
+ NSValue *openURLContextsIMPPointer =
+ [GULSceneDelegateSwizzler originalImplementationForSelector:methodSelector object:self];
+ GULOpenURLContextsIMP openURLContextsIMP = [openURLContextsIMPPointer pointerValue];
+
+ [GULSceneDelegateSwizzler
+ notifyInterceptorsWithMethodSelector:methodSelector
+ callback:^(id<UISceneDelegate> interceptor) {
+ if ([interceptor
+ conformsToProtocol:@protocol(UISceneDelegate)]) {
+ id<UISceneDelegate> sceneInterceptor =
+ (id<UISceneDelegate>)interceptor;
+ [sceneInterceptor scene:scene openURLContexts:URLContexts];
+ }
+ }];
+
+ if (openURLContextsIMP) {
+ openURLContextsIMP(self, methodSelector, scene, URLContexts);
+ }
+ }
+}
+
++ (void)proxySceneDelegateIfNeeded:(UIScene *)scene {
+ Class realClass = [scene.delegate class];
+ NSString *className = NSStringFromClass(realClass);
+
+ // Skip proxying if failed to get the delegate class name for some reason (e.g. `delegate == nil`)
+ // or the class has a prefix of kGULAppDelegatePrefix, which means it has been proxied before.
+ if (className == nil || [className hasPrefix:kGULSceneDelegatePrefix]) {
+ return;
+ }
+
+ NSString *classNameWithPrefix = [kGULSceneDelegatePrefix stringByAppendingString:className];
+ NSString *newClassName =
+ [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString];
+
+ if (NSClassFromString(newClassName)) {
+ GULLogError(
+ kGULLoggerSwizzler, NO,
+ [NSString
+ stringWithFormat:@"I-SWZ%06ld",
+ (long)
+ kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate],
+ @"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class"
+ @": %@, subclass: %@",
+ className, newClassName);
+ return;
+ }
+
+ // Register the new class as subclass of the real one. Do not allocate more than the real class
+ // size.
+ Class sceneDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0);
+ if (sceneDelegateSubClass == Nil) {
+ GULLogError(
+ kGULLoggerSwizzler, NO,
+ [NSString
+ stringWithFormat:@"I-SWZ%06ld",
+ (long)
+ kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate],
+ @"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class"
+ @": %@, subclass: Nil",
+ className);
+ return;
+ }
+
+ NSMutableDictionary<NSString *, NSValue *> *realImplementationsBySelector =
+ [[NSMutableDictionary alloc] init];
+
+ // For scene:openURLContexts:
+ SEL openURLContextsSEL = @selector(scene:openURLContexts:);
+ [self proxyDestinationSelector:openURLContextsSEL
+ implementationsFromSourceSelector:openURLContextsSEL
+ fromClass:[GULSceneDelegateSwizzler class]
+ toClass:sceneDelegateSubClass
+ realClass:realClass
+ storeDestinationImplementationTo:realImplementationsBySelector];
+
+ // Store original implementations to a fake property of the original delegate.
+ objc_setAssociatedObject(scene.delegate, &kGULRealIMPBySelectorKey,
+ [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ objc_setAssociatedObject(scene.delegate, &kGULRealClassKey, realClass,
+ OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+
+ // The subclass size has to be exactly the same size with the original class size. The subclass
+ // cannot have more ivars/properties than its superclass since it will cause an offset in memory
+ // that can lead to overwriting the isa of an object in the next frame.
+ if (class_getInstanceSize(realClass) != class_getInstanceSize(sceneDelegateSubClass)) {
+ GULLogError(
+ kGULLoggerSwizzler, NO,
+ [NSString
+ stringWithFormat:@"I-SWZ%06ld",
+ (long)
+ kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate],
+ @"Cannot create subclass of Scene Delegate, because the created subclass is not the "
+ @"same size. %@",
+ className);
+ NSAssert(NO, @"Classes must be the same size to swizzle isa");
+ return;
+ }
+
+ // Make the newly created class to be the subclass of the real Scene Delegate class.
+ objc_registerClassPair(sceneDelegateSubClass);
+ if (object_setClass(scene.delegate, sceneDelegateSubClass)) {
+ GULLogDebug(
+ kGULLoggerSwizzler, NO,
+ [NSString
+ stringWithFormat:@"I-SWZ%06ld",
+ (long)
+ kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate],
+ @"Successfully created Scene Delegate Proxy automatically. To disable the "
+ @"proxy, set the flag %@ to NO (Boolean) in the Info.plist",
+ [GULSceneDelegateSwizzler correctSceneDelegateProxyKey]);
+ }
+}
+
++ (NSString *)correctSceneDelegateProxyKey {
+ return NSClassFromString(@"FIRCore") ? kGULFirebaseSceneDelegateProxyEnabledPlistKey
+ : kGULGoogleUtilitiesSceneDelegateProxyEnabledPlistKey;
+}
+
+#endif // UISCENE_SUPPORTED
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h
new file mode 100644
index 00000000..62f214ab
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * 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 <Foundation/Foundation.h>
+#import "GoogleUtilities/Network/Private/GULMutableDictionary.h"
+#import "GoogleUtilities/SceneDelegateSwizzler/Private/GULSceneDelegateSwizzler.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GULSceneDelegateSwizzler ()
+
+#if UISCENE_SUPPORTED
+
+/** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer.
+ *
+ * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is
+ * the interceptorID.
+ */
++ (GULMutableDictionary *)interceptors;
+
+/** Deletes all the registered interceptors. */
++ (void)clearInterceptors;
+
+/** ISA Swizzles the given appDelegate as the original app delegate would be.
+ *
+ * @param scene The scene whose delegate needs to be isa swizzled. This should conform to the
+ * scene delegate protocol.
+ */
++ (void)proxySceneDelegateIfNeeded:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0));
+
+#endif // UISCENE_SUPPORTED
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/Private/GULSceneDelegateSwizzler.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/Private/GULSceneDelegateSwizzler.h
new file mode 100644
index 00000000..420b3e76
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/SceneDelegateSwizzler/Private/GULSceneDelegateSwizzler.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * 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 !TARGET_OS_OSX
+#import <UIKit/UIKit.h>
+#endif // !TARGET_OS_OSX
+
+#if ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000))
+#define UISCENE_SUPPORTED 1
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NSString *const GULSceneDelegateInterceptorID;
+
+/** This class contains methods that isa swizzle the scene delegate. */
+@interface GULSceneDelegateSwizzler : NSProxy
+
+#if UISCENE_SUPPORTED
+
+/** Registers a scene delegate interceptor whose methods will be invoked as they're invoked on the
+ * original scene delegate.
+ *
+ * @param interceptor An instance of a class that conforms to the application delegate protocol.
+ * The interceptor is NOT retained.
+ * @return A unique GULSceneDelegateInterceptorID if interceptor was successfully registered; nil
+ * if it fails.
+ */
++ (nullable GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor:
+ (id<UISceneDelegate>)interceptor API_AVAILABLE(ios(13.0), tvos(13.0));
+
+/** Unregisters an interceptor with the given ID if it exists.
+ *
+ * @param interceptorID The object that was generated when the interceptor was registered.
+ */
++ (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID
+ API_AVAILABLE(ios(13.0), tvos(13.0));
+
+/** Do not initialize this class. */
+- (instancetype)init NS_UNAVAILABLE;
+
+#endif // UISCENE_SUPPORTED
+
+/** This method ensures that the original scene delegate has been proxied. Call this before
+ * registering your interceptor. This method is safe to call multiple times (but it only proxies
+ * the scene delegate once).
+ *
+ * The method has no effect for extensions.
+ */
++ (void)proxyOriginalSceneDelegate;
+
+/** Indicates whether scene delegate proxy is explicitly disabled or enabled. Enabled by default.
+ *
+ * @return YES if SceneDelegateProxy is Enabled, NO otherwise.
+ */
++ (BOOL)isSceneDelegateProxyEnabled;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m
new file mode 100644
index 00000000..20fe8eed
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m
@@ -0,0 +1,213 @@
+// Copyright 2018 Google
+//
+// 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 "GoogleUtilities/UserDefaults/Private/GULUserDefaults.h"
+
+#import "GoogleUtilities/Logger/Private/GULLogger.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+static NSTimeInterval const kGULSynchronizeInterval = 1.0;
+
+static NSString *const kGULLogFormat = @"I-GUL%06ld";
+
+static GULLoggerService kGULLogUserDefaultsService = @"[GoogleUtilities/UserDefaults]";
+
+typedef NS_ENUM(NSInteger, GULUDMessageCode) {
+ GULUDMessageCodeInvalidKeyGet = 1,
+ GULUDMessageCodeInvalidKeySet = 2,
+ GULUDMessageCodeInvalidObjectSet = 3,
+ GULUDMessageCodeSynchronizeFailed = 4,
+};
+
+@interface GULUserDefaults ()
+
+/// Equivalent to the suite name for NSUserDefaults.
+@property(readonly) CFStringRef appNameRef;
+
+@property(atomic) BOOL isPreferenceFileExcluded;
+
+@end
+
+@implementation GULUserDefaults {
+ // The application name is the same with the suite name of the NSUserDefaults, and it is used for
+ // preferences.
+ CFStringRef _appNameRef;
+}
+
++ (GULUserDefaults *)standardUserDefaults {
+ static GULUserDefaults *standardUserDefaults;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ standardUserDefaults = [[GULUserDefaults alloc] init];
+ });
+ return standardUserDefaults;
+}
+
+- (instancetype)init {
+ return [self initWithSuiteName:nil];
+}
+
+- (instancetype)initWithSuiteName:(nullable NSString *)suiteName {
+ self = [super init];
+
+ NSString *name = [suiteName copy];
+
+ if (self) {
+ // `kCFPreferencesCurrentApplication` maps to the same defaults database as
+ // `[NSUserDefaults standardUserDefaults]`.
+ _appNameRef =
+ name.length ? (__bridge_retained CFStringRef)name : kCFPreferencesCurrentApplication;
+ }
+
+ return self;
+}
+
+- (void)dealloc {
+ // If we're using a custom `_appNameRef` it needs to be released. If it's a constant, it shouldn't
+ // need to be released since we don't own it.
+ if (CFStringCompare(_appNameRef, kCFPreferencesCurrentApplication, 0) != kCFCompareEqualTo) {
+ CFRelease(_appNameRef);
+ }
+
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(synchronize)
+ object:nil];
+}
+
+- (nullable id)objectForKey:(NSString *)defaultName {
+ NSString *key = [defaultName copy];
+ if (![key isKindOfClass:[NSString class]] || !key.length) {
+ GULLogWarning(@"<GoogleUtilities>", NO,
+ [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeyGet],
+ @"Cannot get object for invalid user default key.");
+ return nil;
+ }
+ return (__bridge_transfer id)CFPreferencesCopyAppValue((__bridge CFStringRef)key, _appNameRef);
+}
+
+- (void)setObject:(nullable id)value forKey:(NSString *)defaultName {
+ NSString *key = [defaultName copy];
+ if (![key isKindOfClass:[NSString class]] || !key.length) {
+ GULLogWarning(kGULLogUserDefaultsService, NO,
+ [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeySet],
+ @"Cannot set object for invalid user default key.");
+ return;
+ }
+ if (!value) {
+ CFPreferencesSetAppValue((__bridge CFStringRef)key, NULL, _appNameRef);
+ [self scheduleSynchronize];
+ return;
+ }
+ BOOL isAcceptableValue =
+ [value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]] ||
+ [value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]] ||
+ [value isKindOfClass:[NSDate class]] || [value isKindOfClass:[NSData class]];
+ if (!isAcceptableValue) {
+ GULLogWarning(kGULLogUserDefaultsService, NO,
+ [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidObjectSet],
+ @"Cannot set invalid object to user defaults. Must be a string, number, array, "
+ @"dictionary, date, or data. Value: %@",
+ value);
+ return;
+ }
+
+ CFPreferencesSetAppValue((__bridge CFStringRef)key, (__bridge CFStringRef)value, _appNameRef);
+ [self scheduleSynchronize];
+}
+
+- (void)removeObjectForKey:(NSString *)key {
+ [self setObject:nil forKey:key];
+}
+
+#pragma mark - Getters
+
+- (NSInteger)integerForKey:(NSString *)defaultName {
+ NSNumber *object = [self objectForKey:defaultName];
+ return object.integerValue;
+}
+
+- (float)floatForKey:(NSString *)defaultName {
+ NSNumber *object = [self objectForKey:defaultName];
+ return object.floatValue;
+}
+
+- (double)doubleForKey:(NSString *)defaultName {
+ NSNumber *object = [self objectForKey:defaultName];
+ return object.doubleValue;
+}
+
+- (BOOL)boolForKey:(NSString *)defaultName {
+ NSNumber *object = [self objectForKey:defaultName];
+ return object.boolValue;
+}
+
+- (nullable NSString *)stringForKey:(NSString *)defaultName {
+ return [self objectForKey:defaultName];
+}
+
+- (nullable NSArray *)arrayForKey:(NSString *)defaultName {
+ return [self objectForKey:defaultName];
+}
+
+- (nullable NSDictionary<NSString *, id> *)dictionaryForKey:(NSString *)defaultName {
+ return [self objectForKey:defaultName];
+}
+
+#pragma mark - Setters
+
+- (void)setInteger:(NSInteger)integer forKey:(NSString *)defaultName {
+ [self setObject:@(integer) forKey:defaultName];
+}
+
+- (void)setFloat:(float)value forKey:(NSString *)defaultName {
+ [self setObject:@(value) forKey:defaultName];
+}
+
+- (void)setDouble:(double)doubleNumber forKey:(NSString *)defaultName {
+ [self setObject:@(doubleNumber) forKey:defaultName];
+}
+
+- (void)setBool:(BOOL)boolValue forKey:(NSString *)defaultName {
+ [self setObject:@(boolValue) forKey:defaultName];
+}
+
+#pragma mark - Save data
+
+- (void)synchronize {
+ if (!CFPreferencesAppSynchronize(_appNameRef)) {
+ GULLogError(kGULLogUserDefaultsService, NO,
+ [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeSynchronizeFailed],
+ @"Cannot synchronize user defaults to disk");
+ }
+}
+
+#pragma mark - Private methods
+
+- (void)scheduleSynchronize {
+ // Synchronize data using a timer so that multiple set... calls can be coalesced under one
+ // synchronize.
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(synchronize)
+ object:nil];
+ // This method may be called on multiple queues (due to set... methods can be called on any queue)
+ // synchronize can be scheduled on different queues, so make sure that it does not crash. If this
+ // instance goes away, self will be released also, no one will retain it and the schedule won't be
+ // called.
+ [self performSelector:@selector(synchronize) withObject:nil afterDelay:kGULSynchronizeInterval];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Private/GULUserDefaults.h b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Private/GULUserDefaults.h
new file mode 100644
index 00000000..0d047818
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Private/GULUserDefaults.h
@@ -0,0 +1,110 @@
+// Copyright 2018 Google
+//
+// 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 <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// A thread-safe user defaults that uses C functions from CFPreferences.h instead of
+/// `NSUserDefaults`. This is to avoid sending an `NSNotification` when it's changed from a
+/// background thread to avoid crashing. // TODO: Insert radar number here.
+@interface GULUserDefaults : NSObject
+
+/// A shared user defaults similar to +[NSUserDefaults standardUserDefaults] and accesses the same
+/// data of the standardUserDefaults.
++ (GULUserDefaults *)standardUserDefaults;
+
+/// Initializes preferences with a suite name that is the same with the NSUserDefaults' suite name.
+/// Both of CFPreferences and NSUserDefaults share the same plist file so their data will exactly
+/// the same.
+///
+/// @param suiteName The name of the suite of the user defaults.
+- (instancetype)initWithSuiteName:(nullable NSString *)suiteName;
+
+#pragma mark - Getters
+
+/// Searches the receiver's search list for a default with the key 'defaultName' and return it. If
+/// another process has changed defaults in the search list, NSUserDefaults will automatically
+/// update to the latest values. If the key in question has been marked as ubiquitous via a Defaults
+/// Configuration File, the latest value may not be immediately available, and the registered value
+/// will be returned instead.
+- (nullable id)objectForKey:(NSString *)defaultName;
+
+/// Equivalent to -objectForKey:, except that it will return nil if the value is not an NSArray.
+- (nullable NSArray *)arrayForKey:(NSString *)defaultName;
+
+/// Equivalent to -objectForKey:, except that it will return nil if the value
+/// is not an NSDictionary.
+- (nullable NSDictionary<NSString *, id> *)dictionaryForKey:(NSString *)defaultName;
+
+/// Equivalent to -objectForKey:, except that it will convert NSNumber values to their NSString
+/// representation. If a non-string non-number value is found, nil will be returned.
+- (nullable NSString *)stringForKey:(NSString *)defaultName;
+
+/// Equivalent to -objectForKey:, except that it converts the returned value to an NSInteger. If the
+/// value is an NSNumber, the result of -integerValue will be returned. If the value is an NSString,
+/// it will be converted to NSInteger if possible. If the value is a boolean, it will be converted
+/// to either 1 for YES or 0 for NO. If the value is absent or can't be converted to an integer, 0
+/// will be returned.
+- (NSInteger)integerForKey:(NSString *)defaultName;
+
+/// Similar to -integerForKey:, except that it returns a float, and boolean values will not be
+/// converted.
+- (float)floatForKey:(NSString *)defaultName;
+
+/// Similar to -integerForKey:, except that it returns a double, and boolean values will not be
+/// converted.
+- (double)doubleForKey:(NSString *)defaultName;
+
+/// Equivalent to -objectForKey:, except that it converts the returned value to a BOOL. If the value
+/// is an NSNumber, NO will be returned if the value is 0, YES otherwise. If the value is an
+/// NSString, values of "YES" or "1" will return YES, and values of "NO", "0", or any other string
+/// will return NO. If the value is absent or can't be converted to a BOOL, NO will be returned.
+- (BOOL)boolForKey:(NSString *)defaultName;
+
+#pragma mark - Setters
+
+/// Immediately stores a value (or removes the value if `nil` is passed as the value) for the
+/// provided key in the search list entry for the receiver's suite name in the current user and any
+/// host, then asynchronously stores the value persistently, where it is made available to other
+/// processes.
+- (void)setObject:(nullable id)value forKey:(NSString *)defaultName;
+
+/// Equivalent to -setObject:forKey: except that the value is converted from a float to an NSNumber.
+- (void)setFloat:(float)value forKey:(NSString *)defaultName;
+
+/// Equivalent to -setObject:forKey: except that the value is converted from a double to an
+/// NSNumber.
+- (void)setDouble:(double)value forKey:(NSString *)defaultName;
+
+/// Equivalent to -setObject:forKey: except that the value is converted from an NSInteger to an
+/// NSNumber.
+- (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName;
+
+/// Equivalent to -setObject:forKey: except that the value is converted from a BOOL to an NSNumber.
+- (void)setBool:(BOOL)value forKey:(NSString *)defaultName;
+
+#pragma mark - Removing Defaults
+
+/// Equivalent to -[... setObject:nil forKey:defaultName]
+- (void)removeObjectForKey:(NSString *)defaultName;
+
+#pragma mark - Save data
+
+/// Blocks the calling thread until all in-progress set operations have completed.
+- (void)synchronize;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/GoogleUtilities/README.md b/StoneIsland/platforms/ios/Pods/GoogleUtilities/README.md
new file mode 100644
index 00000000..c44a3f92
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GoogleUtilities/README.md
@@ -0,0 +1,300 @@
+[![Version](https://img.shields.io/cocoapods/v/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
+[![License](https://img.shields.io/cocoapods/l/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
+[![Platform](https://img.shields.io/cocoapods/p/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
+
+[![Actions Status][gh-abtesting-badge]][gh-actions]
+[![Actions Status][gh-appdistribution-badge]][gh-actions]
+[![Actions Status][gh-auth-badge]][gh-actions]
+[![Actions Status][gh-core-badge]][gh-actions]
+[![Actions Status][gh-crashlytics-badge]][gh-actions]
+[![Actions Status][gh-database-badge]][gh-actions]
+[![Actions Status][gh-datatransport-badge]][gh-actions]
+[![Actions Status][gh-dynamiclinks-badge]][gh-actions]
+[![Actions Status][gh-firebasepod-badge]][gh-actions]
+[![Actions Status][gh-firestore-badge]][gh-actions]
+[![Actions Status][gh-functions-badge]][gh-actions]
+[![Actions Status][gh-inappmessaging-badge]][gh-actions]
+[![Actions Status][gh-interop-badge]][gh-actions]
+[![Actions Status][gh-messaging-badge]][gh-actions]
+[![Actions Status][gh-remoteconfig-badge]][gh-actions]
+[![Actions Status][gh-storage-badge]][gh-actions]
+[![Actions Status][gh-symbolcollision-badge]][gh-actions]
+[![Actions Status][gh-zip-badge]][gh-actions]
+[![Travis](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
+
+# Firebase Apple Open Source Development
+
+This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics,
+FirebasePerformance, and FirebaseML.
+
+The repository also includes GoogleUtilities source. The
+[GoogleUtilities](GoogleUtilities/README.md) pod is
+a set of utilities used by Firebase and other Google products.
+
+Firebase is an app development platform with tools to help you build, grow and
+monetize your app. More information about Firebase can be found at
+[https://firebase.google.com](https://firebase.google.com).
+
+## Installation
+
+See the three subsections for details about three different installation methods.
+1. [Standard pod install](README.md#standard-pod-install)
+1. [Installing from the GitHub repo](README.md#installing-from-github)
+1. [Experimental Carthage](README.md#carthage-ios-only)
+
+### Standard pod install
+
+Go to
+[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
+
+### Installing from GitHub
+
+For releases starting with 5.0.0, the source for each release is also deployed
+to CocoaPods master and available via standard
+[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod).
+
+These instructions can be used to access the Firebase repo at other branches,
+tags, or commits.
+
+#### Background
+
+See
+[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod)
+for instructions and options about overriding pod source locations.
+
+#### Accessing Firebase Source Snapshots
+
+All of the official releases are tagged in this repo and available via CocoaPods. To access a local
+source snapshot or unreleased branch, use Podfile directives like the following:
+
+To access FirebaseFirestore via a branch:
+```
+pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
+pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
+```
+
+To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
+
+```
+pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
+pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
+```
+
+### Carthage (iOS only)
+
+Instructions for the experimental Carthage distribution are at
+[Carthage](Carthage.md).
+
+### Rome
+
+Instructions for installing binary frameworks via
+[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
+
+### Using Firebase from a Framework or a library
+
+[Using Firebase from a Framework or a library](docs/firebase_in_libraries.md)
+
+## Development
+
+To develop Firebase software in this repository, ensure that you have at least
+the following software:
+
+ * Xcode 10.3 (or later)
+ * CocoaPods 1.7.2 (or later)
+ * [CocoaPods generate](https://github.com/square/cocoapods-generate)
+
+For the pod that you want to develop:
+
+`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios`
+
+Note: If the CocoaPods cache is out of date, you may need to run
+`pod repo update` before the `pod gen` command.
+
+Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for
+those platforms. Since 10.2, Xcode does not properly handle multi-platform
+CocoaPods workspaces.
+
+Firestore has a self contained Xcode project. See
+[Firestore/README.md](Firestore/README.md).
+
+### Development for Catalyst
+* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
+* Check the Mac box in the App-iOS Build Settings
+* Sign the App in the Settings Signing & Capabilities tab
+* Click Pods in the Project Manager
+* Add Signing to the iOS host app and unit test targets
+* Select the Unit-unit scheme
+* Run it to build and test
+
+### Adding a New Firebase Pod
+
+See [AddNewPod.md](AddNewPod.md).
+
+### Managing Headers and Imports
+
+See [HeadersImports.md](HeadersImports.md).
+
+### Code Formatting
+
+To ensure that the code is formatted consistently, run the script
+[./scripts/style.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/style.sh)
+before creating a PR.
+
+Travis will verify that any code changes are done in a style compliant way. Install
+`clang-format` and `swiftformat`:
+
+```
+brew install clang-format
+brew install swiftformat
+```
+
+### Running Unit Tests
+
+Select a scheme and press Command-u to build a component and run its unit tests.
+
+#### Viewing Code Coverage (Deprecated)
+
+First, make sure that [xcov](https://github.com/nakiostudio/xcov) is installed with `gem install xcov`.
+
+After running the `AllUnitTests_iOS` scheme in Xcode, execute
+`xcov --workspace Firebase.xcworkspace --scheme AllUnitTests_iOS --output_directory xcov_output`
+at Example/ in the terminal. This will aggregate the coverage, and you can run `open xcov_output/index.html` to see the results.
+
+### Running Sample Apps
+In order to run the sample apps and integration tests, you'll need valid
+`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist
+files without real values, but can be replaced with real plist files. To get your own
+`GoogleService-Info.plist` files:
+
+1. Go to the [Firebase Console](https://console.firebase.google.com/)
+2. Create a new Firebase project, if you don't already have one
+3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
+identifier (e.g. `com.google.Database-Example`)
+4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project.
+
+## Specific Component Instructions
+See the sections below for any special instructions for those components.
+
+### Firebase Auth
+
+If you're doing specific Firebase Auth development, see
+[the Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about
+building and running the FirebaseAuth pod along with various samples and tests.
+
+### Firebase Database
+
+The Firebase Database Integration tests can be run against a locally running Database Emulator
+or against a production instance.
+
+To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before
+running the integration test.
+
+To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to
+`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to
+[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are
+running.
+
+### Firebase Storage
+
+To run the Storage Integration tests, follow the instructions in
+[FIRStorageIntegrationTests.m](FirebaseStorage/Tests/Integration/FIRStorageIntegrationTests.m).
+
+#### Push Notifications
+
+Push notifications can only be delivered to specially provisioned App IDs in the developer portal.
+In order to actually test receiving push notifications, you will need to:
+
+1. Change the bundle identifier of the sample app to something you own in your Apple Developer
+account, and enable that App ID for push notifications.
+2. You'll also need to
+[upload your APNs Provider Authentication Key or certificate to the Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
+at **Project Settings > Cloud Messaging > [Your Firebase App]**.
+3. Ensure your iOS device is added to your Apple Developer portal as a test device.
+
+#### iOS Simulator
+
+The iOS Simulator cannot register for remote notifications, and will not receive push notifications.
+In order to receive push notifications, you'll have to follow the steps above and run the app on a
+physical device.
+
+## Community Supported Efforts
+
+We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are
+very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
+participate in the Firebase community.
+
+### tvOS, macOS, watchOS and Catalyst
+Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on
+tvOS, macOS, watchOS and Catalyst.
+
+For tvOS, checkout the [Sample](Example/tvOSSample).
+For watchOS, currently only Messaging and Storage (and their dependencies) have limited support. Checkout the
+[Independent Watch App Sample](Example/watchOSSample).
+
+Keep in mind that macOS, tvOS, watchOS and Catalyst are not officially supported by Firebase, and this
+repository is actively developed primarily for iOS. While we can catch basic unit test issues with
+Travis, there may be some changes where the SDK no longer works as expected on macOS, tvOS or watchOS. If you
+encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
+
+During app setup in the console, you may get to a step that mentions something like "Checking if the app
+has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/watchOS/Catalyst.
+**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
+
+To install, add a subset of the following to the Podfile:
+
+```
+pod 'Firebase/ABTesting' # No watchOS support yet
+pod 'Firebase/Auth' # No watchOS support yet
+pod 'Firebase/Crashlytics' # No watchOS support yet
+pod 'Firebase/Database' # No watchOS support yet
+pod 'Firebase/Firestore' # No watchOS support yet
+pod 'Firebase/Functions' # No watchOS support yet
+pod 'Firebase/Messaging'
+pod 'Firebase/RemoteConfig' # No watchOS support yet
+pod 'Firebase/Storage'
+```
+
+#### Additional Catalyst Notes
+
+* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
+to Build Settings.
+* FirebaseFirestore requires signing the
+[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
+
+## Roadmap
+
+See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
+plans and directions.
+
+## Contributing
+
+See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase
+iOS SDK.
+
+## License
+
+The contents of this repository is licensed under the
+[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
+
+Your use of Firebase is governed by the
+[Terms of Service for Firebase Services](https://firebase.google.com/terms/).
+
+[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions
+[gh-abtesting-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/abtesting/badge.svg
+[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg
+[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg
+[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg
+[gh-crashlytics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/crashlytics/badge.svg
+[gh-database-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/database/badge.svg
+[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg
+[gh-dynamiclinks-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/dynamiclinks/badge.svg
+[gh-firebasepod-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firebasepod/badge.svg
+[gh-firestore-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firestore/badge.svg
+[gh-functions-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/functions/badge.svg
+[gh-inappmessaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/inappmessaging/badge.svg
+[gh-interop-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/interop/badge.svg
+[gh-messaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/messaging/badge.svg
+[gh-remoteconfig-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/remoteconfig/badge.svg
+[gh-storage-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/storage/badge.svg
+[gh-symbolcollision-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/symbolcollision/badge.svg
+[gh-zip-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/zip/badge.svg