summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig
diff options
context:
space:
mode:
Diffstat (limited to 'StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig')
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRAppInternal.h173
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponent.h91
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponentContainer.h50
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponentType.h34
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h35
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRDependency.h45
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRErrorCode.h39
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRErrors.h24
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h39
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRLibrary.h50
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRLogger.h156
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIROptionsInternal.h119
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FirebaseCoreInternal.h31
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h23
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRConfigValue.m91
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m656
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h58
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.m117
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h75
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h61
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h123
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FIRRemoteConfig.h376
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig.h17
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigConstants.h58
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.h60
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.m336
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h121
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m1045
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDefines.h34
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.h37
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.m165
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigSettings.m459
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h25
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConstants3P.m20
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.h57
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.m240
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNFetch.m568
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h55
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.m233
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h47
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULHeartbeatDateStorage.h49
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULKeychainStorage.h79
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULKeychainUtils.h61
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULSecureCoding.h36
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/NSData+zlib/Private/GULNSDataInternal.h22
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInterop.h66
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInteropListener.h24
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropEventNames.h28
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropParameterNames.h73
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/LICENSE202
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/README.md298
51 files changed, 6981 insertions, 0 deletions
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRAppInternal.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRAppInternal.h
new file mode 100644
index 00000000..9a0c943d
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRAppInternal.h
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+#if SWIFT_PACKAGE
+// TODO(paulb777): Investigate if there's a common strategy for both Cocoapods and Swift PM.
+#import "FIRApp.h"
+#else
+#import <FirebaseCore/FIRApp.h>
+#endif
+
+// The has_include is a workaround so the old IID needed for the FIS tests can find FIRErrors.h
+#if __has_include("FirebaseCore/Sources/Private/FIRErrors.h")
+#import "FirebaseCore/Sources/Private/FIRErrors.h"
+#else
+#import <FirebaseCore/FIRErrors.h>
+#endif
+
+@class FIRComponentContainer;
+@protocol FIRLibrary;
+
+/**
+ * The internal interface to FIRApp. This is meant for first-party integrators, who need to receive
+ * FIRApp notifications, log info about the success or failure of their configuration, and access
+ * other internal functionality of FIRApp.
+ *
+ * TODO(b/28296561): Restructure this header.
+ */
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NS_ENUM(NSInteger, FIRConfigType) {
+ FIRConfigTypeCore = 1,
+ FIRConfigTypeSDK = 2,
+};
+
+extern NSString *const kFIRDefaultAppName;
+extern NSString *const kFIRAppReadyToConfigureSDKNotification;
+extern NSString *const kFIRAppDeleteNotification;
+extern NSString *const kFIRAppIsDefaultAppKey;
+extern NSString *const kFIRAppNameKey;
+extern NSString *const kFIRGoogleAppIDKey;
+
+/**
+ * The format string for the User Defaults key used for storing the data collection enabled flag.
+ * This includes formatting to append the Firebase App's name.
+ */
+extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat;
+
+/**
+ * The plist key used for storing the data collection enabled flag.
+ */
+extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey;
+
+/**
+ * A notification fired containing diagnostic information when SDK errors occur.
+ */
+extern NSString *const kFIRAppDiagnosticsNotification;
+
+/** @var FIRAuthStateDidChangeInternalNotification
+ @brief The name of the @c NSNotificationCenter notification which is posted when the auth state
+ changes (e.g. a new token has been produced, a user logs in or out). The object parameter of
+ the notification is a dictionary possibly containing the key:
+ @c FIRAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not
+ contain this key it indicates a sign-out event took place.
+ */
+extern NSString *const FIRAuthStateDidChangeInternalNotification;
+
+/** @var FIRAuthStateDidChangeInternalNotificationTokenKey
+ @brief A key present in the dictionary object parameter of the
+ @c FIRAuthStateDidChangeInternalNotification notification. The value associated with this
+ key will contain the new access token.
+ */
+extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey;
+
+/** @var FIRAuthStateDidChangeInternalNotificationAppKey
+ @brief A key present in the dictionary object parameter of the
+ @c FIRAuthStateDidChangeInternalNotification notification. The value associated with this
+ key will contain the FIRApp associated with the auth instance.
+ */
+extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey;
+
+/** @var FIRAuthStateDidChangeInternalNotificationUIDKey
+ @brief A key present in the dictionary object parameter of the
+ @c FIRAuthStateDidChangeInternalNotification notification. The value associated with this
+ key will contain the new user's UID (or nil if there is no longer a user signed in).
+ */
+extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey;
+
+@interface FIRApp ()
+
+/**
+ * A flag indicating if this is the default app (has the default app name).
+ */
+@property(nonatomic, readonly) BOOL isDefaultApp;
+
+/*
+ * The container of interop SDKs for this app.
+ */
+@property(nonatomic) FIRComponentContainer *container;
+
+/**
+ * Creates an error for failing to configure a subspec service. This method is called by each
+ * FIRApp notification listener.
+ */
++ (NSError *)errorForSubspecConfigurationFailureWithDomain:(NSString *)domain
+ errorCode:(FIRErrorCode)code
+ service:(NSString *)service
+ reason:(NSString *)reason;
+/**
+ * Checks if the default app is configured without trying to configure it.
+ */
++ (BOOL)isDefaultAppConfigured;
+
+/**
+ * Registers a given third-party library with the given version number to be reported for
+ * analytics.
+ *
+ * @param name Name of the library.
+ * @param version Version of the library.
+ */
++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version;
+
+/**
+ * Registers a given internal library with the given version number to be reported for
+ * analytics.
+ *
+ * @param library Optional parameter for component registration.
+ * @param name Name of the library.
+ * @param version Version of the library.
+ */
++ (void)registerInternalLibrary:(nonnull Class<FIRLibrary>)library
+ withName:(nonnull NSString *)name
+ withVersion:(nonnull NSString *)version;
+
+/**
+ * A concatenated string representing all the third-party libraries and version numbers.
+ */
++ (NSString *)firebaseUserAgent;
+
+/**
+ * Used by each SDK to send logs about SDK configuration status to Clearcut.
+ *
+ * @note This API is a no-op, please remove calls to it.
+ */
+- (void)sendLogsWithServiceName:(NSString *)serviceName
+ version:(NSString *)version
+ error:(NSError *)error;
+
+/**
+ * Can be used by the unit tests in eack SDK to reset FIRApp. This method is thread unsafe.
+ */
++ (void)resetApps;
+
+/**
+ * Can be used by the unit tests in each SDK to set customized options.
+ */
+- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponent.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponent.h
new file mode 100644
index 00000000..cb51ee70
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponent.h
@@ -0,0 +1,91 @@
+/*
+ * 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>
+
+@class FIRApp;
+@class FIRComponentContainer;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Provides a system to clean up cached instances returned from the component system.
+NS_SWIFT_NAME(ComponentLifecycleMaintainer)
+@protocol FIRComponentLifecycleMaintainer
+/// The associated app will be deleted, clean up any resources as they are about to be deallocated.
+- (void)appWillBeDeleted:(FIRApp *)app;
+@end
+
+typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container,
+ BOOL *isCacheable)
+ NS_SWIFT_NAME(ComponentCreationBlock);
+
+@class FIRDependency;
+
+/// Describes the timing of instantiation. Note: new components should default to lazy unless there
+/// is a strong reason to be eager.
+typedef NS_ENUM(NSInteger, FIRInstantiationTiming) {
+ FIRInstantiationTimingLazy,
+ FIRInstantiationTimingAlwaysEager,
+ FIRInstantiationTimingEagerInDefaultApp
+} NS_SWIFT_NAME(InstantiationTiming);
+
+/// A component that can be used from other Firebase SDKs.
+NS_SWIFT_NAME(Component)
+@interface FIRComponent : NSObject
+
+/// The protocol describing functionality provided from the Component.
+@property(nonatomic, strong, readonly) Protocol *protocol;
+
+/// The timing of instantiation.
+@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming;
+
+/// An array of dependencies for the component.
+@property(nonatomic, copy, readonly) NSArray<FIRDependency *> *dependencies;
+
+/// A block to instantiate an instance of the component with the appropriate dependencies.
+@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock;
+
+// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format
+// for the next two methods.
+// clang-format off
+
+/// Creates a component with no dependencies that will be lazily initialized.
++ (instancetype)componentWithProtocol:(Protocol *)protocol
+ creationBlock:(FIRComponentCreationBlock)creationBlock
+NS_SWIFT_NAME(init(_:creationBlock:));
+
+/// Creates a component to be registered with the component container.
+///
+/// @param protocol - The protocol describing functionality provided by the component.
+/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's
+/// a good reason to be instantiated earlier.
+/// @param dependencies - Any dependencies the `implementingClass` has, optional or required.
+/// @param creationBlock - A block to instantiate the component with a container, and if
+/// @return A component that can be registered with the component container.
++ (instancetype)componentWithProtocol:(Protocol *)protocol
+ instantiationTiming:(FIRInstantiationTiming)instantiationTiming
+ dependencies:(NSArray<FIRDependency *> *)dependencies
+ creationBlock:(FIRComponentCreationBlock)creationBlock
+NS_SWIFT_NAME(init(_:instantiationTiming:dependencies:creationBlock:));
+
+// clang-format on
+
+/// Unavailable.
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponentContainer.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponentContainer.h
new file mode 100644
index 00000000..db2bafef
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponentContainer.h
@@ -0,0 +1,50 @@
+/*
+ * 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 has_include is a workaround so the old IID needed for the FIS tests can find the headers.
+#if __has_include("FirebaseCore/Sources/Private/FIRComponentType.h")
+#import "FirebaseCore/Sources/Private/FIRComponentType.h"
+#import "FirebaseCore/Sources/Private/FIRLibrary.h"
+#else
+#import <FirebaseCore/FIRComponentType.h>
+#import <FirebaseCore/FIRLibrary.h>
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// A type-safe macro to retrieve a component from a container. This should be used to retrieve
+/// components instead of using the container directly.
+#define FIR_COMPONENT(type, container) \
+ [FIRComponentType<id<type>> instanceForProtocol:@protocol(type) inContainer:container]
+
+@class FIRApp;
+
+/// A container that holds different components that are registered via the
+/// `registerAsComponentRegistrant:` call. These classes should conform to `FIRComponentRegistrant`
+/// in order to properly register components for Core.
+NS_SWIFT_NAME(FirebaseComponentContainer)
+@interface FIRComponentContainer : NSObject
+
+/// A weak reference to the app that an instance of the container belongs to.
+@property(nonatomic, weak, readonly) FIRApp *app;
+
+/// Unavailable. Use the `container` property on `FIRApp`.
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponentType.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponentType.h
new file mode 100644
index 00000000..6f2aca7b
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRComponentType.h
@@ -0,0 +1,34 @@
+/*
+ * 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>
+
+@class FIRComponentContainer;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Do not use directly. A placeholder type in order to provide a macro that will warn users of
+/// mis-matched protocols.
+NS_SWIFT_NAME(ComponentType)
+@interface FIRComponentType<__covariant T> : NSObject
+
+/// Do not use directly. A factory method to retrieve an instance that provides a specific
+/// functionality.
++ (T)instanceForProtocol:(Protocol *)protocol inContainer:(FIRComponentContainer *)container;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h
new file mode 100644
index 00000000..76c0c05f
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h
@@ -0,0 +1,35 @@
+/*
+ * 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 FIRDiagnosticsData;
+@class FIROptions;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Connects FIRCore with the CoreDiagnostics library. */
+@interface FIRCoreDiagnosticsConnector : NSObject
+
+/** Logs FirebaseCore related data.
+ *
+ * @param options The options object containing data to log.
+ */
++ (void)logCoreTelemetryWithOptions:(FIROptions *)options;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRDependency.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRDependency.h
new file mode 100644
index 00000000..46e9b7ea
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRDependency.h
@@ -0,0 +1,45 @@
+/*
+ * 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 dependency on a specific protocol's functionality.
+NS_SWIFT_NAME(Dependency)
+@interface FIRDependency : NSObject
+
+/// The protocol describing functionality being depended on.
+@property(nonatomic, strong, readonly) Protocol *protocol;
+
+/// A flag to specify if the dependency is required or not.
+@property(nonatomic, readonly) BOOL isRequired;
+
+/// Initializes a dependency that is required. Calls `initWithProtocol:isRequired` with `YES` for
+/// the required parameter.
+/// Creates a required dependency on the specified protocol's functionality.
++ (instancetype)dependencyWithProtocol:(Protocol *)protocol;
+
+/// Creates a dependency on the specified protocol's functionality and specify if it's required for
+/// the class's functionality.
++ (instancetype)dependencyWithProtocol:(Protocol *)protocol isRequired:(BOOL)required;
+
+/// Use `dependencyWithProtocol:isRequired:` instead.
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRErrorCode.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRErrorCode.h
new file mode 100644
index 00000000..c90d9eec
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRErrorCode.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/** Error codes in Firebase error domain. */
+typedef NS_ENUM(NSInteger, FIRErrorCode) {
+ /**
+ * Unknown error.
+ */
+ FIRErrorCodeUnknown = 0,
+ /**
+ * Loading data from the GoogleService-Info.plist file failed. This is a fatal error and should
+ * not be ignored. Further calls to the API will fail and/or possibly cause crashes.
+ */
+ FIRErrorCodeInvalidPlistFile = -100,
+
+ /**
+ * Validating the Google App ID format failed.
+ */
+ FIRErrorCodeInvalidAppID = -101,
+
+ /**
+ * Error code for failing to configure a specific service. It's deprecated, but
+ * still used after copybara.
+ */
+ FIRErrorCodeConfigFailed = -114,
+};
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRErrors.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRErrors.h
new file mode 100644
index 00000000..19e47328
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRErrors.h
@@ -0,0 +1,24 @@
+/*
+ * 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>
+
+#include "FIRErrorCode.h"
+
+extern NSString *const kFirebaseErrorDomain;
+extern NSString *const kFirebaseConfigErrorDomain;
+extern NSString *const kFirebaseCoreErrorDomain;
+extern NSString *const kFirebasePerfErrorDomain;
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h
new file mode 100644
index 00000000..bfff73e5
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h
@@ -0,0 +1,39 @@
+// 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
+
+@interface FIRHeartbeatInfo : NSObject
+
+// Enum representing the different heartbeat codes.
+typedef NS_ENUM(NSInteger, FIRHeartbeatInfoCode) {
+ FIRHeartbeatInfoCodeNone = 0,
+ FIRHeartbeatInfoCodeSDK = 1,
+ FIRHeartbeatInfoCodeGlobal = 2,
+ FIRHeartbeatInfoCodeCombined = 3,
+};
+
+/**
+ * Get heartbeat code requred for the sdk.
+ * @param heartbeatTag String representing the sdk heartbeat tag.
+ * @return Heartbeat code indicating whether or not an sdk/global heartbeat
+ * needs to be sent
+ */
++ (FIRHeartbeatInfoCode)heartbeatCodeForTag:(NSString *)heartbeatTag;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRLibrary.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRLibrary.h
new file mode 100644
index 00000000..e7a9e077
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRLibrary.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef FIRLibrary_h
+#define FIRLibrary_h
+
+#import <Foundation/Foundation.h>
+
+// The has_include is a workaround so the old IID needed for the FIS tests can find the headers.
+#if __has_include("FirebaseCore/Sources/Private/FIRComponent.h")
+#import "FirebaseCore/Sources/Private/FIRComponent.h"
+#else
+#import <FirebaseCore/FIRComponent.h>
+#endif
+
+@class FIRApp;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Provide an interface to register a library for userAgent logging and availability to others.
+NS_SWIFT_NAME(Library)
+@protocol FIRLibrary
+
+/// Returns one or more FIRComponents that will be registered in
+/// FIRApp and participate in dependency resolution and injection.
++ (NSArray<FIRComponent *> *)componentsToRegister;
+
+@optional
+/// Implement this method if the library needs notifications for lifecycle events. This method is
+/// called when the developer calls `FirebaseApp.configure()`.
++ (void)configureWithApp:(FIRApp *)app;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif /* FIRLibrary_h */
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRLogger.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRLogger.h
new file mode 100644
index 00000000..6fd77844
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIRLogger.h
@@ -0,0 +1,156 @@
+/*
+ * 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 SWIFT_PACKAGE
+// TODO(paulb777): Investigate if there's a common strategy for both Cocoapods and Swift PM.
+#import "FIRLoggerLevel.h"
+#else
+#import <FirebaseCore/FIRLoggerLevel.h>
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * The Firebase services used in Firebase logger.
+ */
+typedef NSString *const FIRLoggerService;
+
+extern FIRLoggerService kFIRLoggerABTesting;
+extern FIRLoggerService kFIRLoggerAdMob;
+extern FIRLoggerService kFIRLoggerAnalytics;
+extern FIRLoggerService kFIRLoggerAuth;
+extern FIRLoggerService kFIRLoggerCrash;
+extern FIRLoggerService kFIRLoggerCore;
+extern FIRLoggerService kFIRLoggerMLKit;
+extern FIRLoggerService kFIRLoggerPerf;
+extern FIRLoggerService kFIRLoggerRemoteConfig;
+
+/**
+ * The key used to store the logger's error count.
+ */
+extern NSString *const kFIRLoggerErrorCountKey;
+
+/**
+ * The key used to store the logger's warning count.
+ */
+extern NSString *const kFIRLoggerWarningCountKey;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * Enables or disables Analytics debug mode.
+ * If set to YES, the logging level for Analytics will be set to FIRLoggerLevelDebug.
+ * Enabling the debug mode has no effect if the app is running from App Store.
+ * (required) analytics debug mode flag.
+ */
+void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode);
+
+/**
+ * Changes the default logging level of FIRLoggerLevelNotice to a user-specified level.
+ * The default level cannot be set above FIRLoggerLevelNotice if the app is running from App Store.
+ * (required) log level (one of the FIRLoggerLevel enum values).
+ */
+void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel);
+
+/**
+ * Checks if the specified logger level is loggable given the current settings.
+ * (required) log level (one of the FIRLoggerLevel enum values).
+ * (required) whether or not this function is called from the Analytics component.
+ */
+BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent);
+
+/**
+ * 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 FIRLoggerLevelNotice to avoid log spamming.
+ * (required) log level (one of the FIRLoggerLevel enum values).
+ * (required) service name of type FIRLoggerService.
+ * (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 FIRLogBasic(FIRLoggerLevel level,
+ FIRLoggerService service,
+ 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 FIRLoggerService.
+ * (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:
+ * FIRLogError(kFIRLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name);
+ */
+extern void FIRLogError(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
+ NS_FORMAT_FUNCTION(3, 4);
+extern void FIRLogWarning(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
+ NS_FORMAT_FUNCTION(3, 4);
+extern void FIRLogNotice(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
+ NS_FORMAT_FUNCTION(3, 4);
+extern void FIRLogInfo(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
+ NS_FORMAT_FUNCTION(3, 4);
+extern void FIRLogDebug(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
+ NS_FORMAT_FUNCTION(3, 4);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+@interface FIRLoggerWrapper : NSObject
+
+/**
+ * Objective-C wrapper for FIRLogBasic to allow weak linking to FIRLogger
+ * (required) log level (one of the FIRLoggerLevel enum values).
+ * (required) service name of type FIRLoggerService.
+ * (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:(FIRLoggerLevel)level
+ withService:(FIRLoggerService)service
+ withCode:(NSString *)messageCode
+ withMessage:(NSString *)message
+ withArgs:(va_list)args;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIROptionsInternal.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIROptionsInternal.h
new file mode 100644
index 00000000..acaf4586
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FIROptionsInternal.h
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#if SWIFT_PACKAGE
+// TODO(paulb777): Investigate if there's a common strategy for both Cocoapods and Swift PM.
+#import "FIROptions.h"
+#else
+#import <FirebaseCore/FIROptions.h>
+#endif
+
+/**
+ * Keys for the strings in the plist file.
+ */
+extern NSString *const kFIRAPIKey;
+extern NSString *const kFIRTrackingID;
+extern NSString *const kFIRGoogleAppID;
+extern NSString *const kFIRClientID;
+extern NSString *const kFIRGCMSenderID;
+extern NSString *const kFIRAndroidClientID;
+extern NSString *const kFIRDatabaseURL;
+extern NSString *const kFIRStorageBucket;
+extern NSString *const kFIRBundleID;
+extern NSString *const kFIRProjectID;
+
+/**
+ * Keys for the plist file name
+ */
+extern NSString *const kServiceInfoFileName;
+
+extern NSString *const kServiceInfoFileType;
+
+/**
+ * This header file exposes the initialization of FIROptions to internal use.
+ */
+@interface FIROptions ()
+
+/**
+ * resetDefaultOptions and initInternalWithOptionsDictionary: are exposed only for unit tests.
+ */
++ (void)resetDefaultOptions;
+
+/**
+ * Initializes the options with dictionary. The above strings are the keys of the dictionary.
+ * This is the designated initializer.
+ */
+- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary;
+
+/**
+ * defaultOptions and defaultOptionsDictionary are exposed in order to be used in FIRApp and
+ * other first party services.
+ */
++ (FIROptions *)defaultOptions;
+
++ (NSDictionary *)defaultOptionsDictionary;
+
+/**
+ * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at
+ * runtime.
+ */
+@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet;
+
+/**
+ * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless
+ * explicitly disabled in GoogleService-Info.plist.
+ */
+@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled;
+
+/**
+ * Whether or not Analytics Collection was completely disabled. If YES, then
+ * isAnalyticsCollectionEnabled will be NO.
+ */
+@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated;
+
+/**
+ * The version ID of the client library, e.g. @"1100000".
+ */
+@property(nonatomic, readonly, copy) NSString *libraryVersionID;
+
+/**
+ * The flag indicating whether this object was constructed with the values in the default plist
+ * file.
+ */
+@property(nonatomic) BOOL usingOptionsFromDefaultPlist;
+
+/**
+ * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in
+ * GoogleService-Info.plist.
+ */
+@property(nonatomic, readonly) BOOL isMeasurementEnabled;
+
+/**
+ * Whether or not Analytics was enabled in the developer console.
+ */
+@property(nonatomic, readonly) BOOL isAnalyticsEnabled;
+
+/**
+ * Whether or not SignIn was enabled in the developer console.
+ */
+@property(nonatomic, readonly) BOOL isSignInEnabled;
+
+/**
+ * Whether or not editing is locked. This should occur after FIROptions has been set on a FIRApp.
+ */
+@property(nonatomic, getter=isEditingLocked) BOOL editingLocked;
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FirebaseCoreInternal.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FirebaseCoreInternal.h
new file mode 100644
index 00000000..93af6cb8
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseCore/Sources/Private/FirebaseCoreInternal.h
@@ -0,0 +1,31 @@
+// 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 FirebaseCore;
+#else
+#import <FirebaseCore/FirebaseCore.h>
+#endif
+
+#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
+#import "FirebaseCore/Sources/Private/FIRComponent.h"
+#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
+#import "FirebaseCore/Sources/Private/FIRDependency.h"
+#import "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h"
+#import "FirebaseCore/Sources/Private/FIRLibrary.h"
+#import "FirebaseCore/Sources/Private/FIRLogger.h"
+#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h
new file mode 100644
index 00000000..cd40f172
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h
@@ -0,0 +1,23 @@
+// 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
+// Installations Public headers. Any package manager complexity should be
+// handled here.
+
+#if SWIFT_PACKAGE
+@import FirebaseInstallations;
+#else
+#import <FirebaseInstallations/FirebaseInstallations.h>
+#endif
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRConfigValue.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRConfigValue.m
new file mode 100644
index 00000000..09d9f880
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRConfigValue.m
@@ -0,0 +1,91 @@
+/*
+ * 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 <FirebaseRemoteConfig/FIRRemoteConfig.h>
+
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h"
+
+@implementation FIRRemoteConfigValue {
+ /// Data backing the config value.
+ NSData *_data;
+ FIRRemoteConfigSource _source;
+}
+
+/// Designated initializer
+- (instancetype)initWithData:(NSData *)data source:(FIRRemoteConfigSource)source {
+ self = [super init];
+ if (self) {
+ _data = [data copy];
+ _source = source;
+ }
+ return self;
+}
+
+/// Superclass's designated initializer
+- (instancetype)init {
+ return [self initWithData:nil source:FIRRemoteConfigSourceStatic];
+}
+
+/// The string is a UTF-8 representation of NSData.
+- (NSString *)stringValue {
+ return [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding];
+}
+
+/// Number representation of a UTF-8 string.
+- (NSNumber *)numberValue {
+ return [NSNumber numberWithDouble:self.stringValue.doubleValue];
+}
+
+/// Internal representation of the FIRRemoteConfigValue as a NSData object.
+- (NSData *)dataValue {
+ return _data;
+}
+
+/// Boolean representation of a UTF-8 string.
+- (BOOL)boolValue {
+ return self.stringValue.boolValue;
+}
+
+/// Returns a foundation object (NSDictionary / NSArray) representation for JSON data.
+- (id)JSONValue {
+ NSError *error;
+ if (!_data) {
+ return nil;
+ }
+ id JSONObject = [NSJSONSerialization JSONObjectWithData:_data options:kNilOptions error:&error];
+ if (error) {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000065", @"Error parsing data as JSON.");
+ return nil;
+ }
+ return JSONObject;
+}
+
+/// Debug description showing the representations of all types.
+- (NSString *)debugDescription {
+ NSString *content = [NSString
+ stringWithFormat:@"Boolean: %d, String: %@, Number: %@, JSON:%@, Data: %@, Source: %zd",
+ self.boolValue, self.stringValue, self.numberValue, self.JSONValue, _data,
+ (long)self.source];
+ return [NSString stringWithFormat:@"<%@: %p, %@>", [self class], self, content];
+}
+
+/// Copy method.
+- (id)copyWithZone:(NSZone *)zone {
+ FIRRemoteConfigValue *value = [[[self class] allocWithZone:zone] initWithData:_data];
+ return value;
+}
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m
new file mode 100644
index 00000000..143b6e6d
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m
@@ -0,0 +1,656 @@
+/*
+ * 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 <FirebaseRemoteConfig/FIRRemoteConfig.h>
+
+#import <FirebaseABTesting/FIRExperimentController.h>
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
+#import "FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h"
+#import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h"
+#import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h"
+#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h"
+#import "FirebaseRemoteConfig/Sources/RCNDevice.h"
+
+/// Remote Config Error Domain.
+/// TODO: Rename according to obj-c style for constants.
+NSString *const FIRRemoteConfigErrorDomain = @"com.google.remoteconfig.ErrorDomain";
+/// Remote Config Error Info End Time Seconds;
+NSString *const FIRRemoteConfigThrottledEndTimeInSecondsKey = @"error_throttled_end_time_seconds";
+/// Remote Config Developer Mode Key
+static NSString *const kRemoteConfigDeveloperKey = @"_rcn_developer";
+/// Minimum required time interval between fetch requests made to the backend.
+static NSString *const kRemoteConfigMinimumFetchIntervalKey = @"_rcn_minimum_fetch_interval";
+/// Timeout value for waiting on a fetch response.
+static NSString *const kRemoteConfigFetchTimeoutKey = @"_rcn_fetch_timeout";
+
+@interface FIRRemoteConfigSettings () {
+ BOOL _developerModeEnabled;
+}
+@end
+
+// Implementations depend upon multiple deprecated APIs
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+@implementation FIRRemoteConfigSettings
+- (instancetype)initWithDeveloperModeEnabled:(BOOL)developerModeEnabled {
+ self = [self init];
+ if (self) {
+ _developerModeEnabled = developerModeEnabled;
+ }
+ return self;
+}
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ _developerModeEnabled = NO;
+ _minimumFetchInterval = RCNDefaultMinimumFetchInterval;
+ _fetchTimeout = RCNHTTPDefaultConnectionTimeout;
+ }
+ return self;
+}
+
+- (BOOL)isDeveloperModeEnabled {
+ return _developerModeEnabled;
+}
+
+@end
+
+@implementation FIRRemoteConfig {
+ /// All the config content.
+ RCNConfigContent *_configContent;
+ RCNConfigDBManager *_DBManager;
+ RCNConfigSettings *_settings;
+ RCNConfigFetch *_configFetch;
+ RCNConfigExperiment *_configExperiment;
+ dispatch_queue_t _queue;
+ NSString *_appName;
+}
+
+static NSMutableDictionary<NSString *, NSMutableDictionary<NSString *, FIRRemoteConfig *> *>
+ *RCInstances;
+
++ (nonnull FIRRemoteConfig *)remoteConfigWithApp:(FIRApp *_Nonnull)firebaseApp {
+ return [FIRRemoteConfig remoteConfigWithFIRNamespace:FIRNamespaceGoogleMobilePlatform
+ app:firebaseApp];
+}
+
++ (nonnull FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *_Nonnull)firebaseNamespace {
+ if (![FIRApp isDefaultAppConfigured]) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000047",
+ @"FIRApp not configured. Please make sure you have called [FIRApp configure]");
+ // TODO: Maybe throw an exception here? That'd be a breaking change though, but at this point
+ // RC can't work as expected.
+ }
+
+ return [FIRRemoteConfig remoteConfigWithFIRNamespace:firebaseNamespace app:[FIRApp defaultApp]];
+}
+
++ (nonnull FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *_Nonnull)firebaseNamespace
+ app:(FIRApp *_Nonnull)firebaseApp {
+ // Use the provider to generate and return instances of FIRRemoteConfig for this specific app and
+ // namespace. This will ensure the app is configured before Remote Config can return an instance.
+ id<FIRRemoteConfigProvider> provider =
+ FIR_COMPONENT(FIRRemoteConfigProvider, firebaseApp.container);
+ return [provider remoteConfigForNamespace:firebaseNamespace];
+}
+
++ (FIRRemoteConfig *)remoteConfig {
+ // If the default app is not configured at this point, warn the developer.
+ if (![FIRApp isDefaultAppConfigured]) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000047",
+ @"FIRApp not configured. Please make sure you have called [FIRApp configure]");
+ // TODO: Maybe throw an exception here? That'd be a breaking change though, but at this point
+ // RC can't work as expected.
+ }
+
+ return [FIRRemoteConfig remoteConfigWithFIRNamespace:FIRNamespaceGoogleMobilePlatform
+ app:[FIRApp defaultApp]];
+}
+
+/// Singleton instance of serial queue for queuing all incoming RC calls.
++ (dispatch_queue_t)sharedRemoteConfigSerialQueue {
+ static dispatch_once_t onceToken;
+ static dispatch_queue_t sharedRemoteConfigQueue;
+ dispatch_once(&onceToken, ^{
+ sharedRemoteConfigQueue =
+ dispatch_queue_create(RCNRemoteConfigQueueLabel, DISPATCH_QUEUE_SERIAL);
+ });
+ return sharedRemoteConfigQueue;
+}
+
+/// Designated initializer
+- (instancetype)initWithAppName:(NSString *)appName
+ FIROptions:(FIROptions *)options
+ namespace:(NSString *)FIRNamespace
+ DBManager:(RCNConfigDBManager *)DBManager
+ configContent:(RCNConfigContent *)configContent
+ analytics:(nullable id<FIRAnalyticsInterop>)analytics {
+ self = [super init];
+ if (self) {
+ _appName = appName;
+ _DBManager = DBManager;
+ // The fully qualified Firebase namespace is namespace:firappname.
+ _FIRNamespace = [NSString stringWithFormat:@"%@:%@", FIRNamespace, appName];
+
+ // Initialize RCConfigContent if not already.
+ _configContent = configContent;
+ _settings = [[RCNConfigSettings alloc] initWithDatabaseManager:_DBManager
+ namespace:_FIRNamespace
+ firebaseAppName:appName
+ googleAppID:options.googleAppID];
+
+ FIRExperimentController *experimentController = [FIRExperimentController sharedInstance];
+ _configExperiment = [[RCNConfigExperiment alloc] initWithDBManager:_DBManager
+ experimentController:experimentController];
+ /// Serial queue for read and write lock.
+ _queue = [FIRRemoteConfig sharedRemoteConfigSerialQueue];
+
+ // Initialize with default config settings.
+ [self setDefaultConfigSettings];
+ _configFetch = [[RCNConfigFetch alloc] initWithContent:_configContent
+ DBManager:_DBManager
+ settings:_settings
+ analytics:analytics
+ experiment:_configExperiment
+ queue:_queue
+ namespace:_FIRNamespace
+ options:options];
+
+ [_settings loadConfigFromMetadataTable];
+ }
+ return self;
+}
+
+// Initialize with default config settings.
+- (void)setDefaultConfigSettings {
+ // Set the default config settings.
+ self->_settings.fetchTimeout = RCNHTTPDefaultConnectionTimeout;
+ self->_settings.minimumFetchInterval = RCNDefaultMinimumFetchInterval;
+}
+
+- (void)ensureInitializedWithCompletionHandler:
+ (nonnull FIRRemoteConfigInitializationCompletion)completionHandler {
+ __weak FIRRemoteConfig *weakSelf = self;
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
+ FIRRemoteConfig *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ BOOL initializationSuccess = [self->_configContent initializationSuccessful];
+ NSError *error = nil;
+ if (!initializationSuccess) {
+ error = [[NSError alloc]
+ initWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorInternalError
+ userInfo:@{NSLocalizedDescriptionKey : @"Timed out waiting for database load."}];
+ }
+ completionHandler(error);
+ });
+}
+
+#pragma mark - fetch
+
+- (void)fetchWithCompletionHandler:(FIRRemoteConfigFetchCompletion)completionHandler {
+ dispatch_async(_queue, ^{
+ [self fetchWithExpirationDuration:self->_settings.minimumFetchInterval
+ completionHandler:completionHandler];
+ });
+}
+
+- (void)fetchWithExpirationDuration:(NSTimeInterval)expirationDuration
+ completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler {
+ FIRRemoteConfigFetchCompletion completionHandlerCopy = nil;
+ if (completionHandler) {
+ completionHandlerCopy = [completionHandler copy];
+ }
+ [_configFetch fetchConfigWithExpirationDuration:expirationDuration
+ completionHandler:completionHandlerCopy];
+}
+
+#pragma mark - fetchAndActivate
+
+- (void)fetchAndActivateWithCompletionHandler:
+ (FIRRemoteConfigFetchAndActivateCompletion)completionHandler {
+ __weak FIRRemoteConfig *weakSelf = self;
+ FIRRemoteConfigFetchCompletion fetchCompletion =
+ ^(FIRRemoteConfigFetchStatus fetchStatus, NSError *fetchError) {
+ FIRRemoteConfig *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ // Fetch completed. We are being called on the main queue.
+ // If fetch is successful, try to activate the fetched config
+ if (fetchStatus == FIRRemoteConfigFetchStatusSuccess && !fetchError) {
+ [strongSelf activateWithCompletionHandler:^(NSError *_Nullable activateError) {
+ if (completionHandler) {
+ FIRRemoteConfigFetchAndActivateStatus status =
+ activateError ? FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData
+ : FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote;
+ completionHandler(status, nil);
+ }
+ }];
+ } else if (completionHandler) {
+ FIRRemoteConfigFetchAndActivateStatus status =
+ fetchStatus == FIRRemoteConfigFetchStatusSuccess
+ ? FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData
+ : FIRRemoteConfigFetchAndActivateStatusError;
+ completionHandler(status, fetchError);
+ }
+ };
+ [self fetchWithCompletionHandler:fetchCompletion];
+}
+
+#pragma mark - apply
+
+- (BOOL)activateFetched {
+ // TODO: We block on the async activate to complete. This method is deprecated and needs
+ // to be removed at the next possible breaking change.
+ __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
+ __block BOOL didActivate = NO;
+ [self activateWithCompletionHandler:^(NSError *_Nullable error) {
+ didActivate = error ? false : true;
+ dispatch_semaphore_signal(semaphore);
+ }];
+ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
+ return didActivate;
+}
+
+typedef void (^FIRRemoteConfigActivateChangeCompletion)(BOOL changed, NSError *_Nullable error);
+
+- (void)activateWithCompletion:(FIRRemoteConfigActivateChangeCompletion)completion {
+ [self activateWithEitherHandler:completion deprecatedHandler:nil];
+}
+
+- (void)activateWithCompletionHandler:(FIRRemoteConfigActivateCompletion)completionHandler {
+ [self activateWithEitherHandler:nil deprecatedHandler:completionHandler];
+}
+
+- (void)activateWithEitherHandler:(FIRRemoteConfigActivateChangeCompletion)completion
+ deprecatedHandler:(FIRRemoteConfigActivateCompletion)deprecatedHandler {
+ __weak FIRRemoteConfig *weakSelf = self;
+ void (^applyBlock)(void) = ^(void) {
+ FIRRemoteConfig *strongSelf = weakSelf;
+ if (!strongSelf) {
+ NSError *error = [NSError errorWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorInternalError
+ userInfo:@{@"ActivationFailureReason" : @"Internal Error."}];
+ if (completion) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ completion(NO, error);
+ });
+ } else if (deprecatedHandler) {
+ deprecatedHandler(error);
+ }
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000068", @"Internal error activating config.");
+ return;
+ }
+ // Check if the last fetched config has already been activated. Fetches with no data change are
+ // ignored.
+ if (strongSelf->_settings.lastETagUpdateTime == 0 ||
+ strongSelf->_settings.lastETagUpdateTime <= strongSelf->_settings.lastApplyTimeInterval) {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000069",
+ @"Most recently fetched config is already activated.");
+ if (completion) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ completion(NO, nil);
+ });
+ } else if (deprecatedHandler) {
+ NSError *error = [NSError
+ errorWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorInternalError
+ userInfo:@{
+ @"ActivationFailureReason" : @"Most recently fetched config already activated"
+ }];
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ deprecatedHandler(error);
+ });
+ }
+ return;
+ }
+ [strongSelf->_configContent copyFromDictionary:self->_configContent.fetchedConfig
+ toSource:RCNDBSourceActive
+ forNamespace:self->_FIRNamespace];
+ [strongSelf updateExperiments];
+ strongSelf->_settings.lastApplyTimeInterval = [[NSDate date] timeIntervalSince1970];
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000069", @"Config activated.");
+ if (completion) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ completion(YES, nil);
+ });
+ } else if (deprecatedHandler) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ deprecatedHandler(nil);
+ });
+ }
+ };
+ dispatch_async(_queue, applyBlock);
+}
+
+- (void)updateExperiments {
+ [self->_configExperiment updateExperiments];
+}
+
+#pragma mark - helpers
+- (NSString *)fullyQualifiedNamespace:(NSString *)namespace {
+ // If this is already a fully qualified namespace, return.
+ if ([namespace rangeOfString:@":"].location != NSNotFound) {
+ return namespace;
+ }
+ NSString *fullyQualifiedNamespace = [NSString stringWithFormat:@"%@:%@", namespace, _appName];
+ return fullyQualifiedNamespace;
+}
+
+#pragma mark - Get Config Result
+
+- (FIRRemoteConfigValue *)objectForKeyedSubscript:(NSString *)key {
+ return [self configValueForKey:key];
+}
+
+- (FIRRemoteConfigValue *)configValueForKey:(NSString *)key {
+ return [self configValueForKey:key namespace:_FIRNamespace];
+}
+
+- (FIRRemoteConfigValue *)configValueForKey:(NSString *)key namespace:(NSString *)aNamespace {
+ if (!key || !aNamespace) {
+ return [[FIRRemoteConfigValue alloc] initWithData:[NSData data]
+ source:FIRRemoteConfigSourceStatic];
+ }
+ NSString *FQNamespace = [self fullyQualifiedNamespace:aNamespace];
+
+ __block FIRRemoteConfigValue *value;
+ dispatch_sync(_queue, ^{
+ value = self->_configContent.activeConfig[FQNamespace][key];
+ if (value) {
+ if (value.source != FIRRemoteConfigSourceRemote) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000001",
+ @"Key %@ should come from source:%zd instead coming from source: %zd.", key,
+ (long)FIRRemoteConfigSourceRemote, (long)value.source);
+ }
+ return;
+ }
+ value = self->_configContent.defaultConfig[FQNamespace][key];
+ if (value) {
+ return;
+ }
+
+ value = [[FIRRemoteConfigValue alloc] initWithData:[NSData data]
+ source:FIRRemoteConfigSourceStatic];
+ });
+ return value;
+}
+
+- (FIRRemoteConfigValue *)configValueForKey:(NSString *)key source:(FIRRemoteConfigSource)source {
+ return [self configValueForKey:key namespace:_FIRNamespace source:source];
+}
+
+- (FIRRemoteConfigValue *)configValueForKey:(NSString *)key
+ namespace:(NSString *)aNamespace
+ source:(FIRRemoteConfigSource)source {
+ if (!key || !aNamespace) {
+ return [[FIRRemoteConfigValue alloc] initWithData:[NSData data]
+ source:FIRRemoteConfigSourceStatic];
+ }
+ NSString *FQNamespace = [self fullyQualifiedNamespace:aNamespace];
+
+ __block FIRRemoteConfigValue *value;
+ dispatch_sync(_queue, ^{
+ if (source == FIRRemoteConfigSourceRemote) {
+ value = self->_configContent.activeConfig[FQNamespace][key];
+ } else if (source == FIRRemoteConfigSourceDefault) {
+ value = self->_configContent.defaultConfig[FQNamespace][key];
+ } else {
+ value = [[FIRRemoteConfigValue alloc] initWithData:[NSData data]
+ source:FIRRemoteConfigSourceStatic];
+ }
+ });
+ return value;
+}
+
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
+ objects:(id __unsafe_unretained[])stackbuf
+ count:(NSUInteger)len {
+ __block NSUInteger localValue;
+ dispatch_sync(_queue, ^{
+ localValue =
+ [self->_configContent.activeConfig[self->_FIRNamespace] countByEnumeratingWithState:state
+ objects:stackbuf
+ count:len];
+ });
+ return localValue;
+}
+
+#pragma mark - Properties
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-property-ivar"
+/// Last fetch completion time.
+- (NSDate *)lastFetchTime {
+ __block NSDate *fetchTime;
+ dispatch_sync(_queue, ^{
+ NSTimeInterval lastFetchTime = self->_settings.lastFetchTimeInterval;
+ fetchTime = [NSDate dateWithTimeIntervalSince1970:lastFetchTime];
+ });
+ return fetchTime;
+}
+#pragma clang diagnostic pop
+
+- (FIRRemoteConfigFetchStatus)lastFetchStatus {
+ __block FIRRemoteConfigFetchStatus currentStatus;
+ dispatch_sync(_queue, ^{
+ currentStatus = self->_settings.lastFetchStatus;
+ });
+ return currentStatus;
+}
+
+- (NSArray *)allKeysFromSource:(FIRRemoteConfigSource)source {
+ return [self allKeysFromSource:source namespace:_FIRNamespace];
+}
+
+- (NSArray *)allKeysFromSource:(FIRRemoteConfigSource)source namespace:(NSString *)aNamespace {
+ __block NSArray *keys = [[NSArray alloc] init];
+ dispatch_sync(_queue, ^{
+ if (!aNamespace) {
+ return;
+ }
+ NSString *FQNamespace = [self fullyQualifiedNamespace:aNamespace];
+ switch (source) {
+ case FIRRemoteConfigSourceDefault:
+ if (self->_configContent.defaultConfig[FQNamespace]) {
+ keys = [[self->_configContent.defaultConfig[FQNamespace] allKeys] copy];
+ }
+ break;
+ case FIRRemoteConfigSourceRemote:
+ if (self->_configContent.activeConfig[FQNamespace]) {
+ keys = [[self->_configContent.activeConfig[FQNamespace] allKeys] copy];
+ }
+ break;
+ default:
+ break;
+ }
+ });
+ return keys;
+}
+
+- (nonnull NSSet *)keysWithPrefix:(nullable NSString *)prefix {
+ return [self keysWithPrefix:prefix namespace:_FIRNamespace];
+}
+
+- (nonnull NSSet *)keysWithPrefix:(nullable NSString *)prefix
+ namespace:(nullable NSString *)aNamespace {
+ __block NSMutableSet *keys = [[NSMutableSet alloc] init];
+ __block NSString *namespaceToCheck = aNamespace;
+ dispatch_sync(_queue, ^{
+ if (!namespaceToCheck.length) {
+ return;
+ }
+ NSString *FQNamespace = [self fullyQualifiedNamespace:namespaceToCheck];
+ if (self->_configContent.activeConfig[FQNamespace]) {
+ NSArray *allKeys = [self->_configContent.activeConfig[FQNamespace] allKeys];
+ if (!prefix.length) {
+ keys = [NSMutableSet setWithArray:allKeys];
+ } else {
+ for (NSString *key in allKeys) {
+ if ([key hasPrefix:prefix]) {
+ [keys addObject:key];
+ }
+ }
+ }
+ }
+ });
+ return [keys copy];
+}
+
+#pragma mark - Defaults
+
+- (void)setDefaults:(NSDictionary<NSString *, NSObject *> *)defaults {
+ [self setDefaults:defaults namespace:_FIRNamespace];
+}
+
+- (void)setDefaults:(NSDictionary<NSString *, NSObject *> *)defaultConfig
+ namespace:(NSString *)aNamespace {
+ if (!aNamespace) {
+ FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000036", @"The namespace cannot be empty or nil.");
+ return;
+ }
+ NSString *FQNamespace = [self fullyQualifiedNamespace:aNamespace];
+ NSDictionary *defaultConfigCopy = [[NSDictionary alloc] init];
+ if (defaultConfig) {
+ defaultConfigCopy = [defaultConfig copy];
+ }
+ void (^setDefaultsBlock)(void) = ^(void) {
+ NSDictionary *namespaceToDefaults = @{FQNamespace : defaultConfigCopy};
+ [self->_configContent copyFromDictionary:namespaceToDefaults
+ toSource:RCNDBSourceDefault
+ forNamespace:FQNamespace];
+ self->_settings.lastSetDefaultsTimeInterval = [[NSDate date] timeIntervalSince1970];
+ };
+ dispatch_async(_queue, setDefaultsBlock);
+}
+
+- (FIRRemoteConfigValue *)defaultValueForKey:(NSString *)key {
+ return [self defaultValueForKey:key namespace:_FIRNamespace];
+}
+
+- (FIRRemoteConfigValue *)defaultValueForKey:(NSString *)key namespace:(NSString *)aNamespace {
+ if (!key || !aNamespace) {
+ return nil;
+ }
+ NSString *FQNamespace = [self fullyQualifiedNamespace:aNamespace];
+ __block FIRRemoteConfigValue *value;
+ dispatch_sync(_queue, ^{
+ NSDictionary *defaultConfig = self->_configContent.defaultConfig;
+ value = defaultConfig[FQNamespace][key];
+ if (value) {
+ if (value.source != FIRRemoteConfigSourceDefault) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000002",
+ @"Key %@ should come from source:%zd instead coming from source: %zd", key,
+ (long)FIRRemoteConfigSourceDefault, (long)value.source);
+ }
+ }
+ });
+ return value;
+}
+
+- (void)setDefaultsFromPlistFileName:(nullable NSString *)fileName {
+ return [self setDefaultsFromPlistFileName:fileName namespace:_FIRNamespace];
+}
+
+- (void)setDefaultsFromPlistFileName:(nullable NSString *)fileName
+ namespace:(nullable NSString *)namespace {
+ if (!namespace || namespace.length == 0) {
+ FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000036", @"The namespace cannot be empty or nil.");
+ return;
+ }
+ NSString *FQNamespace = [self fullyQualifiedNamespace:namespace];
+ if (!fileName || fileName.length == 0) {
+ FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000037",
+ @"The plist file '%@' could not be found by Remote Config.", fileName);
+ return;
+ }
+ NSArray *bundles = @[ [NSBundle mainBundle], [NSBundle bundleForClass:[self class]] ];
+
+ for (NSBundle *bundle in bundles) {
+ NSString *plistFile = [bundle pathForResource:fileName ofType:@"plist"];
+ // Use the first one we find.
+ if (plistFile) {
+ NSDictionary *defaultConfig = [[NSDictionary alloc] initWithContentsOfFile:plistFile];
+ if (defaultConfig) {
+ [self setDefaults:defaultConfig namespace:FQNamespace];
+ }
+ return;
+ }
+ }
+ FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000037",
+ @"The plist file '%@' could not be found by Remote Config.", fileName);
+}
+
+#pragma mark - custom variables
+
+- (FIRRemoteConfigSettings *)configSettings {
+ __block BOOL developerModeEnabled = NO;
+ __block NSTimeInterval minimumFetchInterval = RCNDefaultMinimumFetchInterval;
+ __block NSTimeInterval fetchTimeout = RCNHTTPDefaultConnectionTimeout;
+ dispatch_sync(_queue, ^{
+ developerModeEnabled = [self->_settings.customVariables[kRemoteConfigDeveloperKey] boolValue];
+ minimumFetchInterval = self->_settings.minimumFetchInterval;
+ fetchTimeout = self->_settings.fetchTimeout;
+ });
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000066",
+ @"Successfully read configSettings. Developer Mode: %@, Minimum Fetch Interval:%f, "
+ @"Fetch timeout: %f",
+ developerModeEnabled ? @"true" : @"false", minimumFetchInterval, fetchTimeout);
+ FIRRemoteConfigSettings *settings =
+ [[FIRRemoteConfigSettings alloc] initWithDeveloperModeEnabled:developerModeEnabled];
+ settings.minimumFetchInterval = minimumFetchInterval;
+ settings.fetchTimeout = fetchTimeout;
+ /// The NSURLSession needs to be recreated whenever the fetch timeout may be updated.
+ [_configFetch recreateNetworkSession];
+ return settings;
+}
+
+- (void)setConfigSettings:(FIRRemoteConfigSettings *)configSettings {
+ void (^setConfigSettingsBlock)(void) = ^(void) {
+ if (!configSettings) {
+ return;
+ }
+
+ NSDictionary *settingsToSave = @{
+ kRemoteConfigDeveloperKey : @(configSettings.isDeveloperModeEnabled),
+ };
+ self->_settings.customVariables = settingsToSave;
+ self->_settings.minimumFetchInterval = configSettings.minimumFetchInterval;
+ self->_settings.fetchTimeout = configSettings.fetchTimeout;
+ /// The NSURLSession needs to be recreated whenever the fetch timeout may be updated.
+ [self->_configFetch recreateNetworkSession];
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000067",
+ @"Successfully set configSettings. Developer Mode: %@, Minimum Fetch Interval:%f, "
+ @"Fetch timeout:%f",
+ configSettings.isDeveloperModeEnabled ? @"true" : @"false",
+ configSettings.minimumFetchInterval, configSettings.fetchTimeout);
+ };
+ dispatch_async(_queue, setConfigSettingsBlock);
+}
+
+#pragma clang diagnostic push // "-Wdeprecated-declarations"
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h
new file mode 100644
index 00000000..f31d5c4e
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h
@@ -0,0 +1,58 @@
+/*
+ * 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>
+
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
+
+@class FIRApp;
+@class FIRRemoteConfig;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Provides and creates instances of Remote Config based on the namespace provided. Used in the
+/// interop registration process to keep track of RC instances for each `FIRApp` instance.
+@protocol FIRRemoteConfigProvider
+
+/// Cached instances of Remote Config objects.
+@property(nonatomic, strong) NSMutableDictionary<NSString *, FIRRemoteConfig *> *instances;
+
+/// Default method for retrieving a Remote Config instance, or creating one if it doesn't exist.
+- (FIRRemoteConfig *)remoteConfigForNamespace:(NSString *)remoteConfigNamespace;
+
+@end
+
+/// A concrete implementation for FIRRemoteConfigInterop to create Remote Config instances and
+/// register with Core's component system.
+@interface FIRRemoteConfigComponent : NSObject <FIRRemoteConfigProvider, FIRLibrary>
+
+/// The FIRApp that instances will be set up with.
+@property(nonatomic, weak, readonly) FIRApp *app;
+
+/// Cached instances of Remote Config objects.
+@property(nonatomic, strong) NSMutableDictionary<NSString *, FIRRemoteConfig *> *instances;
+
+/// Default method for retrieving a Remote Config instance, or creating one if it doesn't exist.
+- (FIRRemoteConfig *)remoteConfigForNamespace:(NSString *)remoteConfigNamespace;
+
+/// Default initializer.
+- (instancetype)initWithApp:(FIRApp *)app NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init __attribute__((unavailable("Use `initWithApp:`.")));
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.m
new file mode 100644
index 00000000..b82c13dc
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.m
@@ -0,0 +1,117 @@
+/*
+ * 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 "FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h"
+
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
+#import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
+#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
+
+#ifndef FIRRemoteConfig_VERSION
+#error "FIRRemoteConfig_VERSION is not defined: \
+add -DFIRRemoteConfig_VERSION=... to the build invocation"
+#endif
+
+#define STR(x) STR_EXPAND(x)
+#define STR_EXPAND(x) #x
+
+@implementation FIRRemoteConfigComponent
+
+/// Default method for retrieving a Remote Config instance, or creating one if it doesn't exist.
+- (FIRRemoteConfig *)remoteConfigForNamespace:(NSString *)remoteConfigNamespace {
+ if (!remoteConfigNamespace) {
+ // TODO: Throw an error? Return nil? What do we want to do?
+ return nil;
+ }
+
+ // Validate the required information is available.
+ FIROptions *options = self.app.options;
+ NSString *errorPropertyName;
+ if (options.googleAppID.length == 0) {
+ errorPropertyName = @"googleAppID";
+ } else if (options.GCMSenderID.length == 0) {
+ errorPropertyName = @"GCMSenderID";
+ }
+
+ if (errorPropertyName) {
+ [NSException
+ raise:kFirebaseConfigErrorDomain
+ format:@"%@",
+ [NSString
+ stringWithFormat:
+ @"Firebase Remote Config is missing the required %@ property from the "
+ @"configured FirebaseApp and will not be able to function properly. Please "
+ @"fix this issue to ensure that Firebase is correctly configured.",
+ errorPropertyName]];
+ }
+
+ FIRRemoteConfig *instance = self.instances[remoteConfigNamespace];
+ if (!instance) {
+ FIRApp *app = self.app;
+ id<FIRAnalyticsInterop> analytics =
+ app.isDefaultApp ? FIR_COMPONENT(FIRAnalyticsInterop, app.container) : nil;
+ instance = [[FIRRemoteConfig alloc] initWithAppName:app.name
+ FIROptions:app.options
+ namespace:remoteConfigNamespace
+ DBManager:[RCNConfigDBManager sharedInstance]
+ configContent:[RCNConfigContent sharedInstance]
+ analytics:analytics];
+ self.instances[remoteConfigNamespace] = instance;
+ }
+
+ return instance;
+}
+
+/// Default initializer.
+- (instancetype)initWithApp:(FIRApp *)app {
+ self = [super init];
+ if (self) {
+ _app = app;
+ _instances = [[NSMutableDictionary alloc] initWithCapacity:1];
+ }
+ return self;
+}
+
+#pragma mark - Lifecycle
+
++ (void)load {
+ // Register as an internal library to be part of the initialization process. The name comes from
+ // go/firebase-sdk-platform-info.
+ [FIRApp registerInternalLibrary:self
+ withName:@"fire-rc"
+ withVersion:[NSString stringWithUTF8String:STR(FIRRemoteConfig_VERSION)]];
+}
+
+#pragma mark - Interoperability
+
++ (NSArray<FIRComponent *> *)componentsToRegister {
+ FIRDependency *analyticsDep = [FIRDependency dependencyWithProtocol:@protocol(FIRAnalyticsInterop)
+ isRequired:NO];
+ FIRComponent *rcProvider = [FIRComponent
+ componentWithProtocol:@protocol(FIRRemoteConfigProvider)
+ instantiationTiming:FIRInstantiationTimingAlwaysEager
+ dependencies:@[ analyticsDep ]
+ creationBlock:^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) {
+ // Cache the component so instances of Remote Config are cached.
+ *isCacheable = YES;
+ return [[FIRRemoteConfigComponent alloc] initWithApp:container.app];
+ }];
+ return @[ rcProvider ];
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h
new file mode 100644
index 00000000..8c58d852
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h
@@ -0,0 +1,75 @@
+/*
+ * 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 <FirebaseRemoteConfig/FIRRemoteConfig.h>
+
+#import <FirebaseRemoteConfig/RCNConfigFetch.h>
+#import <FirebaseRemoteConfig/RCNConfigSettings.h>
+#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
+
+@class FIROptions;
+@class RCNConfigContent;
+@class RCNConfigDBManager;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class RCNConfigSettings;
+
+@interface FIRRemoteConfig () {
+ NSString *_FIRNamespace;
+}
+
+/// Internal settings
+@property(nonatomic, readonly, strong) RCNConfigSettings *settings;
+
+/// Config settings are custom settings.
+@property(nonatomic, readwrite, strong, nonnull) RCNConfigFetch *configFetch;
+
+/// Returns the FIRRemoteConfig instance for your namespace and for the default Firebase App.
+/// This singleton object contains the complete set of Remote Config parameter values available to
+/// the app, including the Active Config and Default Config.. This object also caches values fetched
+/// from the Remote Config Server until they are copied to the Active Config by calling
+/// activateFetched. When you fetch values from the Remote Config Server using the default Firebase
+/// namespace service, you should use this class method to create a shared instance of the
+/// FIRRemoteConfig object to ensure that your app will function properly with the Remote Config
+/// Server and the Firebase service. This API is used internally by 2P teams.
++ (FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *)remoteConfigNamespace
+ NS_SWIFT_NAME(remoteConfig(FIRNamespace:));
+
+/// Returns the FIRRemoteConfig instance for your namespace and for the default 3P developer's app.
+/// This singleton object contains the complete set of Remote Config parameter values available to
+/// the app, including the Active Config and Default Config. This object also caches values fetched
+/// from the Remote Config Server until they are copied to the Active Config by calling
+/// activateFetched. When you fetch values from the Remote Config Server using the default Firebase
+/// namespace service, you should use this class method to create a shared instance of the
+/// FIRRemoteConfig object to ensure that your app will function properly with the Remote Config
+/// Server and the Firebase service.
++ (FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *)remoteConfigNamespace
+ app:(FIRApp *)app
+ NS_SWIFT_NAME(remoteConfig(FIRNamespace:app:));
+
+/// Initialize a FIRRemoteConfig instance with all the required parameters directly. This exists so
+/// tests can create FIRRemoteConfig objects without needing FIRApp.
+- (instancetype)initWithAppName:(NSString *)appName
+ FIROptions:(FIROptions *)options
+ namespace:(NSString *)FIRNamespace
+ DBManager:(RCNConfigDBManager *)DBManager
+ configContent:(RCNConfigContent *)configContent
+ analytics:(nullable id<FIRAnalyticsInterop>)analytics;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h
new file mode 100644
index 00000000..00c18a11
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.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>
+
+#import <FirebaseRemoteConfig/FIRRemoteConfig.h>
+#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
+
+@class FIROptions;
+@class RCNConfigContent;
+@class RCNConfigSettings;
+@class RCNConfigExperiment;
+@class RCNConfigDBManager;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Completion handler invoked by NSSessionFetcher.
+typedef void (^RCNConfigFetcherCompletion)(NSData *data, NSURLResponse *response, NSError *error);
+
+@interface RCNConfigFetch : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/// Designated initializer
+- (instancetype)initWithContent:(RCNConfigContent *)content
+ DBManager:(RCNConfigDBManager *)DBManager
+ settings:(RCNConfigSettings *)settings
+ analytics:(nullable id<FIRAnalyticsInterop>)analytics
+ experiment:(nullable RCNConfigExperiment *)experiment
+ queue:(dispatch_queue_t)queue
+ namespace:(NSString *)firebaseNamespace
+ options:(FIROptions *)firebaseOptions NS_DESIGNATED_INITIALIZER;
+
+/// Fetches config data keyed by namespace. Completion block will be called on the main queue.
+/// @param expirationDuration Expiration duration, in seconds.
+/// @param completionHandler Callback handler.
+- (void)fetchConfigWithExpirationDuration:(NSTimeInterval)expirationDuration
+ completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler;
+
+/// Add the ability to update NSURLSession's timeout after a session has already been created.
+- (void)recreateNetworkSession;
+
+/// Provide fetchSession for tests to override.
+@property(nonatomic, readwrite, strong, nonnull) NSURLSession *fetchSession;
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h
new file mode 100644
index 00000000..0d077c55
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h
@@ -0,0 +1,123 @@
+/*
+ * 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>
+
+#import <FirebaseRemoteConfig/FIRRemoteConfig.h>
+
+@class RCNConfigDBManager;
+
+/// This internal class contains a set of variables that are unique among all the config instances.
+/// It also handles all metadata and internal metadata. This class is not thread safe and does not
+/// inherently allow for synchronized accesss. Callers are responsible for synchronization
+/// (currently using serial dispatch queues).
+@interface RCNConfigSettings : NSObject
+
+/// The time interval that config data stays fresh.
+@property(nonatomic, readwrite, assign) NSTimeInterval minimumFetchInterval;
+
+/// The timeout to set for outgoing fetch requests.
+@property(nonatomic, readwrite, assign) NSTimeInterval fetchTimeout;
+
+#pragma mark - Data required by config request.
+/// Device authentication ID required by config request.
+@property(nonatomic, copy) NSString *deviceAuthID;
+/// Secret Token required by config request.
+@property(nonatomic, copy) NSString *secretToken;
+/// Device data version of checkin information.
+@property(nonatomic, copy) NSString *deviceDataVersion;
+/// InstallationsID.
+@property(nonatomic, copy) NSString *configInstallationsIdentifier;
+/// Installations token.
+@property(nonatomic, copy) NSString *configInstallationsToken;
+
+/// A list of successful fetch timestamps in milliseconds.
+/// TODO Not used anymore. Safe to remove.
+@property(nonatomic, readonly, copy) NSArray *successFetchTimes;
+/// A list of failed fetch timestamps in milliseconds.
+@property(nonatomic, readonly, copy) NSArray *failureFetchTimes;
+/// Custom variable (aka App context digest). This is the pending custom variables request before
+/// fetching.
+@property(nonatomic, copy) NSDictionary *customVariables;
+/// Cached internal metadata from internal metadata table. It contains customized information such
+/// as HTTP connection timeout, HTTP read timeout, success/failure throttling rate and time
+/// interval. Client has the default value of each parameters, they are only saved in
+/// internalMetadata if they have been customize by developers.
+@property(nonatomic, readonly, copy) NSDictionary *internalMetadata;
+/// Device conditions since last successful fetch from the backend. Device conditions including
+/// app
+/// version, iOS version, device localte, language, GMP project ID and Game project ID. Used for
+/// determing whether to throttle.
+@property(nonatomic, readonly, copy) NSDictionary *deviceContext;
+/// Bundle Identifier
+@property(nonatomic, readonly, copy) NSString *bundleIdentifier;
+/// The time of last successful config fetch.
+@property(nonatomic, readonly, assign) NSTimeInterval lastFetchTimeInterval;
+/// Last fetch status.
+@property(nonatomic, readwrite, assign) FIRRemoteConfigFetchStatus lastFetchStatus;
+/// The reason that last fetch failed.
+@property(nonatomic, readwrite, assign) FIRRemoteConfigError lastFetchError;
+/// The time of last apply timestamp.
+@property(nonatomic, readwrite, assign) NSTimeInterval lastApplyTimeInterval;
+/// The time of last setDefaults timestamp.
+@property(nonatomic, readwrite, assign) NSTimeInterval lastSetDefaultsTimeInterval;
+/// The latest eTag value stored from the last successful response.
+@property(nonatomic, readwrite, assign) NSString *lastETag;
+/// The timestamp of the last eTag update.
+@property(nonatomic, readwrite, assign) NSTimeInterval lastETagUpdateTime;
+
+#pragma mark Throttling properties
+
+/// Throttling intervals are based on https://cloud.google.com/storage/docs/exponential-backoff
+/// Returns true if client has fetched config and has not got back from server. This is used to
+/// determine whether there is another config task infight when fetching.
+@property(atomic, readwrite, assign) BOOL isFetchInProgress;
+/// Returns the current retry interval in seconds set for exponential backoff.
+@property(nonatomic, readwrite, assign) double exponentialBackoffRetryInterval;
+/// Returns the time in seconds until the next request is allowed while in exponential backoff mode.
+@property(nonatomic, readonly, assign) NSTimeInterval exponentialBackoffThrottleEndTime;
+
+#pragma mark Throttling Methods
+
+/// Designated initializer.
+- (instancetype)initWithDatabaseManager:(RCNConfigDBManager *)manager
+ namespace:(NSString *)FIRNamespace
+ firebaseAppName:(NSString *)appName
+ googleAppID:(NSString *)googleAppID;
+
+/// Returns a fetch request with the latest device and config change.
+/// Whenever user issues a fetch api call, collect the latest request.
+/// @param userProperties User properties to set to config request.
+/// @return Config fetch request string
+- (NSString *)nextRequestWithUserProperties:(NSDictionary *)userProperties;
+
+/// Returns metadata from metadata table.
+- (NSDictionary *)loadConfigFromMetadataTable;
+
+/// Updates internal content with the latest successful config response.
+- (void)updateInternalContentWithResponse:(NSDictionary *)response;
+
+/// Updates the metadata table with the current fetch status.
+/// @param fetchSuccess True if fetch was successful.
+- (void)updateMetadataWithFetchSuccessStatus:(BOOL)fetchSuccess;
+
+/// Returns true if we are in exponential backoff mode and it is not yet the next request time.
+- (BOOL)shouldThrottle;
+
+/// Returns true if the last fetch is outside the minimum fetch interval supplied.
+- (BOOL)hasMinimumFetchIntervalElapsed:(NSTimeInterval)minimumFetchInterval;
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FIRRemoteConfig.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FIRRemoteConfig.h
new file mode 100644
index 00000000..b51847b2
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FIRRemoteConfig.h
@@ -0,0 +1,376 @@
+/*
+ * 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 FIRApp;
+
+/// The Firebase Remote Config service default namespace, to be used if the API method does not
+/// specify a different namespace. Use the default namespace if configuring from the Google Firebase
+/// service.
+extern NSString *const _Nonnull FIRNamespaceGoogleMobilePlatform NS_SWIFT_NAME(
+ NamespaceGoogleMobilePlatform);
+
+/// Key used to manage throttling in NSError user info when the refreshing of Remote Config
+/// parameter values (data) is throttled. The value of this key is the elapsed time since 1970,
+/// measured in seconds.
+extern NSString *const _Nonnull FIRRemoteConfigThrottledEndTimeInSecondsKey NS_SWIFT_NAME(
+ RemoteConfigThrottledEndTimeInSecondsKey);
+
+/// Indicates whether updated data was successfully fetched.
+typedef NS_ENUM(NSInteger, FIRRemoteConfigFetchStatus) {
+ /// Config has never been fetched.
+ FIRRemoteConfigFetchStatusNoFetchYet,
+ /// Config fetch succeeded.
+ FIRRemoteConfigFetchStatusSuccess,
+ /// Config fetch failed.
+ FIRRemoteConfigFetchStatusFailure,
+ /// Config fetch was throttled.
+ FIRRemoteConfigFetchStatusThrottled,
+} NS_SWIFT_NAME(RemoteConfigFetchStatus);
+
+/// Indicates whether updated data was successfully fetched and activated.
+typedef NS_ENUM(NSInteger, FIRRemoteConfigFetchAndActivateStatus) {
+ /// The remote fetch succeeded and fetched data was activated.
+ FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote,
+ /// The fetch and activate succeeded from already fetched but yet unexpired config data. You can
+ /// control this using minimumFetchInterval property in FIRRemoteConfigSettings.
+ FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData,
+ /// The fetch and activate failed.
+ FIRRemoteConfigFetchAndActivateStatusError
+} NS_SWIFT_NAME(RemoteConfigFetchAndActivateStatus);
+
+/// Remote Config error domain that handles errors when fetching data from the service.
+extern NSString *const _Nonnull FIRRemoteConfigErrorDomain NS_SWIFT_NAME(RemoteConfigErrorDomain);
+/// Firebase Remote Config service fetch error.
+typedef NS_ENUM(NSInteger, FIRRemoteConfigError) {
+ /// Unknown or no error.
+ FIRRemoteConfigErrorUnknown = 8001,
+ /// Frequency of fetch requests exceeds throttled limit.
+ FIRRemoteConfigErrorThrottled = 8002,
+ /// Internal error that covers all internal HTTP errors.
+ FIRRemoteConfigErrorInternalError = 8003,
+} NS_SWIFT_NAME(RemoteConfigError);
+
+/// Enumerated value that indicates the source of Remote Config data. Data can come from
+/// the Remote Config service, the DefaultConfig that is available when the app is first installed,
+/// or a static initialized value if data is not available from the service or DefaultConfig.
+typedef NS_ENUM(NSInteger, FIRRemoteConfigSource) {
+ FIRRemoteConfigSourceRemote, ///< The data source is the Remote Config service.
+ FIRRemoteConfigSourceDefault, ///< The data source is the DefaultConfig defined for this app.
+ FIRRemoteConfigSourceStatic, ///< The data doesn't exist, return a static initialized value.
+} NS_SWIFT_NAME(RemoteConfigSource);
+
+/// Completion handler invoked by fetch methods when they get a response from the server.
+///
+/// @param status Config fetching status.
+/// @param error Error message on failure.
+typedef void (^FIRRemoteConfigFetchCompletion)(FIRRemoteConfigFetchStatus status,
+ NSError *_Nullable error)
+ NS_SWIFT_NAME(RemoteConfigFetchCompletion);
+
+/// Completion handler invoked by activate method upon completion.
+/// @param error Error message on failure. Nil if activation was successful.
+typedef void (^FIRRemoteConfigActivateCompletion)(NSError *_Nullable error)
+ NS_SWIFT_NAME(RemoteConfigActivateCompletion);
+
+/// Completion handler invoked upon completion of Remote Config initialization.
+///
+/// @param initializationError nil if initialization succeeded.
+typedef void (^FIRRemoteConfigInitializationCompletion)(NSError *_Nullable initializationError)
+ NS_SWIFT_NAME(RemoteConfigInitializationCompletion);
+
+/// Completion handler invoked by the fetchAndActivate method. Used to convey status of fetch and,
+/// if successful, resultant activate call
+/// @param status Config fetching status.
+/// @param error Error message on failure of config fetch
+typedef void (^FIRRemoteConfigFetchAndActivateCompletion)(
+ FIRRemoteConfigFetchAndActivateStatus status, NSError *_Nullable error)
+ NS_SWIFT_NAME(RemoteConfigFetchAndActivateCompletion);
+
+#pragma mark - FIRRemoteConfigValue
+/// This class provides a wrapper for Remote Config parameter values, with methods to get parameter
+/// values as different data types.
+NS_SWIFT_NAME(RemoteConfigValue)
+@interface FIRRemoteConfigValue : NSObject <NSCopying>
+/// Gets the value as a string.
+@property(nonatomic, readonly, nullable) NSString *stringValue;
+/// Gets the value as a number value.
+@property(nonatomic, readonly, nullable) NSNumber *numberValue;
+/// Gets the value as a NSData object.
+@property(nonatomic, readonly, nonnull) NSData *dataValue;
+/// Gets the value as a boolean.
+@property(nonatomic, readonly) BOOL boolValue;
+/// Gets a foundation object (NSDictionary / NSArray) by parsing the value as JSON. This method uses
+/// NSJSONSerialization's JSONObjectWithData method with an options value of 0.
+@property(nonatomic, readonly, nullable) id JSONValue NS_SWIFT_NAME(jsonValue);
+/// Identifies the source of the fetched value.
+@property(nonatomic, readonly) FIRRemoteConfigSource source;
+@end
+
+#pragma mark - FIRRemoteConfigSettings
+/// Firebase Remote Config settings.
+NS_SWIFT_NAME(RemoteConfigSettings)
+@interface FIRRemoteConfigSettings : NSObject
+/// Indicates the default value in seconds to set for the minimum interval that needs to elapse
+/// before a fetch request can again be made to the Remote Config backend. After a fetch request to
+/// the backend has succeeded, no additional fetch requests to the backend will be allowed until the
+/// minimum fetch interval expires. Note that you can override this default on a per-fetch request
+/// basis using -[FIRRemoteConfig fetchWithExpirationDuration:completionHandler]. For E.g. setting
+/// the expiration duration to 0 in the fetch request will override the minimumFetchInterval and
+/// allow the request to the backend.
+@property(nonatomic, assign) NSTimeInterval minimumFetchInterval;
+/// Indicates the default value in seconds to abandon a pending fetch request made to the backend.
+/// This value is set for outgoing requests as the timeoutIntervalForRequest as well as the
+/// timeoutIntervalForResource on the NSURLSession's configuration.
+@property(nonatomic, assign) NSTimeInterval fetchTimeout;
+/// Indicates whether Developer Mode is enabled.
+@property(nonatomic, readonly) BOOL isDeveloperModeEnabled DEPRECATED_MSG_ATTRIBUTE(
+ "This no longer needs to be set during development. Refer to documentation for additional "
+ "details.");
+/// Initializes FIRRemoteConfigSettings, which is used to set properties for custom settings. To
+/// make custom settings take effect, pass the FIRRemoteConfigSettings instance to the
+/// configSettings property of FIRRemoteConfig.
+- (nonnull FIRRemoteConfigSettings *)initWithDeveloperModeEnabled:(BOOL)developerModeEnabled
+ DEPRECATED_MSG_ATTRIBUTE("This no longer needs to be set during development. Refer to "
+ "documentation for additional details.");
+@end
+
+#pragma mark - FIRRemoteConfig
+/// Firebase Remote Config class. The shared instance method +remoteConfig can be created and used
+/// to fetch, activate and read config results and set default config results.
+NS_SWIFT_NAME(RemoteConfig)
+@interface FIRRemoteConfig : NSObject <NSFastEnumeration>
+/// Last successful fetch completion time.
+@property(nonatomic, readwrite, strong, nullable) NSDate *lastFetchTime;
+/// Last fetch status. The status can be any enumerated value from FIRRemoteConfigFetchStatus.
+@property(nonatomic, readonly, assign) FIRRemoteConfigFetchStatus lastFetchStatus;
+/// Config settings are custom settings.
+@property(nonatomic, readwrite, strong, nonnull) FIRRemoteConfigSettings *configSettings;
+
+/// Returns the FIRRemoteConfig instance configured for the default Firebase app. This singleton
+/// object contains the complete set of Remote Config parameter values available to the app,
+/// including the Active Config and Default Config. This object also caches values fetched from the
+/// Remote Config Server until they are copied to the Active Config by calling activateFetched. When
+/// you fetch values from the Remote Config Server using the default Firebase namespace service, you
+/// should use this class method to create a shared instance of the FIRRemoteConfig object to ensure
+/// that your app will function properly with the Remote Config Server and the Firebase service.
++ (nonnull FIRRemoteConfig *)remoteConfig NS_SWIFT_NAME(remoteConfig());
+
+/// Returns the FIRRemoteConfig instance for your (non-default) Firebase appID. Note that Firebase
+/// analytics does not work for non-default app instances. This singleton object contains the
+/// complete set of Remote Config parameter values available to the app, including the Active Config
+/// and Default Config. This object also caches values fetched from the Remote Config Server until
+/// they are copied to the Active Config by calling activateFetched. When you fetch values from the
+/// Remote Config Server using the default Firebase namespace service, you should use this class
+/// method to create a shared instance of the FIRRemoteConfig object to ensure that your app will
+/// function properly with the Remote Config Server and the Firebase service.
++ (nonnull FIRRemoteConfig *)remoteConfigWithApp:(nonnull FIRApp *)app
+ NS_SWIFT_NAME(remoteConfig(app:));
+
+/// Unavailable. Use +remoteConfig instead.
+- (nonnull instancetype)init __attribute__((unavailable("Use +remoteConfig instead.")));
+
+/// Ensures initialization is complete and clients can begin querying for Remote Config values.
+/// @param completionHandler Initialization complete callback with error parameter.
+- (void)ensureInitializedWithCompletionHandler:
+ (void (^_Nonnull)(NSError *_Nullable initializationError))completionHandler;
+#pragma mark - Fetch
+/// Fetches Remote Config data with a callback. Call activateFetched to make fetched data available
+/// to your app.
+///
+/// Note: This method uses a Firebase Installations token to identify the app instance, and once
+/// it's called, it periodically sends data to the Firebase backend. (see
+/// `[FIRInstallations authTokenWithCompletion:]`).
+/// To stop the periodic sync, developers need to call `[FIRInstallations deleteWithCompletion:]`
+/// and avoid calling this method again.
+///
+/// @param completionHandler Fetch operation callback with status and error parameters.
+- (void)fetchWithCompletionHandler:(void (^_Nullable)(FIRRemoteConfigFetchStatus status,
+ NSError *_Nullable error))completionHandler;
+
+/// Fetches Remote Config data and sets a duration that specifies how long config data lasts.
+/// Call activateFetched to make fetched data available to your app.
+///
+/// Note: This method uses a Firebase Installations token to identify the app instance, and once
+/// it's called, it periodically sends data to the Firebase backend. (see
+/// `[FIRInstallations authTokenWithCompletion:]`).
+/// To stop the periodic sync, developers need to call `[FIRInstallations deleteWithCompletion:]`
+/// and avoid calling this method again.
+///
+/// @param expirationDuration Override the (default or optionally set minimumFetchInterval property
+/// in FIRRemoteConfigSettings) minimumFetchInterval for only the current request, in seconds.
+/// Setting a value of 0 seconds will force a fetch to the backend.
+/// @param completionHandler Fetch operation callback with status and error parameters.
+- (void)fetchWithExpirationDuration:(NSTimeInterval)expirationDuration
+ completionHandler:(void (^_Nullable)(FIRRemoteConfigFetchStatus status,
+ NSError *_Nullable error))completionHandler;
+
+/// Fetches Remote Config data and if successful, activates fetched data. Optional completion
+/// handler callback is invoked after the attempted activation of data, if the fetch call succeeded.
+///
+/// Note: This method uses a Firebase Installations token to identify the app instance, and once
+/// it's called, it periodically sends data to the Firebase backend. (see
+/// `[FIRInstallations authTokenWithCompletion:]`).
+/// To stop the periodic sync, developers need to call `[FIRInstallations deleteWithCompletion:]`
+/// and avoid calling this method again.
+///
+/// @param completionHandler Fetch operation callback with status and error parameters.
+- (void)fetchAndActivateWithCompletionHandler:
+ (void (^_Nullable)(FIRRemoteConfigFetchAndActivateStatus status,
+ NSError *_Nullable error))completionHandler;
+
+#pragma mark - Apply
+
+/// Applies Fetched Config data to the Active Config, causing updates to the behavior and appearance
+/// of the app to take effect (depending on how config data is used in the app).
+/// @param completion Activate operation callback with changed and error parameters.
+- (void)activateWithCompletion:(void (^_Nullable)(BOOL changed,
+ NSError *_Nullable error))completion;
+
+/// Applies Fetched Config data to the Active Config, causing updates to the behavior and appearance
+/// of the app to take effect (depending on how config data is used in the app).
+/// @param completionHandler Activate operation callback.
+- (void)activateWithCompletionHandler:(nullable FIRRemoteConfigActivateCompletion)completionHandler
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig activateWithCompletion:] instead.");
+
+/// This method is deprecated. Please use -[FIRRemoteConfig activateWithCompletionHandler:] instead.
+/// Applies Fetched Config data to the Active Config, causing updates to the behavior and appearance
+/// of the app to take effect (depending on how config data is used in the app).
+/// Returns true if there was a Fetched Config, and it was activated.
+/// Returns false if no Fetched Config was found, or the Fetched Config was already activated.
+- (BOOL)activateFetched DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig activate] instead.");
+
+#pragma mark - Get Config
+/// Enables access to configuration values by using object subscripting syntax.
+/// <pre>
+/// // Example:
+/// FIRRemoteConfig *config = [FIRRemoteConfig remoteConfig];
+/// FIRRemoteConfigValue *value = config[@"yourKey"];
+/// BOOL b = value.boolValue;
+/// NSNumber *number = config[@"yourKey"].numberValue;
+/// </pre>
+- (nonnull FIRRemoteConfigValue *)objectForKeyedSubscript:(nonnull NSString *)key;
+
+/// Gets the config value.
+/// @param key Config key.
+- (nonnull FIRRemoteConfigValue *)configValueForKey:(nullable NSString *)key;
+
+/// Gets the config value of a given namespace.
+/// @param key Config key.
+/// @param aNamespace Config results under a given namespace.
+- (nonnull FIRRemoteConfigValue *)configValueForKey:(nullable NSString *)key
+ namespace:(nullable NSString *)aNamespace
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig configValueForKey:] instead.");
+
+/// Gets the config value of a given namespace and a given source.
+/// @param key Config key.
+/// @param source Config value source.
+- (nonnull FIRRemoteConfigValue *)configValueForKey:(nullable NSString *)key
+ source:(FIRRemoteConfigSource)source;
+
+/// Gets the config value of a given namespace and a given source.
+/// @param key Config key.
+/// @param aNamespace Config results under a given namespace.
+/// @param source Config value source.
+- (nonnull FIRRemoteConfigValue *)configValueForKey:(nullable NSString *)key
+ namespace:(nullable NSString *)aNamespace
+ source:(FIRRemoteConfigSource)source
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig configValueForKey:source:] instead.");
+
+/// Gets all the parameter keys from a given source and a given namespace.
+///
+/// @param source The config data source.
+/// @return An array of keys under the given source and namespace.
+- (nonnull NSArray<NSString *> *)allKeysFromSource:(FIRRemoteConfigSource)source;
+
+/// Gets all the parameter keys from a given source and a given namespace.
+///
+/// @param source The config data source.
+/// @param aNamespace The config data namespace.
+/// @return An array of keys under the given source and namespace.
+- (nonnull NSArray<NSString *> *)allKeysFromSource:(FIRRemoteConfigSource)source
+ namespace:(nullable NSString *)aNamespace
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig allKeysFromSource:] instead.");
+
+/// Returns the set of parameter keys that start with the given prefix, from the default namespace
+/// in the active config.
+///
+/// @param prefix The key prefix to look for. If prefix is nil or empty, returns all the
+/// keys.
+/// @return The set of parameter keys that start with the specified prefix.
+- (nonnull NSSet<NSString *> *)keysWithPrefix:(nullable NSString *)prefix;
+
+/// Returns the set of parameter keys that start with the given prefix, from the given namespace in
+/// the active config.
+///
+/// @param prefix The key prefix to look for. If prefix is nil or empty, returns all the
+/// keys in the given namespace.
+/// @param aNamespace The namespace in which to look up the keys. If the namespace is invalid,
+/// returns an empty set.
+/// @return The set of parameter keys that start with the specified prefix.
+- (nonnull NSSet<NSString *> *)keysWithPrefix:(nullable NSString *)prefix
+ namespace:(nullable NSString *)aNamespace
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig keysWithPrefix:] instead.");
+
+#pragma mark - Defaults
+/// Sets config defaults for parameter keys and values in the default namespace config.
+/// @param defaults A dictionary mapping a NSString * key to a NSObject * value.
+- (void)setDefaults:(nullable NSDictionary<NSString *, NSObject *> *)defaults;
+
+/// Sets config defaults for parameter keys and values in the default namespace config.
+///
+/// @param defaults A dictionary mapping a NSString * key to a NSObject * value.
+/// @param aNamespace Config under a given namespace.
+- (void)setDefaults:(nullable NSDictionary<NSString *, NSObject *> *)defaults
+ namespace:(nullable NSString *)aNamespace
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig setDefaults:] instead.");
+
+/// Sets default configs from plist for default namespace;
+/// @param fileName The plist file name, with no file name extension. For example, if the plist file
+/// is defaultSamples.plist, call:
+/// [[FIRRemoteConfig remoteConfig] setDefaultsFromPlistFileName:@"defaultSamples"];
+- (void)setDefaultsFromPlistFileName:(nullable NSString *)fileName
+ NS_SWIFT_NAME(setDefaults(fromPlist:));
+
+/// Sets default configs from plist for a given namespace;
+/// @param fileName The plist file name, with no file name extension. For example, if the plist file
+/// is defaultSamples.plist, call:
+/// [[FIRRemoteConfig remoteConfig] setDefaultsFromPlistFileName:@"defaultSamples"];
+/// @param aNamespace The namespace where the default config is set.
+- (void)setDefaultsFromPlistFileName:(nullable NSString *)fileName
+ namespace:(nullable NSString *)aNamespace
+ NS_SWIFT_NAME(setDefaults(fromPlist:namespace:))
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig setDefaultsFromPlistFileName:] instead.");
+
+/// Returns the default value of a given key and a given namespace from the default config.
+///
+/// @param key The parameter key of default config.
+/// @return Returns the default value of the specified key and namespace. Returns
+/// nil if the key or namespace doesn't exist in the default config.
+- (nullable FIRRemoteConfigValue *)defaultValueForKey:(nullable NSString *)key;
+
+/// Returns the default value of a given key and a given namespace from the default config.
+///
+/// @param key The parameter key of default config.
+/// @param aNamespace The namespace of default config.
+/// @return Returns the default value of the specified key and namespace. Returns
+/// nil if the key or namespace doesn't exist in the default config.
+- (nullable FIRRemoteConfigValue *)defaultValueForKey:(nullable NSString *)key
+ namespace:(nullable NSString *)aNamespace
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig defaultValueForKey:] instead.");
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig.h
new file mode 100644
index 00000000..9ae8cea4
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig.h
@@ -0,0 +1,17 @@
+/*
+ * 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 "FIRRemoteConfig.h"
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigConstants.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigConstants.h
new file mode 100644
index 00000000..5a29aabb
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigConstants.h
@@ -0,0 +1,58 @@
+/*
+ * 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>
+
+#define RCN_SEC_PER_MIN 60
+#define RCN_MSEC_PER_SEC 1000
+
+/// Key prefix applied to all the packages (bundle IDs) in internal metadata.
+static NSString *const RCNInternalMetadataAllPackagesPrefix = @"all_packages";
+
+/// HTTP connection default timeout in seconds.
+static const NSTimeInterval RCNHTTPDefaultConnectionTimeout = 60;
+/// Default duration of how long config data lasts to stay fresh.
+static const NSTimeInterval RCNDefaultMinimumFetchInterval = 43200;
+
+/// Label for serial queue for read/write lock on ivars.
+static const char *RCNRemoteConfigQueueLabel = "com.google.GoogleConfigService.FIRRemoteConfig";
+
+/// Constants for key names in the fetch response.
+/// Key that includes an array of template entries.
+static NSString *const RCNFetchResponseKeyEntries = @"entries";
+/// Key that includes data for experiment descriptions in ABT.
+static NSString *const RCNFetchResponseKeyExperimentDescriptions = @"experimentDescriptions";
+/// Error key.
+static NSString *const RCNFetchResponseKeyError = @"error";
+/// Error code.
+static NSString *const RCNFetchResponseKeyErrorCode = @"code";
+/// Error status.
+static NSString *const RCNFetchResponseKeyErrorStatus = @"status";
+/// Error message.
+static NSString *const RCNFetchResponseKeyErrorMessage = @"message";
+/// The current state of the backend template.
+static NSString *const RCNFetchResponseKeyState = @"state";
+/// Default state (when not set).
+static NSString *const RCNFetchResponseKeyStateUnspecified = @"INSTANCE_STATE_UNSPECIFIED";
+/// Config key/value map and/or ABT experiment list differs from last fetch.
+/// TODO: Migrate to the new HTTP error codes once available in the backend. b/117182055
+static NSString *const RCNFetchResponseKeyStateUpdate = @"UPDATE";
+/// No template fetched.
+static NSString *const RCNFetchResponseKeyStateNoTemplate = @"NO_TEMPLATE";
+/// Config key/value map and ABT experiment list both match last fetch.
+static NSString *const RCNFetchResponseKeyStateNoChange = @"NO_CHANGE";
+/// Template found, but evaluates to empty (e.g. all keys omitted).
+static NSString *const RCNFetchResponseKeyStateEmptyConfig = @"EMPTY_CONFIG";
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.h
new file mode 100644
index 00000000..cc83c2eb
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.h
@@ -0,0 +1,60 @@
+/*
+ * 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>
+
+typedef NS_ENUM(NSInteger, RCNDBSource) {
+ RCNDBSourceActive,
+ RCNDBSourceDefault,
+ RCNDBSourceFetched,
+};
+
+@class RCNConfigDBManager;
+
+/// This class handles all the config content that is fetched from the server, cached in local
+/// config or persisted in database.
+@interface RCNConfigContent : NSObject
+/// Shared Singleton Instance
++ (instancetype)sharedInstance;
+
+/// Fetched config (aka pending config) data that is latest data from server that might or might
+/// not be applied.
+@property(nonatomic, readonly, copy) NSDictionary *fetchedConfig;
+/// Active config that is available to external users;
+@property(nonatomic, readonly, copy) NSDictionary *activeConfig;
+/// Local default config that is provided by external users;
+@property(nonatomic, readonly, copy) NSDictionary *defaultConfig;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/// Designated initializer;
+- (instancetype)initWithDBManager:(RCNConfigDBManager *)DBManager NS_DESIGNATED_INITIALIZER;
+
+/// Returns true if initalization succeeded.
+- (BOOL)initializationSuccessful;
+
+/// Update config content from fetch response in JSON format.
+- (void)updateConfigContentWithResponse:(NSDictionary *)response
+ forNamespace:(NSString *)FIRNamespace;
+
+/// Copy from a given dictionary to one of the data source.
+/// @param fromDictionary The data to copy from.
+/// @param source The data source to copy to(pending/active/default).
+- (void)copyFromDictionary:(NSDictionary *)fromDictionary
+ toSource:(RCNDBSource)source
+ forNamespace:(NSString *)FIRNamespace;
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.m
new file mode 100644
index 00000000..dc7c796c
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.m
@@ -0,0 +1,336 @@
+/*
+ * 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 "FirebaseRemoteConfig/Sources/RCNConfigContent.h"
+
+#import <FirebaseRemoteConfig/FIRRemoteConfig.h>
+#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigDefines.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h"
+
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
+
+@implementation RCNConfigContent {
+ /// Active config data that is currently used.
+ NSMutableDictionary *_activeConfig;
+ /// Pending config (aka Fetched config) data that is latest data from server that might or might
+ /// not be applied.
+ NSMutableDictionary *_fetchedConfig;
+ /// Default config provided by user.
+ NSMutableDictionary *_defaultConfig;
+ /// DBManager
+ RCNConfigDBManager *_DBManager;
+ /// Current bundle identifier;
+ NSString *_bundleIdentifier;
+ /// Dispatch semaphore to block all config reads until we have read from the database. This only
+ /// potentially blocks on the first read. Should be a no-wait for all subsequent reads once we
+ /// have data read into memory from the database.
+ dispatch_semaphore_t _configLoadFromDBSemaphore;
+ /// Boolean indicating if initial DB load of fetched,active and default config has succeeded.
+ BOOL _isConfigLoadFromDBCompleted;
+ /// Boolean indicating that the load from database has initiated at least once.
+ BOOL _isDatabaseLoadAlreadyInitiated;
+}
+
+/// Default timeout when waiting to read data from database.
+static const NSTimeInterval kDatabaseLoadTimeoutSecs = 30.0;
+
+/// Singleton instance of RCNConfigContent.
++ (instancetype)sharedInstance {
+ static dispatch_once_t onceToken;
+ static RCNConfigContent *sharedInstance;
+ dispatch_once(&onceToken, ^{
+ sharedInstance =
+ [[RCNConfigContent alloc] initWithDBManager:[RCNConfigDBManager sharedInstance]];
+ });
+ return sharedInstance;
+}
+
+- (instancetype)init {
+ NSAssert(NO, @"Invalid initializer.");
+ return nil;
+}
+
+/// Designated initializer
+- (instancetype)initWithDBManager:(RCNConfigDBManager *)DBManager {
+ self = [super init];
+ if (self) {
+ _activeConfig = [[NSMutableDictionary alloc] init];
+ _fetchedConfig = [[NSMutableDictionary alloc] init];
+ _defaultConfig = [[NSMutableDictionary alloc] init];
+ _bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
+ if (!_bundleIdentifier) {
+ FIRLogNotice(kFIRLoggerRemoteConfig, @"I-RCN000038",
+ @"Main bundle identifier is missing. Remote Config might not work properly.");
+ _bundleIdentifier = @"";
+ }
+ _DBManager = DBManager;
+ _configLoadFromDBSemaphore = dispatch_semaphore_create(0);
+ [self loadConfigFromMainTable];
+ }
+ return self;
+}
+
+// Blocking call that returns true/false once database load completes / times out.
+// @return Initialization status.
+- (BOOL)initializationSuccessful {
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+ BOOL isDatabaseLoadSuccessful = [self checkAndWaitForInitialDatabaseLoad];
+ return isDatabaseLoadSuccessful;
+}
+
+#pragma mark - update
+/// This function is for copying dictionary when user set up a default config or when user clicks
+/// activate. For now the DBSource can only be Active or Default.
+- (void)copyFromDictionary:(NSDictionary *)fromDict
+ toSource:(RCNDBSource)DBSource
+ forNamespace:(NSString *)FIRNamespace {
+ // Make sure database load has completed.
+ [self checkAndWaitForInitialDatabaseLoad];
+ NSMutableDictionary *toDict;
+ if (!fromDict) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000007",
+ @"The source dictionary to copy from does not exist.");
+ return;
+ }
+ FIRRemoteConfigSource source = FIRRemoteConfigSourceRemote;
+ switch (DBSource) {
+ case RCNDBSourceDefault:
+ toDict = _defaultConfig;
+ source = FIRRemoteConfigSourceDefault;
+ break;
+ case RCNDBSourceFetched:
+ FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000008",
+ @"This shouldn't happen. Destination dictionary should never be pending type.");
+ return;
+ case RCNDBSourceActive:
+ toDict = _activeConfig;
+ source = FIRRemoteConfigSourceRemote;
+ [toDict removeObjectForKey:FIRNamespace];
+ break;
+ default:
+ toDict = _activeConfig;
+ source = FIRRemoteConfigSourceRemote;
+ [toDict removeObjectForKey:FIRNamespace];
+ break;
+ }
+
+ // Completely wipe out DB first.
+ [_DBManager deleteRecordFromMainTableWithNamespace:FIRNamespace
+ bundleIdentifier:_bundleIdentifier
+ fromSource:DBSource];
+
+ toDict[FIRNamespace] = [[NSMutableDictionary alloc] init];
+ NSDictionary *config = fromDict[FIRNamespace];
+ for (NSString *key in config) {
+ if (DBSource == FIRRemoteConfigSourceDefault) {
+ NSObject *value = config[key];
+ NSData *valueData;
+ if ([value isKindOfClass:[NSData class]]) {
+ valueData = (NSData *)value;
+ } else if ([value isKindOfClass:[NSString class]]) {
+ valueData = [(NSString *)value dataUsingEncoding:NSUTF8StringEncoding];
+ } else if ([value isKindOfClass:[NSNumber class]]) {
+ NSString *strValue = [(NSNumber *)value stringValue];
+ valueData = [(NSString *)strValue dataUsingEncoding:NSUTF8StringEncoding];
+ } else if ([value isKindOfClass:[NSDate class]]) {
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
+ [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
+ NSString *strValue = [dateFormatter stringFromDate:(NSDate *)value];
+ valueData = [(NSString *)strValue dataUsingEncoding:NSUTF8StringEncoding];
+ } else {
+ continue;
+ }
+ toDict[FIRNamespace][key] = [[FIRRemoteConfigValue alloc] initWithData:valueData
+ source:source];
+ NSArray *values = @[ _bundleIdentifier, FIRNamespace, key, valueData ];
+ [self updateMainTableWithValues:values fromSource:DBSource];
+ } else {
+ FIRRemoteConfigValue *value = config[key];
+ toDict[FIRNamespace][key] = [[FIRRemoteConfigValue alloc] initWithData:value.dataValue
+ source:source];
+ NSArray *values = @[ _bundleIdentifier, FIRNamespace, key, value.dataValue ];
+ [self updateMainTableWithValues:values fromSource:DBSource];
+ }
+ }
+}
+
+- (void)updateConfigContentWithResponse:(NSDictionary *)response
+ forNamespace:(NSString *)currentNamespace {
+ // Make sure database load has completed.
+ [self checkAndWaitForInitialDatabaseLoad];
+ NSString *state = response[RCNFetchResponseKeyState];
+
+ if (!state) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000049", @"State field in fetch response is nil.");
+ return;
+ }
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000059",
+ @"Updating config content from Response for namespace:%@ with state: %@",
+ currentNamespace, response[RCNFetchResponseKeyState]);
+
+ if ([state isEqualToString:RCNFetchResponseKeyStateNoChange]) {
+ [self handleNoChangeStateForConfigNamespace:currentNamespace];
+ return;
+ }
+
+ /// Handle empty config state
+ if ([state isEqualToString:RCNFetchResponseKeyStateEmptyConfig]) {
+ [self handleEmptyConfigStateForConfigNamespace:currentNamespace];
+ return;
+ }
+
+ /// Handle no template state.
+ if ([state isEqualToString:RCNFetchResponseKeyStateNoTemplate]) {
+ [self handleNoTemplateStateForConfigNamespace:currentNamespace];
+ return;
+ }
+
+ /// Handle update state
+ if ([state isEqualToString:RCNFetchResponseKeyStateUpdate]) {
+ [self handleUpdateStateForConfigNamespace:currentNamespace
+ withEntries:response[RCNFetchResponseKeyEntries]];
+ return;
+ }
+}
+
+#pragma mark State handling
+- (void)handleNoChangeStateForConfigNamespace:(NSString *)currentNamespace {
+ if (!_fetchedConfig[currentNamespace]) {
+ _fetchedConfig[currentNamespace] = [[NSMutableDictionary alloc] init];
+ }
+}
+
+- (void)handleEmptyConfigStateForConfigNamespace:(NSString *)currentNamespace {
+ if (_fetchedConfig[currentNamespace]) {
+ [_fetchedConfig[currentNamespace] removeAllObjects];
+ } else {
+ // If namespace has empty status and it doesn't exist in _fetchedConfig, we will
+ // still add an entry for that namespace. Even if it will not be persisted in database.
+ // TODO: Add generics for all collection types.
+ _fetchedConfig[currentNamespace] = [[NSMutableDictionary alloc] init];
+ }
+ [_DBManager deleteRecordFromMainTableWithNamespace:currentNamespace
+ bundleIdentifier:_bundleIdentifier
+ fromSource:RCNDBSourceFetched];
+}
+
+- (void)handleNoTemplateStateForConfigNamespace:(NSString *)currentNamespace {
+ // Remove the namespace.
+ [_fetchedConfig removeObjectForKey:currentNamespace];
+ [_DBManager deleteRecordFromMainTableWithNamespace:currentNamespace
+ bundleIdentifier:_bundleIdentifier
+ fromSource:RCNDBSourceFetched];
+}
+- (void)handleUpdateStateForConfigNamespace:(NSString *)currentNamespace
+ withEntries:(NSDictionary *)entries {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000058", @"Update config in DB for namespace:%@",
+ currentNamespace);
+ // Clear before updating
+ [_DBManager deleteRecordFromMainTableWithNamespace:currentNamespace
+ bundleIdentifier:_bundleIdentifier
+ fromSource:RCNDBSourceFetched];
+ if ([_fetchedConfig objectForKey:currentNamespace]) {
+ [_fetchedConfig[currentNamespace] removeAllObjects];
+ } else {
+ _fetchedConfig[currentNamespace] = [[NSMutableDictionary alloc] init];
+ }
+
+ // Store the fetched config values.
+ for (NSString *key in entries) {
+ NSData *valueData = [entries[key] dataUsingEncoding:NSUTF8StringEncoding];
+ if (!valueData) {
+ continue;
+ }
+ _fetchedConfig[currentNamespace][key] =
+ [[FIRRemoteConfigValue alloc] initWithData:valueData source:FIRRemoteConfigSourceRemote];
+ NSArray *values = @[ _bundleIdentifier, currentNamespace, key, valueData ];
+ [self updateMainTableWithValues:values fromSource:RCNDBSourceFetched];
+ }
+}
+
+#pragma mark - database
+
+/// This method is only meant to be called at init time. The underlying logic will need to be
+/// revaluated if the assumption changes at a later time.
+- (void)loadConfigFromMainTable {
+ if (!_DBManager) {
+ return;
+ }
+
+ NSAssert(!_isDatabaseLoadAlreadyInitiated, @"Database load has already been initiated");
+ _isDatabaseLoadAlreadyInitiated = true;
+
+ [_DBManager
+ loadMainWithBundleIdentifier:_bundleIdentifier
+ completionHandler:^(BOOL success, NSDictionary *fetchedConfig,
+ NSDictionary *activeConfig, NSDictionary *defaultConfig) {
+ self->_fetchedConfig = [fetchedConfig mutableCopy];
+ self->_activeConfig = [activeConfig mutableCopy];
+ self->_defaultConfig = [defaultConfig mutableCopy];
+ dispatch_semaphore_signal(self->_configLoadFromDBSemaphore);
+ }];
+}
+
+/// Update the current config result to main table.
+/// @param values Values in a row to write to the table.
+/// @param source The source the config data is coming from. It determines which table to write to.
+- (void)updateMainTableWithValues:(NSArray *)values fromSource:(RCNDBSource)source {
+ [_DBManager insertMainTableWithValues:values fromSource:source completionHandler:nil];
+}
+#pragma mark - getter/setter
+- (NSDictionary *)fetchedConfig {
+ /// If this is the first time reading the fetchedConfig, we might still be reading it from the
+ /// database.
+ [self checkAndWaitForInitialDatabaseLoad];
+ return _fetchedConfig;
+}
+
+- (NSDictionary *)activeConfig {
+ /// If this is the first time reading the activeConfig, we might still be reading it from the
+ /// database.
+ [self checkAndWaitForInitialDatabaseLoad];
+ return _activeConfig;
+}
+
+- (NSDictionary *)defaultConfig {
+ /// If this is the first time reading the fetchedConfig, we might still be reading it from the
+ /// database.
+ [self checkAndWaitForInitialDatabaseLoad];
+ return _defaultConfig;
+}
+
+/// We load the database async at init time. Block all further calls to active/fetched/default
+/// configs until load is done.
+/// @return Database load completion status.
+- (BOOL)checkAndWaitForInitialDatabaseLoad {
+ /// Wait on semaphore until done. This should be a no-op for subsequent calls.
+ if (!_isConfigLoadFromDBCompleted) {
+ long result = dispatch_semaphore_wait(
+ _configLoadFromDBSemaphore,
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDatabaseLoadTimeoutSecs * NSEC_PER_SEC)));
+ if (result != 0) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000048",
+ @"Timed out waiting for fetched config to be loaded from DB");
+ return false;
+ }
+ _isConfigLoadFromDBCompleted = true;
+ }
+ return true;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h
new file mode 100644
index 00000000..540a2b78
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h
@@ -0,0 +1,121 @@
+/*
+ * 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>
+
+#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h"
+
+typedef NS_ENUM(NSInteger, RCNUpdateOption) {
+ RCNUpdateOptionApplyTime,
+ RCNUpdateOptionDefaultTime,
+ RCNUpdateOptionFetchStatus,
+};
+
+/// Column names in metadata table
+static NSString *const RCNKeyBundleIdentifier = @"bundle_identifier";
+static NSString *const RCNKeyFetchTime = @"fetch_time";
+static NSString *const RCNKeyDigestPerNamespace = @"digest_per_ns";
+static NSString *const RCNKeyDeviceContext = @"device_context";
+static NSString *const RCNKeyAppContext = @"app_context";
+static NSString *const RCNKeySuccessFetchTime = @"success_fetch_time";
+static NSString *const RCNKeyFailureFetchTime = @"failure_fetch_time";
+static NSString *const RCNKeyLastFetchStatus = @"last_fetch_status";
+static NSString *const RCNKeyLastFetchError = @"last_fetch_error";
+static NSString *const RCNKeyLastApplyTime = @"last_apply_time";
+static NSString *const RCNKeyLastSetDefaultsTime = @"last_set_defaults_time";
+
+/// Persist config data in sqlite database on device. Managing data read/write from/to database.
+@interface RCNConfigDBManager : NSObject
+/// Shared Singleton Instance
++ (instancetype)sharedInstance;
+
+/// Database Operation Completion callback.
+/// @param success Decide whether the DB operation succeeds.
+/// @param result Return operation result data.
+typedef void (^RCNDBCompletion)(BOOL success, NSDictionary *result);
+
+/// Database Load Operation Completion callback.
+/// @param success Decide whether the DB operation succeeds.
+/// @param fetchedConfig Return fetchedConfig loaded from DB
+/// @param activeConfig Return activeConfig loaded from DB
+/// @param defaultConfig Return defaultConfig loaded from DB
+typedef void (^RCNDBLoadCompletion)(BOOL success,
+ NSDictionary *fetchedConfig,
+ NSDictionary *activeConfig,
+ NSDictionary *defaultConfig);
+
+/// Returns the current version of the Remote Config database.
++ (NSString *)remoteConfigPathForDatabase;
+
+/// Load config content from main table to cached memory during app start.
+- (void)loadMainWithBundleIdentifier:(NSString *)bundleIdentifier
+ completionHandler:(RCNDBLoadCompletion)handler;
+/// Load config settings from metadata table to cached memory during app start. Config settings
+/// include success/failure fetch times, device contenxt, app context, etc.
+- (NSDictionary *)loadMetadataWithBundleIdentifier:(NSString *)bundleIdentifier;
+/// Load internal metadata from internal metadata table, such as customized HTTP connection/read
+/// timeout, throttling time interval and number limit of throttling, etc.
+/// This call needs to be blocking to ensure throttling works during apps starts.
+- (NSDictionary *)loadInternalMetadataTable;
+/// Load experiment from experiment table.
+/// @param handler The callback when reading from DB is complete.
+- (void)loadExperimentWithCompletionHandler:(RCNDBCompletion)handler;
+
+/// Insert a record in metadata table.
+/// @param columnNameToValue The column name and its value to be inserted in metadata table.
+/// @param handler The callback.
+- (void)insertMetadataTableWithValues:(NSDictionary *)columnNameToValue
+ completionHandler:(RCNDBCompletion)handler;
+/// Insert a record in main table.
+/// @param values Values to be inserted.
+- (void)insertMainTableWithValues:(NSArray *)values
+ fromSource:(RCNDBSource)source
+ completionHandler:(RCNDBCompletion)handler;
+/// Insert a record in internal metadata table.
+/// @param values Values to be inserted.
+- (void)insertInternalMetadataTableWithValues:(NSArray *)values
+ completionHandler:(RCNDBCompletion)handler;
+/// Insert exepriment data in experiment table.
+/// @param key The key of experiment data belongs to, which are defined in
+/// RCNConfigDefines.h.
+/// @param value The value that experiment.
+/// @param handler The callback.
+- (void)insertExperimentTableWithKey:(NSString *)key
+ value:(NSData *)value
+ completionHandler:(RCNDBCompletion)handler;
+
+- (void)updateMetadataWithOption:(RCNUpdateOption)option
+ values:(NSArray *)values
+ completionHandler:(RCNDBCompletion)handler;
+/// Clear the record of given namespace and package name
+/// before updating the table.
+- (void)deleteRecordFromMainTableWithNamespace:(NSString *)namespace_p
+ bundleIdentifier:(NSString *)bundleIdentifier
+ fromSource:(RCNDBSource)source;
+/// Remove all the records of given package name from metadata/internal metadata DB before updating
+/// new values from response.
+- (void)deleteRecordWithBundleIdentifier:(NSString *)bundlerIdentifier
+ isInternalDB:(BOOL)isInternalDB;
+/// Remove all the records from a config content table.
+- (void)deleteAllRecordsFromTableWithSource:(RCNDBSource)source;
+
+/// Remove all the records from experiment table with given key.
+/// @param key The key of experiment data belongs to, which are defined in RCNConfigDefines.h.
+- (void)deleteExperimentTableForKey:(NSString *)key;
+
+/// Returns true if this a new install of the Config database.
+- (BOOL)isNewDatabase;
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m
new file mode 100644
index 00000000..b3c704de
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m
@@ -0,0 +1,1045 @@
+/*
+ * 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 <sqlite3.h>
+
+#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigDefines.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h"
+
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
+
+/// Using macro for securely preprocessing string concatenation in query before runtime.
+#define RCNTableNameMain "main"
+#define RCNTableNameMainActive "main_active"
+#define RCNTableNameMainDefault "main_default"
+#define RCNTableNameMetadata "fetch_metadata"
+#define RCNTableNameInternalMetadata "internal_metadata"
+#define RCNTableNameExperiment "experiment"
+
+static BOOL gIsNewDatabase;
+/// SQLite file name in versions 0, 1 and 2.
+static NSString *const RCNDatabaseName = @"RemoteConfig.sqlite3";
+/// The application support sub-directory that the Remote Config database resides in.
+static NSString *const RCNRemoteConfigApplicationSupportSubDirectory = @"Google/RemoteConfig";
+
+/// Remote Config database path for deprecated V0 version.
+static NSString *RemoteConfigPathForOldDatabaseV0() {
+ NSArray *dirPaths =
+ NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString *docPath = dirPaths.firstObject;
+ return [docPath stringByAppendingPathComponent:RCNDatabaseName];
+}
+
+/// Remote Config database path for current database.
+static NSString *RemoteConfigPathForDatabase(void) {
+ NSArray *dirPaths =
+ NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
+ NSString *appSupportPath = dirPaths.firstObject;
+ NSArray *components =
+ @[ appSupportPath, RCNRemoteConfigApplicationSupportSubDirectory, RCNDatabaseName ];
+ return [NSString pathWithComponents:components];
+}
+
+static BOOL RemoteConfigAddSkipBackupAttributeToItemAtPath(NSString *filePathString) {
+ NSURL *URL = [NSURL fileURLWithPath:filePathString];
+ assert([[NSFileManager defaultManager] fileExistsAtPath:[URL path]]);
+
+ NSError *error = nil;
+ BOOL success = [URL setResourceValue:[NSNumber numberWithBool:YES]
+ forKey:NSURLIsExcludedFromBackupKey
+ error:&error];
+ if (!success) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000017", @"Error excluding %@ from backup %@.",
+ [URL lastPathComponent], error);
+ }
+ return success;
+}
+
+static BOOL RemoteConfigCreateFilePathIfNotExist(NSString *filePath) {
+ if (!filePath || !filePath.length) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000018",
+ @"Failed to create subdirectory for an empty file path.");
+ return NO;
+ }
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ if (![fileManager fileExistsAtPath:filePath]) {
+ gIsNewDatabase = YES;
+ NSError *error;
+ [fileManager createDirectoryAtPath:[filePath stringByDeletingLastPathComponent]
+ withIntermediateDirectories:YES
+ attributes:nil
+ error:&error];
+ if (error) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000019",
+ @"Failed to create subdirectory for database file: %@.", error);
+ return NO;
+ }
+ }
+ return YES;
+}
+
+static NSArray *RemoteConfigMetadataTableColumnsInOrder() {
+ return @[
+ RCNKeyBundleIdentifier, RCNKeyFetchTime, RCNKeyDigestPerNamespace, RCNKeyDeviceContext,
+ RCNKeyAppContext, RCNKeySuccessFetchTime, RCNKeyFailureFetchTime, RCNKeyLastFetchStatus,
+ RCNKeyLastFetchError, RCNKeyLastApplyTime, RCNKeyLastSetDefaultsTime
+ ];
+}
+
+@interface RCNConfigDBManager () {
+ /// Database storing all the config information.
+ sqlite3 *_database;
+ /// Serial queue for database read/write operations.
+ dispatch_queue_t _databaseOperationQueue;
+}
+@end
+
+@implementation RCNConfigDBManager
+
++ (instancetype)sharedInstance {
+ static dispatch_once_t onceToken;
+ static RCNConfigDBManager *sharedInstance;
+ dispatch_once(&onceToken, ^{
+ sharedInstance = [[RCNConfigDBManager alloc] init];
+ });
+ return sharedInstance;
+}
+
+/// Returns the current version of the Remote Config database.
++ (NSString *)remoteConfigPathForDatabase {
+ return RemoteConfigPathForDatabase();
+}
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ _databaseOperationQueue =
+ dispatch_queue_create("com.google.GoogleConfigService.database", DISPATCH_QUEUE_SERIAL);
+ [self createOrOpenDatabase];
+ }
+ return self;
+}
+
+#pragma mark - database
+- (void)migrateV1NamespaceToV2Namespace {
+ for (int table = 0; table < 3; table++) {
+ NSString *tableName = @"" RCNTableNameMain;
+ switch (table) {
+ case 1:
+ tableName = @"" RCNTableNameMainActive;
+ break;
+ case 2:
+ tableName = @"" RCNTableNameMainDefault;
+ break;
+ default:
+ break;
+ }
+ NSString *SQLString = [NSString
+ stringWithFormat:@"SELECT namespace FROM %@ WHERE namespace NOT LIKE '%%:%%'", tableName];
+ const char *SQL = [SQLString UTF8String];
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return;
+ }
+ NSMutableArray<NSString *> *namespaceArray = [[NSMutableArray alloc] init];
+ while (sqlite3_step(statement) == SQLITE_ROW) {
+ NSString *configNamespace =
+ [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
+ [namespaceArray addObject:configNamespace];
+ }
+ sqlite3_finalize(statement);
+
+ // Update.
+ for (NSString *namespaceToUpdate in namespaceArray) {
+ NSString *newNamespace =
+ [NSString stringWithFormat:@"%@:%@", namespaceToUpdate, kFIRDefaultAppName];
+ NSString *updateSQLString =
+ [NSString stringWithFormat:@"UPDATE %@ SET namespace = ? WHERE namespace = ?", tableName];
+ const char *updateSQL = [updateSQLString UTF8String];
+ sqlite3_stmt *updateStatement = [self prepareSQL:updateSQL];
+ if (!updateStatement) {
+ return;
+ }
+ NSArray<NSString *> *updateParams = @[ newNamespace, namespaceToUpdate ];
+ [self bindStringsToStatement:updateStatement stringArray:updateParams];
+
+ int result = sqlite3_step(updateStatement);
+ if (result != SQLITE_DONE) {
+ [self logErrorWithSQL:SQL finalizeStatement:updateStatement returnValue:NO];
+ return;
+ }
+ sqlite3_finalize(updateStatement);
+ }
+ }
+}
+
+- (void)createOrOpenDatabase {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_async(_databaseOperationQueue, ^{
+ RCNConfigDBManager *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ NSString *oldV0DBPath = RemoteConfigPathForOldDatabaseV0();
+ // Backward Compatibility
+ if ([[NSFileManager defaultManager] fileExistsAtPath:oldV0DBPath]) {
+ FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000009",
+ @"Old database V0 exists, removed it and replace with the new one.");
+ [strongSelf removeDatabase:oldV0DBPath];
+ }
+ NSString *dbPath = [RCNConfigDBManager remoteConfigPathForDatabase];
+ FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000062", @"Loading database at path %@", dbPath);
+ const char *databasePath = dbPath.UTF8String;
+
+ // Create or open database path.
+ if (!RemoteConfigCreateFilePathIfNotExist(dbPath)) {
+ return;
+ }
+ int flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FILEPROTECTION_COMPLETE |
+ SQLITE_OPEN_FULLMUTEX;
+ if (sqlite3_open_v2(databasePath, &strongSelf->_database, flags, NULL) == SQLITE_OK) {
+ // Always try to create table if not exists for backward compatibility.
+ if (![strongSelf createTableSchema]) {
+ // Remove database before fail.
+ [strongSelf removeDatabase:dbPath];
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000010", @"Failed to create table.");
+ // Create a new database if existing database file is corrupted.
+ if (!RemoteConfigCreateFilePathIfNotExist(dbPath)) {
+ return;
+ }
+ if (sqlite3_open_v2(databasePath, &strongSelf->_database, flags, NULL) == SQLITE_OK) {
+ if (![strongSelf createTableSchema]) {
+ // Remove database before fail.
+ [strongSelf removeDatabase:dbPath];
+ // If it failed again, there's nothing we can do here.
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000010", @"Failed to create table.");
+ } else {
+ // Exclude the app data used from iCloud backup.
+ RemoteConfigAddSkipBackupAttributeToItemAtPath(dbPath);
+ }
+ } else {
+ [strongSelf logDatabaseError];
+ }
+ } else {
+ // DB file already exists. Migrate any V1 namespace column entries to V2 fully qualified
+ // 'namespace:FIRApp' entries.
+ [self migrateV1NamespaceToV2Namespace];
+ // Exclude the app data used from iCloud backup.
+ RemoteConfigAddSkipBackupAttributeToItemAtPath(dbPath);
+ }
+ } else {
+ [strongSelf logDatabaseError];
+ }
+ });
+}
+
+- (BOOL)createTableSchema {
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+ static const char *createTableMain =
+ "create TABLE IF NOT EXISTS " RCNTableNameMain
+ " (_id INTEGER PRIMARY KEY, bundle_identifier TEXT, namespace TEXT, key TEXT, value BLOB)";
+
+ static const char *createTableMainActive =
+ "create TABLE IF NOT EXISTS " RCNTableNameMainActive
+ " (_id INTEGER PRIMARY KEY, bundle_identifier TEXT, namespace TEXT, key TEXT, value BLOB)";
+
+ static const char *createTableMainDefault =
+ "create TABLE IF NOT EXISTS " RCNTableNameMainDefault
+ " (_id INTEGER PRIMARY KEY, bundle_identifier TEXT, namespace TEXT, key TEXT, value BLOB)";
+
+ static const char *createTableMetadata =
+ "create TABLE IF NOT EXISTS " RCNTableNameMetadata
+ " (_id INTEGER PRIMARY KEY, bundle_identifier"
+ " TEXT, fetch_time INTEGER, digest_per_ns BLOB, device_context BLOB, app_context BLOB, "
+ "success_fetch_time BLOB, failure_fetch_time BLOB, last_fetch_status INTEGER, "
+ "last_fetch_error INTEGER, last_apply_time INTEGER, last_set_defaults_time INTEGER)";
+
+ static const char *createTableInternalMetadata =
+ "create TABLE IF NOT EXISTS " RCNTableNameInternalMetadata
+ " (_id INTEGER PRIMARY KEY, key TEXT, value BLOB)";
+
+ static const char *createTableExperiment = "create TABLE IF NOT EXISTS " RCNTableNameExperiment
+ " (_id INTEGER PRIMARY KEY, key TEXT, value BLOB)";
+
+ return [self executeQuery:createTableMain] && [self executeQuery:createTableMainActive] &&
+ [self executeQuery:createTableMainDefault] && [self executeQuery:createTableMetadata] &&
+ [self executeQuery:createTableInternalMetadata] &&
+ [self executeQuery:createTableExperiment];
+}
+
+- (void)removeDatabaseOnDatabaseQueueAtPath:(NSString *)path {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_sync(_databaseOperationQueue, ^{
+ RCNConfigDBManager *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ if (sqlite3_close(strongSelf->_database) != SQLITE_OK) {
+ [self logDatabaseError];
+ }
+ strongSelf->_database = nil;
+
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSError *error;
+ if (![fileManager removeItemAtPath:path error:&error]) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000011",
+ @"Failed to remove database at path %@ for error %@.", path, error);
+ }
+ });
+}
+
+- (void)removeDatabase:(NSString *)path {
+ if (sqlite3_close(_database) != SQLITE_OK) {
+ [self logDatabaseError];
+ }
+ _database = nil;
+
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSError *error;
+ if (![fileManager removeItemAtPath:path error:&error]) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000011",
+ @"Failed to remove database at path %@ for error %@.", path, error);
+ }
+}
+
+#pragma mark - execute
+- (BOOL)executeQuery:(const char *)SQL {
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+ char *error;
+ if (sqlite3_exec(_database, SQL, nil, nil, &error) != SQLITE_OK) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000012", @"Failed to execute query with error %s.",
+ error);
+ return NO;
+ }
+ return YES;
+}
+
+#pragma mark - insert
+- (void)insertMetadataTableWithValues:(NSDictionary *)columnNameToValue
+ completionHandler:(RCNDBCompletion)handler {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_async(_databaseOperationQueue, ^{
+ BOOL success = [weakSelf insertMetadataTableWithValues:columnNameToValue];
+ if (handler) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler(success, nil);
+ });
+ }
+ });
+}
+
+- (BOOL)insertMetadataTableWithValues:(NSDictionary *)columnNameToValue {
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+ static const char *SQL =
+ "INSERT INTO " RCNTableNameMetadata
+ " (bundle_identifier, fetch_time, digest_per_ns, device_context, "
+ "app_context, success_fetch_time, failure_fetch_time, last_fetch_status, "
+ "last_fetch_error, last_apply_time, last_set_defaults_time) values (?, ?, ?, ?, ?, "
+ "?, ?, ?, ?, ?, ?)";
+
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ [self logErrorWithSQL:SQL finalizeStatement:nil returnValue:NO];
+ return NO;
+ }
+
+ NSArray *columns = RemoteConfigMetadataTableColumnsInOrder();
+ int index = 0;
+ for (NSString *columnName in columns) {
+ if ([columnName isEqualToString:RCNKeyBundleIdentifier]) {
+ NSString *value = columnNameToValue[columnName];
+ if (![self bindStringToStatement:statement index:++index string:value]) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ } else if ([columnName isEqualToString:RCNKeyFetchTime] ||
+ [columnName isEqualToString:RCNKeyLastApplyTime] ||
+ [columnName isEqualToString:RCNKeyLastSetDefaultsTime]) {
+ double value = [columnNameToValue[columnName] doubleValue];
+ if (sqlite3_bind_double(statement, ++index, value) != SQLITE_OK) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ } else if ([columnName isEqualToString:RCNKeyLastFetchStatus] ||
+ [columnName isEqualToString:RCNKeyLastFetchError]) {
+ int value = [columnNameToValue[columnName] intValue];
+ if (sqlite3_bind_int(statement, ++index, value) != SQLITE_OK) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ } else {
+ NSData *data = columnNameToValue[columnName];
+ if (sqlite3_bind_blob(statement, ++index, data.bytes, (int)data.length, NULL) != SQLITE_OK) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ }
+ }
+ if (sqlite3_step(statement) != SQLITE_DONE) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ sqlite3_finalize(statement);
+ return YES;
+}
+
+- (void)insertMainTableWithValues:(NSArray *)values
+ fromSource:(RCNDBSource)source
+ completionHandler:(RCNDBCompletion)handler {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_async(_databaseOperationQueue, ^{
+ BOOL success = [weakSelf insertMainTableWithValues:values fromSource:source];
+ if (handler) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler(success, nil);
+ });
+ }
+ });
+}
+
+- (BOOL)insertMainTableWithValues:(NSArray *)values fromSource:(RCNDBSource)source {
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+ if (values.count != 4) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000013",
+ @"Failed to insert config record. Wrong number of give parameters, current "
+ @"number is %ld, correct number is 4.",
+ (long)values.count);
+ return NO;
+ }
+ const char *SQL = "INSERT INTO " RCNTableNameMain
+ " (bundle_identifier, namespace, key, value) values (?, ?, ?, ?)";
+ if (source == RCNDBSourceDefault) {
+ SQL = "INSERT INTO " RCNTableNameMainDefault
+ " (bundle_identifier, namespace, key, value) values (?, ?, ?, ?)";
+ } else if (source == RCNDBSourceActive) {
+ SQL = "INSERT INTO " RCNTableNameMainActive
+ " (bundle_identifier, namespace, key, value) values (?, ?, ?, ?)";
+ }
+
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return NO;
+ }
+
+ NSString *aString = values[0];
+ if (![self bindStringToStatement:statement index:1 string:aString]) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ aString = values[1];
+ if (![self bindStringToStatement:statement index:2 string:aString]) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ aString = values[2];
+ if (![self bindStringToStatement:statement index:3 string:aString]) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ NSData *blobData = values[3];
+ if (sqlite3_bind_blob(statement, 4, blobData.bytes, (int)blobData.length, NULL) != SQLITE_OK) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ if (sqlite3_step(statement) != SQLITE_DONE) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ sqlite3_finalize(statement);
+ return YES;
+}
+
+- (void)insertInternalMetadataTableWithValues:(NSArray *)values
+ completionHandler:(RCNDBCompletion)handler {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_async(_databaseOperationQueue, ^{
+ BOOL success = [weakSelf insertInternalMetadataWithValues:values];
+ if (handler) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler(success, nil);
+ });
+ }
+ });
+}
+
+- (BOOL)insertInternalMetadataWithValues:(NSArray *)values {
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+ if (values.count != 2) {
+ return NO;
+ }
+ const char *SQL =
+ "INSERT OR REPLACE INTO " RCNTableNameInternalMetadata " (key, value) values (?, ?)";
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return NO;
+ }
+ NSString *aString = values[0];
+ if (![self bindStringToStatement:statement index:1 string:aString]) {
+ [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ return NO;
+ }
+ NSData *blobData = values[1];
+ if (sqlite3_bind_blob(statement, 2, blobData.bytes, (int)blobData.length, NULL) != SQLITE_OK) {
+ [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ return NO;
+ }
+ if (sqlite3_step(statement) != SQLITE_DONE) {
+ [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ return NO;
+ }
+ sqlite3_finalize(statement);
+ return YES;
+}
+
+- (void)insertExperimentTableWithKey:(NSString *)key
+ value:(NSData *)serializedValue
+ completionHandler:(RCNDBCompletion)handler {
+ dispatch_async(_databaseOperationQueue, ^{
+ BOOL success = [self insertExperimentTableWithKey:key value:serializedValue];
+ if (handler) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler(success, nil);
+ });
+ }
+ });
+}
+
+- (BOOL)insertExperimentTableWithKey:(NSString *)key value:(NSData *)dataValue {
+ if ([key isEqualToString:@RCNExperimentTableKeyMetadata]) {
+ return [self updateExperimentMetadata:dataValue];
+ }
+
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+ const char *SQL = "INSERT INTO " RCNTableNameExperiment " (key, value) values (?, ?)";
+
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return NO;
+ }
+
+ if (![self bindStringToStatement:statement index:1 string:key]) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+
+ if (sqlite3_bind_blob(statement, 2, dataValue.bytes, (int)dataValue.length, NULL) != SQLITE_OK) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+
+ if (sqlite3_step(statement) != SQLITE_DONE) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ sqlite3_finalize(statement);
+ return YES;
+}
+
+- (BOOL)updateExperimentMetadata:(NSData *)dataValue {
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+ const char *SQL = "INSERT OR REPLACE INTO " RCNTableNameExperiment
+ " (_id, key, value) values ((SELECT _id from " RCNTableNameExperiment
+ " WHERE key = ?), ?, ?)";
+
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return NO;
+ }
+
+ if (![self bindStringToStatement:statement index:1 string:@RCNExperimentTableKeyMetadata]) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+
+ if (![self bindStringToStatement:statement index:2 string:@RCNExperimentTableKeyMetadata]) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ if (sqlite3_bind_blob(statement, 3, dataValue.bytes, (int)dataValue.length, NULL) != SQLITE_OK) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+
+ if (sqlite3_step(statement) != SQLITE_DONE) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ sqlite3_finalize(statement);
+ return YES;
+}
+
+#pragma mark - update
+
+- (void)updateMetadataWithOption:(RCNUpdateOption)option
+ values:(NSArray *)values
+ completionHandler:(RCNDBCompletion)handler {
+ dispatch_async(_databaseOperationQueue, ^{
+ BOOL success = [self updateMetadataTableWithOption:option andValues:values];
+ if (handler) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler(success, nil);
+ });
+ }
+ });
+}
+
+- (BOOL)updateMetadataTableWithOption:(RCNUpdateOption)option andValues:(NSArray *)values {
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+ static const char *SQL =
+ "UPDATE " RCNTableNameMetadata " (last_fetch_status, last_fetch_error, last_apply_time, "
+ "last_set_defaults_time) values (?, ?, ?, ?)";
+ if (option == RCNUpdateOptionFetchStatus) {
+ SQL = "UPDATE " RCNTableNameMetadata " SET last_fetch_status = ?, last_fetch_error = ?";
+ } else if (option == RCNUpdateOptionApplyTime) {
+ SQL = "UPDATE " RCNTableNameMetadata " SET last_apply_time = ?";
+ } else if (option == RCNUpdateOptionDefaultTime) {
+ SQL = "UPDATE " RCNTableNameMetadata " SET last_set_defaults_time = ?";
+ } else {
+ return NO;
+ }
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return NO;
+ }
+
+ int index = 0;
+ if ((option == RCNUpdateOptionApplyTime || option == RCNUpdateOptionDefaultTime) &&
+ values.count == 1) {
+ double value = [values[0] doubleValue];
+ if (sqlite3_bind_double(statement, ++index, value) != SQLITE_OK) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ } else if (option == RCNUpdateOptionFetchStatus && values.count == 2) {
+ int value = [values[0] intValue];
+ if (sqlite3_bind_int(statement, ++index, value) != SQLITE_OK) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ value = [values[1] intValue];
+ if (sqlite3_bind_int(statement, ++index, value) != SQLITE_OK) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ }
+ if (sqlite3_step(statement) != SQLITE_DONE) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ sqlite3_finalize(statement);
+ return YES;
+}
+#pragma mark - read from DB
+
+- (NSDictionary *)loadMetadataWithBundleIdentifier:(NSString *)bundleIdentifier {
+ __block NSDictionary *metadataTableResult;
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_sync(_databaseOperationQueue, ^{
+ metadataTableResult = [weakSelf loadMetadataTableWithBundleIdentifier:bundleIdentifier];
+ });
+ if (metadataTableResult) {
+ return metadataTableResult;
+ }
+ return [[NSDictionary alloc] init];
+}
+
+- (NSMutableDictionary *)loadMetadataTableWithBundleIdentifier:(NSString *)bundleIdentifier {
+ NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
+ const char *SQL =
+ "SELECT bundle_identifier, fetch_time, digest_per_ns, device_context, app_context, "
+ "success_fetch_time, failure_fetch_time , last_fetch_status, "
+ "last_fetch_error, last_apply_time, last_set_defaults_time FROM " RCNTableNameMetadata
+ " WHERE bundle_identifier = ?";
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return nil;
+ }
+
+ NSArray *params = @[ bundleIdentifier ];
+ [self bindStringsToStatement:statement stringArray:params];
+
+ while (sqlite3_step(statement) == SQLITE_ROW) {
+ NSString *dbBundleIdentifier =
+ [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
+
+ if (dbBundleIdentifier && ![dbBundleIdentifier isEqualToString:bundleIdentifier]) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000014",
+ @"Load Metadata from table error: Wrong package name %@, should be %@.",
+ dbBundleIdentifier, bundleIdentifier);
+ return nil;
+ }
+
+ double fetchTime = sqlite3_column_double(statement, 1);
+ NSData *digestPerNamespace = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 2)
+ length:sqlite3_column_bytes(statement, 2)];
+ NSData *deviceContext = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 3)
+ length:sqlite3_column_bytes(statement, 3)];
+ NSData *appContext = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 4)
+ length:sqlite3_column_bytes(statement, 4)];
+ NSData *successTimeDigest = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 5)
+ length:sqlite3_column_bytes(statement, 5)];
+ NSData *failureTimeDigest = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 6)
+ length:sqlite3_column_bytes(statement, 6)];
+
+ int lastFetchStatus = sqlite3_column_int(statement, 7);
+ int lastFetchFailReason = sqlite3_column_int(statement, 8);
+ double lastApplyTimestamp = sqlite3_column_double(statement, 9);
+ double lastSetDefaultsTimestamp = sqlite3_column_double(statement, 10);
+
+ NSError *error;
+ NSMutableDictionary *deviceContextDict = nil;
+ if (deviceContext) {
+ deviceContextDict = [NSJSONSerialization JSONObjectWithData:deviceContext
+ options:NSJSONReadingMutableContainers
+ error:&error];
+ }
+
+ NSMutableDictionary *appContextDict = nil;
+ if (appContext) {
+ appContextDict = [NSJSONSerialization JSONObjectWithData:appContext
+ options:NSJSONReadingMutableContainers
+ error:&error];
+ }
+
+ NSMutableDictionary<NSString *, id> *digestPerNamespaceDictionary = nil;
+ if (digestPerNamespace) {
+ digestPerNamespaceDictionary =
+ [NSJSONSerialization JSONObjectWithData:digestPerNamespace
+ options:NSJSONReadingMutableContainers
+ error:&error];
+ }
+
+ NSMutableArray *successTimes = nil;
+ if (successTimeDigest) {
+ successTimes = [NSJSONSerialization JSONObjectWithData:successTimeDigest
+ options:NSJSONReadingMutableContainers
+ error:&error];
+ }
+
+ NSMutableArray *failureTimes = nil;
+ if (failureTimeDigest) {
+ failureTimes = [NSJSONSerialization JSONObjectWithData:failureTimeDigest
+ options:NSJSONReadingMutableContainers
+ error:&error];
+ }
+
+ dict[RCNKeyBundleIdentifier] = bundleIdentifier;
+ dict[RCNKeyFetchTime] = @(fetchTime);
+ dict[RCNKeyDigestPerNamespace] = digestPerNamespaceDictionary;
+ dict[RCNKeyDeviceContext] = deviceContextDict;
+ dict[RCNKeyAppContext] = appContextDict;
+ dict[RCNKeySuccessFetchTime] = successTimes;
+ dict[RCNKeyFailureFetchTime] = failureTimes;
+ dict[RCNKeyLastFetchStatus] = @(lastFetchStatus);
+ dict[RCNKeyLastFetchError] = @(lastFetchFailReason);
+ dict[RCNKeyLastApplyTime] = @(lastApplyTimestamp);
+ dict[RCNKeyLastSetDefaultsTime] = @(lastSetDefaultsTimestamp);
+
+ break;
+ }
+ sqlite3_finalize(statement);
+ return dict;
+}
+
+- (void)loadExperimentWithCompletionHandler:(RCNDBCompletion)handler {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_async(_databaseOperationQueue, ^{
+ RCNConfigDBManager *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ NSMutableArray *experimentPayloads =
+ [strongSelf loadExperimentTableFromKey:@RCNExperimentTableKeyPayload];
+ if (!experimentPayloads) {
+ experimentPayloads = [[NSMutableArray alloc] init];
+ }
+
+ NSMutableDictionary *experimentMetadata;
+ NSMutableArray *experiments =
+ [strongSelf loadExperimentTableFromKey:@RCNExperimentTableKeyMetadata];
+ // There should be only one entry for experiment metadata.
+ if (experiments.count > 0) {
+ NSError *error;
+ experimentMetadata = [NSJSONSerialization JSONObjectWithData:experiments[0]
+ options:NSJSONReadingMutableContainers
+ error:&error];
+ }
+ if (!experimentMetadata) {
+ experimentMetadata = [[NSMutableDictionary alloc] init];
+ }
+
+ if (handler) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler(
+ YES, @{
+ @RCNExperimentTableKeyPayload : [experimentPayloads copy],
+ @RCNExperimentTableKeyMetadata : [experimentMetadata copy]
+ });
+ });
+ }
+ });
+}
+
+- (NSMutableArray<NSData *> *)loadExperimentTableFromKey:(NSString *)key {
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+
+ NSMutableArray *results = [[NSMutableArray alloc] init];
+ const char *SQL = "SELECT value FROM " RCNTableNameExperiment " WHERE key = ?";
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return nil;
+ }
+
+ NSArray *params = @[ key ];
+ [self bindStringsToStatement:statement stringArray:params];
+ NSData *experimentData;
+ while (sqlite3_step(statement) == SQLITE_ROW) {
+ experimentData = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 0)
+ length:sqlite3_column_bytes(statement, 0)];
+ if (experimentData) {
+ [results addObject:experimentData];
+ }
+ }
+
+ sqlite3_finalize(statement);
+ return results;
+}
+
+- (NSDictionary *)loadInternalMetadataTable {
+ __block NSMutableDictionary *internalMetadataTableResult;
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_sync(_databaseOperationQueue, ^{
+ internalMetadataTableResult = [weakSelf loadInternalMetadataTableInternal];
+ });
+ return internalMetadataTableResult;
+}
+
+- (NSMutableDictionary *)loadInternalMetadataTableInternal {
+ NSMutableDictionary *internalMetadata = [[NSMutableDictionary alloc] init];
+ const char *SQL = "SELECT key, value FROM " RCNTableNameInternalMetadata;
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return nil;
+ }
+
+ while (sqlite3_step(statement) == SQLITE_ROW) {
+ NSString *key = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
+
+ NSData *dataValue = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 1)
+ length:sqlite3_column_bytes(statement, 1)];
+ internalMetadata[key] = dataValue;
+ }
+ sqlite3_finalize(statement);
+ return internalMetadata;
+}
+
+/// This method is only meant to be called at init time. The underlying logic will need to be
+/// revaluated if the assumption changes at a later time.
+- (void)loadMainWithBundleIdentifier:(NSString *)bundleIdentifier
+ completionHandler:(RCNDBLoadCompletion)handler {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_async(_databaseOperationQueue, ^{
+ RCNConfigDBManager *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ __block NSDictionary *fetchedConfig =
+ [strongSelf loadMainTableWithBundleIdentifier:bundleIdentifier
+ fromSource:RCNDBSourceFetched];
+ __block NSDictionary *activeConfig =
+ [strongSelf loadMainTableWithBundleIdentifier:bundleIdentifier
+ fromSource:RCNDBSourceActive];
+ __block NSDictionary *defaultConfig =
+ [strongSelf loadMainTableWithBundleIdentifier:bundleIdentifier
+ fromSource:RCNDBSourceDefault];
+ if (handler) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ fetchedConfig = fetchedConfig ? fetchedConfig : [[NSDictionary alloc] init];
+ activeConfig = activeConfig ? activeConfig : [[NSDictionary alloc] init];
+ defaultConfig = defaultConfig ? defaultConfig : [[NSDictionary alloc] init];
+ handler(YES, fetchedConfig, activeConfig, defaultConfig);
+ });
+ }
+ });
+}
+
+- (NSMutableDictionary *)loadMainTableWithBundleIdentifier:(NSString *)bundleIdentifier
+ fromSource:(RCNDBSource)source {
+ NSMutableDictionary *namespaceToConfig = [[NSMutableDictionary alloc] init];
+ const char *SQL = "SELECT bundle_identifier, namespace, key, value FROM " RCNTableNameMain
+ " WHERE bundle_identifier = ?";
+ if (source == RCNDBSourceDefault) {
+ SQL = "SELECT bundle_identifier, namespace, key, value FROM " RCNTableNameMainDefault
+ " WHERE bundle_identifier = ?";
+ } else if (source == RCNDBSourceActive) {
+ SQL = "SELECT bundle_identifier, namespace, key, value FROM " RCNTableNameMainActive
+ " WHERE bundle_identifier = ?";
+ }
+ NSArray *params = @[ bundleIdentifier ];
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return nil;
+ }
+ [self bindStringsToStatement:statement stringArray:params];
+
+ while (sqlite3_step(statement) == SQLITE_ROW) {
+ NSString *configNamespace =
+ [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
+ NSString *key = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 2)];
+ NSData *value = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 3)
+ length:sqlite3_column_bytes(statement, 3)];
+ if (!namespaceToConfig[configNamespace]) {
+ namespaceToConfig[configNamespace] = [[NSMutableDictionary alloc] init];
+ }
+
+ if (source == RCNDBSourceDefault) {
+ namespaceToConfig[configNamespace][key] =
+ [[FIRRemoteConfigValue alloc] initWithData:value source:FIRRemoteConfigSourceDefault];
+ } else {
+ namespaceToConfig[configNamespace][key] =
+ [[FIRRemoteConfigValue alloc] initWithData:value source:FIRRemoteConfigSourceRemote];
+ }
+ }
+ sqlite3_finalize(statement);
+ return namespaceToConfig;
+}
+
+#pragma mark - delete
+- (void)deleteRecordFromMainTableWithNamespace:(NSString *)namespace_p
+ bundleIdentifier:(NSString *)bundleIdentifier
+ fromSource:(RCNDBSource)source {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_async(_databaseOperationQueue, ^{
+ RCNConfigDBManager *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ NSArray *params = @[ bundleIdentifier, namespace_p ];
+ const char *SQL =
+ "DELETE FROM " RCNTableNameMain " WHERE bundle_identifier = ? and namespace = ?";
+ if (source == RCNDBSourceDefault) {
+ SQL = "DELETE FROM " RCNTableNameMainDefault " WHERE bundle_identifier = ? and namespace = ?";
+ } else if (source == RCNDBSourceActive) {
+ SQL = "DELETE FROM " RCNTableNameMainActive " WHERE bundle_identifier = ? and namespace = ?";
+ }
+ [strongSelf executeQuery:SQL withParams:params];
+ });
+}
+
+- (void)deleteRecordWithBundleIdentifier:(NSString *)bundleIdentifier
+ isInternalDB:(BOOL)isInternalDB {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_async(_databaseOperationQueue, ^{
+ RCNConfigDBManager *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ const char *SQL = "DELETE FROM " RCNTableNameInternalMetadata " WHERE key LIKE ?";
+ if (!isInternalDB) {
+ SQL = "DELETE FROM " RCNTableNameMetadata " WHERE bundle_identifier = ?";
+ }
+ NSArray *params = @[ bundleIdentifier ];
+ [strongSelf executeQuery:SQL withParams:params];
+ });
+}
+
+- (void)deleteAllRecordsFromTableWithSource:(RCNDBSource)source {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_async(_databaseOperationQueue, ^{
+ RCNConfigDBManager *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ const char *SQL = "DELETE FROM " RCNTableNameMain;
+ if (source == RCNDBSourceDefault) {
+ SQL = "DELETE FROM " RCNTableNameMainDefault;
+ } else if (source == RCNDBSourceActive) {
+ SQL = "DELETE FROM " RCNTableNameMainActive;
+ }
+ [strongSelf executeQuery:SQL];
+ });
+}
+
+- (void)deleteExperimentTableForKey:(NSString *)key {
+ __weak RCNConfigDBManager *weakSelf = self;
+ dispatch_async(_databaseOperationQueue, ^{
+ RCNConfigDBManager *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ NSArray *params = @[ key ];
+ const char *SQL = "DELETE FROM " RCNTableNameExperiment " WHERE key = ?";
+ [strongSelf executeQuery:SQL withParams:params];
+ });
+}
+
+#pragma mark - helper
+- (BOOL)executeQuery:(const char *)SQL withParams:(NSArray *)params {
+ RCN_MUST_NOT_BE_MAIN_THREAD();
+ sqlite3_stmt *statement = [self prepareSQL:SQL];
+ if (!statement) {
+ return NO;
+ }
+
+ [self bindStringsToStatement:statement stringArray:params];
+ if (sqlite3_step(statement) != SQLITE_DONE) {
+ return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ }
+ sqlite3_finalize(statement);
+ return YES;
+}
+
+/// Params only accept TEXT format string.
+- (BOOL)bindStringsToStatement:(sqlite3_stmt *)statement stringArray:(NSArray *)array {
+ int index = 1;
+ for (NSString *param in array) {
+ if (![self bindStringToStatement:statement index:index string:param]) {
+ return [self logErrorWithSQL:nil finalizeStatement:statement returnValue:NO];
+ }
+ index++;
+ }
+ return YES;
+}
+
+- (BOOL)bindStringToStatement:(sqlite3_stmt *)statement index:(int)index string:(NSString *)value {
+ if (sqlite3_bind_text(statement, index, [value UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
+ return [self logErrorWithSQL:nil finalizeStatement:statement returnValue:NO];
+ }
+ return YES;
+}
+
+- (sqlite3_stmt *)prepareSQL:(const char *)SQL {
+ sqlite3_stmt *statement = nil;
+ if (sqlite3_prepare_v2(_database, SQL, -1, &statement, NULL) != SQLITE_OK) {
+ [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
+ return nil;
+ }
+ return statement;
+}
+
+- (NSString *)errorMessage {
+ return [NSString stringWithFormat:@"%s", sqlite3_errmsg(_database)];
+}
+
+- (int)errorCode {
+ return sqlite3_errcode(_database);
+}
+
+- (void)logDatabaseError {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000015", @"Error message: %@. Error code: %d.",
+ [self errorMessage], [self errorCode]);
+}
+
+- (BOOL)logErrorWithSQL:(const char *)SQL
+ finalizeStatement:(sqlite3_stmt *)statement
+ returnValue:(BOOL)returnValue {
+ if (SQL) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000016", @"Failed with SQL: %s.", SQL);
+ }
+ [self logDatabaseError];
+
+ if (statement) {
+ sqlite3_finalize(statement);
+ }
+
+ return returnValue;
+}
+
+- (BOOL)isNewDatabase {
+ return gIsNewDatabase;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDefines.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDefines.h
new file mode 100644
index 00000000..9181355b
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDefines.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef RCNConfigDefines_h
+#define RCNConfigDefines_h
+
+#if defined(DEBUG)
+#define RCN_MUST_NOT_BE_MAIN_THREAD() \
+ do { \
+ NSAssert(![NSThread isMainThread], @"Must not be executing on the main thread."); \
+ } while (0);
+#else
+#define RCN_MUST_NOT_BE_MAIN_THREAD() \
+ do { \
+ } while (0);
+#endif
+
+#define RCNExperimentTableKeyPayload "experiment_payload"
+#define RCNExperimentTableKeyMetadata "experiment_metadata"
+
+#endif
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.h
new file mode 100644
index 00000000..34779d42
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.h
@@ -0,0 +1,37 @@
+/*
+ * 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 FIRExperimentController;
+@class RCNConfigDBManager;
+
+/// Handles experiment information update and persistence.
+@interface RCNConfigExperiment : NSObject
+
+/// Designated initializer;
+- (instancetype)initWithDBManager:(RCNConfigDBManager *)DBManager
+ experimentController:(FIRExperimentController *)controller NS_DESIGNATED_INITIALIZER;
+
+/// Use `initWithDBManager:` instead.
+- (instancetype)init NS_UNAVAILABLE;
+
+/// Update/Persist experiment information from config fetch response.
+- (void)updateExperimentsWithResponse:(NSArray<NSDictionary<NSString *, id> *> *)response;
+
+/// Update experiments to Firebase Analytics when activateFetched happens.
+- (void)updateExperiments;
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.m
new file mode 100644
index 00000000..0c4c3cd2
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.m
@@ -0,0 +1,165 @@
+/*
+ * 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 "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h"
+
+#import <FirebaseABTesting/ABTExperimentPayload.h>
+#import <FirebaseABTesting/FIRExperimentController.h>
+#import <FirebaseABTesting/FIRLifecycleEvents.h>
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigDefines.h"
+
+static NSString *const kExperimentMetadataKeyLastStartTime = @"last_experiment_start_time";
+
+static NSString *const kServiceOrigin = @"frc";
+static NSString *const kMethodNameLatestStartTime =
+ @"latestExperimentStartTimestampBetweenTimestamp:andPayloads:";
+
+@interface RCNConfigExperiment ()
+@property(nonatomic, strong)
+ NSMutableArray<NSData *> *experimentPayloads; ///< Experiment payloads.
+@property(nonatomic, strong)
+ NSMutableDictionary<NSString *, id> *experimentMetadata; ///< Experiment metadata
+@property(nonatomic, strong) RCNConfigDBManager *DBManager; ///< Database Manager.
+@property(nonatomic, strong) FIRExperimentController *experimentController;
+@property(nonatomic, strong) NSDateFormatter *experimentStartTimeDateFormatter;
+@end
+
+@implementation RCNConfigExperiment
+/// Designated initializer
+- (instancetype)initWithDBManager:(RCNConfigDBManager *)DBManager
+ experimentController:(FIRExperimentController *)controller {
+ self = [super init];
+ if (self) {
+ _experimentPayloads = [[NSMutableArray alloc] init];
+ _experimentMetadata = [[NSMutableDictionary alloc] init];
+ _experimentStartTimeDateFormatter = [[NSDateFormatter alloc] init];
+ [_experimentStartTimeDateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
+ [_experimentStartTimeDateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
+ // Locale needs to be hardcoded. See
+ // https://developer.apple.com/library/ios/#qa/qa1480/_index.html for more details.
+ [_experimentStartTimeDateFormatter
+ setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
+ [_experimentStartTimeDateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
+
+ _DBManager = DBManager;
+ _experimentController = controller;
+ [self loadExperimentFromTable];
+ }
+ return self;
+}
+
+- (void)loadExperimentFromTable {
+ if (!_DBManager) {
+ return;
+ }
+ __weak RCNConfigExperiment *weakSelf = self;
+ RCNDBCompletion completionHandler = ^(BOOL success, NSDictionary<NSString *, id> *result) {
+ RCNConfigExperiment *strongSelf = weakSelf;
+ if (strongSelf == nil) {
+ return;
+ }
+ if (result[@RCNExperimentTableKeyPayload]) {
+ [strongSelf->_experimentPayloads removeAllObjects];
+ for (NSData *experiment in result[@RCNExperimentTableKeyPayload]) {
+ if (![NSJSONSerialization isValidJSONObject:experiment]) {
+ FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000031",
+ @"Experiment payload could not be parsed as JSON.");
+ } else {
+ [strongSelf->_experimentPayloads addObject:experiment];
+ }
+ }
+ }
+ if (result[@RCNExperimentTableKeyMetadata]) {
+ strongSelf->_experimentMetadata = [result[@RCNExperimentTableKeyMetadata] mutableCopy];
+ }
+ };
+ [_DBManager loadExperimentWithCompletionHandler:completionHandler];
+}
+
+- (void)updateExperimentsWithResponse:(NSArray<NSDictionary<NSString *, id> *> *)response {
+ // cache fetched experiment payloads.
+ [_experimentPayloads removeAllObjects];
+ [_DBManager deleteExperimentTableForKey:@RCNExperimentTableKeyPayload];
+
+ for (NSDictionary<NSString *, id> *experiment in response) {
+ NSError *error;
+ NSData *JSONPayload = [NSJSONSerialization dataWithJSONObject:experiment
+ options:kNilOptions
+ error:&error];
+ if (!JSONPayload || error) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000030",
+ @"Invalid experiment payload to be serialized.");
+ } else {
+ [_experimentPayloads addObject:JSONPayload];
+ [_DBManager insertExperimentTableWithKey:@RCNExperimentTableKeyPayload
+ value:JSONPayload
+ completionHandler:nil];
+ }
+ }
+}
+
+- (void)updateExperiments {
+ FIRLifecycleEvents *lifecycleEvent = [[FIRLifecycleEvents alloc] init];
+
+ // Get the last experiment start time prior to the latest payload.
+ NSTimeInterval lastStartTime =
+ [_experimentMetadata[kExperimentMetadataKeyLastStartTime] doubleValue];
+
+ // Update the last experiment start time with the latest payload.
+ [self updateExperimentStartTime];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ [self.experimentController
+ updateExperimentsWithServiceOrigin:kServiceOrigin
+ events:lifecycleEvent
+ policy:ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest
+ lastStartTime:lastStartTime
+ payloads:_experimentPayloads];
+#pragma clang diagnostic pop
+}
+
+- (void)updateExperimentStartTime {
+ NSTimeInterval existingLastStartTime =
+ [_experimentMetadata[kExperimentMetadataKeyLastStartTime] doubleValue];
+
+ NSTimeInterval latestStartTime =
+ [self latestStartTimeWithExistingLastStartTime:existingLastStartTime];
+
+ _experimentMetadata[kExperimentMetadataKeyLastStartTime] = @(latestStartTime);
+
+ if (![NSJSONSerialization isValidJSONObject:_experimentMetadata]) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000028",
+ @"Invalid fetched experiment metadata to be serialized.");
+ return;
+ }
+ NSError *error;
+ NSData *serializedExperimentMetadata =
+ [NSJSONSerialization dataWithJSONObject:_experimentMetadata
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+ [_DBManager insertExperimentTableWithKey:@RCNExperimentTableKeyMetadata
+ value:serializedExperimentMetadata
+ completionHandler:nil];
+}
+
+- (NSTimeInterval)latestStartTimeWithExistingLastStartTime:(NSTimeInterval)existingLastStartTime {
+ return [self.experimentController
+ latestExperimentStartTimestampBetweenTimestamp:existingLastStartTime
+ andPayloads:_experimentPayloads];
+}
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigSettings.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigSettings.m
new file mode 100644
index 00000000..46ca22bd
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigSettings.m
@@ -0,0 +1,459 @@
+/*
+ * 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 "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h"
+
+#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h"
+#import "FirebaseRemoteConfig/Sources/RCNDevice.h"
+#import "FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h"
+
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
+#import "GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h"
+
+static NSString *const kRCNGroupPrefix = @"frc.group.";
+static NSString *const kRCNUserDefaultsKeyNamelastETag = @"lastETag";
+static NSString *const kRCNUserDefaultsKeyNameLastSuccessfulFetchTime = @"lastSuccessfulFetchTime";
+static const int kRCNExponentialBackoffMinimumInterval = 60 * 2; // 2 mins.
+static const int kRCNExponentialBackoffMaximumInterval = 60 * 60 * 4; // 4 hours.
+
+@interface RCNConfigSettings () {
+ /// A list of successful fetch timestamps in seconds.
+ NSMutableArray *_successFetchTimes;
+ /// A list of failed fetch timestamps in seconds.
+ NSMutableArray *_failureFetchTimes;
+ /// Device conditions since last successful fetch from the backend. Device conditions including
+ /// app
+ /// version, iOS version, device localte, language, GMP project ID and Game project ID. Used for
+ /// determing whether to throttle.
+ NSMutableDictionary *_deviceContext;
+ /// Custom variables (aka App context digest). This is the pending custom variables request before
+ /// fetching.
+ NSMutableDictionary *_customVariables;
+ /// Cached internal metadata from internal metadata table. It contains customized information such
+ /// as HTTP connection timeout, HTTP read timeout, success/failure throttling rate and time
+ /// interval. Client has the default value of each parameters, they are only saved in
+ /// internalMetadata if they have been customize by developers.
+ NSMutableDictionary *_internalMetadata;
+ /// Last fetch status.
+ FIRRemoteConfigFetchStatus _lastFetchStatus;
+ /// Last fetch Error.
+ FIRRemoteConfigError _lastFetchError;
+ /// The time of last apply timestamp.
+ NSTimeInterval _lastApplyTimeInterval;
+ /// The time of last setDefaults timestamp.
+ NSTimeInterval _lastSetDefaultsTimeInterval;
+ /// The database manager.
+ RCNConfigDBManager *_DBManager;
+ // The namespace for this instance.
+ NSString *_FIRNamespace;
+ // The Google App ID of the configured FIRApp.
+ NSString *_googleAppID;
+ /// The user defaults manager scoped to this RC instance of FIRApp and namespace.
+ RCNUserDefaultsManager *_userDefaultsManager;
+ /// The timestamp of last eTag update.
+ NSTimeInterval _lastETagUpdateTime;
+}
+@end
+
+@implementation RCNConfigSettings
+
+- (instancetype)initWithDatabaseManager:(RCNConfigDBManager *)manager
+ namespace:(NSString *)FIRNamespace
+ firebaseAppName:(NSString *)appName
+ googleAppID:(NSString *)googleAppID {
+ self = [super init];
+ if (self) {
+ _FIRNamespace = FIRNamespace;
+ _googleAppID = googleAppID;
+ _bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
+ if (!_bundleIdentifier) {
+ FIRLogNotice(kFIRLoggerRemoteConfig, @"I-RCN000038",
+ @"Main bundle identifier is missing. Remote Config might not work properly.");
+ _bundleIdentifier = @"";
+ }
+ _minimumFetchInterval = RCNDefaultMinimumFetchInterval;
+ _deviceContext = [[NSMutableDictionary alloc] init];
+ _customVariables = [[NSMutableDictionary alloc] init];
+ _successFetchTimes = [[NSMutableArray alloc] init];
+ _failureFetchTimes = [[NSMutableArray alloc] init];
+ _DBManager = manager;
+
+ _internalMetadata = [[_DBManager loadInternalMetadataTable] mutableCopy];
+ if (!_internalMetadata) {
+ _internalMetadata = [[NSMutableDictionary alloc] init];
+ }
+ _userDefaultsManager = [[RCNUserDefaultsManager alloc] initWithAppName:appName
+ bundleID:_bundleIdentifier
+ namespace:_FIRNamespace];
+
+ // Check if the config database is new. If so, clear the configs saved in userDefaults.
+ if ([_DBManager isNewDatabase]) {
+ FIRLogNotice(kFIRLoggerRemoteConfig, @"I-RCN000072",
+ @"New config database created. Resetting user defaults.");
+ [_userDefaultsManager resetUserDefaults];
+ }
+
+ _isFetchInProgress = NO;
+ }
+ return self;
+}
+
+#pragma mark - read from / update userDefaults
+- (NSString *)lastETag {
+ return [_userDefaultsManager lastETag];
+}
+
+- (void)setLastETag:(NSString *)lastETag {
+ [self setLastETagUpdateTime:[[NSDate date] timeIntervalSince1970]];
+ [_userDefaultsManager setLastETag:lastETag];
+}
+
+- (void)setLastETagUpdateTime:(NSTimeInterval)lastETagUpdateTime {
+ [_userDefaultsManager setLastETagUpdateTime:lastETagUpdateTime];
+}
+
+- (NSTimeInterval)lastFetchTimeInterval {
+ return _userDefaultsManager.lastFetchTime;
+}
+
+- (NSTimeInterval)lastETagUpdateTime {
+ return _userDefaultsManager.lastETagUpdateTime;
+}
+
+// TODO: Update logic for app extensions as required.
+- (void)updateLastFetchTimeInterval:(NSTimeInterval)lastFetchTimeInterval {
+ _userDefaultsManager.lastFetchTime = lastFetchTimeInterval;
+}
+
+#pragma mark - load from DB
+- (NSDictionary *)loadConfigFromMetadataTable {
+ NSDictionary *metadata = [[_DBManager loadMetadataWithBundleIdentifier:_bundleIdentifier] copy];
+ if (metadata) {
+ // TODO: Remove (all metadata in general) once ready to
+ // migrate to user defaults completely.
+ if (metadata[RCNKeyDeviceContext]) {
+ self->_deviceContext = [metadata[RCNKeyDeviceContext] mutableCopy];
+ }
+ if (metadata[RCNKeyAppContext]) {
+ self->_customVariables = [metadata[RCNKeyAppContext] mutableCopy];
+ }
+ if (metadata[RCNKeySuccessFetchTime]) {
+ self->_successFetchTimes = [metadata[RCNKeySuccessFetchTime] mutableCopy];
+ }
+ if (metadata[RCNKeyFailureFetchTime]) {
+ self->_failureFetchTimes = [metadata[RCNKeyFailureFetchTime] mutableCopy];
+ }
+ if (metadata[RCNKeyLastFetchStatus]) {
+ self->_lastFetchStatus =
+ (FIRRemoteConfigFetchStatus)[metadata[RCNKeyLastFetchStatus] intValue];
+ }
+ if (metadata[RCNKeyLastFetchError]) {
+ self->_lastFetchError = (FIRRemoteConfigError)[metadata[RCNKeyLastFetchError] intValue];
+ }
+ if (metadata[RCNKeyLastApplyTime]) {
+ self->_lastApplyTimeInterval = [metadata[RCNKeyLastApplyTime] doubleValue];
+ }
+ if (metadata[RCNKeyLastFetchStatus]) {
+ self->_lastSetDefaultsTimeInterval = [metadata[RCNKeyLastSetDefaultsTime] doubleValue];
+ }
+ }
+ return metadata;
+}
+
+#pragma mark - update DB/cached
+
+// Update internal metadata content to cache and DB.
+- (void)updateInternalContentWithResponse:(NSDictionary *)response {
+ // Remove all the keys with current pakcage name.
+ [_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier isInternalDB:YES];
+
+ for (NSString *key in _internalMetadata.allKeys) {
+ if ([key hasPrefix:_bundleIdentifier]) {
+ [_internalMetadata removeObjectForKey:key];
+ }
+ }
+
+ for (NSString *entry in response) {
+ NSData *val = [response[entry] dataUsingEncoding:NSUTF8StringEncoding];
+ NSArray *values = @[ entry, val ];
+ _internalMetadata[entry] = response[entry];
+ [self updateInternalMetadataTableWithValues:values];
+ }
+}
+
+- (void)updateInternalMetadataTableWithValues:(NSArray *)values {
+ [_DBManager insertInternalMetadataTableWithValues:values completionHandler:nil];
+}
+
+/// If the last fetch was not successful, update the (exponential backoff) period that we wait until
+/// fetching again. Any subsequent fetch requests will be checked and allowed only if past this
+/// throttle end time.
+- (void)updateExponentialBackoffTime {
+ // If not in exponential backoff mode, reset the retry interval.
+ if (_lastFetchStatus == FIRRemoteConfigFetchStatusSuccess) {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000057",
+ @"Throttling: Entering exponential backoff mode.");
+ _exponentialBackoffRetryInterval = kRCNExponentialBackoffMinimumInterval;
+ } else {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000057",
+ @"Throttling: Updating throttling interval.");
+ // Double the retry interval until we hit the truncated exponential backoff. More info here:
+ // https://cloud.google.com/storage/docs/exponential-backoff
+ _exponentialBackoffRetryInterval =
+ ((_exponentialBackoffRetryInterval * 2) < kRCNExponentialBackoffMaximumInterval)
+ ? _exponentialBackoffRetryInterval * 2
+ : _exponentialBackoffRetryInterval;
+ }
+
+ // Randomize the next retry interval.
+ int randomPlusMinusInterval = ((arc4random() % 2) == 0) ? -1 : 1;
+ NSTimeInterval randomizedRetryInterval =
+ _exponentialBackoffRetryInterval +
+ (0.5 * _exponentialBackoffRetryInterval * randomPlusMinusInterval);
+ _exponentialBackoffThrottleEndTime =
+ [[NSDate date] timeIntervalSince1970] + randomizedRetryInterval;
+}
+
+- (void)updateMetadataWithFetchSuccessStatus:(BOOL)fetchSuccess {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000056", @"Updating metadata with fetch result.");
+ if (!fetchSuccess) {
+ [self updateExponentialBackoffTime];
+ }
+
+ [self updateFetchTimeWithSuccessFetch:fetchSuccess];
+ _lastFetchStatus =
+ fetchSuccess ? FIRRemoteConfigFetchStatusSuccess : FIRRemoteConfigFetchStatusFailure;
+ _lastFetchError = fetchSuccess ? FIRRemoteConfigErrorUnknown : FIRRemoteConfigErrorInternalError;
+ if (fetchSuccess) {
+ [self updateLastFetchTimeInterval:[[NSDate date] timeIntervalSince1970]];
+ // Note: We expect the googleAppID to always be available.
+ _deviceContext = FIRRemoteConfigDeviceContextWithProjectIdentifier(_googleAppID);
+ }
+
+ [self updateMetadataTable];
+}
+
+- (void)updateFetchTimeWithSuccessFetch:(BOOL)isSuccessfulFetch {
+ NSTimeInterval epochTimeInterval = [[NSDate date] timeIntervalSince1970];
+ if (isSuccessfulFetch) {
+ [_successFetchTimes addObject:@(epochTimeInterval)];
+ } else {
+ [_failureFetchTimes addObject:@(epochTimeInterval)];
+ }
+}
+
+- (void)updateMetadataTable {
+ [_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier isInternalDB:NO];
+ NSError *error;
+ // Objects to be serialized cannot be invalid.
+ if (!_bundleIdentifier) {
+ return;
+ }
+ if (![NSJSONSerialization isValidJSONObject:_customVariables]) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000028",
+ @"Invalid custom variables to be serialized.");
+ return;
+ }
+ if (![NSJSONSerialization isValidJSONObject:_deviceContext]) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000029",
+ @"Invalid device context to be serialized.");
+ return;
+ }
+
+ if (![NSJSONSerialization isValidJSONObject:_successFetchTimes]) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000031",
+ @"Invalid success fetch times to be serialized.");
+ return;
+ }
+ if (![NSJSONSerialization isValidJSONObject:_failureFetchTimes]) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000032",
+ @"Invalid failure fetch times to be serialized.");
+ return;
+ }
+ NSData *serializedAppContext = [NSJSONSerialization dataWithJSONObject:_customVariables
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+ NSData *serializedDeviceContext =
+ [NSJSONSerialization dataWithJSONObject:_deviceContext
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+ // The digestPerNamespace is not used and only meant for backwards DB compatibility.
+ NSData *serializedDigestPerNamespace =
+ [NSJSONSerialization dataWithJSONObject:@{} options:NSJSONWritingPrettyPrinted error:&error];
+ NSData *serializedSuccessTime = [NSJSONSerialization dataWithJSONObject:_successFetchTimes
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+ NSData *serializedFailureTime = [NSJSONSerialization dataWithJSONObject:_failureFetchTimes
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+
+ if (!serializedDigestPerNamespace || !serializedDeviceContext || !serializedAppContext ||
+ !serializedSuccessTime || !serializedFailureTime) {
+ return;
+ }
+
+ NSDictionary *columnNameToValue = @{
+ RCNKeyBundleIdentifier : _bundleIdentifier,
+ RCNKeyFetchTime : @(self.lastFetchTimeInterval),
+ RCNKeyDigestPerNamespace : serializedDigestPerNamespace,
+ RCNKeyDeviceContext : serializedDeviceContext,
+ RCNKeyAppContext : serializedAppContext,
+ RCNKeySuccessFetchTime : serializedSuccessTime,
+ RCNKeyFailureFetchTime : serializedFailureTime,
+ RCNKeyLastFetchStatus : [NSString stringWithFormat:@"%ld", (long)_lastFetchStatus],
+ RCNKeyLastFetchError : [NSString stringWithFormat:@"%ld", (long)_lastFetchError],
+ RCNKeyLastApplyTime : @(_lastApplyTimeInterval),
+ RCNKeyLastSetDefaultsTime : @(_lastSetDefaultsTimeInterval)
+ };
+
+ [_DBManager insertMetadataTableWithValues:columnNameToValue completionHandler:nil];
+}
+
+#pragma mark - fetch request
+
+/// Returns a fetch request with the latest device and config change.
+/// Whenever user issues a fetch api call, collect the latest request.
+- (NSString *)nextRequestWithUserProperties:(NSDictionary *)userProperties {
+ // Note: We only set user properties as mentioned in the new REST API Design doc
+ NSString *ret = [NSString stringWithFormat:@"{"];
+ ret = [ret stringByAppendingString:[NSString stringWithFormat:@"app_instance_id:'%@'",
+ _configInstallationsIdentifier]];
+ ret = [ret stringByAppendingString:[NSString stringWithFormat:@", app_instance_id_token:'%@'",
+ _configInstallationsToken]];
+ ret = [ret stringByAppendingString:[NSString stringWithFormat:@", app_id:'%@'", _googleAppID]];
+
+ ret = [ret stringByAppendingString:[NSString stringWithFormat:@", country_code:'%@'",
+ FIRRemoteConfigDeviceCountry()]];
+ ret = [ret stringByAppendingString:[NSString stringWithFormat:@", language_code:'%@'",
+ FIRRemoteConfigDeviceLocale()]];
+ ret = [ret
+ stringByAppendingString:[NSString stringWithFormat:@", platform_version:'%@'",
+ [GULAppEnvironmentUtil systemVersion]]];
+ ret = [ret stringByAppendingString:[NSString stringWithFormat:@", time_zone:'%@'",
+ FIRRemoteConfigTimezone()]];
+ ret = [ret stringByAppendingString:[NSString stringWithFormat:@", package_name:'%@'",
+ _bundleIdentifier]];
+ ret = [ret stringByAppendingString:[NSString stringWithFormat:@", app_version:'%@'",
+ FIRRemoteConfigAppVersion()]];
+ ret = [ret stringByAppendingString:[NSString stringWithFormat:@", app_build:'%@'",
+ FIRRemoteConfigAppBuildVersion()]];
+ ret = [ret stringByAppendingString:[NSString stringWithFormat:@", sdk_version:'%@'",
+ FIRRemoteConfigPodVersion()]];
+
+ if (userProperties && userProperties.count > 0) {
+ NSError *error;
+ NSData *jsonData = [NSJSONSerialization dataWithJSONObject:userProperties
+ options:0
+ error:&error];
+ if (!error) {
+ ret = [ret
+ stringByAppendingString:[NSString
+ stringWithFormat:@", analytics_user_properties:%@",
+ [[NSString alloc]
+ initWithData:jsonData
+ encoding:NSUTF8StringEncoding]]];
+ }
+ }
+ ret = [ret stringByAppendingString:@"}"];
+ return ret;
+}
+
+#pragma mark - getter/setter
+
+- (void)setLastFetchError:(FIRRemoteConfigError)lastFetchError {
+ if (_lastFetchError != lastFetchError) {
+ _lastFetchError = lastFetchError;
+ [_DBManager updateMetadataWithOption:RCNUpdateOptionFetchStatus
+ values:@[ @(_lastFetchStatus), @(_lastFetchError) ]
+ completionHandler:nil];
+ }
+}
+
+- (NSArray *)successFetchTimes {
+ return [_successFetchTimes copy];
+}
+
+- (NSArray *)failureFetchTimes {
+ return [_failureFetchTimes copy];
+}
+
+- (NSDictionary *)customVariables {
+ return [_customVariables copy];
+}
+
+- (NSDictionary *)internalMetadata {
+ return [_internalMetadata copy];
+}
+
+- (NSDictionary *)deviceContext {
+ return [_deviceContext copy];
+}
+
+- (void)setCustomVariables:(NSDictionary *)customVariables {
+ _customVariables = [[NSMutableDictionary alloc] initWithDictionary:customVariables];
+ [self updateMetadataTable];
+}
+
+- (void)setMinimumFetchInterval:(NSTimeInterval)minimumFetchInterval {
+ if (minimumFetchInterval < 0) {
+ _minimumFetchInterval = 0;
+ } else {
+ _minimumFetchInterval = minimumFetchInterval;
+ }
+}
+
+- (void)setFetchTimeout:(NSTimeInterval)fetchTimeout {
+ if (fetchTimeout <= 0) {
+ _fetchTimeout = RCNHTTPDefaultConnectionTimeout;
+ } else {
+ _fetchTimeout = fetchTimeout;
+ }
+}
+
+- (void)setLastApplyTimeInterval:(NSTimeInterval)lastApplyTimestamp {
+ _lastApplyTimeInterval = lastApplyTimestamp;
+ [_DBManager updateMetadataWithOption:RCNUpdateOptionApplyTime
+ values:@[ @(lastApplyTimestamp) ]
+ completionHandler:nil];
+}
+
+- (void)setLastSetDefaultsTimeInterval:(NSTimeInterval)lastSetDefaultsTimestamp {
+ _lastSetDefaultsTimeInterval = lastSetDefaultsTimestamp;
+ [_DBManager updateMetadataWithOption:RCNUpdateOptionDefaultTime
+ values:@[ @(lastSetDefaultsTimestamp) ]
+ completionHandler:nil];
+}
+
+#pragma mark Throttling
+
+- (BOOL)hasMinimumFetchIntervalElapsed:(NSTimeInterval)minimumFetchInterval {
+ if (self.lastFetchTimeInterval == 0) return YES;
+
+ // Check if last config fetch is within minimum fetch interval in seconds.
+ NSTimeInterval diffInSeconds = [[NSDate date] timeIntervalSince1970] - self.lastFetchTimeInterval;
+ return diffInSeconds > minimumFetchInterval;
+}
+
+- (BOOL)shouldThrottle {
+ NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
+ return ((self.lastFetchTimeInterval > 0) &&
+ (_lastFetchStatus != FIRRemoteConfigFetchStatusSuccess) &&
+ (_exponentialBackoffThrottleEndTime - now > 0));
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h
new file mode 100644
index 00000000..28d2d693
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h
@@ -0,0 +1,25 @@
+/*
+ * 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 <FirebaseRemoteConfig/FIRRemoteConfig.h>
+
+@interface FIRRemoteConfigValue ()
+@property(nonatomic, readwrite, assign) FIRRemoteConfigSource source;
+
+/// Designated initializer.
+- (instancetype)initWithData:(NSData *)data
+ source:(FIRRemoteConfigSource)source NS_DESIGNATED_INITIALIZER;
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConstants3P.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConstants3P.m
new file mode 100644
index 00000000..687d5878
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConstants3P.m
@@ -0,0 +1,20 @@
+/*
+ * 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 <FirebaseRemoteConfig/FIRRemoteConfig.h>
+
+/// Firebase Remote Config service default namespace.
+NSString *const FIRNamespaceGoogleMobilePlatform = @"firebase";
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.h
new file mode 100644
index 00000000..15697e3c
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.h
@@ -0,0 +1,57 @@
+/*
+ * 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>
+
+typedef NS_ENUM(NSInteger, RCNDeviceModel) {
+ RCNDeviceModelOther,
+ RCNDeviceModelPhone,
+ RCNDeviceModelTablet,
+ RCNDeviceModelTV,
+ RCNDeviceModelGlass,
+ RCNDeviceModelCar,
+ RCNDeviceModelWearable,
+};
+
+/// CocoaPods SDK version
+NSString *FIRRemoteConfigPodVersion(void);
+
+/// App version.
+NSString *FIRRemoteConfigAppVersion(void);
+
+/// App build version
+NSString *FIRRemoteConfigAppBuildVersion(void);
+
+/// Device country, in lowercase.
+NSString *FIRRemoteConfigDeviceCountry(void);
+
+/// Device locale, in language_country format, e.g. en_US.
+NSString *FIRRemoteConfigDeviceLocale(void);
+
+/// Device subtype.
+RCNDeviceModel FIRRemoteConfigDeviceSubtype(void);
+
+/// Device timezone.
+NSString *FIRRemoteConfigTimezone(void);
+
+/// Update device context to the given dictionary.
+NSMutableDictionary *FIRRemoteConfigDeviceContextWithProjectIdentifier(
+ NSString *GMPProjectIdentifier);
+
+/// Check whether client has changed device context, including app version,
+/// iOS version, device country etc. This is used to determine whether to throttle.
+BOOL FIRRemoteConfigHasDeviceContextChanged(NSDictionary *deviceContext,
+ NSString *GMPProjectIdentifier);
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.m
new file mode 100644
index 00000000..cc5b8c12
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.m
@@ -0,0 +1,240 @@
+/*
+ * 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 "FirebaseRemoteConfig/Sources/RCNDevice.h"
+
+#import <sys/utsname.h>
+
+#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
+#import "GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h"
+
+#define STR(x) STR_EXPAND(x)
+#define STR_EXPAND(x) #x
+
+static NSString *const RCNDeviceContextKeyVersion = @"app_version";
+static NSString *const RCNDeviceContextKeyBuild = @"app_build";
+static NSString *const RCNDeviceContextKeyOSVersion = @"os_version";
+static NSString *const RCNDeviceContextKeyDeviceLocale = @"device_locale";
+static NSString *const RCNDeviceContextKeyLocaleLanguage = @"locale_language";
+static NSString *const RCNDeviceContextKeyGMPProjectIdentifier = @"GMP_project_Identifier";
+
+NSString *FIRRemoteConfigAppVersion() {
+ return [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"];
+}
+
+NSString *FIRRemoteConfigAppBuildVersion() {
+ return [[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"];
+}
+
+NSString *FIRRemoteConfigPodVersion() {
+ return [NSString stringWithUTF8String:STR(FIRRemoteConfig_VERSION)];
+}
+
+RCNDeviceModel FIRRemoteConfigDeviceSubtype() {
+ NSString *model = [GULAppEnvironmentUtil deviceModel];
+ if ([model hasPrefix:@"iPhone"]) {
+ return RCNDeviceModelPhone;
+ }
+ if ([model isEqualToString:@"iPad"]) {
+ return RCNDeviceModelTablet;
+ }
+ return RCNDeviceModelOther;
+}
+
+NSString *FIRRemoteConfigDeviceCountry() {
+ return [[[NSLocale currentLocale] objectForKey:NSLocaleCountryCode] lowercaseString];
+}
+
+NSDictionary<NSString *, NSArray *> *FIRRemoteConfigFirebaseLocaleMap() {
+ return @{
+ // Albanian
+ @"sq" : @[ @"sq_AL" ],
+ // Belarusian
+ @"be" : @[ @"be_BY" ],
+ // Bulgarian
+ @"bg" : @[ @"bg_BG" ],
+ // Catalan
+ @"ca" : @[ @"ca", @"ca_ES" ],
+ // Croatian
+ @"hr" : @[ @"hr", @"hr_HR" ],
+ // Czech
+ @"cs" : @[ @"cs", @"cs_CZ" ],
+ // Danish
+ @"da" : @[ @"da", @"da_DK" ],
+ // Estonian
+ @"et" : @[ @"et_EE" ],
+ // Finnish
+ @"fi" : @[ @"fi", @"fi_FI" ],
+ // Hebrew
+ @"he" : @[ @"he", @"iw_IL" ],
+ // Hindi
+ @"hi" : @[ @"hi_IN" ],
+ // Hungarian
+ @"hu" : @[ @"hu", @"hu_HU" ],
+ // Icelandic
+ @"is" : @[ @"is_IS" ],
+ // Indonesian
+ @"id" : @[ @"id", @"in_ID", @"id_ID" ],
+ // Irish
+ @"ga" : @[ @"ga_IE" ],
+ // Korean
+ @"ko" : @[ @"ko", @"ko_KR", @"ko-KR" ],
+ // Latvian
+ @"lv" : @[ @"lv_LV" ],
+ // Lithuanian
+ @"lt" : @[ @"lt_LT" ],
+ // Macedonian
+ @"mk" : @[ @"mk_MK" ],
+ // Malay
+ @"ms" : @[ @"ms_MY" ],
+ // Maltese
+ @"mt" : @[ @"mt_MT" ],
+ // Polish
+ @"pl" : @[ @"pl", @"pl_PL", @"pl-PL" ],
+ // Romanian
+ @"ro" : @[ @"ro", @"ro_RO" ],
+ // Russian
+ @"ru" : @[ @"ru_RU", @"ru", @"ru_BY", @"ru_KZ", @"ru-RU" ],
+ // Slovak
+ @"sk" : @[ @"sk", @"sk_SK" ],
+ // Slovenian
+ @"sl" : @[ @"sl_SI" ],
+ // Swedish
+ @"sv" : @[ @"sv", @"sv_SE", @"sv-SE" ],
+ // Turkish
+ @"tr" : @[ @"tr", @"tr-TR", @"tr_TR" ],
+ // Ukrainian
+ @"uk" : @[ @"uk", @"uk_UA" ],
+ // Vietnamese
+ @"vi" : @[ @"vi", @"vi_VN" ],
+ // The following are groups of locales or locales that sub-divide a
+ // language).
+ // Arabic
+ @"ar" : @[
+ @"ar", @"ar_DZ", @"ar_BH", @"ar_EG", @"ar_IQ", @"ar_JO", @"ar_KW",
+ @"ar_LB", @"ar_LY", @"ar_MA", @"ar_OM", @"ar_QA", @"ar_SA", @"ar_SD",
+ @"ar_SY", @"ar_TN", @"ar_AE", @"ar_YE", @"ar_GB", @"ar-IQ", @"ar_US"
+ ],
+ // Simplified Chinese
+ @"zh_Hans" : @[ @"zh_CN", @"zh_SG", @"zh-Hans" ],
+ // Traditional Chinese
+ // Remove zh_HK until console added to the list. Otherwise client sends
+ // zh_HK and server/console falls back to zh.
+ // @"zh_Hant" : @[ @"zh_HK", @"zh_TW", @"zh-Hant", @"zh-HK", @"zh-TW" ],
+ @"zh_Hant" : @[ @"zh_TW", @"zh-Hant", @"zh-TW" ],
+ // Dutch
+ @"nl" : @[ @"nl", @"nl_BE", @"nl_NL", @"nl-NL" ],
+ // English
+ @"en" : @[
+ @"en", @"en_AU", @"en_CA", @"en_IN", @"en_IE", @"en_MT", @"en_NZ", @"en_PH",
+ @"en_SG", @"en_ZA", @"en_GB", @"en_US", @"en_AE", @"en-AE", @"en_AS", @"en-AU",
+ @"en_BD", @"en-CA", @"en_EG", @"en_ES", @"en_GB", @"en-GB", @"en_HK", @"en_ID",
+ @"en-IN", @"en_NG", @"en-PH", @"en_PK", @"en-SG", @"en-US"
+ ],
+ // French
+ @"fr" :
+ @[ @"fr", @"fr_BE", @"fr_CA", @"fr_FR", @"fr_LU", @"fr_CH", @"fr-CA", @"fr-FR", @"fr_MA" ],
+ // German
+ @"de" : @[ @"de", @"de_AT", @"de_DE", @"de_LU", @"de_CH", @"de-DE" ],
+ // Greek
+ @"el" : @[ @"el", @"el_CY", @"el_GR" ],
+ // Italian
+ @"it" : @[ @"it", @"it_IT", @"it_CH", @"it-IT" ],
+ // Japanese
+ @"ja" : @[ @"ja", @"ja_JP", @"ja_JP_JP", @"ja-JP" ],
+ // Norwegian
+ @"no" : @[ @"nb", @"no_NO", @"no_NO_NY", @"nb_NO" ],
+ // Brazilian Portuguese
+ @"pt_BR" : @[ @"pt_BR", @"pt-BR" ],
+ // European Portuguese
+ @"pt_PT" : @[ @"pt", @"pt_PT", @"pt-PT" ],
+ // Serbian
+ @"sr" : @[ @"sr_BA", @"sr_ME", @"sr_RS", @"sr_Latn_BA", @"sr_Latn_ME", @"sr_Latn_RS" ],
+ // European Spanish
+ @"es_ES" : @[ @"es", @"es_ES", @"es-ES" ],
+ // Mexican Spanish
+ @"es_MX" : @[ @"es-MX", @"es_MX", @"es_US", @"es-US" ],
+ // Latin American Spanish
+ @"es_419" : @[
+ @"es_AR", @"es_BO", @"es_CL", @"es_CO", @"es_CR", @"es_DO", @"es_EC",
+ @"es_SV", @"es_GT", @"es_HN", @"es_NI", @"es_PA", @"es_PY", @"es_PE",
+ @"es_PR", @"es_UY", @"es_VE", @"es-AR", @"es-CL", @"es-CO"
+ ],
+ // Thai
+ @"th" : @[ @"th", @"th_TH", @"th_TH_TH" ],
+ };
+}
+
+NSArray<NSString *> *FIRRemoteConfigAppManagerLocales() {
+ NSMutableArray *locales = [NSMutableArray array];
+ NSDictionary<NSString *, NSArray *> *localesMap = FIRRemoteConfigFirebaseLocaleMap();
+ for (NSString *key in localesMap) {
+ [locales addObjectsFromArray:localesMap[key]];
+ }
+ return locales;
+}
+NSString *FIRRemoteConfigDeviceLocale() {
+ NSArray<NSString *> *locales = FIRRemoteConfigAppManagerLocales();
+ NSArray<NSString *> *preferredLocalizations =
+ [NSBundle preferredLocalizationsFromArray:locales
+ forPreferences:[NSLocale preferredLanguages]];
+ NSString *legalDocsLanguage = [preferredLocalizations firstObject];
+ // Use en as the default language
+ return legalDocsLanguage ? legalDocsLanguage : @"en";
+}
+
+NSString *FIRRemoteConfigTimezone() {
+ NSTimeZone *timezone = [NSTimeZone systemTimeZone];
+ return timezone.name;
+}
+
+NSMutableDictionary *FIRRemoteConfigDeviceContextWithProjectIdentifier(
+ NSString *GMPProjectIdentifier) {
+ NSMutableDictionary *deviceContext = [[NSMutableDictionary alloc] init];
+ deviceContext[RCNDeviceContextKeyVersion] = FIRRemoteConfigAppVersion();
+ deviceContext[RCNDeviceContextKeyBuild] = FIRRemoteConfigAppBuildVersion();
+ deviceContext[RCNDeviceContextKeyOSVersion] = [GULAppEnvironmentUtil systemVersion];
+ deviceContext[RCNDeviceContextKeyDeviceLocale] = FIRRemoteConfigDeviceLocale();
+ // NSDictionary setObjectForKey will fail if there's no GMP project ID, must check ahead.
+ if (GMPProjectIdentifier) {
+ deviceContext[RCNDeviceContextKeyGMPProjectIdentifier] = GMPProjectIdentifier;
+ }
+ return deviceContext;
+}
+
+BOOL FIRRemoteConfigHasDeviceContextChanged(NSDictionary *deviceContext,
+ NSString *GMPProjectIdentifier) {
+ if (![deviceContext[RCNDeviceContextKeyVersion] isEqual:FIRRemoteConfigAppVersion()]) {
+ return YES;
+ }
+ if (![deviceContext[RCNDeviceContextKeyBuild] isEqual:FIRRemoteConfigAppBuildVersion()]) {
+ return YES;
+ }
+ if (![deviceContext[RCNDeviceContextKeyOSVersion]
+ isEqual:[GULAppEnvironmentUtil systemVersion]]) {
+ return YES;
+ }
+ if (![deviceContext[RCNDeviceContextKeyDeviceLocale] isEqual:FIRRemoteConfigDeviceLocale()]) {
+ return YES;
+ }
+ // GMP project id is optional.
+ if (deviceContext[RCNDeviceContextKeyGMPProjectIdentifier] &&
+ ![deviceContext[RCNDeviceContextKeyGMPProjectIdentifier] isEqual:GMPProjectIdentifier]) {
+ return YES;
+ }
+ return NO;
+}
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNFetch.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNFetch.m
new file mode 100644
index 00000000..250e2318
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNFetch.m
@@ -0,0 +1,568 @@
+/*
+ * 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 "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h"
+
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
+#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h"
+#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h"
+#import "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h"
+#import "FirebaseRemoteConfig/Sources/RCNDevice.h"
+#import "GoogleUtilities/NSData+zlib/Private/GULNSDataInternal.h"
+
+#ifdef RCN_STAGING_SERVER
+static NSString *const kServerURLDomain =
+ @"https://staging-firebaseremoteconfig.sandbox.googleapis.com";
+#else
+static NSString *const kServerURLDomain = @"https://firebaseremoteconfig.googleapis.com";
+#endif
+
+static NSString *const kServerURLVersion = @"/v1";
+static NSString *const kServerURLProjects = @"/projects/";
+static NSString *const kServerURLNamespaces = @"/namespaces/";
+static NSString *const kServerURLQuery = @":fetch?";
+static NSString *const kServerURLKey = @"key=";
+static NSString *const kRequestJSONKeyAppID = @"app_id";
+
+static NSString *const kHTTPMethodPost = @"POST"; ///< HTTP request method config fetch using
+static NSString *const kContentTypeHeaderName = @"Content-Type"; ///< HTTP Header Field Name
+static NSString *const kContentEncodingHeaderName =
+ @"Content-Encoding"; ///< HTTP Header Field Name
+static NSString *const kAcceptEncodingHeaderName = @"Accept-Encoding"; ///< HTTP Header Field Name
+static NSString *const kETagHeaderName = @"etag"; ///< HTTP Header Field Name
+static NSString *const kIfNoneMatchETagHeaderName = @"if-none-match"; ///< HTTP Header Field Name
+static NSString *const kInstallationsAuthTokenHeaderName = @"x-goog-firebase-installations-auth";
+// Sends the bundle ID. Refer to b/130301479 for details.
+static NSString *const kiOSBundleIdentifierHeaderName =
+ @"X-Ios-Bundle-Identifier"; ///< HTTP Header Field Name
+
+/// Config HTTP request content type proto buffer
+static NSString *const kContentTypeValueJSON = @"application/json";
+
+/// HTTP status codes. Ref: https://cloud.google.com/apis/design/errors#error_retries
+static NSInteger const kRCNFetchResponseHTTPStatusCodeOK = 200;
+static NSInteger const kRCNFetchResponseHTTPStatusTooManyRequests = 429;
+static NSInteger const kRCNFetchResponseHTTPStatusCodeInternalError = 500;
+static NSInteger const kRCNFetchResponseHTTPStatusCodeServiceUnavailable = 503;
+static NSInteger const kRCNFetchResponseHTTPStatusCodeGatewayTimeout = 504;
+
+// Deprecated error code previously from FirebaseCore
+static const NSInteger sFIRErrorCodeConfigFailed = -114;
+
+#pragma mark - RCNConfig
+
+@implementation RCNConfigFetch {
+ RCNConfigContent *_content;
+ RCNConfigSettings *_settings;
+ id<FIRAnalyticsInterop> _analytics;
+ RCNConfigExperiment *_experiment;
+ dispatch_queue_t _lockQueue; /// Guard the read/write operation.
+ NSURLSession *_fetchSession; /// Managed internally by the fetch instance.
+ NSString *_FIRNamespace;
+ FIROptions *_options;
+}
+
+- (instancetype)init {
+ NSAssert(NO, @"Invalid initializer.");
+ return nil;
+}
+
+/// Designated initializer
+- (instancetype)initWithContent:(RCNConfigContent *)content
+ DBManager:(RCNConfigDBManager *)DBManager
+ settings:(RCNConfigSettings *)settings
+ analytics:(nullable id<FIRAnalyticsInterop>)analytics
+ experiment:(RCNConfigExperiment *)experiment
+ queue:(dispatch_queue_t)queue
+ namespace:(NSString *)FIRNamespace
+ options:(FIROptions *)options {
+ self = [super init];
+ if (self) {
+ _FIRNamespace = FIRNamespace;
+ _settings = settings;
+ _analytics = analytics;
+ _experiment = experiment;
+ _lockQueue = queue;
+ _content = content;
+ _fetchSession = [self newFetchSession];
+ _options = options;
+ }
+ return self;
+}
+
+/// Force a new NSURLSession creation for updated config.
+- (void)recreateNetworkSession {
+ if (_fetchSession) {
+ [_fetchSession invalidateAndCancel];
+ }
+ _fetchSession = [self newFetchSession];
+}
+
+/// Return the current session. (Tests).
+- (NSURLSession *)currentNetworkSession {
+ return _fetchSession;
+}
+
+- (void)dealloc {
+ [_fetchSession invalidateAndCancel];
+}
+
+#pragma mark - Fetch Config API
+
+- (void)fetchConfigWithExpirationDuration:(NSTimeInterval)expirationDuration
+ completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler {
+ // Note: We expect the googleAppID to always be available.
+ BOOL hasDeviceContextChanged =
+ FIRRemoteConfigHasDeviceContextChanged(_settings.deviceContext, _options.googleAppID);
+
+ __weak RCNConfigFetch *weakSelf = self;
+ RCNConfigFetch *fetchWithExpirationSelf = weakSelf;
+ dispatch_async(fetchWithExpirationSelf->_lockQueue, ^{
+ RCNConfigFetch *strongSelf = fetchWithExpirationSelf;
+
+ // Check whether we are outside of the minimum fetch interval.
+ if (![strongSelf->_settings hasMinimumFetchIntervalElapsed:expirationDuration] &&
+ !hasDeviceContextChanged) {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000051", @"Returning cached data.");
+ return [strongSelf reportCompletionOnHandler:completionHandler
+ withStatus:FIRRemoteConfigFetchStatusSuccess
+ withError:nil];
+ }
+
+ // Check if a fetch is already in progress.
+ if (strongSelf->_settings.isFetchInProgress) {
+ // Check if we have some fetched data.
+ if (strongSelf->_settings.lastFetchTimeInterval > 0) {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000052",
+ @"A fetch is already in progress. Using previous fetch results.");
+ return [strongSelf reportCompletionOnHandler:completionHandler
+ withStatus:strongSelf->_settings.lastFetchStatus
+ withError:nil];
+ } else {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000053",
+ @"A fetch is already in progress. Ignoring duplicate request.");
+ NSError *error =
+ [NSError errorWithDomain:FIRRemoteConfigErrorDomain
+ code:sFIRErrorCodeConfigFailed
+ userInfo:@{
+ NSLocalizedDescriptionKey :
+ @"FetchError: Duplicate request while the previous one is pending"
+ }];
+ return [strongSelf reportCompletionOnHandler:completionHandler
+ withStatus:FIRRemoteConfigFetchStatusFailure
+ withError:error];
+ }
+ }
+
+ // Check whether cache data is within throttle limit.
+ if ([strongSelf->_settings shouldThrottle] && !hasDeviceContextChanged) {
+ // Must set lastFetchStatus before FailReason.
+ strongSelf->_settings.lastFetchStatus = FIRRemoteConfigFetchStatusThrottled;
+ strongSelf->_settings.lastFetchError = FIRRemoteConfigErrorThrottled;
+ NSTimeInterval throttledEndTime = strongSelf->_settings.exponentialBackoffThrottleEndTime;
+
+ NSError *error =
+ [NSError errorWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorThrottled
+ userInfo:@{
+ FIRRemoteConfigThrottledEndTimeInSecondsKey : @(throttledEndTime)
+ }];
+ return [strongSelf reportCompletionOnHandler:completionHandler
+ withStatus:strongSelf->_settings.lastFetchStatus
+ withError:error];
+ }
+ strongSelf->_settings.isFetchInProgress = YES;
+ [strongSelf refreshInstallationsTokenWithCompletionHandler:completionHandler];
+ });
+}
+
+#pragma mark - Fetch helpers
+
+- (NSString *)FIRAppNameFromFullyQualifiedNamespace {
+ return [[_FIRNamespace componentsSeparatedByString:@":"] lastObject];
+}
+/// Refresh installation ID token before fetching config. installation ID is now mandatory for fetch
+/// requests to work.(b/14751422).
+- (void)refreshInstallationsTokenWithCompletionHandler:
+ (FIRRemoteConfigFetchCompletion)completionHandler {
+ FIRInstallations *installations = [FIRInstallations
+ installationsWithApp:[FIRApp appNamed:[self FIRAppNameFromFullyQualifiedNamespace]]];
+ if (!installations || !_options.GCMSenderID) {
+ NSString *errorDescription = @"Failed to get GCMSenderID";
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000074", @"%@",
+ [NSString stringWithFormat:@"%@", errorDescription]);
+ self->_settings.isFetchInProgress = NO;
+ return [self
+ reportCompletionOnHandler:completionHandler
+ withStatus:FIRRemoteConfigFetchStatusFailure
+ withError:[NSError errorWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorInternalError
+ userInfo:@{
+ NSLocalizedDescriptionKey : errorDescription
+ }]];
+ }
+ FIRInstallationsTokenHandler installationsTokenHandler = ^(
+ FIRInstallationsAuthTokenResult *tokenResult, NSError *error) {
+ if (!tokenResult || !tokenResult.authToken || error) {
+ NSString *errorDescription =
+ [NSString stringWithFormat:@"Failed to get installations token. Error : %@.", error];
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000073", @"%@",
+ [NSString stringWithFormat:@"%@", errorDescription]);
+ self->_settings.isFetchInProgress = NO;
+ return [self
+ reportCompletionOnHandler:completionHandler
+ withStatus:FIRRemoteConfigFetchStatusFailure
+ withError:[NSError errorWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorInternalError
+ userInfo:@{
+ NSLocalizedDescriptionKey : errorDescription
+ }]];
+ }
+
+ // We have a valid token. Get the backing installationID.
+ __weak RCNConfigFetch *weakSelf = self;
+ [installations installationIDWithCompletion:^(NSString *_Nullable identifier,
+ NSError *_Nullable error) {
+ RCNConfigFetch *strongSelf = weakSelf;
+
+ // Dispatch to the RC serial queue to update settings on the queue.
+ dispatch_async(strongSelf->_lockQueue, ^{
+ RCNConfigFetch *strongSelfQueue = weakSelf;
+
+ // Update config settings with the IID and token.
+ strongSelfQueue->_settings.configInstallationsToken = tokenResult.authToken;
+ strongSelfQueue->_settings.configInstallationsIdentifier = identifier;
+
+ if (!identifier || error) {
+ NSString *errorDescription =
+ [NSString stringWithFormat:@"Error getting iid : %@.", error];
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000055", @"%@",
+ [NSString stringWithFormat:@"%@", errorDescription]);
+ strongSelfQueue->_settings.isFetchInProgress = NO;
+ return [strongSelfQueue
+ reportCompletionOnHandler:completionHandler
+ withStatus:FIRRemoteConfigFetchStatusFailure
+ withError:[NSError
+ errorWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorInternalError
+ userInfo:@{
+ NSLocalizedDescriptionKey : errorDescription
+ }]];
+ }
+
+ FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000022", @"Success to get iid : %@.",
+ strongSelfQueue->_settings.configInstallationsIdentifier);
+ [strongSelf doFetchCall:completionHandler];
+ });
+ }];
+ };
+
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000039", @"Starting requesting token.");
+ [installations authTokenWithCompletion:installationsTokenHandler];
+}
+
+- (void)doFetchCall:(FIRRemoteConfigFetchCompletion)completionHandler {
+ [self getAnalyticsUserPropertiesWithCompletionHandler:^(NSDictionary *userProperties) {
+ dispatch_async(self->_lockQueue, ^{
+ [self fetchWithUserProperties:userProperties completionHandler:completionHandler];
+ });
+ }];
+}
+
+- (void)getAnalyticsUserPropertiesWithCompletionHandler:
+ (FIRAInteropUserPropertiesCallback)completionHandler {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000060", @"Fetch with user properties completed.");
+ id<FIRAnalyticsInterop> analytics = self->_analytics;
+ if (analytics == nil) {
+ completionHandler(@{});
+ } else {
+ [analytics getUserPropertiesWithCallback:completionHandler];
+ }
+}
+
+- (void)reportCompletionOnHandler:(FIRRemoteConfigFetchCompletion)completionHandler
+ withStatus:(FIRRemoteConfigFetchStatus)status
+ withError:(NSError *)error {
+ if (completionHandler) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completionHandler(status, error);
+ });
+ }
+}
+
+- (void)fetchWithUserProperties:(NSDictionary *)userProperties
+ completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000061", @"Fetch with user properties initiated.");
+
+ NSString *postRequestString = [_settings nextRequestWithUserProperties:userProperties];
+
+ // Get POST request content.
+ NSData *content = [postRequestString dataUsingEncoding:NSUTF8StringEncoding];
+ NSError *compressionError;
+ NSData *compressedContent = [NSData gul_dataByGzippingData:content error:&compressionError];
+ if (compressionError) {
+ NSString *errString = [NSString stringWithFormat:@"Failed to compress the config request."];
+ FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000033", @"%@", errString);
+
+ self->_settings.isFetchInProgress = NO;
+ return [self
+ reportCompletionOnHandler:completionHandler
+ withStatus:FIRRemoteConfigFetchStatusFailure
+ withError:[NSError
+ errorWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorInternalError
+ userInfo:@{NSLocalizedDescriptionKey : errString}]];
+ }
+
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000040", @"Start config fetch.");
+ __weak RCNConfigFetch *weakSelf = self;
+ RCNConfigFetcherCompletion fetcherCompletion = ^(NSData *data, NSURLResponse *response,
+ NSError *error) {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000050",
+ @"config fetch completed. Error: %@ StatusCode: %ld", (error ? error : @"nil"),
+ (long)[((NSHTTPURLResponse *)response) statusCode]);
+
+ // The fetch has completed.
+ self->_settings.isFetchInProgress = NO;
+
+ RCNConfigFetch *fetcherCompletionSelf = weakSelf;
+ if (!fetcherCompletionSelf) {
+ return;
+ };
+
+ dispatch_async(fetcherCompletionSelf->_lockQueue, ^{
+ RCNConfigFetch *strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+
+ NSInteger statusCode = [((NSHTTPURLResponse *)response) statusCode];
+
+ if (error || (statusCode != kRCNFetchResponseHTTPStatusCodeOK)) {
+ // Update metadata about fetch failure.
+ [strongSelf->_settings updateMetadataWithFetchSuccessStatus:NO];
+ if (error) {
+ if (strongSelf->_settings.lastFetchStatus == FIRRemoteConfigFetchStatusSuccess) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000025",
+ @"RCN Fetch failure: %@. Using cached config result.", error);
+ } else {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000026",
+ @"RCN Fetch failure: %@. No cached config result.", error);
+ }
+ }
+ if (statusCode != kRCNFetchResponseHTTPStatusCodeOK) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000026",
+ @"RCN Fetch failure. Response http error code: %ld", (long)statusCode);
+ // Response error code 429, 500, 503 will trigger exponential backoff mode.
+ if (statusCode == kRCNFetchResponseHTTPStatusTooManyRequests ||
+ statusCode == kRCNFetchResponseHTTPStatusCodeInternalError ||
+ statusCode == kRCNFetchResponseHTTPStatusCodeServiceUnavailable ||
+ statusCode == kRCNFetchResponseHTTPStatusCodeGatewayTimeout) {
+ if ([strongSelf->_settings shouldThrottle]) {
+ // Must set lastFetchStatus before FailReason.
+ strongSelf->_settings.lastFetchStatus = FIRRemoteConfigFetchStatusThrottled;
+ strongSelf->_settings.lastFetchError = FIRRemoteConfigErrorThrottled;
+ NSTimeInterval throttledEndTime =
+ strongSelf->_settings.exponentialBackoffThrottleEndTime;
+
+ NSError *error = [NSError
+ errorWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorThrottled
+ userInfo:@{
+ FIRRemoteConfigThrottledEndTimeInSecondsKey : @(throttledEndTime)
+ }];
+ return [strongSelf reportCompletionOnHandler:completionHandler
+ withStatus:strongSelf->_settings.lastFetchStatus
+ withError:error];
+ }
+ } // Response error code 429, 500, 503
+ } // StatusCode != kRCNFetchResponseHTTPStatusCodeOK
+ // Return back the received error.
+ // Must set lastFetchStatus before setting Fetch Error.
+ strongSelf->_settings.lastFetchStatus = FIRRemoteConfigFetchStatusFailure;
+ strongSelf->_settings.lastFetchError = FIRRemoteConfigErrorInternalError;
+ NSDictionary<NSErrorUserInfoKey, id> *userInfo = @{
+ NSLocalizedDescriptionKey :
+ (error ? [error localizedDescription]
+ : [NSString
+ stringWithFormat:@"Internal Error. Status code: %ld", (long)statusCode])
+ };
+ return [strongSelf
+ reportCompletionOnHandler:completionHandler
+ withStatus:FIRRemoteConfigFetchStatusFailure
+ withError:[NSError errorWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorInternalError
+ userInfo:userInfo]];
+ }
+
+ // Fetch was successful. Check if we have data.
+ NSError *retError;
+ if (!data) {
+ FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000043", @"RCN Fetch: No data in fetch response");
+ return [strongSelf reportCompletionOnHandler:completionHandler
+ withStatus:FIRRemoteConfigFetchStatusSuccess
+ withError:nil];
+ }
+
+ // Config fetch succeeded.
+ // JSONObjectWithData is always expected to return an NSDictionary in our case
+ NSMutableDictionary *fetchedConfig =
+ [NSJSONSerialization JSONObjectWithData:data
+ options:NSJSONReadingMutableContainers
+ error:&retError];
+ if (retError) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000042",
+ @"RCN Fetch failure: %@. Could not parse response data as JSON", error);
+ }
+
+ // Check and log if we received an error from the server
+ if (fetchedConfig && fetchedConfig.count == 1 && fetchedConfig[RCNFetchResponseKeyError]) {
+ NSString *errStr = [NSString stringWithFormat:@"RCN Fetch Failure: Server returned error:"];
+ NSDictionary *errDict = fetchedConfig[RCNFetchResponseKeyError];
+ if (errDict[RCNFetchResponseKeyErrorCode]) {
+ errStr = [errStr
+ stringByAppendingString:[NSString
+ stringWithFormat:@"code: %@",
+ errDict[RCNFetchResponseKeyErrorCode]]];
+ }
+ if (errDict[RCNFetchResponseKeyErrorStatus]) {
+ errStr = [errStr stringByAppendingString:
+ [NSString stringWithFormat:@". Status: %@",
+ errDict[RCNFetchResponseKeyErrorStatus]]];
+ }
+ if (errDict[RCNFetchResponseKeyErrorMessage]) {
+ errStr =
+ [errStr stringByAppendingString:
+ [NSString stringWithFormat:@". Message: %@",
+ errDict[RCNFetchResponseKeyErrorMessage]]];
+ }
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000044", @"%@.", errStr);
+ return [strongSelf
+ reportCompletionOnHandler:completionHandler
+ withStatus:FIRRemoteConfigFetchStatusFailure
+ withError:[NSError
+ errorWithDomain:FIRRemoteConfigErrorDomain
+ code:FIRRemoteConfigErrorInternalError
+ userInfo:@{NSLocalizedDescriptionKey : errStr}]];
+ }
+
+ // Add the fetched config to the database.
+ if (fetchedConfig) {
+ // Update config content to cache and DB.
+ [self->_content updateConfigContentWithResponse:fetchedConfig
+ forNamespace:self->_FIRNamespace];
+ // Update experiments.
+ [strongSelf->_experiment
+ updateExperimentsWithResponse:fetchedConfig[RCNFetchResponseKeyExperimentDescriptions]];
+ } else {
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000063",
+ @"Empty response with no fetched config.");
+ }
+
+ // We had a successful fetch. Update the current eTag in settings if different.
+ NSString *latestETag = ((NSHTTPURLResponse *)response).allHeaderFields[kETagHeaderName];
+ if (!self->_settings.lastETag || !([self->_settings.lastETag isEqualToString:latestETag])) {
+ self->_settings.lastETag = latestETag;
+ }
+
+ [self->_settings updateMetadataWithFetchSuccessStatus:YES];
+ return [strongSelf reportCompletionOnHandler:completionHandler
+ withStatus:FIRRemoteConfigFetchStatusSuccess
+ withError:nil];
+ });
+ };
+
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000061", @"Making remote config fetch.");
+
+ NSURLSessionDataTask *dataTask = [self URLSessionDataTaskWithContent:compressedContent
+ completionHandler:fetcherCompletion];
+ [dataTask resume];
+}
+
+- (NSString *)constructServerURL {
+ NSString *serverURLStr = [[NSString alloc] initWithString:kServerURLDomain];
+ serverURLStr = [serverURLStr stringByAppendingString:kServerURLVersion];
+
+ if (_options.projectID) {
+ serverURLStr = [serverURLStr stringByAppendingString:kServerURLProjects];
+ serverURLStr = [serverURLStr stringByAppendingString:_options.projectID];
+ } else {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000070",
+ @"Missing `projectID` from `FirebaseOptions`, please ensure the configured "
+ @"`FirebaseApp` is configured with `FirebaseOptions` that contains a `projectID`.");
+ }
+
+ serverURLStr = [serverURLStr stringByAppendingString:kServerURLNamespaces];
+
+ // Get the namespace from the fully qualified namespace string of "namespace:FIRAppName".
+ NSString *namespace =
+ [_FIRNamespace substringToIndex:[_FIRNamespace rangeOfString:@":"].location];
+ serverURLStr = [serverURLStr stringByAppendingString:namespace];
+ serverURLStr = [serverURLStr stringByAppendingString:kServerURLQuery];
+
+ if (_options.APIKey) {
+ serverURLStr = [serverURLStr stringByAppendingString:kServerURLKey];
+ serverURLStr = [serverURLStr stringByAppendingString:_options.APIKey];
+ } else {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000071",
+ @"Missing `APIKey` from `FirebaseOptions`, please ensure the configured "
+ @"`FirebaseApp` is configured with `FirebaseOptions` that contains an `APIKey`.");
+ }
+
+ return serverURLStr;
+}
+
+- (NSURLSession *)newFetchSession {
+ NSURLSessionConfiguration *config =
+ [[NSURLSessionConfiguration defaultSessionConfiguration] copy];
+ config.timeoutIntervalForRequest = _settings.fetchTimeout;
+ config.timeoutIntervalForResource = _settings.fetchTimeout;
+ NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
+ return session;
+}
+
+- (NSURLSessionDataTask *)URLSessionDataTaskWithContent:(NSData *)content
+ completionHandler:
+ (RCNConfigFetcherCompletion)fetcherCompletion {
+ NSURL *URL = [NSURL URLWithString:[self constructServerURL]];
+ FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000046", @"%@",
+ [NSString stringWithFormat:@"Making config request: %@", [URL absoluteString]]);
+
+ NSTimeInterval timeoutInterval = _fetchSession.configuration.timeoutIntervalForResource;
+ NSMutableURLRequest *URLRequest =
+ [[NSMutableURLRequest alloc] initWithURL:URL
+ cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+ timeoutInterval:timeoutInterval];
+ URLRequest.HTTPMethod = kHTTPMethodPost;
+ [URLRequest setValue:kContentTypeValueJSON forHTTPHeaderField:kContentTypeHeaderName];
+ [URLRequest setValue:_settings.configInstallationsToken
+ forHTTPHeaderField:kInstallationsAuthTokenHeaderName];
+ [URLRequest setValue:[[NSBundle mainBundle] bundleIdentifier]
+ forHTTPHeaderField:kiOSBundleIdentifierHeaderName];
+ [URLRequest setValue:@"gzip" forHTTPHeaderField:kContentEncodingHeaderName];
+ [URLRequest setValue:@"gzip" forHTTPHeaderField:kAcceptEncodingHeaderName];
+ // Set the eTag from the last successful fetch, if available.
+ if (_settings.lastETag) {
+ [URLRequest setValue:_settings.lastETag forHTTPHeaderField:kIfNoneMatchETagHeaderName];
+ }
+ [URLRequest setHTTPBody:content];
+
+ return [_fetchSession dataTaskWithRequest:URLRequest completionHandler:fetcherCompletion];
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h
new file mode 100644
index 00000000..020d651e
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h
@@ -0,0 +1,55 @@
+/*
+ * 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
+
+@interface RCNUserDefaultsManager : NSObject
+
+/// The last eTag received from the backend.
+@property(nonatomic, assign) NSString *lastETag;
+/// The time of the last eTag update.
+@property(nonatomic, assign) NSTimeInterval lastETagUpdateTime;
+/// The time of the last successful fetch.
+@property(nonatomic, assign) NSTimeInterval lastFetchTime;
+/// The time of the last successful fetch.
+@property(nonatomic, assign) NSString *lastFetchStatus;
+/// Boolean indicating if the last (one or more) fetch(es) was/were unsuccessful, in which case we
+/// are in an exponential backoff mode.
+@property(nonatomic, assign) BOOL isClientThrottledWithExponentialBackoff;
+/// Time when the next request can be made while being throttled.
+@property(nonatomic, assign) NSTimeInterval throttleEndTime;
+/// The retry interval increases exponentially for cumulative fetch failures. Refer to
+/// go/rc-client-throttling for details.
+@property(nonatomic, assign) NSTimeInterval currentThrottlingRetryIntervalSeconds;
+
+/// Designated initializer.
+- (instancetype)initWithAppName:(NSString *)appName
+ bundleID:(NSString *)bundleIdentifier
+ namespace:(NSString *)firebaseNamespace NS_DESIGNATED_INITIALIZER;
+
+// NOLINTBEGIN
+/// Use `initWithAppName:bundleID:namespace:` instead.
+- (instancetype)init
+ __attribute__((unavailable("Use `initWithAppName:bundleID:namespace:` instead.")));
+// NOLINTEND
+
+/// Delete all saved userdefaults for this instance.
+- (void)resetUserDefaults;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.m b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.m
new file mode 100644
index 00000000..edd716c2
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.m
@@ -0,0 +1,233 @@
+/*
+ * 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 "FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h"
+#import <FirebaseRemoteConfig/FIRRemoteConfig.h>
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
+
+static NSString *const kRCNGroupPrefix = @"group";
+static NSString *const kRCNGroupSuffix = @"firebase";
+static NSString *const kRCNUserDefaultsKeyNamelastETag = @"lastETag";
+static NSString *const kRCNUserDefaultsKeyNamelastETagUpdateTime = @"lastETagUpdateTime";
+static NSString *const kRCNUserDefaultsKeyNameLastSuccessfulFetchTime = @"lastSuccessfulFetchTime";
+static NSString *const kRCNUserDefaultsKeyNamelastFetchStatus = @"lastFetchStatus";
+static NSString *const kRCNUserDefaultsKeyNameIsClientThrottled =
+ @"isClientThrottledWithExponentialBackoff";
+static NSString *const kRCNUserDefaultsKeyNameThrottleEndTime = @"throttleEndTime";
+static NSString *const kRCNUserDefaultsKeyNamecurrentThrottlingRetryInterval =
+ @"currentThrottlingRetryInterval";
+
+@interface RCNUserDefaultsManager () {
+ /// User Defaults instance for this bundleID. NSUserDefaults is guaranteed to be thread-safe.
+ NSUserDefaults *_userDefaults;
+ /// The suite name for this user defaults instance. It is a combination of a prefix and the
+ /// bundleID. This is because you cannot use just the bundleID of the current app as the suite
+ /// name when initializing user defaults.
+ NSString *_userDefaultsSuiteName;
+ /// The FIRApp that this instance is scoped within.
+ NSString *_firebaseAppName;
+ /// The Firebase Namespace that this instance is scoped within.
+ NSString *_firebaseNamespace;
+ /// The bundleID of the app. In case of an extension, this will be the bundleID of the parent app.
+ NSString *_bundleIdentifier;
+}
+
+@end
+
+@implementation RCNUserDefaultsManager
+
+#pragma mark Initializers.
+
+/// Designated initializer.
+- (instancetype)initWithAppName:(NSString *)appName
+ bundleID:(NSString *)bundleIdentifier
+ namespace:(NSString *)firebaseNamespace {
+ self = [super init];
+ if (self) {
+ _firebaseAppName = appName;
+ _bundleIdentifier = bundleIdentifier;
+ NSInteger location = [firebaseNamespace rangeOfString:@":"].location;
+ if (location == NSNotFound) {
+ FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000064",
+ @"Error: Namespace %@ is not fully qualified app:namespace.", firebaseNamespace);
+ _firebaseNamespace = firebaseNamespace;
+ } else {
+ _firebaseNamespace = [firebaseNamespace substringToIndex:location];
+ }
+
+ // Initialize the user defaults with a prefix and the bundleID. For app extensions, this will be
+ // the bundleID of the app extension.
+ _userDefaults =
+ [RCNUserDefaultsManager sharedUserDefaultsForBundleIdentifier:_bundleIdentifier];
+ }
+
+ return self;
+}
+
++ (NSUserDefaults *)sharedUserDefaultsForBundleIdentifier:(NSString *)bundleIdentifier {
+ static dispatch_once_t onceToken;
+ static NSUserDefaults *sharedInstance;
+ dispatch_once(&onceToken, ^{
+ NSString *userDefaultsSuiteName =
+ [RCNUserDefaultsManager userDefaultsSuiteNameForBundleIdentifier:bundleIdentifier];
+ sharedInstance = [[NSUserDefaults alloc] initWithSuiteName:userDefaultsSuiteName];
+ });
+ return sharedInstance;
+}
+
++ (NSString *)userDefaultsSuiteNameForBundleIdentifier:(NSString *)bundleIdentifier {
+ NSString *suiteName =
+ [NSString stringWithFormat:@"%@.%@.%@", kRCNGroupPrefix, bundleIdentifier, kRCNGroupSuffix];
+ return suiteName;
+}
+
+#pragma mark Public properties.
+
+- (NSString *)lastETag {
+ return [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNamelastETag];
+}
+
+- (void)setLastETag:(NSString *)lastETag {
+ if (lastETag) {
+ [self setInstanceUserDefaultsValue:lastETag forKey:kRCNUserDefaultsKeyNamelastETag];
+ }
+}
+
+- (NSTimeInterval)lastETagUpdateTime {
+ NSNumber *lastETagUpdateTime =
+ [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNamelastETagUpdateTime];
+ return lastETagUpdateTime.doubleValue;
+}
+
+- (void)setLastETagUpdateTime:(NSTimeInterval)lastETagUpdateTime {
+ if (lastETagUpdateTime) {
+ [self setInstanceUserDefaultsValue:@(lastETagUpdateTime)
+ forKey:kRCNUserDefaultsKeyNamelastETagUpdateTime];
+ }
+}
+
+- (NSTimeInterval)lastFetchTime {
+ NSNumber *lastFetchTime =
+ [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameLastSuccessfulFetchTime];
+ return lastFetchTime.doubleValue;
+}
+
+- (void)setLastFetchTime:(NSTimeInterval)lastFetchTime {
+ [self setInstanceUserDefaultsValue:@(lastFetchTime)
+ forKey:kRCNUserDefaultsKeyNameLastSuccessfulFetchTime];
+}
+
+- (NSString *)lastFetchStatus {
+ return [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNamelastFetchStatus];
+}
+
+- (void)setLastFetchStatus:(NSString *)lastFetchStatus {
+ if (lastFetchStatus) {
+ [self setInstanceUserDefaultsValue:lastFetchStatus
+ forKey:kRCNUserDefaultsKeyNamelastFetchStatus];
+ }
+}
+
+- (BOOL)isClientThrottledWithExponentialBackoff {
+ NSNumber *isClientThrottled =
+ [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameIsClientThrottled];
+ return isClientThrottled.boolValue;
+}
+
+- (void)setIsClientThrottledWithExponentialBackoff:(BOOL)isClientThrottled {
+ [self setInstanceUserDefaultsValue:@(isClientThrottled)
+ forKey:kRCNUserDefaultsKeyNameIsClientThrottled];
+}
+
+- (NSTimeInterval)throttleEndTime {
+ NSNumber *throttleEndTime =
+ [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameThrottleEndTime];
+ return throttleEndTime.doubleValue;
+}
+
+- (void)setThrottleEndTime:(NSTimeInterval)throttleEndTime {
+ [self setInstanceUserDefaultsValue:@(throttleEndTime)
+ forKey:kRCNUserDefaultsKeyNameThrottleEndTime];
+}
+
+- (NSTimeInterval)currentThrottlingRetryIntervalSeconds {
+ NSNumber *throttleEndTime = [[self instanceUserDefaults]
+ objectForKey:kRCNUserDefaultsKeyNamecurrentThrottlingRetryInterval];
+ return throttleEndTime.doubleValue;
+}
+
+- (void)setCurrentThrottlingRetryIntervalSeconds:(NSTimeInterval)throttlingRetryIntervalSeconds {
+ [self setInstanceUserDefaultsValue:@(throttlingRetryIntervalSeconds)
+ forKey:kRCNUserDefaultsKeyNamecurrentThrottlingRetryInterval];
+}
+
+#pragma mark Public methods.
+- (void)resetUserDefaults {
+ [self resetInstanceUserDefaults];
+}
+
+#pragma mark Private methods.
+
+// There is a nested hierarchy for the userdefaults as follows:
+// [FIRAppName][FIRNamespaceName][Key]
+- (nonnull NSDictionary *)appUserDefaults {
+ NSString *appPath = _firebaseAppName;
+ NSDictionary *appDict = [_userDefaults valueForKeyPath:appPath];
+ if (!appDict) {
+ appDict = [[NSDictionary alloc] init];
+ }
+ return appDict;
+}
+
+// Search for the user defaults for this (app, namespace) instance using the valueForKeyPath method.
+- (nonnull NSDictionary *)instanceUserDefaults {
+ NSString *appNamespacePath =
+ [NSString stringWithFormat:@"%@.%@", _firebaseAppName, _firebaseNamespace];
+ NSDictionary *appNamespaceDict = [_userDefaults valueForKeyPath:appNamespacePath];
+
+ if (!appNamespaceDict) {
+ appNamespaceDict = [[NSMutableDictionary alloc] init];
+ }
+ return appNamespaceDict;
+}
+
+// Update users defaults for just this (app, namespace) instance.
+- (void)setInstanceUserDefaultsValue:(NSObject *)value forKey:(NSString *)key {
+ @synchronized(_userDefaults) {
+ NSMutableDictionary *appUserDefaults = [[self appUserDefaults] mutableCopy];
+ NSMutableDictionary *appNamespaceUserDefaults = [[self instanceUserDefaults] mutableCopy];
+ [appNamespaceUserDefaults setObject:value forKey:key];
+ [appUserDefaults setObject:appNamespaceUserDefaults forKey:_firebaseNamespace];
+ [_userDefaults setObject:appUserDefaults forKey:_firebaseAppName];
+ // We need to synchronize to have this value updated for the extension.
+ [_userDefaults synchronize];
+ }
+}
+
+// Delete any existing userdefaults for this instance.
+- (void)resetInstanceUserDefaults {
+ @synchronized(_userDefaults) {
+ NSMutableDictionary *appUserDefaults = [[self appUserDefaults] mutableCopy];
+ NSMutableDictionary *appNamespaceUserDefaults = [[self instanceUserDefaults] mutableCopy];
+ [appNamespaceUserDefaults removeAllObjects];
+ [appUserDefaults setObject:appNamespaceUserDefaults forKey:_firebaseNamespace];
+ [_userDefaults setObject:appUserDefaults forKey:_firebaseAppName];
+ // We need to synchronize to have this value updated for the extension.
+ [_userDefaults synchronize];
+ }
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h
new file mode 100644
index 00000000..2fb16226
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/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/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULHeartbeatDateStorage.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULHeartbeatDateStorage.h
new file mode 100644
index 00000000..9432dfc0
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/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/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULKeychainStorage.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULKeychainStorage.h
new file mode 100644
index 00000000..dc01a836
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/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/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULKeychainUtils.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULKeychainUtils.h
new file mode 100644
index 00000000..de4bef2f
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/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/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULSecureCoding.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/Environment/Private/GULSecureCoding.h
new file mode 100644
index 00000000..8484b395
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/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/FirebaseRemoteConfig/GoogleUtilities/NSData+zlib/Private/GULNSDataInternal.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/GoogleUtilities/NSData+zlib/Private/GULNSDataInternal.h
new file mode 100644
index 00000000..903589d5
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/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/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInterop.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInterop.h
new file mode 100644
index 00000000..6581b536
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInterop.h
@@ -0,0 +1,66 @@
+/*
+ * 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>
+
+@protocol FIRAnalyticsInteropListener;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Block typedef callback parameter to getUserPropertiesWithCallback:.
+typedef void (^FIRAInteropUserPropertiesCallback)(NSDictionary<NSString *, id> *userProperties);
+
+/// Connector for bridging communication between Firebase SDKs and FirebaseAnalytics API.
+@protocol FIRAnalyticsInterop
+
+/// Sets user property when trigger event is logged. This API is only available in the SDK.
+- (void)setConditionalUserProperty:(NSDictionary<NSString *, id> *)conditionalUserProperty;
+
+/// Clears user property if set.
+- (void)clearConditionalUserProperty:(NSString *)userPropertyName
+ forOrigin:(NSString *)origin
+ clearEventName:(NSString *)clearEventName
+ clearEventParameters:(NSDictionary<NSString *, NSString *> *)clearEventParameters;
+
+/// Returns currently set user properties.
+- (NSArray<NSDictionary<NSString *, NSString *> *> *)conditionalUserProperties:(NSString *)origin
+ propertyNamePrefix:
+ (NSString *)propertyNamePrefix;
+
+/// Returns the maximum number of user properties.
+- (NSInteger)maxUserProperties:(NSString *)origin;
+
+/// Returns the user properties to a callback function.
+- (void)getUserPropertiesWithCallback:(FIRAInteropUserPropertiesCallback)callback;
+
+/// Logs events.
+- (void)logEventWithOrigin:(NSString *)origin
+ name:(NSString *)name
+ parameters:(nullable NSDictionary<NSString *, id> *)parameters;
+
+/// Sets user property.
+- (void)setUserPropertyWithOrigin:(NSString *)origin name:(NSString *)name value:(id)value;
+
+/// Registers an Analytics listener for the given origin.
+- (void)registerAnalyticsListener:(id<FIRAnalyticsInteropListener>)listener
+ withOrigin:(NSString *)origin;
+
+/// Unregisters an Analytics listener for the given origin.
+- (void)unregisterAnalyticsListenerWithOrigin:(NSString *)origin;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInteropListener.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInteropListener.h
new file mode 100644
index 00000000..45cde550
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInteropListener.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/// Handles events and messages from Analytics.
+@protocol FIRAnalyticsInteropListener <NSObject>
+
+/// Triggers when an Analytics event happens for the registered origin with
+/// `FIRAnalyticsInterop`s `registerAnalyticsListener:withOrigin:`.
+- (void)messageTriggered:(NSString *)name parameters:(NSDictionary *)parameters;
+
+@end \ No newline at end of file
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropEventNames.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropEventNames.h
new file mode 100644
index 00000000..efc54ab2
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropEventNames.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+/// @file FIRInteropEventNames.h
+
+#import <Foundation/Foundation.h>
+
+/// Notification open event name.
+static NSString *const kFIRIEventNotificationOpen = @"_no";
+
+/// Notification foreground event name.
+static NSString *const kFIRIEventNotificationForeground = @"_nf";
+
+/// Campaign event name.
+static NSString *const kFIRIEventFirebaseCampaign = @"_cmp";
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropParameterNames.h b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropParameterNames.h
new file mode 100644
index 00000000..ae440bec
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropParameterNames.h
@@ -0,0 +1,73 @@
+/*
+ * 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>
+
+/// @file FIRInteropParameterNames.h
+///
+/// Predefined event parameter names used by Firebase. This file is a subset of the
+/// FirebaseAnalytics FIRParameterNames.h public header.
+///
+/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban
+/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your
+/// property. Highly recommended (NSString).
+/// <pre>
+/// NSDictionary *params = @{
+/// kFIRParameterSource : @"InMobi",
+/// // ...
+/// };
+/// </pre>
+static NSString *const kFIRIParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source";
+
+/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended
+/// (NSString).
+/// <pre>
+/// NSDictionary *params = @{
+/// kFIRParameterMedium : @"email",
+/// // ...
+/// };
+/// </pre>
+static NSString *const kFIRIParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium";
+
+/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to
+/// capture campaign information, otherwise can be populated by developer. Highly Recommended
+/// (NSString).
+/// <pre>
+/// NSDictionary *params = @{
+/// kFIRParameterCampaign : @"winter_promotion",
+/// // ...
+/// };
+/// </pre>
+static NSString *const kFIRIParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) =
+ @"campaign";
+
+/// Message identifier.
+static NSString *const kFIRIParameterMessageIdentifier = @"_nmid";
+
+/// Message name.
+static NSString *const kFIRIParameterMessageName = @"_nmn";
+
+/// Message send time.
+static NSString *const kFIRIParameterMessageTime = @"_nmt";
+
+/// Message device time.
+static NSString *const kFIRIParameterMessageDeviceTime = @"_ndt";
+
+/// Topic message.
+static NSString *const kFIRIParameterTopic = @"_nt";
+
+/// Stores the message_id of the last notification opened by the app.
+static NSString *const kFIRIUserPropertyLastNotification = @"_ln";
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/LICENSE b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/README.md b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/README.md
new file mode 100644
index 00000000..1d9f0f67
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseRemoteConfig/README.md
@@ -0,0 +1,298 @@
+[![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-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-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