From 1288ffc14f574250078dfd4a204970ef86676453 Mon Sep 17 00:00:00 2001 From: sara al zhrani Date: Tue, 2 Nov 2021 23:10:50 +0300 Subject: [PATCH 1/3] what's up --- ...tion TabBarControllerViewController.swift | 29 + saraWhatsUp/.DS_Store | Bin 0 -> 6148 bytes saraWhatsUp/Podfile | 16 + saraWhatsUp/Podfile.lock | 97 + .../Pods/Firebase/CoreOnly/Sources/Firebase.h | 81 + .../CoreOnly/Sources/module.modulemap | 4 + saraWhatsUp/Pods/Firebase/LICENSE | 202 + saraWhatsUp/Pods/Firebase/README.md | 319 + .../FirebaseAuth/FirebaseAuth/CHANGELOG.md | 315 + .../Pods/FirebaseAuth/FirebaseAuth/README.md | 17 + .../Sources/Auth/FIRActionCodeSettings.m | 45 + .../FirebaseAuth/Sources/Auth/FIRAuth.m | 2274 ++++++ .../Sources/Auth/FIRAuthDataResult.m | 83 + .../Sources/Auth/FIRAuthDataResult_Internal.h | 46 + .../Sources/Auth/FIRAuthDispatcher.h | 63 + .../Sources/Auth/FIRAuthDispatcher.m | 46 + .../Sources/Auth/FIRAuthGlobalWorkQueue.h | 31 + .../Sources/Auth/FIRAuthGlobalWorkQueue.m | 30 + .../Sources/Auth/FIRAuthOperationType.h | 47 + .../Sources/Auth/FIRAuthSerialTaskQueue.h | 50 + .../Sources/Auth/FIRAuthSerialTaskQueue.m | 56 + .../Sources/Auth/FIRAuthSettings.m | 40 + .../Sources/Auth/FIRAuthTokenResult.m | 166 + .../Auth/FIRAuthTokenResult_Internal.h | 36 + .../Sources/Auth/FIRAuth_Internal.h | 152 + .../AuthProvider/Email/FIREmailAuthProvider.m | 41 + .../Email/FIREmailPasswordAuthCredential.h | 61 + .../Email/FIREmailPasswordAuthCredential.m | 92 + .../Sources/AuthProvider/FIRAuthCredential.m | 46 + .../AuthProvider/FIRAuthCredential_Internal.h | 41 + .../Sources/AuthProvider/FIRAuthProvider.m | 66 + .../Facebook/FIRFacebookAuthCredential.h | 36 + .../Facebook/FIRFacebookAuthCredential.m | 72 + .../Facebook/FIRFacebookAuthProvider.m | 40 + .../GameCenter/FIRGameCenterAuthCredential.h | 80 + .../GameCenter/FIRGameCenterAuthCredential.m | 92 + .../GameCenter/FIRGameCenterAuthProvider.m | 92 + .../GitHub/FIRGitHubAuthCredential.h | 41 + .../GitHub/FIRGitHubAuthCredential.m | 70 + .../GitHub/FIRGitHubAuthProvider.m | 40 + .../Google/FIRGoogleAuthCredential.h | 38 + .../Google/FIRGoogleAuthCredential.m | 77 + .../Google/FIRGoogleAuthProvider.m | 41 + .../AuthProvider/OAuth/FIROAuthCredential.m | 130 + .../OAuth/FIROAuthCredential_Internal.h | 78 + .../AuthProvider/OAuth/FIROAuthProvider.m | 445 ++ .../Phone/FIRPhoneAuthCredential.m | 107 + .../Phone/FIRPhoneAuthCredential_Internal.h | 73 + .../AuthProvider/Phone/FIRPhoneAuthProvider.m | 754 ++ .../Twitter/FIRTwitterAuthCredential.h | 48 + .../Twitter/FIRTwitterAuthCredential.m | 74 + .../Twitter/FIRTwitterAuthProvider.m | 40 + .../Backend/FIRAuthBackend+MultiFactor.h | 125 + .../Backend/FIRAuthBackend+MultiFactor.m | 96 + .../Sources/Backend/FIRAuthBackend.h | 620 ++ .../Sources/Backend/FIRAuthBackend.m | 1453 ++++ .../Sources/Backend/FIRAuthRPCRequest.h | 57 + .../Sources/Backend/FIRAuthRPCResponse.h | 48 + .../Backend/FIRAuthRequestConfiguration.h | 57 + .../Backend/FIRAuthRequestConfiguration.m | 35 + .../Backend/FIRIdentityToolkitRequest.h | 76 + .../Backend/FIRIdentityToolkitRequest.m | 140 + .../Backend/RPC/FIRCreateAuthURIRequest.h | 88 + .../Backend/RPC/FIRCreateAuthURIRequest.m | 105 + .../Backend/RPC/FIRCreateAuthURIResponse.h | 61 + .../Backend/RPC/FIRCreateAuthURIResponse.m | 35 + .../Backend/RPC/FIRDeleteAccountRequest.h | 50 + .../Backend/RPC/FIRDeleteAccountRequest.m | 69 + .../Backend/RPC/FIRDeleteAccountResponse.h | 30 + .../Backend/RPC/FIRDeleteAccountResponse.m | 29 + .../Backend/RPC/FIREmailLinkSignInRequest.h | 66 + .../Backend/RPC/FIREmailLinkSignInRequest.m | 82 + .../Backend/RPC/FIREmailLinkSignInResponse.h | 71 + .../Backend/RPC/FIREmailLinkSignInResponse.m | 50 + .../Backend/RPC/FIRGetAccountInfoRequest.h | 53 + .../Backend/RPC/FIRGetAccountInfoRequest.m | 49 + .../Backend/RPC/FIRGetAccountInfoResponse.h | 158 + .../Backend/RPC/FIRGetAccountInfoResponse.m | 117 + .../RPC/FIRGetOOBConfirmationCodeRequest.h | 178 + .../RPC/FIRGetOOBConfirmationCodeRequest.m | 296 + .../RPC/FIRGetOOBConfirmationCodeResponse.h | 35 + .../RPC/FIRGetOOBConfirmationCodeResponse.m | 35 + .../Backend/RPC/FIRGetProjectConfigRequest.h | 40 + .../Backend/RPC/FIRGetProjectConfigRequest.m | 40 + .../Backend/RPC/FIRGetProjectConfigResponse.h | 40 + .../Backend/RPC/FIRGetProjectConfigResponse.m | 40 + .../Backend/RPC/FIRResetPasswordRequest.h | 55 + .../Backend/RPC/FIRResetPasswordRequest.m | 68 + .../Backend/RPC/FIRResetPasswordResponse.h | 52 + .../Backend/RPC/FIRResetPasswordResponse.m | 32 + .../Backend/RPC/FIRSecureTokenRequest.h | 113 + .../Backend/RPC/FIRSecureTokenRequest.m | 177 + .../Backend/RPC/FIRSecureTokenResponse.h | 50 + .../Backend/RPC/FIRSecureTokenResponse.m | 73 + .../RPC/FIRSendVerificationCodeRequest.h | 64 + .../RPC/FIRSendVerificationCodeRequest.m | 92 + .../RPC/FIRSendVerificationCodeResponse.h | 32 + .../RPC/FIRSendVerificationCodeResponse.m | 35 + .../Backend/RPC/FIRSetAccountInfoRequest.h | 151 + .../Backend/RPC/FIRSetAccountInfoRequest.m | 187 + .../Backend/RPC/FIRSetAccountInfoResponse.h | 98 + .../Backend/RPC/FIRSetAccountInfoResponse.m | 64 + .../RPC/FIRSignInWithGameCenterRequest.h | 91 + .../RPC/FIRSignInWithGameCenterRequest.m | 80 + .../RPC/FIRSignInWithGameCenterResponse.h | 64 + .../RPC/FIRSignInWithGameCenterResponse.m | 40 + .../Backend/RPC/FIRSignUpNewUserRequest.h | 72 + .../Backend/RPC/FIRSignUpNewUserRequest.m | 98 + .../Backend/RPC/FIRSignUpNewUserResponse.h | 44 + .../Backend/RPC/FIRSignUpNewUserResponse.m | 35 + .../Backend/RPC/FIRVerifyAssertionRequest.h | 118 + .../Backend/RPC/FIRVerifyAssertionRequest.m | 185 + .../Backend/RPC/FIRVerifyAssertionResponse.h | 221 + .../Backend/RPC/FIRVerifyAssertionResponse.m | 100 + .../Backend/RPC/FIRVerifyClientRequest.h | 55 + .../Backend/RPC/FIRVerifyClientRequest.m | 62 + .../Backend/RPC/FIRVerifyClientResponse.h | 38 + .../Backend/RPC/FIRVerifyClientResponse.m | 34 + .../Backend/RPC/FIRVerifyCustomTokenRequest.h | 58 + .../Backend/RPC/FIRVerifyCustomTokenRequest.m | 67 + .../RPC/FIRVerifyCustomTokenResponse.h | 52 + .../RPC/FIRVerifyCustomTokenResponse.m | 36 + .../Backend/RPC/FIRVerifyPasswordRequest.h | 81 + .../Backend/RPC/FIRVerifyPasswordRequest.m | 103 + .../Backend/RPC/FIRVerifyPasswordResponse.h | 82 + .../Backend/RPC/FIRVerifyPasswordResponse.m | 52 + .../Backend/RPC/FIRVerifyPhoneNumberRequest.h | 90 + .../Backend/RPC/FIRVerifyPhoneNumberRequest.m | 141 + .../RPC/FIRVerifyPhoneNumberResponse.h | 64 + .../RPC/FIRVerifyPhoneNumberResponse.m | 43 + .../Enroll/FIRFinalizeMFAEnrollmentRequest.h | 39 + .../Enroll/FIRFinalizeMFAEnrollmentRequest.m | 63 + .../Enroll/FIRFinalizeMFAEnrollmentResponse.h | 30 + .../Enroll/FIRFinalizeMFAEnrollmentResponse.m | 30 + .../Enroll/FIRStartMFAEnrollmentRequest.h | 35 + .../Enroll/FIRStartMFAEnrollmentRequest.m | 60 + .../Enroll/FIRStartMFAEnrollmentResponse.h | 29 + .../Enroll/FIRStartMFAEnrollmentResponse.m | 34 + .../SignIn/FIRFinalizeMFASignInRequest.h | 37 + .../SignIn/FIRFinalizeMFASignInRequest.m | 59 + .../SignIn/FIRFinalizeMFASignInResponse.h | 30 + .../SignIn/FIRFinalizeMFASignInResponse.m | 28 + .../SignIn/FIRStartMFASignInRequest.h | 39 + .../SignIn/FIRStartMFASignInRequest.m | 64 + .../SignIn/FIRStartMFASignInResponse.h | 28 + .../SignIn/FIRStartMFASignInResponse.m | 32 + .../Unenroll/FIRWithdrawMFARequest.h | 34 + .../Unenroll/FIRWithdrawMFARequest.m | 60 + .../Unenroll/FIRWithdrawMFAResponse.h | 29 + .../Unenroll/FIRWithdrawMFAResponse.m | 32 + .../Sources/Backend/RPC/Proto/FIRAuthProto.h | 30 + .../RPC/Proto/FIRAuthProtoMFAEnrollment.h | 33 + .../RPC/Proto/FIRAuthProtoMFAEnrollment.m | 43 + .../FIRAuthProtoFinalizeMFAPhoneRequestInfo.h | 31 + .../FIRAuthProtoFinalizeMFAPhoneRequestInfo.m | 46 + ...FIRAuthProtoFinalizeMFAPhoneResponseInfo.h | 27 + ...FIRAuthProtoFinalizeMFAPhoneResponseInfo.m | 33 + .../FIRAuthProtoStartMFAPhoneRequestInfo.h | 36 + .../FIRAuthProtoStartMFAPhoneRequestInfo.m | 74 + .../FIRAuthProtoStartMFAPhoneResponseInfo.h | 27 + .../FIRAuthProtoStartMFAPhoneResponseInfo.m | 33 + .../MultiFactor/FIRMultiFactor+Internal.h | 39 + .../Sources/MultiFactor/FIRMultiFactor.m | 195 + .../FIRMultiFactorAssertion+Internal.h | 33 + .../MultiFactor/FIRMultiFactorAssertion.m | 29 + .../MultiFactor/FIRMultiFactorConstants.m | 26 + .../MultiFactor/FIRMultiFactorInfo+Internal.h | 37 + .../Sources/MultiFactor/FIRMultiFactorInfo.m | 74 + .../FIRMultiFactorResolver+Internal.h | 34 + .../MultiFactor/FIRMultiFactorResolver.m | 101 + .../FIRMultiFactorSession+Internal.h | 39 + .../MultiFactor/FIRMultiFactorSession.m | 52 + .../FIRPhoneMultiFactorAssertion+Internal.h | 33 + .../Phone/FIRPhoneMultiFactorAssertion.m | 43 + .../Phone/FIRPhoneMultiFactorGenerator.m | 36 + .../Phone/FIRPhoneMultiFactorInfo+Internal.h | 30 + .../Phone/FIRPhoneMultiFactorInfo.m | 41 + .../FirebaseAuth/FIRActionCodeSettings.h | 89 + .../FirebaseAuth/FIRAdditionalUserInfo.h | 57 + .../Sources/Public/FirebaseAuth/FIRAuth.h | 867 +++ .../FirebaseAuth/FIRAuthAPNSTokenType.h | 41 + .../Public/FirebaseAuth/FIRAuthCredential.h | 41 + .../Public/FirebaseAuth/FIRAuthDataResult.h | 57 + .../Public/FirebaseAuth/FIRAuthErrors.h | 436 ++ .../Public/FirebaseAuth/FIRAuthSettings.h | 35 + .../Public/FirebaseAuth/FIRAuthTokenResult.h | 69 + .../Public/FirebaseAuth/FIRAuthUIDelegate.h | 54 + .../FirebaseAuth/FIREmailAuthProvider.h | 73 + .../FirebaseAuth/FIRFacebookAuthProvider.h | 54 + .../FirebaseAuth/FIRFederatedAuthProvider.h | 54 + .../FirebaseAuth/FIRGameCenterAuthProvider.h | 65 + .../FirebaseAuth/FIRGitHubAuthProvider.h | 54 + .../FirebaseAuth/FIRGoogleAuthProvider.h | 56 + .../Public/FirebaseAuth/FIRMultiFactor.h | 89 + .../FirebaseAuth/FIRMultiFactorAssertion.h | 36 + .../Public/FirebaseAuth/FIRMultiFactorInfo.h | 50 + .../FirebaseAuth/FIRMultiFactorResolver.h | 56 + .../FirebaseAuth/FIRMultiFactorSession.h | 31 + .../Public/FirebaseAuth/FIROAuthCredential.h | 53 + .../Public/FirebaseAuth/FIROAuthProvider.h | 124 + .../FirebaseAuth/FIRPhoneAuthCredential.h | 37 + .../FirebaseAuth/FIRPhoneAuthProvider.h | 144 + .../FIRPhoneMultiFactorAssertion.h | 33 + .../FIRPhoneMultiFactorGenerator.h | 43 + .../FirebaseAuth/FIRPhoneMultiFactorInfo.h | 38 + .../FirebaseAuth/FIRTwitterAuthProvider.h | 54 + .../Sources/Public/FirebaseAuth/FIRUser.h | 550 ++ .../Sources/Public/FirebaseAuth/FIRUserInfo.h | 60 + .../Public/FirebaseAuth/FIRUserMetadata.h | 45 + .../Public/FirebaseAuth/FirebaseAuth.h | 51 + .../Sources/Storage/FIRAuthKeychainServices.h | 99 + .../Sources/Storage/FIRAuthKeychainServices.m | 342 + .../Sources/Storage/FIRAuthUserDefaults.h | 36 + .../Sources/Storage/FIRAuthUserDefaults.m | 74 + .../Sources/SystemService/FIRAuthAPNSToken.h | 63 + .../Sources/SystemService/FIRAuthAPNSToken.m | 57 + .../SystemService/FIRAuthAPNSTokenManager.h | 83 + .../SystemService/FIRAuthAPNSTokenManager.m | 250 + .../SystemService/FIRAuthAppCredential.h | 52 + .../SystemService/FIRAuthAppCredential.m | 64 + .../FIRAuthAppCredentialManager.h | 90 + .../FIRAuthAppCredentialManager.m | 180 + .../FIRAuthNotificationManager.h | 76 + .../FIRAuthNotificationManager.m | 189 + .../SystemService/FIRAuthStoredUserManager.h | 108 + .../SystemService/FIRAuthStoredUserManager.m | 175 + .../SystemService/FIRSecureTokenService.h | 99 + .../SystemService/FIRSecureTokenService.m | 227 + .../Sources/User/FIRAdditionalUserInfo.m | 97 + .../User/FIRAdditionalUserInfo_Internal.h | 46 + .../FirebaseAuth/Sources/User/FIRUser.m | 1627 +++++ .../Sources/User/FIRUserInfoImpl.h | 60 + .../Sources/User/FIRUserInfoImpl.m | 131 + .../Sources/User/FIRUserMetadata.m | 64 + .../Sources/User/FIRUserMetadata_Internal.h | 37 + .../Sources/User/FIRUser_Internal.h | 107 + .../Utilities/FIRAuthDefaultUIDelegate.h | 47 + .../Utilities/FIRAuthDefaultUIDelegate.m | 126 + .../Sources/Utilities/FIRAuthErrorUtils.h | 610 ++ .../Sources/Utilities/FIRAuthErrorUtils.m | 1410 ++++ .../Sources/Utilities/FIRAuthExceptionUtils.h | 41 + .../Sources/Utilities/FIRAuthExceptionUtils.m | 41 + .../Sources/Utilities/FIRAuthInternalErrors.h | 543 ++ .../Sources/Utilities/FIRAuthURLPresenter.h | 69 + .../Sources/Utilities/FIRAuthURLPresenter.m | 208 + .../Sources/Utilities/FIRAuthWebUtils.h | 102 + .../Sources/Utilities/FIRAuthWebUtils.m | 211 + .../Sources/Utilities/FIRAuthWebView.h | 44 + .../Sources/Utilities/FIRAuthWebView.m | 104 + .../Utilities/FIRAuthWebViewController.h | 78 + .../Utilities/FIRAuthWebViewController.m | 118 + .../Sources/Utilities/NSData+FIRBase64.h | 31 + .../Sources/Utilities/NSData+FIRBase64.m | 33 + .../Sources/Private/FIRAppInternal.h | 153 + .../Sources/Private/FIRComponent.h | 91 + .../Sources/Private/FIRComponentContainer.h | 41 + .../Sources/Private/FIRComponentType.h | 34 + .../Private/FIRCoreDiagnosticsConnector.h | 35 + .../Sources/Private/FIRDependency.h | 45 + .../Sources/Private/FIRHeartbeatInfo.h | 39 + .../FirebaseCore/Sources/Private/FIRLibrary.h | 44 + .../FirebaseCore/Sources/Private/FIRLogger.h | 146 + .../Sources/Private/FIROptionsInternal.h | 115 + .../Sources/Private/FirebaseCoreInternal.h | 28 + .../Interop/Auth/Public/FIRAuthInterop.h | 44 + saraWhatsUp/Pods/FirebaseAuth/LICENSE | 202 + saraWhatsUp/Pods/FirebaseAuth/README.md | 319 + .../Sources/FIRAnalyticsConfiguration.h | 56 + .../Sources/FIRAnalyticsConfiguration.m | 62 + .../FirebaseCore/Sources/FIRApp.m | 856 +++ .../Sources/FIRAppAssociationRegistration.h | 49 + .../Sources/FIRAppAssociationRegistration.m | 47 + .../FirebaseCore/Sources/FIRBundleUtil.h | 53 + .../FirebaseCore/Sources/FIRBundleUtil.m | 79 + .../FirebaseCore/Sources/FIRComponent.m | 65 + .../Sources/FIRComponentContainer.m | 214 + .../Sources/FIRComponentContainerInternal.h | 49 + .../FirebaseCore/Sources/FIRComponentType.m | 28 + .../FirebaseCore/Sources/FIRConfiguration.m | 46 + .../Sources/FIRConfigurationInternal.h | 29 + .../Sources/FIRCoreDiagnosticsConnector.m | 61 + .../FirebaseCore/Sources/FIRDependency.m | 44 + .../FirebaseCore/Sources/FIRDiagnosticsData.h | 35 + .../FirebaseCore/Sources/FIRDiagnosticsData.m | 66 + .../Sources/FIRFirebaseUserAgent.h | 36 + .../Sources/FIRFirebaseUserAgent.m | 107 + .../FirebaseCore/Sources/FIRHeartbeatInfo.m | 72 + .../FirebaseCore/Sources/FIRLogger.m | 174 + .../FirebaseCore/Sources/FIROptions.m | 498 ++ .../FirebaseCore/Sources/FIRVersion.m | 32 + .../Sources/Private/FIRAppInternal.h | 153 + .../Sources/Private/FIRComponent.h | 91 + .../Sources/Private/FIRComponentContainer.h | 41 + .../Sources/Private/FIRComponentType.h | 34 + .../Private/FIRCoreDiagnosticsConnector.h | 35 + .../Sources/Private/FIRDependency.h | 45 + .../Sources/Private/FIRHeartbeatInfo.h | 39 + .../FirebaseCore/Sources/Private/FIRLibrary.h | 44 + .../FirebaseCore/Sources/Private/FIRLogger.h | 146 + .../Sources/Private/FIROptionsInternal.h | 115 + .../Sources/Private/FirebaseCoreInternal.h | 28 + .../Sources/Public/FirebaseCore/FIRApp.h | 127 + .../Public/FirebaseCore/FIRConfiguration.h | 45 + .../Public/FirebaseCore/FIRLoggerLevel.h | 38 + .../Sources/Public/FirebaseCore/FIROptions.h | 126 + .../Sources/Public/FirebaseCore/FIRVersion.h | 25 + .../Public/FirebaseCore/FirebaseCore.h | 21 + .../Public/FIRCoreDiagnosticsData.h | 61 + .../Public/FIRCoreDiagnosticsInterop.h | 34 + saraWhatsUp/Pods/FirebaseCore/LICENSE | 202 + saraWhatsUp/Pods/FirebaseCore/README.md | 319 + .../FIRCDLibrary/FIRCoreDiagnostics.m | 551 ++ .../Protogen/nanopb/firebasecore.nanopb.c | 60 + .../Protogen/nanopb/firebasecore.nanopb.h | 193 + .../FIRCDLibrary/Public/FIRCoreDiagnostics.h | 18 + .../Public/FIRCoreDiagnosticsData.h | 61 + .../Public/FIRCoreDiagnosticsInterop.h | 34 + .../Pods/FirebaseCoreDiagnostics/LICENSE | 202 + .../Pods/FirebaseCoreDiagnostics/README.md | 319 + .../Sources/Interop/FIRAppCheckInterop.h | 48 + .../Interop/FIRAppCheckTokenResultInterop.h | 32 + .../Sources/Private/FIRAppInternal.h | 153 + .../Sources/Private/FIRComponent.h | 91 + .../Sources/Private/FIRComponentContainer.h | 41 + .../Sources/Private/FIRComponentType.h | 34 + .../Private/FIRCoreDiagnosticsConnector.h | 35 + .../Sources/Private/FIRDependency.h | 45 + .../Sources/Private/FIRHeartbeatInfo.h | 39 + .../FirebaseCore/Sources/Private/FIRLibrary.h | 44 + .../FirebaseCore/Sources/Private/FIRLogger.h | 146 + .../Sources/Private/FIROptionsInternal.h | 115 + .../Sources/Private/FirebaseCoreInternal.h | 28 + .../Sources/Api/FIRDataSnapshot.m | 105 + .../Sources/Api/FIRDatabase.m | 260 + .../Sources/Api/FIRDatabaseComponent.h | 46 + .../Sources/Api/FIRDatabaseComponent.m | 172 + .../Sources/Api/FIRDatabaseConfig.h | 72 + .../Sources/Api/FIRDatabaseConfig.m | 96 + .../Sources/Api/FIRDatabaseQuery.m | 765 ++ .../Sources/Api/FIRMutableData.m | 149 + .../Sources/Api/FIRServerValue.m | 33 + .../Sources/Api/FIRTransactionResult.m | 39 + .../Api/Private/FIRDataSnapshot_Private.h | 28 + .../Api/Private/FIRDatabaseQuery_Private.h | 43 + .../Private/FIRDatabaseReference_Private.h | 27 + .../Sources/Api/Private/FIRDatabase_Private.h | 37 + .../Api/Private/FIRMutableData_Private.h | 26 + .../Private/FIRTransactionResult_Private.h | 25 + .../Sources/Api/Private/FTypedefs_Private.h | 62 + .../Sources/Constants/FConstants.h | 201 + .../Sources/Constants/FConstants.m | 191 + .../Sources/Core/FCompoundHash.h | 38 + .../Sources/Core/FCompoundHash.m | 259 + .../Sources/Core/FListenProvider.h | 32 + .../Sources/Core/FListenProvider.m | 25 + .../Sources/Core/FPersistentConnection.h | 103 + .../Sources/Core/FPersistentConnection.m | 1334 ++++ .../Sources/Core/FQueryParams.h | 60 + .../Sources/Core/FQueryParams.m | 393 + .../Sources/Core/FQuerySpec.h | 36 + .../Sources/Core/FQuerySpec.m | 86 + .../Sources/Core/FRangeMerge.h | 39 + .../Sources/Core/FRangeMerge.m | 134 + .../FirebaseDatabase/Sources/Core/FRepo.h | 102 + .../FirebaseDatabase/Sources/Core/FRepo.m | 1542 ++++ .../FirebaseDatabase/Sources/Core/FRepoInfo.h | 53 + .../FirebaseDatabase/Sources/Core/FRepoInfo.m | 153 + .../Sources/Core/FRepoManager.h | 34 + .../Sources/Core/FRepoManager.m | 148 + .../Sources/Core/FRepo_Private.h | 42 + .../Sources/Core/FServerValues.h | 40 + .../Sources/Core/FServerValues.m | 269 + .../Sources/Core/FSnapshotHolder.h | 27 + .../Sources/Core/FSnapshotHolder.m | 46 + .../Sources/Core/FSparseSnapshotTree.h | 34 + .../Sources/Core/FSparseSnapshotTree.m | 144 + .../Sources/Core/FSyncPoint.h | 74 + .../Sources/Core/FSyncPoint.m | 325 + .../FirebaseDatabase/Sources/Core/FSyncTree.h | 85 + .../FirebaseDatabase/Sources/Core/FSyncTree.m | 1093 +++ .../Sources/Core/FWriteRecord.h | 45 + .../Sources/Core/FWriteRecord.m | 139 + .../Sources/Core/FWriteTree.h | 70 + .../Sources/Core/FWriteTree.m | 577 ++ .../Sources/Core/FWriteTreeRef.h | 57 + .../Sources/Core/FWriteTreeRef.m | 159 + .../Sources/Core/Operation/FAckUserWrite.h | 37 + .../Sources/Core/Operation/FAckUserWrite.m | 66 + .../Sources/Core/Operation/FMerge.h | 32 + .../Sources/Core/Operation/FMerge.m | 85 + .../Sources/Core/Operation/FOperation.h | 34 + .../Sources/Core/Operation/FOperationSource.h | 37 + .../Sources/Core/Operation/FOperationSource.m | 86 + .../Sources/Core/Operation/FOverwrite.h | 32 + .../Sources/Core/Operation/FOverwrite.m | 67 + .../Sources/Core/Utilities/FIRRetryHelper.h | 33 + .../Sources/Core/Utilities/FIRRetryHelper.m | 140 + .../Sources/Core/Utilities/FImmutableTree.h | 59 + .../Sources/Core/Utilities/FImmutableTree.m | 486 ++ .../Sources/Core/Utilities/FPath.h | 46 + .../Sources/Core/Utilities/FPath.m | 304 + .../Sources/Core/Utilities/FTree.h | 52 + .../Sources/Core/Utilities/FTree.m | 193 + .../Sources/Core/Utilities/FTreeNode.h | 25 + .../Sources/Core/Utilities/FTreeNode.m | 35 + .../Sources/Core/View/FCacheNode.h | 46 + .../Sources/Core/View/FCacheNode.m | 60 + .../Sources/Core/View/FCancelEvent.h | 31 + .../Sources/Core/View/FCancelEvent.m | 57 + .../Sources/Core/View/FChange.h | 41 + .../Sources/Core/View/FChange.m | 72 + .../Core/View/FChildEventRegistration.h | 37 + .../Core/View/FChildEventRegistration.m | 112 + .../Sources/Core/View/FDataEvent.h | 41 + .../Sources/Core/View/FDataEvent.m | 83 + .../Sources/Core/View/FEvent.h | 27 + .../Sources/Core/View/FEventRaiser.h | 36 + .../Sources/Core/View/FEventRaiser.m | 74 + .../Sources/Core/View/FEventRegistration.h | 38 + .../Core/View/FKeepSyncedEventRegistration.h | 28 + .../Core/View/FKeepSyncedEventRegistration.m | 70 + .../Core/View/FValueEventRegistration.h | 34 + .../Core/View/FValueEventRegistration.m | 102 + .../Sources/Core/View/FView.h | 58 + .../Sources/Core/View/FView.m | 285 + .../Sources/Core/View/FViewCache.h | 40 + .../Sources/Core/View/FViewCache.m | 72 + .../View/Filter/FChildChangeAccumulator.h | 27 + .../View/Filter/FChildChangeAccumulator.m | 99 + .../Core/View/Filter/FCompleteChildSource.h | 30 + .../Sources/Core/View/Filter/FIndexedFilter.h | 26 + .../Sources/Core/View/Filter/FIndexedFilter.m | 164 + .../Sources/Core/View/Filter/FLimitedFilter.h | 25 + .../Sources/Core/View/Filter/FLimitedFilter.m | 285 + .../Sources/Core/View/Filter/FNodeFilter.h | 77 + .../FirebaseDatabase/Sources/FClock.h | 35 + .../FirebaseDatabase/Sources/FClock.m | 58 + .../Sources/FEventGenerator.h | 28 + .../Sources/FEventGenerator.m | 169 + .../Sources/FIRDatabaseConfig_Private.h | 33 + .../Sources/FIRDatabaseReference.m | 542 ++ .../FirebaseDatabase/Sources/FIndex.h | 51 + .../FirebaseDatabase/Sources/FIndex.m | 39 + .../FirebaseDatabase/Sources/FKeyIndex.h | 22 + .../FirebaseDatabase/Sources/FKeyIndex.m | 123 + .../Sources/FListenComplete.h | 28 + .../Sources/FListenComplete.m | 55 + .../FirebaseDatabase/Sources/FMaxNode.h | 22 + .../FirebaseDatabase/Sources/FMaxNode.m | 58 + .../FirebaseDatabase/Sources/FNamedNode.h | 31 + .../FirebaseDatabase/Sources/FNamedNode.m | 102 + .../FirebaseDatabase/Sources/FPathIndex.h | 23 + .../FirebaseDatabase/Sources/FPathIndex.m | 135 + .../FirebaseDatabase/Sources/FPriorityIndex.h | 23 + .../FirebaseDatabase/Sources/FPriorityIndex.m | 126 + .../FirebaseDatabase/Sources/FRangedFilter.h | 31 + .../FirebaseDatabase/Sources/FRangedFilter.m | 129 + .../Sources/FTransformedEnumerator.h | 24 + .../Sources/FTransformedEnumerator.m | 44 + .../FirebaseDatabase/Sources/FValueIndex.h | 22 + .../FirebaseDatabase/Sources/FValueIndex.m | 112 + .../FirebaseDatabase/Sources/FViewProcessor.h | 42 + .../FirebaseDatabase/Sources/FViewProcessor.m | 831 +++ .../Sources/FViewProcessorResult.h | 29 + .../Sources/FViewProcessorResult.m | 35 + .../FIRDatabaseConnectionContextProvider.h | 70 + .../FIRDatabaseConnectionContextProvider.m | 225 + .../Sources/Persistence/FCachePolicy.h | 41 + .../Sources/Persistence/FCachePolicy.m | 82 + .../Persistence/FLevelDBStorageEngine.h | 39 + .../Persistence/FLevelDBStorageEngine.m | 1002 +++ .../Sources/Persistence/FPendingPut.h | 53 + .../Sources/Persistence/FPendingPut.m | 113 + .../Sources/Persistence/FPersistenceManager.h | 60 + .../Sources/Persistence/FPersistenceManager.m | 231 + .../Sources/Persistence/FPruneForest.h | 38 + .../Sources/Persistence/FPruneForest.m | 194 + .../Sources/Persistence/FStorageEngine.h | 60 + .../Sources/Persistence/FTrackedQuery.h | 43 + .../Sources/Persistence/FTrackedQuery.m | 113 + .../Persistence/FTrackedQueryManager.h | 52 + .../Persistence/FTrackedQueryManager.m | 375 + .../FirebaseDatabase/FIRDataEventType.h | 39 + .../Public/FirebaseDatabase/FIRDataSnapshot.h | 142 + .../Public/FirebaseDatabase/FIRDatabase.h | 186 + .../FirebaseDatabase/FIRDatabaseQuery.h | 467 ++ .../FirebaseDatabase/FIRDatabaseReference.h | 906 +++ .../Public/FirebaseDatabase/FIRMutableData.h | 128 + .../Public/FirebaseDatabase/FIRServerValue.h | 53 + .../FirebaseDatabase/FIRTransactionResult.h | 50 + .../FirebaseDatabase/FirebaseDatabase.h | 29 + .../Sources/Realtime/FConnection.h | 61 + .../Sources/Realtime/FConnection.m | 238 + .../Sources/Realtime/FWebSocketConnection.h | 67 + .../Sources/Realtime/FWebSocketConnection.m | 504 ++ .../Sources/Snapshot/FChildrenNode.h | 42 + .../Sources/Snapshot/FChildrenNode.m | 418 ++ .../Sources/Snapshot/FCompoundWrite.h | 64 + .../Sources/Snapshot/FCompoundWrite.m | 304 + .../Sources/Snapshot/FEmptyNode.h | 24 + .../Sources/Snapshot/FEmptyNode.m | 30 + .../Sources/Snapshot/FIndexedNode.h | 55 + .../Sources/Snapshot/FIndexedNode.m | 218 + .../Sources/Snapshot/FLeafNode.h | 27 + .../Sources/Snapshot/FLeafNode.m | 266 + .../FirebaseDatabase/Sources/Snapshot/FNode.h | 50 + .../Sources/Snapshot/FSnapshotUtilities.h | 49 + .../Sources/Snapshot/FSnapshotUtilities.m | 394 + .../Sources/Utilities/FAtomicNumber.h | 23 + .../Sources/Utilities/FAtomicNumber.m | 55 + .../Sources/Utilities/FEventEmitter.h | 36 + .../Sources/Utilities/FEventEmitter.m | 161 + .../Sources/Utilities/FNextPushId.h | 27 + .../Sources/Utilities/FNextPushId.m | 144 + .../Sources/Utilities/FParsedUrl.h | 25 + .../Sources/Utilities/FParsedUrl.m | 24 + .../Sources/Utilities/FStringUtilities.h | 26 + .../Sources/Utilities/FStringUtilities.m | 72 + .../Sources/Utilities/FTypedefs.h | 46 + .../Sources/Utilities/FUtilities.h | 88 + .../Sources/Utilities/FUtilities.m | 443 ++ .../Sources/Utilities/FValidation.h | 55 + .../Sources/Utilities/FValidation.m | 461 ++ .../Utilities/Tuples/FTupleBoolBlock.h | 25 + .../Utilities/Tuples/FTupleBoolBlock.m | 24 + .../Utilities/Tuples/FTupleCallbackStatus.h | 24 + .../Utilities/Tuples/FTupleCallbackStatus.m | 22 + .../Sources/Utilities/Tuples/FTupleFirebase.h | 26 + .../Sources/Utilities/Tuples/FTupleFirebase.m | 25 + .../Sources/Utilities/Tuples/FTupleNodePath.h | 28 + .../Sources/Utilities/Tuples/FTupleNodePath.m | 33 + .../Utilities/Tuples/FTupleObjectNode.h | 27 + .../Utilities/Tuples/FTupleObjectNode.m | 32 + .../Sources/Utilities/Tuples/FTupleObjects.h | 24 + .../Sources/Utilities/Tuples/FTupleObjects.m | 24 + .../Utilities/Tuples/FTupleOnDisconnect.h | 27 + .../Utilities/Tuples/FTupleOnDisconnect.m | 26 + .../Utilities/Tuples/FTuplePathValue.h | 25 + .../Utilities/Tuples/FTuplePathValue.m | 38 + .../Tuples/FTupleRemovedQueriesEvents.h | 30 + .../Tuples/FTupleRemovedQueriesEvents.m | 37 + .../Utilities/Tuples/FTupleSetIdPath.h | 27 + .../Utilities/Tuples/FTupleSetIdPath.m | 33 + .../Utilities/Tuples/FTupleStringNode.h | 27 + .../Utilities/Tuples/FTupleStringNode.m | 33 + .../Sources/Utilities/Tuples/FTupleTSN.h | 25 + .../Sources/Utilities/Tuples/FTupleTSN.m | 24 + .../Utilities/Tuples/FTupleTransaction.h | 75 + .../Utilities/Tuples/FTupleTransaction.m | 41 + .../Utilities/Tuples/FTupleUserCallback.h | 32 + .../Utilities/Tuples/FTupleUserCallback.m | 35 + .../FArraySortedDictionary.h | 21 + .../FArraySortedDictionary.m | 266 + .../FImmutableSortedDictionary.h | 54 + .../FImmutableSortedDictionary.m | 142 + .../FImmutableSortedSet.h | 22 + .../FImmutableSortedSet.m | 115 + .../FLLRBEmptyNode.h | 27 + .../FLLRBEmptyNode.m | 72 + .../FImmutableSortedDictionary/FLLRBNode.h | 29 + .../FLLRBValueNode.h | 29 + .../FLLRBValueNode.m | 230 + .../FTreeSortedDictionary.h | 30 + .../FTreeSortedDictionary.m | 326 + .../FTreeSortedDictionaryEnumerator.h | 9 + .../FTreeSortedDictionaryEnumerator.m | 83 + .../third_party/SocketRocket/FSRWebSocket.h | 112 + .../third_party/SocketRocket/FSRWebSocket.m | 1874 +++++ .../SocketRocket/NSData+SRB64Additions.h | 23 + .../SocketRocket/NSData+SRB64Additions.m | 37 + .../third_party/SocketRocket/fbase64.c | 318 + .../third_party/SocketRocket/fbase64.h | 33 + .../third_party/Wrap-leveldb/APLevelDB.h | 105 + .../third_party/Wrap-leveldb/APLevelDB.mm | 500 ++ .../Interop/Auth/Public/FIRAuthInterop.h | 44 + saraWhatsUp/Pods/FirebaseDatabase/LICENSE | 202 + saraWhatsUp/Pods/FirebaseDatabase/README.md | 319 + .../Sources/Interop/FIRAppCheckInterop.h | 48 + .../Interop/FIRAppCheckTokenResultInterop.h | 32 + .../Sources/Private/FIRAppInternal.h | 153 + .../Sources/Private/FIRComponent.h | 91 + .../Sources/Private/FIRComponentContainer.h | 41 + .../Sources/Private/FIRComponentType.h | 34 + .../Private/FIRCoreDiagnosticsConnector.h | 35 + .../Sources/Private/FIRDependency.h | 45 + .../Sources/Private/FIRHeartbeatInfo.h | 39 + .../FirebaseCore/Sources/Private/FIRLibrary.h | 44 + .../FirebaseCore/Sources/Private/FIRLogger.h | 146 + .../Sources/Private/FIROptionsInternal.h | 115 + .../Sources/Private/FirebaseCoreInternal.h | 28 + .../FirebaseStorage/Sources/FIRStorage.m | 373 + .../Sources/FIRStorageComponent.h | 45 + .../Sources/FIRStorageComponent.m | 102 + .../Sources/FIRStorageConstants.m | 87 + .../Sources/FIRStorageConstants_Private.h | 151 + .../Sources/FIRStorageDeleteTask.h | 35 + .../Sources/FIRStorageDeleteTask.m | 83 + .../Sources/FIRStorageDownloadTask.m | 199 + .../Sources/FIRStorageDownloadTask_Private.h | 59 + .../Sources/FIRStorageErrors.h | 70 + .../Sources/FIRStorageErrors.m | 190 + .../Sources/FIRStorageGetDownloadURLTask.h | 35 + .../Sources/FIRStorageGetDownloadURLTask.m | 126 + .../FIRStorageGetDownloadURLTask_Private.h | 31 + .../Sources/FIRStorageGetMetadataTask.h | 35 + .../Sources/FIRStorageGetMetadataTask.m | 98 + .../Sources/FIRStorageListResult.m | 70 + .../Sources/FIRStorageListResult_Private.h | 40 + .../Sources/FIRStorageListTask.h | 57 + .../Sources/FIRStorageListTask.m | 126 + .../Sources/FIRStorageLogger.h | 24 + .../Sources/FIRStorageLogger.m | 22 + .../Sources/FIRStorageMetadata.m | 225 + .../Sources/FIRStorageMetadata_Private.h | 73 + .../Sources/FIRStorageObservableTask.m | 215 + .../FIRStorageObservableTask_Private.h | 51 + .../FirebaseStorage/Sources/FIRStoragePath.h | 106 + .../FirebaseStorage/Sources/FIRStoragePath.m | 195 + .../Sources/FIRStorageReference.m | 492 ++ .../Sources/FIRStorageReference_Private.h | 39 + .../FirebaseStorage/Sources/FIRStorageTask.m | 73 + .../Sources/FIRStorageTaskSnapshot.m | 88 + .../Sources/FIRStorageTaskSnapshot_Private.h | 60 + .../Sources/FIRStorageTask_Private.h | 96 + .../Sources/FIRStorageTokenAuthorizer.h | 54 + .../Sources/FIRStorageTokenAuthorizer.m | 166 + .../Sources/FIRStorageUpdateMetadataTask.h | 36 + .../Sources/FIRStorageUpdateMetadataTask.m | 107 + .../Sources/FIRStorageUploadTask.m | 277 + .../Sources/FIRStorageUploadTask_Private.h | 73 + .../FirebaseStorage/Sources/FIRStorageUtils.h | 122 + .../FirebaseStorage/Sources/FIRStorageUtils.m | 182 + .../Sources/FIRStorage_Private.h | 70 + .../Public/FirebaseStorage/FIRStorage.h | 132 + .../FirebaseStorage/FIRStorageConstants.h | 174 + .../FirebaseStorage/FIRStorageDownloadTask.h | 38 + .../FirebaseStorage/FIRStorageListResult.h | 53 + .../FirebaseStorage/FIRStorageMetadata.h | 140 + .../FIRStorageObservableTask.h | 62 + .../FirebaseStorage/FIRStorageReference.h | 315 + .../Public/FirebaseStorage/FIRStorageTask.h | 75 + .../FirebaseStorage/FIRStorageTaskSnapshot.h | 67 + .../FirebaseStorage/FIRStorageUploadTask.h | 38 + .../Public/FirebaseStorage/FirebaseStorage.h | 26 + .../Interop/Auth/Public/FIRAuthInterop.h | 44 + saraWhatsUp/Pods/FirebaseStorage/LICENSE | 202 + saraWhatsUp/Pods/FirebaseStorage/README.md | 319 + saraWhatsUp/Pods/GTMSessionFetcher/LICENSE | 202 + saraWhatsUp/Pods/GTMSessionFetcher/README.md | 23 + .../Source/GTMSessionFetcher.h | 1386 ++++ .../Source/GTMSessionFetcher.m | 4758 ++++++++++++ .../Source/GTMSessionFetcherLogging.h | 111 + .../Source/GTMSessionFetcherLogging.m | 965 +++ .../Source/GTMSessionFetcherService.h | 210 + .../Source/GTMSessionFetcherService.m | 1383 ++++ .../Source/GTMSessionUploadFetcher.h | 173 + .../Source/GTMSessionUploadFetcher.m | 2001 +++++ .../GDTCCTLibrary/GDTCCTCompressionHelper.m | 95 + .../GDTCCTLibrary/GDTCCTNanopbHelpers.m | 270 + .../GDTCCTLibrary/GDTCCTUploadOperation.m | 573 ++ .../GDTCCTLibrary/GDTCCTUploader.m | 210 + .../GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m | 240 + .../Private/GDTCCTCompressionHelper.h | 40 + .../Private/GDTCCTNanopbHelpers.h | 128 + .../Private/GDTCCTUploadOperation.h | 76 + .../GDTCCTLibrary/Private/GDTCCTUploader.h | 45 + .../Protogen/nanopb/cct.nanopb.c | 128 + .../Protogen/nanopb/cct.nanopb.h | 281 + .../Public/GDTCOREvent+GDTCCTSupport.h | 51 + .../GDTCORLibrary/GDTCORAssert.m | 36 + .../GDTCORLibrary/GDTCORClock.m | 178 + .../GDTCORLibrary/GDTCORConsoleLogger.m | 55 + .../GDTCORDirectorySizeTracker.m | 101 + .../GDTCORLibrary/GDTCOREndpoints.m | 92 + .../GDTCORLibrary/GDTCOREvent.m | 153 + .../GDTCORFlatFileStorage+Promises.m | 104 + .../GDTCORLibrary/GDTCORFlatFileStorage.m | 826 +++ .../GDTCORLibrary/GDTCORLifecycle.m | 119 + .../GDTCORLibrary/GDTCORPlatform.m | 604 ++ .../GDTCORLibrary/GDTCORReachability.m | 125 + .../GDTCORLibrary/GDTCORRegistrar.m | 157 + .../GDTCORStorageEventSelector.m | 39 + .../GDTCORLibrary/GDTCORTransformer.m | 111 + .../GDTCORLibrary/GDTCORTransport.m | 92 + .../GDTCORLibrary/GDTCORUploadBatch.m | 30 + .../GDTCORLibrary/GDTCORUploadCoordinator.m | 176 + .../GDTCORLibrary/Internal/GDTCORAssert.h | 95 + .../Internal/GDTCORDirectorySizeTracker.h | 66 + .../GDTCORLibrary/Internal/GDTCORLifecycle.h | 63 + .../GDTCORLibrary/Internal/GDTCORPlatform.h | 225 + .../Internal/GDTCORReachability.h | 31 + .../GDTCORLibrary/Internal/GDTCORRegistrar.h | 50 + .../Internal/GDTCORStorageEventSelector.h | 61 + .../Internal/GDTCORStorageProtocol.h | 171 + .../GDTCORLibrary/Internal/GDTCORUploader.h | 59 + .../Private/GDTCOREndpoints_Private.h | 27 + .../Private/GDTCOREvent_Private.h | 33 + .../Private/GDTCORFlatFileStorage+Promises.h | 28 + .../Private/GDTCORFlatFileStorage.h | 158 + .../Private/GDTCORReachability_Private.h | 30 + .../Private/GDTCORRegistrar_Private.h | 35 + .../GDTCORLibrary/Private/GDTCORTransformer.h | 57 + .../Private/GDTCORTransformer_Private.h | 37 + .../Private/GDTCORTransport_Private.h | 39 + .../GDTCORLibrary/Private/GDTCORUploadBatch.h | 37 + .../Private/GDTCORUploadCoordinator.h | 68 + .../Public/GoogleDataTransport/GDTCORClock.h | 66 + .../GoogleDataTransport/GDTCORConsoleLogger.h | 144 + .../GoogleDataTransport/GDTCOREndpoints.h | 36 + .../Public/GoogleDataTransport/GDTCOREvent.h | 87 + .../GDTCOREventDataObject.h | 36 + .../GDTCOREventTransformer.h | 38 + .../GoogleDataTransport/GDTCORTargets.h | 40 + .../GoogleDataTransport/GDTCORTransport.h | 92 + .../GoogleDataTransport/GoogleDataTransport.h | 24 + saraWhatsUp/Pods/GoogleDataTransport/LICENSE | 202 + .../Pods/GoogleDataTransport/README.md | 231 + .../GULAppDelegateSwizzler.m | 1070 +++ .../GULSceneDelegateSwizzler.m | 439 ++ .../Internal/GULAppDelegateSwizzler_Private.h | 55 + .../GULSceneDelegateSwizzler_Private.h | 48 + .../GoogleUtilities/GULAppDelegateSwizzler.h | 107 + .../Public/GoogleUtilities/GULApplication.h | 50 + .../GULSceneDelegateSwizzler.h | 76 + .../GoogleUtilities/Common/GULLoggerCodes.h | 56 + .../Environment/GULHeartbeatDateStorage.m | 153 + .../GULHeartbeatDateStorageUserDefaults.m | 68 + .../Environment/GULSecureCoding.m | 103 + .../GoogleUtilities/GULAppEnvironmentUtil.h | 60 + .../GULHeartbeatDateStorable.h | 40 + .../GoogleUtilities/GULHeartbeatDateStorage.h | 54 + .../GULHeartbeatDateStorageUserDefaults.h | 51 + .../GoogleUtilities/GULKeychainStorage.h | 79 + .../Public/GoogleUtilities/GULKeychainUtils.h | 61 + .../Public/GoogleUtilities/GULSecureCoding.h | 36 + .../GULURLSessionDataResponse.h | 31 + .../NSURLSession+GULPromises.h | 37 + .../SecureStorage/GULKeychainStorage.m | 192 + .../SecureStorage/GULKeychainUtils.m | 113 + .../GULURLSessionDataResponse.m | 30 + .../NSURLSession+GULPromises.m | 46 + .../third_party/GULAppEnvironmentUtil.m | 333 + .../GoogleUtilities/Logger/GULLogger.m | 215 + .../Logger/Public/GoogleUtilities/GULLogger.h | 159 + .../Public/GoogleUtilities/GULLoggerLevel.h | 37 + .../NSData+zlib/GULNSData+zlib.m | 207 + .../Public/GoogleUtilities/GULNSData+zlib.h | 49 + .../Network/GULMutableDictionary.m | 101 + .../GoogleUtilities/Network/GULNetwork.m | 390 + .../Network/GULNetworkConstants.m | 41 + .../Network/GULNetworkInternal.h | 24 + .../Network/GULNetworkURLSession.m | 766 ++ .../GoogleUtilities/GULMutableDictionary.h | 46 + .../Public/GoogleUtilities/GULNetwork.h | 87 + .../GoogleUtilities/GULNetworkConstants.h | 71 + .../GULNetworkLoggerProtocol.h | 49 + .../GoogleUtilities/GULNetworkMessageCode.h | 47 + .../GoogleUtilities/GULNetworkURLSession.h | 62 + .../GULReachabilityChecker+Internal.h | 48 + .../Reachability/GULReachabilityChecker.m | 263 + .../Reachability/GULReachabilityMessageCode.h | 29 + .../GoogleUtilities/GULReachabilityChecker.h | 79 + saraWhatsUp/Pods/GoogleUtilities/LICENSE | 247 + saraWhatsUp/Pods/GoogleUtilities/README.md | 189 + .../Pods/Headers/Private/Firebase/Firebase.h | 1 + .../Pods/Headers/Public/Firebase/Firebase.h | 1 + saraWhatsUp/Pods/Manifest.lock | 97 + .../Pods/Pods.xcodeproj/project.pbxproj | 6464 +++++++++++++++++ saraWhatsUp/Pods/PromisesObjC/LICENSE | 202 + saraWhatsUp/Pods/PromisesObjC/README.md | 60 + .../Sources/FBLPromises/FBLPromise+All.m | 86 + .../Sources/FBLPromises/FBLPromise+Always.m | 58 + .../Sources/FBLPromises/FBLPromise+Any.m | 112 + .../Sources/FBLPromises/FBLPromise+Async.m | 70 + .../Sources/FBLPromises/FBLPromise+Await.m | 48 + .../Sources/FBLPromises/FBLPromise+Catch.m | 55 + .../Sources/FBLPromises/FBLPromise+Delay.m | 59 + .../Sources/FBLPromises/FBLPromise+Do.m | 59 + .../Sources/FBLPromises/FBLPromise+Race.m | 65 + .../Sources/FBLPromises/FBLPromise+Recover.m | 54 + .../Sources/FBLPromises/FBLPromise+Reduce.m | 61 + .../Sources/FBLPromises/FBLPromise+Retry.m | 128 + .../Sources/FBLPromises/FBLPromise+Testing.m | 55 + .../Sources/FBLPromises/FBLPromise+Then.m | 50 + .../Sources/FBLPromises/FBLPromise+Timeout.m | 64 + .../Sources/FBLPromises/FBLPromise+Validate.m | 56 + .../Sources/FBLPromises/FBLPromise+Wrap.m | 420 ++ .../Sources/FBLPromises/FBLPromise.m | 299 + .../Sources/FBLPromises/FBLPromiseError.m | 19 + .../FBLPromises/include/FBLPromise+All.h | 63 + .../FBLPromises/include/FBLPromise+Always.h | 54 + .../FBLPromises/include/FBLPromise+Any.h | 69 + .../FBLPromises/include/FBLPromise+Async.h | 60 + .../FBLPromises/include/FBLPromise+Await.h | 32 + .../FBLPromises/include/FBLPromise+Catch.h | 59 + .../FBLPromises/include/FBLPromise+Delay.h | 59 + .../FBLPromises/include/FBLPromise+Do.h | 55 + .../FBLPromises/include/FBLPromise+Race.h | 62 + .../FBLPromises/include/FBLPromise+Recover.h | 60 + .../FBLPromises/include/FBLPromise+Reduce.h | 71 + .../FBLPromises/include/FBLPromise+Retry.h | 165 + .../FBLPromises/include/FBLPromise+Testing.h | 57 + .../FBLPromises/include/FBLPromise+Then.h | 63 + .../FBLPromises/include/FBLPromise+Timeout.h | 57 + .../FBLPromises/include/FBLPromise+Validate.h | 60 + .../FBLPromises/include/FBLPromise+Wrap.h | 316 + .../Sources/FBLPromises/include/FBLPromise.h | 93 + .../FBLPromises/include/FBLPromiseError.h | 43 + .../FBLPromises/include/FBLPromisePrivate.h | 66 + .../Sources/FBLPromises/include/FBLPromises.h | 32 + .../Firebase/Firebase.debug.xcconfig | 13 + .../Firebase/Firebase.release.xcconfig | 13 + .../FirebaseAuth/FirebaseAuth-Info.plist | 26 + .../FirebaseAuth/FirebaseAuth-dummy.m | 5 + .../FirebaseAuth/FirebaseAuth-umbrella.h | 49 + .../FirebaseAuth/FirebaseAuth.debug.xcconfig | 15 + .../FirebaseAuth/FirebaseAuth.modulemap | 6 + .../FirebaseAuth.release.xcconfig | 15 + .../FirebaseCore/FirebaseCore-Info.plist | 26 + .../FirebaseCore/FirebaseCore-dummy.m | 5 + .../FirebaseCore/FirebaseCore-umbrella.h | 22 + .../FirebaseCore/FirebaseCore.debug.xcconfig | 16 + .../FirebaseCore/FirebaseCore.modulemap | 6 + .../FirebaseCore.release.xcconfig | 16 + .../FirebaseCoreDiagnostics-Info.plist | 26 + .../FirebaseCoreDiagnostics-dummy.m | 5 + .../FirebaseCoreDiagnostics-umbrella.h | 17 + .../FirebaseCoreDiagnostics.debug.xcconfig | 17 + .../FirebaseCoreDiagnostics.modulemap | 6 + .../FirebaseCoreDiagnostics.release.xcconfig | 17 + .../FirebaseDatabase-Info.plist | 26 + .../FirebaseDatabase/FirebaseDatabase-dummy.m | 5 + .../FirebaseDatabase-umbrella.h | 25 + .../FirebaseDatabase.debug.xcconfig | 15 + .../FirebaseDatabase.modulemap | 6 + .../FirebaseDatabase.release.xcconfig | 15 + .../FirebaseStorage-Info.plist | 26 + .../FirebaseStorage/FirebaseStorage-dummy.m | 5 + .../FirebaseStorage-umbrella.h | 27 + .../FirebaseStorage.debug.xcconfig | 15 + .../FirebaseStorage/FirebaseStorage.modulemap | 6 + .../FirebaseStorage.release.xcconfig | 15 + .../GTMSessionFetcher-Info.plist | 26 + .../GTMSessionFetcher-dummy.m | 5 + .../GTMSessionFetcher-prefix.pch | 12 + .../GTMSessionFetcher-umbrella.h | 20 + .../GTMSessionFetcher.debug.xcconfig | 12 + .../GTMSessionFetcher.modulemap | 6 + .../GTMSessionFetcher.release.xcconfig | 12 + .../GoogleDataTransport-Info.plist | 26 + .../GoogleDataTransport-dummy.m | 5 + .../GoogleDataTransport-umbrella.h | 25 + .../GoogleDataTransport.debug.xcconfig | 16 + .../GoogleDataTransport.modulemap | 6 + .../GoogleDataTransport.release.xcconfig | 16 + .../GoogleUtilities-Info.plist | 26 + .../GoogleUtilities/GoogleUtilities-dummy.m | 5 + .../GoogleUtilities-umbrella.h | 38 + .../GoogleUtilities.debug.xcconfig | 15 + .../GoogleUtilities/GoogleUtilities.modulemap | 6 + .../GoogleUtilities.release.xcconfig | 15 + .../Pods-saraWhatsUp-Info.plist | 26 + ...Pods-saraWhatsUp-acknowledgements.markdown | 2163 ++++++ .../Pods-saraWhatsUp-acknowledgements.plist | 2261 ++++++ .../Pods-saraWhatsUp/Pods-saraWhatsUp-dummy.m | 5 + ...Up-frameworks-Debug-input-files.xcfilelist | 12 + ...p-frameworks-Debug-output-files.xcfilelist | 11 + ...-frameworks-Release-input-files.xcfilelist | 12 + ...frameworks-Release-output-files.xcfilelist | 11 + .../Pods-saraWhatsUp-frameworks.sh | 206 + .../Pods-saraWhatsUp-umbrella.h | 16 + .../Pods-saraWhatsUp.debug.xcconfig | 12 + .../Pods-saraWhatsUp.modulemap | 6 + .../Pods-saraWhatsUp.release.xcconfig | 12 + .../PromisesObjC/PromisesObjC-Info.plist | 26 + .../PromisesObjC/PromisesObjC-dummy.m | 5 + .../PromisesObjC/PromisesObjC-umbrella.h | 36 + .../PromisesObjC/PromisesObjC.debug.xcconfig | 12 + .../PromisesObjC/PromisesObjC.modulemap | 6 + .../PromisesObjC.release.xcconfig | 12 + .../leveldb-library-Info.plist | 26 + .../leveldb-library/leveldb-library-dummy.m | 5 + .../leveldb-library-prefix.pch | 12 + .../leveldb-library-umbrella.h | 31 + .../leveldb-library.debug.xcconfig | 15 + .../leveldb-library/leveldb-library.modulemap | 6 + .../leveldb-library.release.xcconfig | 15 + .../nanopb/nanopb-Info.plist | 26 + .../nanopb/nanopb-dummy.m | 5 + .../nanopb/nanopb-prefix.pch | 12 + .../nanopb/nanopb-umbrella.h | 26 + .../nanopb/nanopb.debug.xcconfig | 11 + .../nanopb/nanopb.modulemap | 6 + .../nanopb/nanopb.release.xcconfig | 11 + saraWhatsUp/Pods/leveldb-library/LICENSE | 27 + saraWhatsUp/Pods/leveldb-library/README.md | 225 + .../Pods/leveldb-library/db/builder.cc | 79 + saraWhatsUp/Pods/leveldb-library/db/builder.h | 30 + saraWhatsUp/Pods/leveldb-library/db/c.cc | 566 ++ .../Pods/leveldb-library/db/db_impl.cc | 1550 ++++ saraWhatsUp/Pods/leveldb-library/db/db_impl.h | 216 + .../Pods/leveldb-library/db/db_iter.cc | 309 + saraWhatsUp/Pods/leveldb-library/db/db_iter.h | 26 + .../Pods/leveldb-library/db/dbformat.cc | 140 + .../Pods/leveldb-library/db/dbformat.h | 218 + .../Pods/leveldb-library/db/dumpfile.cc | 232 + .../Pods/leveldb-library/db/filename.cc | 141 + .../Pods/leveldb-library/db/filename.h | 84 + .../Pods/leveldb-library/db/log_format.h | 35 + .../Pods/leveldb-library/db/log_reader.cc | 274 + .../Pods/leveldb-library/db/log_reader.h | 112 + .../Pods/leveldb-library/db/log_writer.cc | 111 + .../Pods/leveldb-library/db/log_writer.h | 54 + .../Pods/leveldb-library/db/memtable.cc | 136 + .../Pods/leveldb-library/db/memtable.h | 87 + saraWhatsUp/Pods/leveldb-library/db/repair.cc | 450 ++ .../Pods/leveldb-library/db/skiplist.h | 382 + .../Pods/leveldb-library/db/snapshot.h | 95 + .../Pods/leveldb-library/db/table_cache.cc | 120 + .../Pods/leveldb-library/db/table_cache.h | 58 + .../Pods/leveldb-library/db/version_edit.cc | 260 + .../Pods/leveldb-library/db/version_edit.h | 106 + .../Pods/leveldb-library/db/version_set.cc | 1585 ++++ .../Pods/leveldb-library/db/version_set.h | 393 + .../Pods/leveldb-library/db/write_batch.cc | 150 + .../leveldb-library/db/write_batch_internal.h | 45 + .../Pods/leveldb-library/include/leveldb/c.h | 270 + .../leveldb-library/include/leveldb/cache.h | 111 + .../include/leveldb/comparator.h | 64 + .../Pods/leveldb-library/include/leveldb/db.h | 167 + .../include/leveldb/dumpfile.h | 28 + .../leveldb-library/include/leveldb/env.h | 387 + .../leveldb-library/include/leveldb/export.h | 33 + .../include/leveldb/filter_policy.h | 72 + .../include/leveldb/iterator.h | 112 + .../leveldb-library/include/leveldb/options.h | 187 + .../leveldb-library/include/leveldb/slice.h | 115 + .../leveldb-library/include/leveldb/status.h | 122 + .../leveldb-library/include/leveldb/table.h | 84 + .../include/leveldb/table_builder.h | 93 + .../include/leveldb/write_batch.h | 83 + saraWhatsUp/Pods/leveldb-library/port/port.h | 19 + .../Pods/leveldb-library/port/port_example.h | 104 + .../Pods/leveldb-library/port/port_stdcxx.h | 153 + .../leveldb-library/port/thread_annotations.h | 108 + .../Pods/leveldb-library/table/block.cc | 266 + .../Pods/leveldb-library/table/block.h | 44 + .../leveldb-library/table/block_builder.cc | 108 + .../leveldb-library/table/block_builder.h | 55 + .../leveldb-library/table/filter_block.cc | 106 + .../Pods/leveldb-library/table/filter_block.h | 69 + .../Pods/leveldb-library/table/format.cc | 141 + .../Pods/leveldb-library/table/format.h | 100 + .../Pods/leveldb-library/table/iterator.cc | 76 + .../leveldb-library/table/iterator_wrapper.h | 92 + .../Pods/leveldb-library/table/merger.cc | 191 + .../Pods/leveldb-library/table/merger.h | 26 + .../Pods/leveldb-library/table/table.cc | 273 + .../leveldb-library/table/table_builder.cc | 265 + .../table/two_level_iterator.cc | 171 + .../table/two_level_iterator.h | 31 + .../Pods/leveldb-library/util/arena.cc | 66 + saraWhatsUp/Pods/leveldb-library/util/arena.h | 71 + .../Pods/leveldb-library/util/bloom.cc | 92 + .../Pods/leveldb-library/util/cache.cc | 400 + .../Pods/leveldb-library/util/coding.cc | 192 + .../Pods/leveldb-library/util/coding.h | 104 + .../Pods/leveldb-library/util/comparator.cc | 73 + .../Pods/leveldb-library/util/crc32c.cc | 380 + .../Pods/leveldb-library/util/crc32c.h | 43 + saraWhatsUp/Pods/leveldb-library/util/env.cc | 92 + .../Pods/leveldb-library/util/env_posix.cc | 876 +++ .../util/env_posix_test_helper.h | 28 + .../util/env_windows_test_helper.h | 25 + .../leveldb-library/util/filter_policy.cc | 11 + saraWhatsUp/Pods/leveldb-library/util/hash.cc | 55 + saraWhatsUp/Pods/leveldb-library/util/hash.h | 19 + .../Pods/leveldb-library/util/histogram.cc | 272 + .../Pods/leveldb-library/util/histogram.h | 44 + .../Pods/leveldb-library/util/logging.cc | 85 + .../Pods/leveldb-library/util/logging.h | 45 + .../Pods/leveldb-library/util/mutexlock.h | 39 + .../Pods/leveldb-library/util/no_destructor.h | 46 + .../Pods/leveldb-library/util/options.cc | 14 + .../Pods/leveldb-library/util/posix_logger.h | 130 + .../Pods/leveldb-library/util/random.h | 63 + .../Pods/leveldb-library/util/status.cc | 77 + .../Pods/leveldb-library/util/testharness.cc | 81 + .../Pods/leveldb-library/util/testharness.h | 141 + .../Pods/leveldb-library/util/testutil.h | 66 + .../leveldb-library/util/windows_logger.h | 124 + saraWhatsUp/Pods/nanopb/LICENSE.txt | 20 + saraWhatsUp/Pods/nanopb/README.md | 71 + saraWhatsUp/Pods/nanopb/pb.h | 599 ++ saraWhatsUp/Pods/nanopb/pb_common.c | 97 + saraWhatsUp/Pods/nanopb/pb_common.h | 42 + saraWhatsUp/Pods/nanopb/pb_decode.c | 1564 ++++ saraWhatsUp/Pods/nanopb/pb_decode.h | 178 + saraWhatsUp/Pods/nanopb/pb_encode.c | 913 +++ saraWhatsUp/Pods/nanopb/pb_encode.h | 170 + saraWhatsUp/ProfilePage.swift | 17 + saraWhatsUp/TabBarController.swift | 37 + .../saraWhatsUp.xcodeproj/project.pbxproj | 495 ++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + saraWhatsUp/saraWhatsUp/AppDelegate.swift | 36 + .../Assets.xcassets/22.imageset/Contents.json | 21 + ...ne-chat-speech-buble-miscellaneous-cdr.png | Bin 0 -> 11069 bytes .../AccentColor.colorset/Contents.json | 11 + .../Assets.xcassets/Afnan.imageset/Afnan.jpeg | Bin 0 -> 6010 bytes .../Afnan.imageset/Contents.json | 21 + .../AppIcon.appiconset/Contents.json | 98 + .../saraWhatsUp/Assets.xcassets/Contents.json | 6 + .../Unknown.imageset/Contents.json | 21 + .../hhhhh.imageset/Contents.json | 21 + .../Assets.xcassets/hhhhh.imageset/hhhhh.png | Bin 0 -> 6119 bytes .../logo.imageset/Contents.json | 21 + .../Assets.xcassets/logo.imageset/logo.png | Bin 0 -> 21257 bytes .../new_message_icon.imageset/Contents.json | 21 + .../new_message_icon@3x.png | Bin 0 -> 1880 bytes .../Assets.xcassets/ra.imageset/Contents.json | 21 + .../Assets.xcassets/ra.imageset/ra.png | Bin 0 -> 39077 bytes .../Base.lproj/LaunchScreen.storyboard | 25 + .../saraWhatsUp/Base.lproj/Main.storyboard | 24 + .../saraWhatsUp/GoogleService-Info.plist | 34 + saraWhatsUp/saraWhatsUp/Info.plist | 25 + saraWhatsUp/saraWhatsUp/SceneDelegate.swift | 80 + .../controller/ChatLogController.swift | 320 + .../controller/LoginController+handlers.swift | 118 + .../controller/LoginController.swift | 249 + .../controller/MessagesController.swift | 290 + .../controller/NewMessageController.swift | 83 + .../controller/ProfileController.swift | 109 + .../saraWhatsUp/controller/UserCell.swift | 95 + .../controller/ViewController.swift | 58 + .../saraWhatsUp/model/ChatMessageCell.swift | 92 + .../saraWhatsUp/model/Extensions.swift | 43 + saraWhatsUp/saraWhatsUp/model/Message.swift | 28 + .../saraWhatsUp/model/TabController.swift | 8 + saraWhatsUp/saraWhatsUp/model/User.swift | 23 + 1042 files changed, 140948 insertions(+) create mode 100644 saraWhatsUp/ Do any additional setup after loading the view. } } See video clips in action TabBarControllerViewController.swift create mode 100644 saraWhatsUp/.DS_Store create mode 100644 saraWhatsUp/Podfile create mode 100644 saraWhatsUp/Podfile.lock create mode 100755 saraWhatsUp/Pods/Firebase/CoreOnly/Sources/Firebase.h create mode 100755 saraWhatsUp/Pods/Firebase/CoreOnly/Sources/module.modulemap create mode 100644 saraWhatsUp/Pods/Firebase/LICENSE create mode 100644 saraWhatsUp/Pods/Firebase/README.md create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/CHANGELOG.md create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/README.md create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRActionCodeSettings.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthOperationType.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSettings.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailAuthProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorConstants.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorGenerator.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser_Internal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.m create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRAppInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRComponent.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRComponentContainer.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRComponentType.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRDependency.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRLibrary.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRLogger.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIROptionsInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FirebaseCoreInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/Interop/Auth/Public/FIRAuthInterop.h create mode 100644 saraWhatsUp/Pods/FirebaseAuth/LICENSE create mode 100644 saraWhatsUp/Pods/FirebaseAuth/README.md create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRCoreDiagnosticsConnector.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDependency.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatInfo.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAppInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponent.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentContainer.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentType.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRDependency.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLibrary.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLogger.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIROptionsInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FirebaseCoreInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h create mode 100644 saraWhatsUp/Pods/FirebaseCore/LICENSE create mode 100644 saraWhatsUp/Pods/FirebaseCore/README.md create mode 100644 saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m create mode 100644 saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c create mode 100644 saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h create mode 100644 saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Public/FIRCoreDiagnostics.h create mode 100644 saraWhatsUp/Pods/FirebaseCoreDiagnostics/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h create mode 100644 saraWhatsUp/Pods/FirebaseCoreDiagnostics/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h create mode 100644 saraWhatsUp/Pods/FirebaseCoreDiagnostics/LICENSE create mode 100644 saraWhatsUp/Pods/FirebaseCoreDiagnostics/README.md create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRAppInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRComponent.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRComponentContainer.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRComponentType.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRDependency.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRLibrary.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRLogger.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIROptionsInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FirebaseCoreInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDataSnapshot.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabase.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRMutableData.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRServerValue.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRTransactionResult.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperation.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEvent.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRegistration.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseReference.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FStorageEngine.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FirebaseDatabase.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FTypedefs.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.m create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.c create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.mm create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/Interop/Auth/Public/FIRAuthInterop.h create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/LICENSE create mode 100644 saraWhatsUp/Pods/FirebaseDatabase/README.md create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRAppInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRComponent.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRComponentContainer.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRComponentType.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRDependency.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRLibrary.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRLogger.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIROptionsInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FirebaseCoreInternal.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorage.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageComponent.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageComponent.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageConstants.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageConstants_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDeleteTask.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDeleteTask.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDownloadTask.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageErrors.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageErrors.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetMetadataTask.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetMetadataTask.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListResult.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListResult_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListTask.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListTask.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageLogger.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageLogger.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageMetadata.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageMetadata_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageObservableTask.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageObservableTask_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStoragePath.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStoragePath.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageReference.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageReference_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTask.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTaskSnapshot.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTask_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTokenAuthorizer.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTokenAuthorizer.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUploadTask.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUploadTask_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUtils.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUtils.m create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorage_Private.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageDownloadTask.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageMetadata.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageObservableTask.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageUploadTask.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FirebaseStorage.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/Interop/Auth/Public/FIRAuthInterop.h create mode 100644 saraWhatsUp/Pods/FirebaseStorage/LICENSE create mode 100644 saraWhatsUp/Pods/FirebaseStorage/README.md create mode 100644 saraWhatsUp/Pods/GTMSessionFetcher/LICENSE create mode 100644 saraWhatsUp/Pods/GTMSessionFetcher/README.md create mode 100644 saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h create mode 100644 saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m create mode 100644 saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h create mode 100644 saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m create mode 100644 saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h create mode 100644 saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m create mode 100644 saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h create mode 100644 saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORClock.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/LICENSE create mode 100644 saraWhatsUp/Pods/GoogleDataTransport/README.md create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorageUserDefaults.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorable.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h create mode 100644 saraWhatsUp/Pods/GoogleUtilities/LICENSE create mode 100644 saraWhatsUp/Pods/GoogleUtilities/README.md create mode 120000 saraWhatsUp/Pods/Headers/Private/Firebase/Firebase.h create mode 120000 saraWhatsUp/Pods/Headers/Public/Firebase/Firebase.h create mode 100644 saraWhatsUp/Pods/Manifest.lock create mode 100644 saraWhatsUp/Pods/Pods.xcodeproj/project.pbxproj create mode 100644 saraWhatsUp/Pods/PromisesObjC/LICENSE create mode 100644 saraWhatsUp/Pods/PromisesObjC/README.md create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h create mode 100644 saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h create mode 100644 saraWhatsUp/Pods/Target Support Files/Firebase/Firebase.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/Firebase/Firebase.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch create mode 100644 saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-acknowledgements.markdown create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-acknowledgements.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Debug-input-files.xcfilelist create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Debug-output-files.xcfilelist create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Release-input-files.xcfilelist create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Release-output-files.xcfilelist create mode 100755 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks.sh create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-prefix.pch create mode 100644 saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.release.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-Info.plist create mode 100644 saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-dummy.m create mode 100644 saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-prefix.pch create mode 100644 saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-umbrella.h create mode 100644 saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.debug.xcconfig create mode 100644 saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.modulemap create mode 100644 saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.release.xcconfig create mode 100644 saraWhatsUp/Pods/leveldb-library/LICENSE create mode 100644 saraWhatsUp/Pods/leveldb-library/README.md create mode 100644 saraWhatsUp/Pods/leveldb-library/db/builder.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/builder.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/c.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/db_impl.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/db_impl.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/db_iter.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/db_iter.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/dbformat.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/dbformat.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/dumpfile.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/filename.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/filename.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/log_format.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/log_reader.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/log_reader.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/log_writer.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/log_writer.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/memtable.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/memtable.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/repair.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/skiplist.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/snapshot.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/table_cache.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/table_cache.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/version_edit.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/version_edit.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/version_set.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/version_set.h create mode 100644 saraWhatsUp/Pods/leveldb-library/db/write_batch.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/db/write_batch_internal.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/c.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/cache.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/comparator.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/db.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/dumpfile.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/env.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/export.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/filter_policy.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/iterator.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/options.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/slice.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/status.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/table.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/table_builder.h create mode 100644 saraWhatsUp/Pods/leveldb-library/include/leveldb/write_batch.h create mode 100644 saraWhatsUp/Pods/leveldb-library/port/port.h create mode 100644 saraWhatsUp/Pods/leveldb-library/port/port_example.h create mode 100644 saraWhatsUp/Pods/leveldb-library/port/port_stdcxx.h create mode 100644 saraWhatsUp/Pods/leveldb-library/port/thread_annotations.h create mode 100644 saraWhatsUp/Pods/leveldb-library/table/block.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/table/block.h create mode 100644 saraWhatsUp/Pods/leveldb-library/table/block_builder.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/table/block_builder.h create mode 100644 saraWhatsUp/Pods/leveldb-library/table/filter_block.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/table/filter_block.h create mode 100644 saraWhatsUp/Pods/leveldb-library/table/format.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/table/format.h create mode 100644 saraWhatsUp/Pods/leveldb-library/table/iterator.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/table/iterator_wrapper.h create mode 100644 saraWhatsUp/Pods/leveldb-library/table/merger.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/table/merger.h create mode 100644 saraWhatsUp/Pods/leveldb-library/table/table.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/table/table_builder.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/table/two_level_iterator.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/table/two_level_iterator.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/arena.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/arena.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/bloom.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/cache.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/coding.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/coding.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/comparator.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/crc32c.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/crc32c.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/env.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/env_posix.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/env_posix_test_helper.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/env_windows_test_helper.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/filter_policy.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/hash.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/hash.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/histogram.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/histogram.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/logging.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/logging.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/mutexlock.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/no_destructor.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/options.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/posix_logger.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/random.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/status.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/testharness.cc create mode 100644 saraWhatsUp/Pods/leveldb-library/util/testharness.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/testutil.h create mode 100644 saraWhatsUp/Pods/leveldb-library/util/windows_logger.h create mode 100644 saraWhatsUp/Pods/nanopb/LICENSE.txt create mode 100644 saraWhatsUp/Pods/nanopb/README.md create mode 100644 saraWhatsUp/Pods/nanopb/pb.h create mode 100644 saraWhatsUp/Pods/nanopb/pb_common.c create mode 100644 saraWhatsUp/Pods/nanopb/pb_common.h create mode 100644 saraWhatsUp/Pods/nanopb/pb_decode.c create mode 100644 saraWhatsUp/Pods/nanopb/pb_decode.h create mode 100644 saraWhatsUp/Pods/nanopb/pb_encode.c create mode 100644 saraWhatsUp/Pods/nanopb/pb_encode.h create mode 100644 saraWhatsUp/ProfilePage.swift create mode 100644 saraWhatsUp/TabBarController.swift create mode 100644 saraWhatsUp/saraWhatsUp.xcodeproj/project.pbxproj create mode 100644 saraWhatsUp/saraWhatsUp.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 saraWhatsUp/saraWhatsUp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 saraWhatsUp/saraWhatsUp.xcworkspace/contents.xcworkspacedata create mode 100644 saraWhatsUp/saraWhatsUp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 saraWhatsUp/saraWhatsUp/AppDelegate.swift create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/22.imageset/Contents.json create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/22.imageset/png-clipart-computer-icons-conversation-online-chat-speech-buble-miscellaneous-cdr.png create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/Afnan.imageset/Afnan.jpeg create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/Afnan.imageset/Contents.json create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/Contents.json create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/Unknown.imageset/Contents.json create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/hhhhh.imageset/Contents.json create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/hhhhh.imageset/hhhhh.png create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/logo.imageset/Contents.json create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/logo.imageset/logo.png create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/new_message_icon.imageset/Contents.json create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/new_message_icon.imageset/new_message_icon@3x.png create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/ra.imageset/Contents.json create mode 100644 saraWhatsUp/saraWhatsUp/Assets.xcassets/ra.imageset/ra.png create mode 100644 saraWhatsUp/saraWhatsUp/Base.lproj/LaunchScreen.storyboard create mode 100644 saraWhatsUp/saraWhatsUp/Base.lproj/Main.storyboard create mode 100644 saraWhatsUp/saraWhatsUp/GoogleService-Info.plist create mode 100644 saraWhatsUp/saraWhatsUp/Info.plist create mode 100644 saraWhatsUp/saraWhatsUp/SceneDelegate.swift create mode 100644 saraWhatsUp/saraWhatsUp/controller/ChatLogController.swift create mode 100644 saraWhatsUp/saraWhatsUp/controller/LoginController+handlers.swift create mode 100644 saraWhatsUp/saraWhatsUp/controller/LoginController.swift create mode 100644 saraWhatsUp/saraWhatsUp/controller/MessagesController.swift create mode 100644 saraWhatsUp/saraWhatsUp/controller/NewMessageController.swift create mode 100644 saraWhatsUp/saraWhatsUp/controller/ProfileController.swift create mode 100644 saraWhatsUp/saraWhatsUp/controller/UserCell.swift create mode 100644 saraWhatsUp/saraWhatsUp/controller/ViewController.swift create mode 100644 saraWhatsUp/saraWhatsUp/model/ChatMessageCell.swift create mode 100644 saraWhatsUp/saraWhatsUp/model/Extensions.swift create mode 100644 saraWhatsUp/saraWhatsUp/model/Message.swift create mode 100644 saraWhatsUp/saraWhatsUp/model/TabController.swift create mode 100644 saraWhatsUp/saraWhatsUp/model/User.swift diff --git a/saraWhatsUp/ Do any additional setup after loading the view. } } See video clips in action TabBarControllerViewController.swift b/saraWhatsUp/ Do any additional setup after loading the view. } } See video clips in action TabBarControllerViewController.swift new file mode 100644 index 0000000..1531fbe --- /dev/null +++ b/saraWhatsUp/ Do any additional setup after loading the view. } } See video clips in action TabBarControllerViewController.swift @@ -0,0 +1,29 @@ +// +// Do any additional setup after loading the view. } } See video clips in action TabBarControllerViewController.swift +// saraWhatsUp +// +// Created by sara al zhrani on 26/03/1443 AH. +// + +import UIKit + +class _Do_any_additional_setup_after_loading_the_view_________See_video_clips_in_action__TabBarControllerViewController: UITabBarController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/saraWhatsUp/.DS_Store b/saraWhatsUp/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c49ac71ccc1602fd9d3add3968915e93ef2cfe46 GIT binary patch literal 6148 zcmeHK&2G~`5T0#9*`z|v0Tj6HgE8( zu`YB;*7S_gs zv%K5=M%HTe3+optZPMnY<}+u+3nzE;Nj7lPCt`Hp%}1W@Kjb_*?YrLNFevt0m+$a6 zcf&YHrE};9X!3L~jD21V_$2l-8OKozls0H%ztx^j`#T-h-`<*a*mS4g?Xa6$w`Q{j zZC~&0-a8n-d^LSNdvl`bC3qW2+0^(8K49mZY>%8Yj(B{C7Q*|=*_^-)IEEo`@F9Q% zIpgp=I_x<^K2Fpo@4{-{V{Y4;WqNJ1_T&4>r`uH{_@@!j^Xqoy2+3$ZgD)bH_HXkq zFz*yzpiP2b%@BeG4#?XF)g#RF08p;m?;{CsSe*M4bWJZPo!@x>0 zKBn_r9 J4E$3DegcV&!qET# literal 0 HcmV?d00001 diff --git a/saraWhatsUp/Podfile b/saraWhatsUp/Podfile new file mode 100644 index 0000000..bb48684 --- /dev/null +++ b/saraWhatsUp/Podfile @@ -0,0 +1,16 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' + +target 'saraWhatsUp' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + + # Pods for saraWhatsUp + + pod 'Firebase/Auth' +pod 'Firebase/Storage' + + pod 'Firebase/Database' + +end diff --git a/saraWhatsUp/Podfile.lock b/saraWhatsUp/Podfile.lock new file mode 100644 index 0000000..5268fca --- /dev/null +++ b/saraWhatsUp/Podfile.lock @@ -0,0 +1,97 @@ +PODS: + - Firebase/Auth (8.9.1): + - Firebase/CoreOnly + - FirebaseAuth (~> 8.9.0) + - Firebase/CoreOnly (8.9.1): + - FirebaseCore (= 8.9.1) + - Firebase/Database (8.9.1): + - Firebase/CoreOnly + - FirebaseDatabase (~> 8.9.0) + - Firebase/Storage (8.9.1): + - Firebase/CoreOnly + - FirebaseStorage (~> 8.9.0) + - FirebaseAuth (8.9.0): + - FirebaseCore (~> 8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/Environment (~> 7.6) + - GTMSessionFetcher/Core (~> 1.5) + - FirebaseCore (8.9.1): + - FirebaseCoreDiagnostics (~> 8.0) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/Logger (~> 7.6) + - FirebaseCoreDiagnostics (8.9.0): + - GoogleDataTransport (~> 9.1) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/Logger (~> 7.6) + - nanopb (~> 2.30908.0) + - FirebaseDatabase (8.9.0): + - FirebaseCore (~> 8.0) + - leveldb-library (~> 1.22) + - FirebaseStorage (8.9.0): + - FirebaseCore (~> 8.0) + - GTMSessionFetcher/Core (~> 1.5) + - GoogleDataTransport (9.1.2): + - GoogleUtilities/Environment (~> 7.2) + - nanopb (~> 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/AppDelegateSwizzler (7.6.0): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.6.0): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.6.0): + - GoogleUtilities/Environment + - GoogleUtilities/Network (7.6.0): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.6.0)" + - GoogleUtilities/Reachability (7.6.0): + - GoogleUtilities/Logger + - GTMSessionFetcher/Core (1.7.0) + - leveldb-library (1.22.1) + - nanopb (2.30908.0): + - nanopb/decode (= 2.30908.0) + - nanopb/encode (= 2.30908.0) + - nanopb/decode (2.30908.0) + - nanopb/encode (2.30908.0) + - PromisesObjC (2.0.0) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Database + - Firebase/Storage + +SPEC REPOS: + trunk: + - Firebase + - FirebaseAuth + - FirebaseCore + - FirebaseCoreDiagnostics + - FirebaseDatabase + - FirebaseStorage + - GoogleDataTransport + - GoogleUtilities + - GTMSessionFetcher + - leveldb-library + - nanopb + - PromisesObjC + +SPEC CHECKSUMS: + Firebase: fb5114cd2bf96e2ff7bcb01d0d9a156cf5fd2f07 + FirebaseAuth: 2b78b2a32c07b3ecfa4970bdf1d3632b8304099b + FirebaseCore: c5aab092d9c4b8efea894946166b04c9d9ef0e68 + FirebaseCoreDiagnostics: 5daa63f1c1409d981a2d5007daa100b36eac6a34 + FirebaseDatabase: 2236b804cf0cac165b4620669bedf7ee643a2bcc + FirebaseStorage: 452c98c31ccb40b819764bf3039426c4388d9939 + GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 + GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 + GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91 + leveldb-library: 50c7b45cbd7bf543c81a468fe557a16ae3db8729 + nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 + +PODFILE CHECKSUM: 5f3bfdda36c381b0c15c0819471cdda47eb5b3f8 + +COCOAPODS: 1.11.2 diff --git a/saraWhatsUp/Pods/Firebase/CoreOnly/Sources/Firebase.h b/saraWhatsUp/Pods/Firebase/CoreOnly/Sources/Firebase.h new file mode 100755 index 0000000..3d6ac97 --- /dev/null +++ b/saraWhatsUp/Pods/Firebase/CoreOnly/Sources/Firebase.h @@ -0,0 +1,81 @@ +// 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 + +#if !defined(__has_include) + #error "Firebase.h won't import anything if your compiler doesn't support __has_include. Please \ + import the headers individually." +#else + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + +#endif // defined(__has_include) diff --git a/saraWhatsUp/Pods/Firebase/CoreOnly/Sources/module.modulemap b/saraWhatsUp/Pods/Firebase/CoreOnly/Sources/module.modulemap new file mode 100755 index 0000000..3685b54 --- /dev/null +++ b/saraWhatsUp/Pods/Firebase/CoreOnly/Sources/module.modulemap @@ -0,0 +1,4 @@ +module Firebase { + export * + header "Firebase.h" +} \ No newline at end of file diff --git a/saraWhatsUp/Pods/Firebase/LICENSE b/saraWhatsUp/Pods/Firebase/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/saraWhatsUp/Pods/Firebase/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/saraWhatsUp/Pods/Firebase/README.md b/saraWhatsUp/Pods/Firebase/README.md new file mode 100644 index 0000000..7be298d --- /dev/null +++ b/saraWhatsUp/Pods/Firebase/README.md @@ -0,0 +1,319 @@ +[![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-appcheck-badge]][gh-actions] +[![Actions Status][gh-appdistribution-badge]][gh-actions] +[![Actions Status][gh-auth-badge]][gh-actions] +[![Actions Status][gh-cocoapods-integration-badge]][gh-actions] +[![Actions Status][gh-core-badge]][gh-actions] +[![Actions Status][gh-core-diagnostics-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-google-utilities-badge]][gh-actions] +[![Actions Status][gh-google-utilities-components-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-mlmodeldownloader-badge]][gh-actions] +[![Actions Status][gh-performance-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] + +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics +and FirebaseML. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. +1. [Standard pod install](README.md#standard-pod-install) +1. [Swift Package Manager](SwiftPackageManager.md) +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). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager.md](SwiftPackageManager.md). + +### Installing from GitHub + +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: +```ruby +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: + +```ruby +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). + +### 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 12.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +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 + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### 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/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@13 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. 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. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md). + +## 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 Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### 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. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduces official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on 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 watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are 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-appcheck-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/app_check/badge.svg +[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg +[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg +[gh-cocoapods-integration-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/cocoapods-integration/badge.svg +[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg +[gh-core-diagnostics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core-diagnostics/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-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg +[gh-google-utilities-components-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities-components/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-mlmodeldownloader-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/mlmodeldownloader/badge.svg +[gh-performance-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/performance/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 diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/CHANGELOG.md b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/CHANGELOG.md new file mode 100644 index 0000000..4a0bbf3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/CHANGELOG.md @@ -0,0 +1,315 @@ +# 8.9.0 +- [changed] Improved error logging. (#8704) +- [added] Added MFA support for email link sign-in. (#8705) + +# 8.8.0 +- [fixed] Fall back to reCAPTCHA for phone auth app verification if the push notification is not received before the timeout. (#8653) + +# 8.6.0 +- [fixed] Annotated platform-level availability using `API_UNAVAILABLE` instead of conditionally compiling certain methods with `#if` directives. (#8451) + +# 8.5.0 +- [fixed] Fixed an analyze issue introduced in Xcode 12.5. (#8411) + +# 8.2.0 +- [fixed] Fixed analyze issues introduced in Xcode 12.5. (#8210) +- [fixed] Fixed a bug in the link with email link, Game Center, and phone auth flows. (#8196) + +# 8.0.0 +- [fixed] Fixed a crash that occurred when assigning auth settings. (#7670) + +# 7.8.0 +- [fixed] Fixed auth state sharing during first app launch. (#7472) + +# 7.6.0 +- [fixed] Auth emulator now works across the local network. (#7350) +- [fixed] Fixed incorrect import for watchOS (#7425) + +# 7.4.0 +- [fixed] Check if the reverse client ID is configured as a custom URL scheme before setting it as the callback scheme. (#7211) +- [added] Add ability to sync auth state across devices. (#6924) +- [fixed] Add multi-tenancy support for email link sign-in. (#7246) + +# 7.3.0 +- [fixed] Catalyst browser issue with `verifyPhoneNumber` API. (#7049) + +# 7.1.0 +- [fixed] Fixed completion handler issue in `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)` method. (#6863) + +# 7.0.0 +- [removed] Remove deprecated APIs `dataForKey`,`fetchProvidersForEmail:completion`, `signInAndRetrieveDataWithCredential:completion`, `reauthenticateAndRetrieveDataWithCredential:completion`, `linkAndRetrieveDataWithCredential:completion`. (#6607) +- [added] Add support for the auth emulator. (#6624) +- [changed] The global variables `FirebaseAuthVersionNum` and `FirebaseAuthVersionStr` are deleted. + `FirebaseVersion()` or `FIRFirebaseVersion()` should be used instead. + +# v6.9.1 +- [fixed] Internal source documentation. (#6371) + +# v6.9.0 +- [added] Added support for multi-tenancy (#6142). +- [added] Added basic watchOS support. (#4621) +- [changed] Improved Xcode completion of public API completion handlers in Swift. (#6283) + +# v6.8.0 +- [fixed] Fix bug where multiple keychain entries would result in user persistence failure. (#5906) +- [changed] Added support for using GOOGLE_APP_ID in generic IDP and phone auth reCAPTCHA fallback flows. (#6121) + +# v6.7.1 +- [fixed] Fixed a multithreaded memory access issue on iOS. (#5979) + +# v6.7.0 +- [changed] Functionally neutral source reorganization for preliminary Swift Package Manager support. (#5856) + +# v6.5.3 +- [changed] Remove unused mfa request field "mfa_provider" (#5397) +- [fixed] Suppress deprecation warnings when targeting iOS versions up to iOS 13. (#5437) + +# v6.5.2 +- [fixed] Handle calls to `useUserAccessGroup` soon after configure. (#4175) + +# v6.5.1 +- [changed] File structure changes. No functional change. +- [changed] Code formatting changes. + +# v6.5.0 +- [feature] Added support of Multi-factor Authentication. (#4823) + +# v6.4.1 +- [fixed] Added support of UISceneDelegate for URL redirect. (#4380) +- [fixed] Fixed rawNonce in encoder. (#4337) + +# v6.4.0 +- [feature] Added support for Sign-in with Apple. (#4183) + +# v6.3.1 +- [fixed] Removed usage of a deprecated property on iOS 13. (#4066) + +# v6.3.0 +- [added] Added methods allowing developers to link and reauthenticate with federated providers. (#3971) + +# v6.2.3 +- [fixed] Make sure the first valid auth domain is retrieved. (#3493) +- [fixed] Add assertion for Facebook generic IDP flow. (#3208) +- [fixed] Build for Catalyst. (#3549) + +# v6.2.2 +- [fixed] Fixed an issue where unlinking an email auth provider raised an incorrect error stating the account was not linked to an email auth provider. (#3405) +- [changed] Renamed internal Keychain classes. (#3473) + +# v6.2.1 +- [added] Add new client error MISSING_CLIENT_IDENTIFIER. (#3341) + +# v6.2.0 +- [feature] Expose `secret` of OAuth credential in public header. (#3089) +- [fixed] Fix a keychain issue where API key is incorrectly set. (#3239) + +# v6.1.2 +- [fixed] Fix line limits and linter warnings in public documentation. (#3139) + +# v6.1.1 +- [fixed] Fix an issue where a user can't link with email provider by email link. (#3030) + +# v6.1.0 +- [added] Add support of web.app as an auth domain. (#2959) +- [fixed] Fix an issue where the return type of `getStoredUserForAccessGroup:error:` is nonnull. (#2879) + +# v6.0.0 +- [added] Add support of single sign on. (#2684) +- [deprecated] Deprecate `reauthenticateAndRetrieveDataWithCredential:completion:`, `signInAndRetrieveDataWithCredential:completion:`, `linkAndRetrieveDataWithCredential:completion:`, `fetchProvidersForEmail:completion:`. (#2723, #2756) +- [added] Returned oauth secret token in Generic IDP sign-in for Twitter. (#2663) +- [removed] Remove pendingToken from public API. (#2676) +- [changed] `GULAppDelegateSwizzler` is used for the app delegate swizzling. (#2591) + +# v5.4.2 +- [added] Support new error code ERROR_INVALID_PROVIDER_ID. (#2629) + +# v5.4.1 +- [deprecated] Deprecate Microsoft and Yahoo OAuth Provider ID (#2517) +- [fixed] Fix an issue where an exception was thrown when linking OAuth credentials. (#2521) +- [fixed] Fix an issue where a wrong error was thrown when handling error with + FEDERATED_USER_ID_ALREADY_LINKED. (#2522) + +# v5.4.0 +- [added] Add support of Generic IDP (#2405). + +# v5.3.0 +- [changed] Use the new registerInternalLibrary API to register with FirebaseCore. (#2137) + +# v5.2.0 +- [added] Add support of Game Center sign in (#2127). + +# v5.1.0 +- [added] Add support of custom FDL domain link (#2121). + +# v5.0.5 +- [changed] Restore SafariServices framework dependency (#2002). + +# v5.0.4 +- [fixed] Fix analyzer issues (#1740). + +# v5.0.3 +- [added] Add `FIRAuthErrorCodeMalformedJWT`, which is raised on JWT token parsing. + failures during auth operations (#1436). +- [changed] Migrate to use FirebaseAuthInterop interfaces to access FirebaseAuth (#1501). + +# v5.0.2 +- [fixed] Fix an issue where JWT date timestamps weren't parsed correctly. (#1319) +- [fixed] Fix an issue where anonymous accounts weren't correctly promoted to + non-anonymous when linked with passwordless email auth accounts. (#1383) +- [fixed] Fix an exception from using an invalidated NSURLSession. (#1261) +- [fixed] Fix a data race issue caught by the sanitizer. (#1446) + +# v5.0.1 +- [fixed] Restore 4.x level of support for extensions (#1357). + +# v5.0.0 +- [added] Adds APIs for phone Auth testing to bypass the verification flow (#1192). +- [feature] Changes the callback block signature for sign in and create user methods + to provide an AuthDataResult that includes the user and user info (#1123, #1186). +- [changed] Removes GoogleToolboxForMac dependency (#1175). +- [removed] Removes miscellaneous deprecated APIs (#1188, #1200). + +# v4.6.1 +- [fixed] Fixes crash which occurred when certain Firebase IDTokens were being parsed (#1076). + +# v4.6.0 +- [added] Adds `getIDTokenResultWithCompletion:` and `getIDTokenResultForcingRefresh:completion:` APIs which + call back with an AuthTokenResult object. The Auth token result object contains the ID token JWT string and other properties associated with the token including the decoded available payload claims (#1004). + +- [added] Adds the `updateCurrentUser:completion:` API which sets the currentUser on the calling Auth instance to the provided user object (#1018). + +- [added] Adds client-side validation to prevent setting `handleCodeInApp` to false when performing + email-link authentication. If `handleCodeInApp` is set to false an invalid argument exception + is thrown (#931). + +- [added] Adds support for passing the deep link (which is embedded in the sign-in link sent via email) to the + `signInWithEmail:link:completion:` and `isSignInWithEmailLink:` methods during an + email/link sign-in flow (#1023). + +# v4.5.0 +- [added] Adds new API which provides a way to determine the sign-in methods associated with an + email address. +- [added] Adds new API which allows authentication using only an email link (Passwordless Authentication + with email link). + +# v4.4.4 +- [fixed] Addresses CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF warnings that surface in newer versions of + Xcode and CocoaPods. +- [fixed] Improves FIRUser documentation with clear message explaining when Firebase Auth attempts to validate + users and what happens when an invalidated user is detected (#694) . + +# v4.4.3 +- [added] Adds an explicit dependency on CoreGraphics from Firebase Auth. + +# v4.4.2 +- [fixed] Fixes bug where the FIRAuthResult object returned following a Phone Number authentication + always contained a nil FIRAdditionalUserInfo object. Now the FIRAdditionalUserInfo object is + never nil and its newUser field is populated correctly. + +# v4.4.0 +- [fixed] Adds new APIs which return an AuthDataResult object after successfully creating an + Email/Password user, signing in anonymously, signing in with Email/Password and signing + in with Custom Token. The AuthDataResult object contains the new user and additional + information pertaining to the new user. + +# v4.3.2 +- [fixed] Improves error handling for the phone number sign-in reCAPTCHA flow. +- [fixed] Improves error handling for phone number linking flow. +- [fixed] Fixes issue where after linking an anonymous user to a phone number the user remained + anonymous. + +# v4.3.1 +- [changed] Internal clean up. + +# v4.3.0 +- [added] Provides account creation and last sign-in dates as metadata to the user + object. +- [added] Returns more descriptive errors for some error cases of the phone number + sign-in reCAPTCHA flow. +- [fixed] Fixes an issue that invalid users were not automatically signed out earlier. +- [fixed] Fixes an issue that ID token listeners were not fired in some cases. + +# v4.2.1 +- [fixed] Fixes a threading issue in phone number auth that completion block was not + executed on the main thread in some error cases. + +# v4.2.0 +- [added] Adds new phone number verification API which makes use of an intelligent reCAPTCHA to verify the application. + +# v4.1.1 +- [changed] Improves some method documentation in headers. + +# v4.1.0 +- [added] Allows the app to handle continue URL natively, e.g., from password reset + email. +- [added] Allows the app to set language code, e.g., for sending password reset email. +- [fixed] Fixes an issue that user's phone number did not persist on client. +- [fixed] Fixes an issue that recover email action code type was reported as unknown. +- [feature] Improves app start-up time by moving initialization off from the main + thread. +- [fixed] Better reports missing email error when creating a new password user. +- [fixed] Changes console message logging levels to be more consistent with other + Firebase products on the iOS platform. + +# 2017-05-17 -- v4.0.0 +- [added] Adds Phone Number Authentication. +- [added] Adds support for generic OAuth2 identity providers. +- [added] Adds methods that return additional user data from identity providers if + available when authenticating users. +- [added] Improves session management by automatically refreshing tokens if possible + and signing out users if the session is detected invalidated, for example, + after the user changed password or deleted account from another device. +- [fixed] Fixes an issue that reauthentication creates new user account if the user + credential is valid but does not match the currently signed in user. +- [fixed] Fixes an issue that the "password" provider is not immediately listed on the + client side after adding a password to an account. +- [changed] Changes factory methods to return non-null FIRAuth instances or raises an + exception, instead of returning nullable instances. +- [changed] Changes auth state change listener to only be triggered when the user changes. +- [added] Adds a new listener which is triggered whenever the ID token is changed. +- [changed] Switches ERROR_EMAIL_ALREADY_IN_USE to + ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL when the email used in the + signInWithCredential: call is already in use by another account. +- [deprecated] Deprecates FIREmailPasswordAuthProvider in favor of FIREmailAuthProvider. +- [deprecated] Deprecates getTokenWithCompletion in favor of getIDTokenWithCompletion on + FIRUser. +- [fixed] Changes Swift API names to better align with Swift convention. + +# 2017-02-06 -- v3.1.1 +- [added] Allows handling of additional errors when sending OOB action emails. The + server can respond with the following new error messages: + INVALID_MESSAGE_PAYLOAD,INVALID_SENDER and INVALID_RECIPIENT_EMAIL. +- [fixed] Removes incorrect reference to FIRAuthErrorCodeCredentialTooOld in FIRUser.h. +- [added] Provides additional error information from server if available. + +# 2016-12-13 -- v3.1.0 +- [added] Adds FIRAuth methods that enable the app to follow up with user actions + delivered by email, such as verifying email address or reset password. +- [fixed] No longer applies the keychain workaround introduced in v3.0.5 on iOS 10.2 + simulator or above since the issue has been fixed. +- [fixed] Fixes nullability compilation warnings when used in Swift. +- [fixed] Better reports missing password error. + +# 2016-10-24 -- v3.0.6 +- [changed] Switches to depend on open sourced GoogleToolboxForMac and GTMSessionFetcher. +- [fixed] Improves logging of keychain error when initializing. + +# 2016-09-14 -- v3.0.5 +- [fixed] Works around a keychain issue in iOS 10 simulator. +- [fixed] Reports the correct error for invalid email when signing in with email and + password. + +# 2016-07-18 -- v3.0.4 +- [fixed] Fixes a race condition bug that could crash the app with an exception from + NSURLSession on iOS 9. + +# 2016-06-20 -- v3.0.3 +- [added] Adds documentation for all possible errors returned by each method. +- [fixed] Improves error handling and messages for a variety of error conditions. +- [fixed] Whether or not an user is considered anonymous is now consistent with other + platforms. +- [changed] A saved signed in user is now siloed between different Firebase projects + within the same app. + +# 2016-05-18 -- v3.0.2 +- Initial public release. diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/README.md b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/README.md new file mode 100644 index 0000000..84818f8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/README.md @@ -0,0 +1,17 @@ +# Firebase Auth for iOS + +Firebase Auth enables apps to easily support multiple authentication options +for their end users. + +Please visit [our developer site](https://firebase.google.com/docs/auth/) for +integration instructions, documentation, support information, and terms of +service. + +# Firebase Auth Development + +Example/Auth contains a set of samples and tests that integrate with +FirebaseAuth. + +The unit tests run without any additional configuration along with the rest of +Firebase. See [Tests/Sample/README.md](Tests/Sample/README.md) for +information about setting up, running, and testing the samples. diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRActionCodeSettings.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRActionCodeSettings.m new file mode 100644 index 0000000..b1671e6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRActionCodeSettings.m @@ -0,0 +1,45 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRActionCodeSettings + +- (instancetype)init { + self = [super init]; + if (self) { + _iOSBundleID = [NSBundle mainBundle].bundleIdentifier; + } + return self; +} + +- (void)setIOSBundleID:(NSString *)iOSBundleID { + _iOSBundleID = [iOSBundleID copy]; +} + +- (void)setAndroidPackageName:(NSString *)androidPackageName + installIfNotAvailable:(BOOL)installIfNotAvailable + minimumVersion:(nullable NSString *)minimumVersion { + _androidPackageName = [androidPackageName copy]; + _androidInstallIfNotAvailable = installIfNotAvailable; + _androidMinimumVersion = [minimumVersion copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth.m new file mode 100644 index 0000000..68f892e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth.m @@ -0,0 +1,2274 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" + +#if __has_include() +#import +#endif + +#import +#import +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthOperationType.h" +#import "FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h" +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h" +#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h" +#import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h" +#import "FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h" +#import "FirebaseAuth/Sources/User/FIRUser_Internal.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark-- Logger Service String. +FIRLoggerService kFIRLoggerAuth = @"[Firebase/Auth]"; + +#pragma mark - Constants + +#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 +const NSNotificationName FIRAuthStateDidChangeNotification = @"FIRAuthStateDidChangeNotification"; +#else +NSString *const FIRAuthStateDidChangeNotification = @"FIRAuthStateDidChangeNotification"; +#endif // defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 + +/** @var kMaxWaitTimeForBackoff + @brief The maximum wait time before attempting to retry auto refreshing tokens after a failed + attempt. + @remarks This is the upper limit (in seconds) of the exponential backoff used for retrying + token refresh. + */ +static NSTimeInterval kMaxWaitTimeForBackoff = 16 * 60; + +/** @var kTokenRefreshHeadStart + @brief The amount of time before the token expires that proactive refresh should be attempted. + */ +NSTimeInterval kTokenRefreshHeadStart = 5 * 60; + +/** @var kUserKey + @brief Key of user stored in the keychain. Prefixed with a Firebase app name. + */ +static NSString *const kUserKey = @"%@_firebase_user"; + +/** @var kMissingEmailInvalidParameterExceptionReason + @brief The reason for @c invalidParameterException when the email used to initiate password + reset is nil. + */ +static NSString *const kMissingEmailInvalidParameterExceptionReason = + @"The email used to initiate password reset cannot be nil."; + +/** @var kHandleCodeInAppFalseExceptionReason + @brief The reason for @c invalidParameterException when the handleCodeInApp parameter is false + on the ActionCodeSettings object used to send the link for Email-link Authentication. + */ +static NSString *const kHandleCodeInAppFalseExceptionReason = + @"You must set handleCodeInApp in your ActionCodeSettings to true for Email-link " + "Authentication."; + +static NSString *const kInvalidEmailSignInLinkExceptionMessage = + @"The link provided is not valid for email/link sign-in. Please check the link by calling " + "isSignInWithEmailLink:link: on Auth before attempting to use it for email/link sign-in."; + +/** @var kPasswordResetRequestType + @brief The action code type value for resetting password in the check action code response. + */ +static NSString *const kPasswordResetRequestType = @"PASSWORD_RESET"; + +/** @var kVerifyEmailRequestType + @brief The action code type value for verifying email in the check action code response. + */ +static NSString *const kVerifyEmailRequestType = @"VERIFY_EMAIL"; + +/** @var kRecoverEmailRequestType + @brief The action code type value for recovering email in the check action code response. + */ +static NSString *const kRecoverEmailRequestType = @"RECOVER_EMAIL"; + +/** @var kEmailLinkSignInRequestType + @brief The action code type value for an email sign-in link in the check action code response. +*/ +static NSString *const kEmailLinkSignInRequestType = @"EMAIL_SIGNIN"; + +/** @var kVerifyAndChangeEmailRequestType + @brief The action code type value for verifing and changing email in the check action code + response. + */ +static NSString *const kVerifyAndChangeEmailRequestType = @"VERIFY_AND_CHANGE_EMAIL"; + +/** @var kRevertSecondFactorAdditionRequestType + @brief The action code type value for reverting second factor addition in the check action code + response. + */ +static NSString *const kRevertSecondFactorAdditionRequestType = @"REVERT_SECOND_FACTOR_ADDITION"; + +/** @var kMissingPasswordReason + @brief The reason why the @c FIRAuthErrorCodeWeakPassword error is thrown. + @remarks This error message will be localized in the future. + */ +static NSString *const kMissingPasswordReason = @"Missing Password"; + +/** @var gKeychainServiceNameForAppName + @brief A map from Firebase app name to keychain service names. + @remarks This map is needed for looking up the keychain service name after the FIRApp instance + is deleted, to remove the associated keychain item. Accessing should occur within a + @syncronized([FIRAuth class]) context. + */ +static NSMutableDictionary *gKeychainServiceNameForAppName; + +#pragma mark - FIRActionCodeInfo + +@interface FIRActionCodeInfo () + +/** + @brief The operation being performed. + */ +@property(nonatomic, readwrite) FIRActionCodeOperation operation; + +/** @property email + @brief The email address to which the code was sent. The new email address in the case of + FIRActionCodeOperationRecoverEmail. + */ +@property(nonatomic, nullable, readwrite, copy) NSString *email; + +/** @property previousEmail + @brief The current email address in the case of FIRActionCodeOperationRecoverEmail. + */ +@property(nonatomic, nullable, readwrite, copy) NSString *previousEmail; + +#if TARGET_OS_IOS +/** @property multiFactorInfo + @brief The MultiFactorInfo object of the second factor to be reverted in case of + FIRActionCodeMultiFactorInfoKey. + */ +@property(nonatomic, nullable, readwrite) FIRMultiFactorInfo *multiFactorInfo; +#endif + +@end + +@implementation FIRActionCodeInfo + +- (instancetype)initWithOperation:(FIRActionCodeOperation)operation + email:(NSString *)email + newEmail:(nullable NSString *)newEmail { + self = [super init]; + if (self) { + _operation = operation; + if (newEmail) { + _email = [newEmail copy]; + _previousEmail = [email copy]; + } else { + _email = [email copy]; + } + } + return self; +} + +/** @fn actionCodeOperationForRequestType: + @brief Returns the corresponding operation type per provided request type string. + @param requestType Request type returned in in the server response. + @return The corresponding FIRActionCodeOperation for the supplied request type. + */ ++ (FIRActionCodeOperation)actionCodeOperationForRequestType:(NSString *)requestType { + if ([requestType isEqualToString:kPasswordResetRequestType]) { + return FIRActionCodeOperationPasswordReset; + } + if ([requestType isEqualToString:kVerifyEmailRequestType]) { + return FIRActionCodeOperationVerifyEmail; + } + if ([requestType isEqualToString:kRecoverEmailRequestType]) { + return FIRActionCodeOperationRecoverEmail; + } + if ([requestType isEqualToString:kEmailLinkSignInRequestType]) { + return FIRActionCodeOperationEmailLink; + } + if ([requestType isEqualToString:kVerifyAndChangeEmailRequestType]) { + return FIRActionCodeOperationVerifyAndChangeEmail; + } + if ([requestType isEqualToString:kRevertSecondFactorAdditionRequestType]) { + return FIRActionCodeOperationRevertSecondFactorAddition; + } + return FIRActionCodeOperationUnknown; +} + +@end + +#pragma mark - FIRActionCodeURL + +@implementation FIRActionCodeURL + +/** @fn FIRAuthParseURL:NSString + @brief Parses an incoming URL into all available query items. + @param urlString The url to be parsed. + @return A dictionary of available query items in the target URL. + */ ++ (NSDictionary *)parseURL:(NSString *)urlString { + NSString *linkURL = [NSURLComponents componentsWithString:urlString].query; + if (!linkURL) { + return @{}; + } + NSArray *URLComponents = [linkURL componentsSeparatedByString:@"&"]; + NSMutableDictionary *queryItems = + [[NSMutableDictionary alloc] initWithCapacity:URLComponents.count]; + for (NSString *component in URLComponents) { + NSRange equalRange = [component rangeOfString:@"="]; + if (equalRange.location != NSNotFound) { + NSString *queryItemKey = + [[component substringToIndex:equalRange.location] stringByRemovingPercentEncoding]; + NSString *queryItemValue = + [[component substringFromIndex:equalRange.location + 1] stringByRemovingPercentEncoding]; + if (queryItemKey && queryItemValue) { + queryItems[queryItemKey] = queryItemValue; + } + } + } + return queryItems; +} + ++ (nullable instancetype)actionCodeURLWithLink:(NSString *)link { + NSDictionary *queryItems = [FIRActionCodeURL parseURL:link]; + if (!queryItems.count) { + NSURLComponents *urlComponents = [NSURLComponents componentsWithString:link]; + queryItems = [FIRActionCodeURL parseURL:urlComponents.query]; + } + if (!queryItems.count) { + return nil; + } + NSString *APIKey = queryItems[@"apiKey"]; + NSString *actionCode = queryItems[@"oobCode"]; + NSString *continueURLString = queryItems[@"continueUrl"]; + NSString *languageCode = queryItems[@"languageCode"]; + NSString *mode = queryItems[@"mode"]; + NSString *tenantID = queryItems[@"tenantID"]; + return [[FIRActionCodeURL alloc] initWithAPIKey:APIKey + actionCode:actionCode + continueURLString:continueURLString + languageCode:languageCode + mode:mode + tenantID:tenantID]; +} + +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey + actionCode:(NSString *)actionCode + continueURLString:(NSString *)continueURLString + languageCode:(NSString *)languageCode + mode:(NSString *)mode + tenantID:(NSString *)tenantID { + self = [super init]; + if (self) { + _APIKey = APIKey; + _operation = [FIRActionCodeInfo actionCodeOperationForRequestType:mode]; + _code = actionCode; + _continueURL = [NSURL URLWithString:continueURLString]; + _languageCode = languageCode; + } + return self; +} + +@end + +#pragma mark - FIRAuth + +#if TARGET_OS_IOS +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 +@interface FIRAuth () +#else +@interface FIRAuth () +#endif +#else +@interface FIRAuth () +#endif + +/** @property firebaseAppId + @brief The Firebase app ID. + */ +@property(nonatomic, copy, readonly) NSString *firebaseAppId; + +/** @property additionalFrameworkMarker + @brief Additional framework marker that will be added as part of the header of every request. + */ +@property(nonatomic, copy, nullable) NSString *additionalFrameworkMarker; + +/** @property storedUserManager + @brief The stored user manager. + */ +@property(nonatomic, strong, nullable) FIRAuthStoredUserManager *storedUserManager; + +/** @fn initWithApp: + @brief Creates a @c FIRAuth instance associated with the provided @c FIRApp instance. + @param app The application to associate the auth instance with. + */ +- (instancetype)initWithApp:(FIRApp *)app; + +@end + +@implementation FIRAuth { + /** @var _currentUser + @brief The current user. + */ + FIRUser *_currentUser; + + /** @var _firebaseAppName + @brief The Firebase app name. + */ + NSString *_firebaseAppName; + + /** @var _listenerHandles + @brief Handles returned from @c NSNotificationCenter for blocks which are "auth state did + change" notification listeners. + @remarks Mutations should occur within a @syncronized(self) context. + */ + NSMutableArray *_listenerHandles; + + /** @var _keychainServices + @brief The keychain service. + */ + FIRAuthKeychainServices *_keychainServices; + + /** @var _lastNotifiedUserToken + @brief The user access (ID) token used last time for posting auth state changed notification. + */ + NSString *_lastNotifiedUserToken; + + /** @var _autoRefreshTokens + @brief This flag denotes whether or not tokens should be automatically refreshed. + @remarks Will only be set to @YES if the another Firebase service is included (additionally to + Firebase Auth). + */ + BOOL _autoRefreshTokens; + + /** @var _autoRefreshScheduled + @brief Whether or not token auto-refresh is currently scheduled. + */ + BOOL _autoRefreshScheduled; + + /** @var _isAppInBackground + @brief A flag that is set to YES if the app is put in the background and no when the app is + returned to the foreground. + */ + BOOL _isAppInBackground; + + /** @var _applicationDidBecomeActiveObserver + @brief An opaque object to act as the observer for UIApplicationDidBecomeActiveNotification. + */ + id _applicationDidBecomeActiveObserver; + + /** @var _applicationDidBecomeActiveObserver + @brief An opaque object to act as the observer for + UIApplicationDidEnterBackgroundNotification. + */ + id _applicationDidEnterBackgroundObserver; +} + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self withName:@"fire-auth"]; +} + ++ (void)initialize { + gKeychainServiceNameForAppName = [[NSMutableDictionary alloc] init]; +} + ++ (FIRAuth *)auth { + FIRApp *defaultApp = [FIRApp defaultApp]; + if (!defaultApp) { + [NSException + raise:NSInternalInconsistencyException + format:@"The default FirebaseApp instance must be configured before the default Auth" + @"instance can be initialized. One way to ensure this is to call " + @"`FirebaseApp.configure()` in the App Delegate's " + @"`application(_:didFinishLaunchingWithOptions:)` (or the `@main` struct's " + @"initializer in SwiftUI)."]; + } + return [self authWithApp:defaultApp]; +} + ++ (FIRAuth *)authWithApp:(FIRApp *)app { + // Get the instance of Auth from the container, which will create or return the cached instance + // associated with this app. + id auth = FIR_COMPONENT(FIRAuthInterop, app.container); + return (FIRAuth *)auth; +} + +- (instancetype)initWithApp:(FIRApp *)app { + [FIRAuth setKeychainServiceNameForApp:app]; + self = [self initWithAPIKey:app.options.APIKey appName:app.name]; + if (self) { + _app = app; +#if TARGET_OS_IOS + _authURLPresenter = [[FIRAuthURLPresenter alloc] init]; +#endif + } + return self; +} + +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey appName:(NSString *)appName { + self = [super init]; + if (self) { + _listenerHandles = [NSMutableArray array]; + _requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey]; + _firebaseAppName = [appName copy]; +#if TARGET_OS_IOS + _settings = [[FIRAuthSettings alloc] init]; + static Class applicationClass = nil; + // iOS App extensions should not call [UIApplication sharedApplication], even if UIApplication + // responds to it. + if (![GULAppEnvironmentUtil isAppExtension]) { + Class cls = NSClassFromString(@"UIApplication"); + if (cls && [cls respondsToSelector:NSSelectorFromString(@"sharedApplication")]) { + applicationClass = cls; + } + } + UIApplication *application = [applicationClass sharedApplication]; + + [GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods]; + [GULSceneDelegateSwizzler proxyOriginalSceneDelegate]; +#endif // TARGET_OS_IOS + + // Continue with the rest of initialization in the work thread. + __weak FIRAuth *weakSelf = self; + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + // Load current user from Keychain. + FIRAuth *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + NSString *keychainServiceName = + [FIRAuth keychainServiceNameForAppName:strongSelf->_firebaseAppName]; + if (keychainServiceName) { + strongSelf->_keychainServices = + [[FIRAuthKeychainServices alloc] initWithService:keychainServiceName]; + strongSelf.storedUserManager = + [[FIRAuthStoredUserManager alloc] initWithServiceName:keychainServiceName]; + } + + NSError *error; + NSString *storedUserAccessGroup = + [strongSelf.storedUserManager getStoredUserAccessGroupWithError:&error]; + if (!error) { + if (!storedUserAccessGroup) { + FIRUser *user; + if ([strongSelf getUser:&user error:&error]) { + strongSelf.tenantID = user.tenantID; + [strongSelf updateCurrentUser:user byForce:NO savingToDisk:NO error:&error]; + self->_lastNotifiedUserToken = user.rawAccessToken; + } else { + FIRLogError(kFIRLoggerAuth, @"I-AUT000001", + @"Error loading saved user when starting up: %@", error); + } + } else { + [strongSelf internalUseUserAccessGroup:storedUserAccessGroup error:&error]; + if (error) { + FIRLogError(kFIRLoggerAuth, @"I-AUT000001", + @"Error loading saved user when starting up: %@", error); + } + } + } else { + FIRLogError(kFIRLoggerAuth, @"I-AUT000001", + @"Error loading saved user when starting up: %@", error); + } + +#if TARGET_OS_IOS + // Initialize for phone number auth. + strongSelf->_tokenManager = [[FIRAuthAPNSTokenManager alloc] initWithApplication:application]; + + strongSelf->_appCredentialManager = + [[FIRAuthAppCredentialManager alloc] initWithKeychain:strongSelf->_keychainServices]; + + strongSelf->_notificationManager = [[FIRAuthNotificationManager alloc] + initWithApplication:application + appCredentialManager:strongSelf->_appCredentialManager]; + + [GULAppDelegateSwizzler registerAppDelegateInterceptor:strongSelf]; +#if ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000)) + if (@available(iOS 13, tvos 13, *)) { + [GULSceneDelegateSwizzler registerSceneDelegateInterceptor:strongSelf]; + } +#endif // ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000)) +#endif // TARGET_OS_IOS + }); + } + return self; +} + +- (void)dealloc { + @synchronized(self) { + NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; + while (_listenerHandles.count != 0) { + FIRAuthStateDidChangeListenerHandle handleToRemove = _listenerHandles.lastObject; + [defaultCenter removeObserver:handleToRemove]; + [_listenerHandles removeLastObject]; + } + +#if TARGET_OS_IOS + [defaultCenter removeObserver:_applicationDidBecomeActiveObserver + name:UIApplicationDidBecomeActiveNotification + object:nil]; + [defaultCenter removeObserver:_applicationDidEnterBackgroundObserver + name:UIApplicationDidEnterBackgroundNotification + object:nil]; +#endif + } +} + +#pragma mark - Public API + +- (nullable FIRUser *)currentUser { + __block FIRUser *result; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = self->_currentUser; + }); + return result; +} + +- (void)signInWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRAuthDataResultCallback)completion { +#if TARGET_OS_IOS + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + [provider getCredentialWithUIDelegate:UIDelegate + completion:^(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error) { + if (error) { + decoratedCallback(nil, error); + return; + } + [self + internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:NO + callback:decoratedCallback]; + }]; + }); +#endif // TARGET_OS_IOS +} + +- (void)fetchSignInMethodsForEmail:(nonnull NSString *)email + completion:(nullable FIRSignInMethodQueryCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRCreateAuthURIRequest *request = + [[FIRCreateAuthURIRequest alloc] initWithIdentifier:email + continueURI:@"http://www.google.com/" + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend + createAuthURI:request + callback:^(FIRCreateAuthURIResponse *_Nullable response, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(response.signinMethods, error); + }); + } + }]; + }); +} + +- (void)signInWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + [self internalSignInAndRetrieveDataWithEmail:email + password:password + completion:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + decoratedCallback(authResult, error); + }]; + }); +} + +- (void)signInWithEmail:(NSString *)email + link:(NSString *)link + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + FIREmailPasswordAuthCredential *credential = + [[FIREmailPasswordAuthCredential alloc] initWithEmail:email link:link]; + [self internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:NO + callback:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + decoratedCallback(authResult, error); + }]; + }); +} + +/** @fn signInWithEmail:password:callback: + @brief Signs in using an email address and password. + @param email The user's email address. + @param password The user's password. + @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the global auth work queue in the future. + @remarks This is the internal counterpart of this method, which uses a callback that does not + update the current user. + */ +- (void)signInWithEmail:(NSString *)email + password:(NSString *)password + callback:(FIRAuthResultCallback)callback { + FIRVerifyPasswordRequest *request = + [[FIRVerifyPasswordRequest alloc] initWithEmail:email + password:password + requestConfiguration:_requestConfiguration]; + + if (![request.password length]) { + callback(nil, [FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]); + return; + } + [FIRAuthBackend + verifyPassword:request + callback:^(FIRVerifyPasswordResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + callback(nil, error); + return; + } + [self completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:callback]; + }]; +} + +/** @fn internalSignInAndRetrieveDataWithEmail:password:callback: + @brief Signs in using an email address and password. + @param email The user's email address. + @param password The user's password. + @param completion A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the global auth work queue in the future. + @remarks This is the internal counterpart of this method, which uses a callback that does not + update the current user. + */ +- (void)internalSignInAndRetrieveDataWithEmail:(NSString *)email + password:(NSString *)password + completion:(FIRAuthDataResultCallback)completion { + FIREmailPasswordAuthCredential *credentail = + [[FIREmailPasswordAuthCredential alloc] initWithEmail:email password:password]; + [self internalSignInAndRetrieveDataWithCredential:credentail + isReauthentication:NO + callback:completion]; +} + +/** @fn signInAndRetrieveDataWithGameCenterCredential:callback: + @brief Signs in using a game center credential. + @param credential The Game Center Auth Credential used to sign in. + @param callback A block which is invoked when the sign in finished (or is cancelled). Invoked + asynchronously on the global auth work queue in the future. + */ +- (void)signInAndRetrieveDataWithGameCenterCredential:(FIRGameCenterAuthCredential *)credential + callback:(FIRAuthDataResultCallback)callback { + FIRSignInWithGameCenterRequest *request = + [[FIRSignInWithGameCenterRequest alloc] initWithPlayerID:credential.playerID + publicKeyURL:credential.publicKeyURL + signature:credential.signature + salt:credential.salt + timestamp:credential.timestamp + displayName:credential.displayName + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend + signInWithGameCenter:request + callback:^(FIRSignInWithGameCenterResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (callback) { + callback(nil, error); + } + return; + } + + [self + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (error && callback) { + callback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] + initWithProviderID: + FIRGameCenterAuthProviderID + profile:nil + username:nil + isNewUser:response.isNewUser]; + FIRAuthDataResult *result = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:additionalUserInfo] + : nil; + if (callback) { + callback(result, error); + } + }]; + }]; +} + +/** @fn internalSignInAndRetrieveDataWithEmail:link:completion: + @brief Signs in using an email and email sign-in link. + @param email The user's email address. + @param link The email sign-in link. + @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the global auth work queue in the future. + */ +- (void)internalSignInAndRetrieveDataWithEmail:(nonnull NSString *)email + link:(nonnull NSString *)link + callback:(nullable FIRAuthDataResultCallback)callback { + if (![self isSignInWithEmailLink:link]) { + [FIRAuthExceptionUtils + raiseInvalidParameterExceptionWithReason:kInvalidEmailSignInLinkExceptionMessage]; + return; + } + NSDictionary *queryItems = [FIRAuthWebUtils parseURL:link]; + if (![queryItems count]) { + NSURLComponents *urlComponents = [NSURLComponents componentsWithString:link]; + queryItems = [FIRAuthWebUtils parseURL:urlComponents.query]; + } + NSString *actionCode = queryItems[@"oobCode"]; + + FIREmailLinkSignInRequest *request = + [[FIREmailLinkSignInRequest alloc] initWithEmail:email + oobCode:actionCode + requestConfiguration:_requestConfiguration]; + + [FIRAuthBackend + emailLinkSignin:request + callback:^(FIREmailLinkSignInResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + if (callback) { + callback(nil, error); + } + return; + } + [self completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (error && callback) { + callback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] + initWithProviderID:FIREmailAuthProviderID + profile:nil + username:nil + isNewUser:response.isNewUser]; + FIRAuthDataResult *result = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:additionalUserInfo] + : nil; + if (callback) { + callback(result, error); + } + }]; + }]; +} + +- (void)signInWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback callback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + [self internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:NO + callback:callback]; + }); +} + +- (void)internalSignInWithCredential:(FIRAuthCredential *)credential + callback:(FIRAuthResultCallback)callback { + [self internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:NO + callback:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + callback(authResult.user, error); + }]; +} + +- (void)internalSignInAndRetrieveDataWithCredential:(FIRAuthCredential *)credential + isReauthentication:(BOOL)isReauthentication + callback:(nullable FIRAuthDataResultCallback)callback { + if ([credential isKindOfClass:[FIREmailPasswordAuthCredential class]]) { + // Special case for email/password credentials + FIREmailPasswordAuthCredential *emailPasswordCredential = + (FIREmailPasswordAuthCredential *)credential; + + if (emailPasswordCredential.link) { + // Email link sign in + [self internalSignInAndRetrieveDataWithEmail:emailPasswordCredential.email + link:emailPasswordCredential.link + callback:callback]; + } else { + // Email password sign in + FIRAuthResultCallback completeEmailSignIn = + ^(FIRUser *_Nullable user, NSError *_Nullable error) { + if (callback) { + if (error) { + callback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] initWithProviderID:FIREmailAuthProviderID + profile:nil + username:nil + isNewUser:NO]; + FIRAuthDataResult *result = + user ? [[FIRAuthDataResult alloc] initWithUser:user + additionalUserInfo:additionalUserInfo] + : nil; + callback(result, error); + } + }; + + [self signInWithEmail:emailPasswordCredential.email + password:emailPasswordCredential.password + callback:completeEmailSignIn]; + } + return; + } + + if ([credential isKindOfClass:[FIRGameCenterAuthCredential class]]) { + // Special case for Game Center credentials. + [self signInAndRetrieveDataWithGameCenterCredential:(FIRGameCenterAuthCredential *)credential + callback:callback]; + return; + } + +#if TARGET_OS_IOS + if ([credential isKindOfClass:[FIRPhoneAuthCredential class]]) { + // Special case for phone auth credentials + FIRPhoneAuthCredential *phoneCredential = (FIRPhoneAuthCredential *)credential; + FIRAuthOperationType operation = + isReauthentication ? FIRAuthOperationTypeReauth : FIRAuthOperationTypeSignUpOrSignIn; + [self + signInWithPhoneCredential:phoneCredential + operation:operation + callback:^(FIRVerifyPhoneNumberResponse *_Nullable response, + NSError *_Nullable error) { + if (callback) { + if (error) { + callback(nil, error); + return; + } + + [self + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (error && callback) { + callback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] + initWithProviderID: + FIRPhoneAuthProviderID + profile:nil + username:nil + isNewUser:response + .isNewUser]; + FIRAuthDataResult *result = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo: + additionalUserInfo] + : nil; + if (callback) { + callback(result, error); + } + }]; + } + }]; + return; + } +#endif + FIRVerifyAssertionRequest *request = + [[FIRVerifyAssertionRequest alloc] initWithProviderID:credential.provider + requestConfiguration:_requestConfiguration]; + request.autoCreate = !isReauthentication; + [credential prepareVerifyAssertionRequest:request]; + [FIRAuthBackend + verifyAssertion:request + callback:^(FIRVerifyAssertionResponse *response, NSError *error) { + if (error) { + if (callback) { + callback(nil, error); + } + return; + } + + if (response.needConfirmation) { + if (callback) { + NSString *email = response.email; + FIROAuthCredential *credential = + [[FIROAuthCredential alloc] initWithVerifyAssertionResponse:response]; + callback(nil, + [FIRAuthErrorUtils + accountExistsWithDifferentCredentialErrorWithEmail:email + updatedCredential:credential]); + } + return; + } + + if (!response.providerID.length) { + if (callback) { + callback(nil, [FIRAuthErrorUtils + unexpectedResponseWithDeserializedResponse:response]); + } + return; + } + [self + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (callback) { + if (error) { + callback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [FIRAdditionalUserInfo + userInfoWithVerifyAssertionResponse:response]; + FIROAuthCredential *updatedOAuthCredential = + [[FIROAuthCredential alloc] + initWithVerifyAssertionResponse:response]; + FIRAuthDataResult *result = + user + ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:additionalUserInfo + credential:updatedOAuthCredential] + : nil; + callback(result, error); + } + }]; + }]; +} + +- (void)signInAnonymouslyWithCompletion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + if (self->_currentUser.anonymous) { + FIRAuthDataResult *result = [[FIRAuthDataResult alloc] initWithUser:self->_currentUser + additionalUserInfo:nil]; + decoratedCallback(result, nil); + return; + } + [self internalSignInAnonymouslyWithCompletion:^(FIRSignUpNewUserResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + decoratedCallback(nil, error); + return; + } + [self completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:YES + callback:^(FIRUser *_Nullable user, NSError *_Nullable error) { + if (error) { + decoratedCallback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] initWithProviderID:nil + profile:nil + username:nil + isNewUser:YES]; + FIRAuthDataResult *authDataResult = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:additionalUserInfo] + : nil; + decoratedCallback(authDataResult, error); + }]; + }]; + }); +} + +- (void)signInWithCustomToken:(NSString *)token + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + [self internalSignInAndRetrieveDataWithCustomToken:token + completion:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + decoratedCallback(authResult, error); + }]; + }); +} + +- (void)createUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + [self internalCreateUserWithEmail:email + password:password + completion:^(FIRSignUpNewUserResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + decoratedCallback(nil, error); + return; + } + [self + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (error) { + decoratedCallback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] + initWithProviderID: + FIREmailAuthProviderID + profile:nil + username:nil + isNewUser:YES]; + FIRAuthDataResult *authDataResult = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo: + additionalUserInfo] + : nil; + decoratedCallback(authDataResult, error); + }]; + }]; + }); +} + +- (void)confirmPasswordResetWithCode:(NSString *)code + newPassword:(NSString *)newPassword + completion:(FIRConfirmPasswordResetCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRResetPasswordRequest *request = + [[FIRResetPasswordRequest alloc] initWithOobCode:code + newPassword:newPassword + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend + resetPassword:request + callback:^(FIRResetPasswordResponse *_Nullable response, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (error) { + completion(error); + return; + } + completion(nil); + }); + } + }]; + }); +} + +- (void)checkActionCode:(NSString *)code completion:(FIRCheckActionCodeCallBack)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRResetPasswordRequest *request = + [[FIRResetPasswordRequest alloc] initWithOobCode:code + newPassword:nil + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend + resetPassword:request + callback:^(FIRResetPasswordResponse *_Nullable response, NSError *_Nullable error) { + if (completion) { + if (error) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(nil, error); + }); + return; + } + FIRActionCodeOperation operation = + [FIRActionCodeInfo actionCodeOperationForRequestType:response.requestType]; + FIRActionCodeInfo *actionCodeInfo = + [[FIRActionCodeInfo alloc] initWithOperation:operation + email:response.email + newEmail:response.verifiedEmail]; + dispatch_async(dispatch_get_main_queue(), ^{ + completion(actionCodeInfo, nil); + }); + } + }]; + }); +} + +- (void)verifyPasswordResetCode:(NSString *)code + completion:(FIRVerifyPasswordResetCodeCallback)completion { + [self checkActionCode:code + completion:^(FIRActionCodeInfo *_Nullable info, NSError *_Nullable error) { + if (completion) { + if (error) { + completion(nil, error); + return; + } + completion(info.email, nil); + } + }]; +} + +- (void)applyActionCode:(NSString *)code completion:(FIRApplyActionCodeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRSetAccountInfoRequest *request = + [[FIRSetAccountInfoRequest alloc] initWithRequestConfiguration:self->_requestConfiguration]; + request.OOBCode = code; + [FIRAuthBackend + setAccountInfo:request + callback:^(FIRSetAccountInfoResponse *_Nullable response, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + }]; + }); +} + +- (void)sendPasswordResetWithEmail:(NSString *)email + completion:(nullable FIRSendPasswordResetCallback)completion { + [self sendPasswordResetWithNullableActionCodeSettings:nil email:email completion:completion]; +} + +- (void)sendPasswordResetWithEmail:(NSString *)email + actionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion:(nullable FIRSendPasswordResetCallback)completion { + [self sendPasswordResetWithNullableActionCodeSettings:actionCodeSettings + email:email + completion:completion]; +} + +/** @fn sendPasswordResetWithNullableActionCodeSettings:actionCodeSetting:email:completion: + @brief Initiates a password reset for the given email address and @FIRActionCodeSettings object. + + @param actionCodeSettings Optionally, An @c FIRActionCodeSettings object containing settings + related to the handling action codes. + @param email The email address of the user. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)sendPasswordResetWithNullableActionCodeSettings: + (nullable FIRActionCodeSettings *)actionCodeSettings + email:(NSString *)email + completion: + (nullable FIRSendPasswordResetCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + if (!email) { + [FIRAuthExceptionUtils + raiseInvalidParameterExceptionWithReason:kMissingEmailInvalidParameterExceptionReason]; + return; + } + FIRGetOOBConfirmationCodeRequest *request = [FIRGetOOBConfirmationCodeRequest + passwordResetRequestWithEmail:email + actionCodeSettings:actionCodeSettings + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend getOOBConfirmationCode:request + callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response, + NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + }]; + }); +} + +- (void)sendSignInLinkToEmail:(nonnull NSString *)email + actionCodeSettings:(nonnull FIRActionCodeSettings *)actionCodeSettings + completion:(nullable FIRSendSignInLinkToEmailCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + if (!email) { + [FIRAuthExceptionUtils + raiseInvalidParameterExceptionWithReason:kMissingEmailInvalidParameterExceptionReason]; + } + + if (!actionCodeSettings.handleCodeInApp) { + [FIRAuthExceptionUtils + raiseInvalidParameterExceptionWithReason:kHandleCodeInAppFalseExceptionReason]; + } + FIRGetOOBConfirmationCodeRequest *request = + [FIRGetOOBConfirmationCodeRequest signInWithEmailLinkRequest:email + actionCodeSettings:actionCodeSettings + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend getOOBConfirmationCode:request + callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response, + NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + }]; + }); +} + +- (void)updateCurrentUser:(FIRUser *)user completion:(nullable FIRUserUpdateCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + if (!user) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion([FIRAuthErrorUtils nullUserErrorWithMessage:nil]); + }); + } + return; + } + void (^updateUserBlock)(FIRUser *user) = ^(FIRUser *user) { + NSError *error; + [self updateCurrentUser:user byForce:YES savingToDisk:YES error:(&error)]; + if (error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + return; + } + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(nil); + }); + } + }; + if (![user.requestConfiguration.APIKey isEqualToString:self->_requestConfiguration.APIKey]) { + // If the API keys are different, then we need to confirm that the user belongs to the same + // project before proceeding. + user.requestConfiguration = self->_requestConfiguration; + [user reloadWithCompletion:^(NSError *_Nullable error) { + if (error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + return; + } + updateUserBlock(user); + }]; + } else { + updateUserBlock(user); + } + }); +} + +- (BOOL)signOut:(NSError *_Nullable __autoreleasing *_Nullable)error { + __block BOOL result = YES; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + if (!self->_currentUser) { + return; + } + result = [self updateCurrentUser:nil byForce:NO savingToDisk:YES error:error]; + }); + return result; +} + +- (BOOL)signOutByForceWithUserID:(NSString *)userID error:(NSError *_Nullable *_Nullable)error { + if (_currentUser.uid != userID) { + return YES; + } + return [self updateCurrentUser:nil byForce:YES savingToDisk:YES error:error]; +} + +- (BOOL)isSignInWithEmailLink:(NSString *)link { + if (link.length == 0) { + return NO; + } + NSDictionary *queryItems = [FIRAuthWebUtils parseURL:link]; + if (![queryItems count]) { + NSURLComponents *urlComponents = [NSURLComponents componentsWithString:link]; + if (!urlComponents.query) { + return NO; + } + queryItems = [FIRAuthWebUtils parseURL:urlComponents.query]; + } + + if (![queryItems count]) { + return NO; + } + + NSString *actionCode = queryItems[@"oobCode"]; + NSString *mode = queryItems[@"mode"]; + + if (actionCode && [mode isEqualToString:@"signIn"]) { + return YES; + } + return NO; +} + +- (FIRAuthStateDidChangeListenerHandle)addAuthStateDidChangeListener: + (FIRAuthStateDidChangeListenerBlock)listener { + __block BOOL firstInvocation = YES; + __block NSString *previousUserID; + return [self addIDTokenDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) { + BOOL shouldCallListener = firstInvocation || !(previousUserID == user.uid || + [previousUserID isEqualToString:user.uid]); + firstInvocation = NO; + previousUserID = [user.uid copy]; + if (shouldCallListener) { + listener(auth, user); + } + }]; +} + +- (void)removeAuthStateDidChangeListener:(FIRAuthStateDidChangeListenerHandle)listenerHandle { + [self removeIDTokenDidChangeListener:listenerHandle]; +} + +- (FIRIDTokenDidChangeListenerHandle)addIDTokenDidChangeListener: + (FIRIDTokenDidChangeListenerBlock)listener { + if (!listener) { + [NSException raise:NSInvalidArgumentException format:@"Listener must not be nil."]; + return nil; + } + FIRAuthStateDidChangeListenerHandle handle; + NSNotificationCenter *notifications = [NSNotificationCenter defaultCenter]; + handle = [notifications addObserverForName:FIRAuthStateDidChangeNotification + object:self + queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification *_Nonnull notification) { + FIRAuth *auth = notification.object; + listener(auth, auth.currentUser); + }]; + @synchronized(self) { + [_listenerHandles addObject:handle]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + listener(self, self->_currentUser); + }); + return handle; +} + +- (void)removeIDTokenDidChangeListener:(FIRIDTokenDidChangeListenerHandle)listenerHandle { + [[NSNotificationCenter defaultCenter] removeObserver:listenerHandle]; + @synchronized(self) { + [_listenerHandles removeObject:listenerHandle]; + } +} + +- (void)useAppLanguage { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + self->_requestConfiguration.languageCode = [[NSLocale preferredLanguages] firstObject]; + }); +} + +- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port { + NSAssert(host.length > 0, @"Cannot connect to nil or empty host"); + + NSString *formattedHost; + if ([host containsString:@":"]) { + // Host is an IPv6 address and should be formatted with surrounding brackets. + formattedHost = [NSString stringWithFormat:@"[%@]", host]; + } else { + formattedHost = host; + } + + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + self->_requestConfiguration.emulatorHostAndPort = + [NSString stringWithFormat:@"%@:%ld", formattedHost, (long)port]; +#if TARGET_OS_IOS + self->_settings.appVerificationDisabledForTesting = YES; +#endif + }); +} + +- (nullable NSString *)languageCode { + return _requestConfiguration.languageCode; +} + +- (void)setLanguageCode:(nullable NSString *)languageCode { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + self->_requestConfiguration.languageCode = [languageCode copy]; + }); +} + +- (nullable NSString *)additionalFrameworkMarker { + return self->_requestConfiguration.additionalFrameworkMarker; +} + +- (void)setAdditionalFrameworkMarker:(nullable NSString *)additionalFrameworkMarker { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + self->_requestConfiguration.additionalFrameworkMarker = [additionalFrameworkMarker copy]; + }); +} + +#if TARGET_OS_IOS +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-property-ivar" +// The warning is ignored because we use the token manager to get the token, instead of using the +// ivar. +- (nullable NSData *)APNSToken { + __block NSData *result = nil; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = self->_tokenManager.token.data; + }); + return result; +} +#pragma clang diagnostic pop + +#pragma mark - UIApplicationDelegate + +- (void)application:(UIApplication *)application + didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + [self setAPNSToken:deviceToken type:FIRAuthAPNSTokenTypeUnknown]; +} + +- (void)application:(UIApplication *)application + didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + [self->_tokenManager cancelWithError:error]; + }); +} + +- (void)application:(UIApplication *)application + didReceiveRemoteNotification:(NSDictionary *)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { + [self canHandleNotification:userInfo]; + completionHandler(UIBackgroundFetchResultNoData); +} + +// iOS 10 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +- (void)application:(UIApplication *)application + didReceiveRemoteNotification:(NSDictionary *)userInfo { + [self canHandleNotification:userInfo]; +} +#pragma clang diagnostic pop + +- (BOOL)application:(UIApplication *)app + openURL:(NSURL *)url + options:(NSDictionary *)options { + return [self canHandleURL:url]; +} + +// iOS 10 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(nullable NSString *)sourceApplication + annotation:(id)annotation { + return [self canHandleURL:url]; +} +#pragma clang diagnostic pop + +- (void)setAPNSToken:(NSData *)token type:(FIRAuthAPNSTokenType)type { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + self->_tokenManager.token = [[FIRAuthAPNSToken alloc] initWithData:token type:type]; + }); +} + +- (BOOL)canHandleNotification:(NSDictionary *)userInfo { + __block BOOL result = NO; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = [self->_notificationManager canHandleNotification:userInfo]; + }); + return result; +} + +- (BOOL)canHandleURL:(NSURL *)URL { + __block BOOL result = NO; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = [self->_authURLPresenter canHandleURL:URL]; + }); + return result; +} + +#pragma mark - UISceneDelegate +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 +- (void)scene:(UIScene *)scene + openURLContexts:(NSSet *)URLContexts API_AVAILABLE(ios(13.0)) { + for (UIOpenURLContext *urlContext in URLContexts) { + NSURL *url = [urlContext URL]; + [self canHandleURL:url]; + } +} +#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 +#endif // TARGET_OS_IOS + +#pragma mark - Internal Methods + +#if TARGET_OS_IOS +/** @fn signInWithPhoneCredential:callback: + @brief Signs in using a phone credential. + @param credential The Phone Auth credential used to sign in. + @param operation The type of operation for which this sign-in attempt is initiated. + @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the global auth work queue in the future. + */ +- (void)signInWithPhoneCredential:(FIRPhoneAuthCredential *)credential + operation:(FIRAuthOperationType)operation + callback:(FIRVerifyPhoneNumberResponseCallback)callback { + if (credential.temporaryProof.length && credential.phoneNumber.length) { + FIRVerifyPhoneNumberRequest *request = + [[FIRVerifyPhoneNumberRequest alloc] initWithTemporaryProof:credential.temporaryProof + phoneNumber:credential.phoneNumber + operation:operation + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend verifyPhoneNumber:request callback:callback]; + return; + } + + if (!credential.verificationID.length) { + callback(nil, [FIRAuthErrorUtils missingVerificationIDErrorWithMessage:nil]); + return; + } + if (!credential.verificationCode.length) { + callback(nil, [FIRAuthErrorUtils missingVerificationCodeErrorWithMessage:nil]); + return; + } + FIRVerifyPhoneNumberRequest *request = + [[FIRVerifyPhoneNumberRequest alloc] initWithVerificationID:credential.verificationID + verificationCode:credential.verificationCode + operation:operation + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend verifyPhoneNumber:request callback:callback]; +} + +#endif + +/** @fn internalSignInAndRetrieveDataWithCustomToken:completion: + @brief Signs in a Firebase user given a custom token. + @param token A self-signed custom auth token. + @param completion A block which is invoked when the custom token sign in request completes. + */ +- (void)internalSignInAndRetrieveDataWithCustomToken:(NSString *)token + completion: + (nullable FIRAuthDataResultCallback)completion { + FIRVerifyCustomTokenRequest *request = + [[FIRVerifyCustomTokenRequest alloc] initWithToken:token + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend + verifyCustomToken:request + callback:^(FIRVerifyCustomTokenResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (completion) { + completion(nil, error); + return; + } + } + [self completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (error && completion) { + completion(nil, error); + return; + } + FIRAdditionalUserInfo *additonalUserInfo = + [[FIRAdditionalUserInfo alloc] + initWithProviderID:nil + profile:nil + username:nil + isNewUser:response.isNewUser]; + FIRAuthDataResult *result = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:additonalUserInfo] + : nil; + if (completion) { + completion(result, error); + } + }]; + }]; +} + +/** @fn internalCreateUserWithEmail:password:completion: + @brief Makes a backend request attempting to create a new Firebase user given an email address + and password. + @param email The email address used to create the new Firebase user. + @param password The password used to create the new Firebase user. + @param completion Optionally; a block which is invoked when the request finishes. + */ +- (void)internalCreateUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable FIRSignupNewUserCallback)completion { + FIRSignUpNewUserRequest *request = + [[FIRSignUpNewUserRequest alloc] initWithEmail:email + password:password + displayName:nil + requestConfiguration:_requestConfiguration]; + if (![request.password length]) { + completion( + nil, [FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:kMissingPasswordReason]); + return; + } + if (![request.email length]) { + completion(nil, [FIRAuthErrorUtils missingEmailErrorWithMessage:nil]); + return; + } + [FIRAuthBackend signUpNewUser:request callback:completion]; +} + +/** @fn internalSignInAnonymouslyWithCompletion: + @param completion A block which is invoked when the anonymous sign in request completes. + */ +- (void)internalSignInAnonymouslyWithCompletion:(FIRSignupNewUserCallback)completion { + FIRSignUpNewUserRequest *request = + [[FIRSignUpNewUserRequest alloc] initWithRequestConfiguration:_requestConfiguration]; + [FIRAuthBackend signUpNewUser:request callback:completion]; +} + +/** @fn possiblyPostAuthStateChangeNotification + @brief Posts the auth state change notificaton if current user's token has been changed. + */ +- (void)possiblyPostAuthStateChangeNotification { + NSString *token = _currentUser.rawAccessToken; + if (_lastNotifiedUserToken == token || + (token != nil && [_lastNotifiedUserToken isEqualToString:token])) { + return; + } + _lastNotifiedUserToken = token; + if (_autoRefreshTokens) { + // Shedule new refresh task after successful attempt. + [self scheduleAutoTokenRefresh]; + } + NSMutableDictionary *internalNotificationParameters = [NSMutableDictionary dictionary]; + if (self.app) { + internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationAppKey] = self.app; + } + if (token.length) { + internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationTokenKey] = token; + } + internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationUIDKey] = + _currentUser.uid; + NSNotificationCenter *notifications = [NSNotificationCenter defaultCenter]; + dispatch_async(dispatch_get_main_queue(), ^{ + [notifications postNotificationName:FIRAuthStateDidChangeInternalNotification + object:self + userInfo:internalNotificationParameters]; + [notifications postNotificationName:FIRAuthStateDidChangeNotification object:self]; + }); +} + +- (BOOL)updateKeychainWithUser:(FIRUser *)user error:(NSError *_Nullable *_Nullable)error { + if (user != _currentUser) { + // No-op if the user is no longer signed in. This is not considered an error as we don't check + // whether the user is still current on other callbacks of user operations either. + return YES; + } + if ([self saveUser:user error:error]) { + [self possiblyPostAuthStateChangeNotification]; + return YES; + } + return NO; +} + +/** @fn setKeychainServiceNameForApp + @brief Sets the keychain service name global data for the particular app. + @param app The Firebase app to set keychain service name for. + */ ++ (void)setKeychainServiceNameForApp:(FIRApp *)app { + @synchronized(self) { + gKeychainServiceNameForAppName[app.name] = + [@"firebase_auth_" stringByAppendingString:app.options.googleAppID]; + } +} + +/** @fn keychainServiceNameForAppName: + @brief Gets the keychain service name global data for the particular app by name. + @param appName The name of the Firebase app to get keychain service name for. + */ ++ (NSString *)keychainServiceNameForAppName:(NSString *)appName { + @synchronized(self) { + return gKeychainServiceNameForAppName[appName]; + } +} + +/** @fn deleteKeychainServiceNameForAppName: + @brief Deletes the keychain service name global data for the particular app by name. + @param appName The name of the Firebase app to delete keychain service name for. + */ ++ (void)deleteKeychainServiceNameForAppName:(NSString *)appName { + @synchronized(self) { + [gKeychainServiceNameForAppName removeObjectForKey:appName]; + } +} + +/** @fn scheduleAutoTokenRefreshWithDelay: + @brief Schedules a task to automatically refresh tokens on the current user. The token refresh + is scheduled 5 minutes before the scheduled expiration time. + @remarks If the token expires in less than 5 minutes, schedule the token refresh immediately. + */ +- (void)scheduleAutoTokenRefresh { + NSTimeInterval tokenExpirationInterval = + [_currentUser.accessTokenExpirationDate timeIntervalSinceNow] - kTokenRefreshHeadStart; + [self scheduleAutoTokenRefreshWithDelay:MAX(tokenExpirationInterval, 0) retry:NO]; +} + +/** @fn scheduleAutoTokenRefreshWithDelay: + @brief Schedules a task to automatically refresh tokens on the current user. + @param delay The delay in seconds after which the token refresh task should be scheduled to be + executed. + @param retry Flag to determine whether the invocation is a retry attempt or not. + */ +- (void)scheduleAutoTokenRefreshWithDelay:(NSTimeInterval)delay retry:(BOOL)retry { + NSString *accessToken = _currentUser.rawAccessToken; + if (!accessToken) { + return; + } + if (retry) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000003", + @"Token auto-refresh re-scheduled in %02d:%02d " + @"because of error on previous refresh attempt.", + (int)ceil(delay) / 60, (int)ceil(delay) % 60); + } else { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000004", + @"Token auto-refresh scheduled in %02d:%02d for the new token.", + (int)ceil(delay) / 60, (int)ceil(delay) % 60); + } + _autoRefreshScheduled = YES; + __weak FIRAuth *weakSelf = self; + [[FIRAuthDispatcher sharedInstance] + dispatchAfterDelay:delay + queue:FIRAuthGlobalWorkQueue() + task:^(void) { + FIRAuth *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + if (![strongSelf->_currentUser.rawAccessToken isEqualToString:accessToken]) { + // Another auto refresh must have been scheduled, so keep + // _autoRefreshScheduled unchanged. + return; + } + strongSelf->_autoRefreshScheduled = NO; + if (strongSelf->_isAppInBackground) { + return; + } + NSString *uid = strongSelf->_currentUser.uid; + [strongSelf->_currentUser + internalGetTokenForcingRefresh:YES + callback:^(NSString *_Nullable token, + NSError *_Nullable error) { + if (![strongSelf->_currentUser.uid + isEqualToString:uid]) { + return; + } + if (error) { + // Kicks off exponential back off logic to retry + // failed attempt. Starts with one minute delay + // (60 seconds) if this is the first failed + // attempt. + NSTimeInterval rescheduleDelay; + if (retry) { + rescheduleDelay = + MIN(delay * 2, kMaxWaitTimeForBackoff); + } else { + rescheduleDelay = 60; + } + [strongSelf + scheduleAutoTokenRefreshWithDelay: + rescheduleDelay + retry:YES]; + } + }]; + }]; +} + +#pragma mark - + +/** @fn completeSignInWithTokenService:callback: + @brief Completes a sign-in flow once we have access and refresh tokens for the user. + @param accessToken The STS access token. + @param accessTokenExpirationDate The approximate expiration date of the access token. + @param refreshToken The STS refresh token. + @param anonymous Whether or not the user is anonymous. + @param callback Called when the user has been signed in or when an error occurred. Invoked + asynchronously on the global auth work queue in the future. + */ +- (void)completeSignInWithAccessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(nullable NSString *)refreshToken + anonymous:(BOOL)anonymous + callback:(FIRAuthResultCallback)callback { + [FIRUser retrieveUserWithAuth:self + accessToken:accessToken + accessTokenExpirationDate:accessTokenExpirationDate + refreshToken:refreshToken + anonymous:anonymous + callback:callback]; +} + +/** @fn signInFlowAuthResultCallbackByDecoratingCallback: + @brief Creates a FIRAuthResultCallback block which wraps another FIRAuthResultCallback; trying + to update the current user before forwarding it's invocations along to a subject block + @param callback Called when the user has been updated or when an error has occurred. Invoked + asynchronously on the main thread in the future. + @return Returns a block that updates the current user. + @remarks Typically invoked as part of the complete sign-in flow. For any other uses please + consider alternative ways of updating the current user. +*/ +- (FIRAuthResultCallback)signInFlowAuthResultCallbackByDecoratingCallback: + (nullable FIRAuthResultCallback)callback { + return ^(FIRUser *_Nullable user, NSError *_Nullable error) { + if (error) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(nil, error); + }); + } + return; + } + if (![self updateCurrentUser:user byForce:NO savingToDisk:YES error:&error]) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(nil, error); + }); + } + return; + } + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(user, nil); + }); + } + }; +} + +/** @fn signInFlowAuthDataResultCallbackByDecoratingCallback: + @brief Creates a FIRAuthDataResultCallback block which wraps another FIRAuthDataResultCallback; + trying to update the current user before forwarding it's invocations along to a subject + block. + @param callback Called when the user has been updated or when an error has occurred. Invoked + asynchronously on the main thread in the future. + @return Returns a block that updates the current user. + @remarks Typically invoked as part of the complete sign-in flow. For any other uses please + consider alternative ways of updating the current user. +*/ +- (FIRAuthDataResultCallback)signInFlowAuthDataResultCallbackByDecoratingCallback: + (nullable FIRAuthDataResultCallback)callback { + return ^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) { + if (error) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(nil, error); + }); + } + return; + } + if (![self updateCurrentUser:authResult.user byForce:NO savingToDisk:YES error:&error]) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(nil, error); + }); + } + return; + } + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(authResult, nil); + }); + } + }; +} + +#pragma mark - User-Related Methods + +/** @fn updateCurrentUser:byForce:savingToDisk:error: + @brief Update the current user; initializing the user's internal properties correctly, and + optionally saving the user to disk. + @remarks This method is called during: sign in and sign out events, as well as during class + initialization time. The only time the saveToDisk parameter should be set to NO is during + class initialization time because the user was just read from disk. + @param user The user to use as the current user (including nil, which is passed at sign out + time.) + @param saveToDisk Indicates the method should persist the user data to disk. + */ +- (BOOL)updateCurrentUser:(nullable FIRUser *)user + byForce:(BOOL)force + savingToDisk:(BOOL)saveToDisk + error:(NSError *_Nullable *_Nullable)error { + if (user == _currentUser) { + [self possiblyPostAuthStateChangeNotification]; + return YES; + } + if (user) { + if ((user.tenantID || self.tenantID) && ![self.tenantID isEqualToString:user.tenantID]) { + if (error) { + *error = [FIRAuthErrorUtils tenantIDMismatchError]; + } + return NO; + } + } + + BOOL success = YES; + if (saveToDisk) { + success = [self saveUser:user error:error]; + } + if (success || force) { + _currentUser = user; + [self possiblyPostAuthStateChangeNotification]; + } + return success; +} + +/** @fn saveUser:error: + @brief Persists user. + @param user The user to save. + @param outError Return value for any error which occurs. + @return @YES on success, @NO otherwise. + */ +- (BOOL)saveUser:(nullable FIRUser *)user error:(NSError *_Nullable *_Nullable)outError { + BOOL success; + + if (!self.userAccessGroup) { + NSString *userKey = [NSString stringWithFormat:kUserKey, _firebaseAppName]; + if (!user) { + success = [_keychainServices removeDataForKey:userKey error:outError]; + } else { +#if TARGET_OS_WATCH + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false]; +#else + // Encode the user object. + NSMutableData *archiveData = [NSMutableData data]; +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedArchiver *archiver = + [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiveData]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + [archiver encodeObject:user forKey:userKey]; + [archiver finishEncoding]; + +#if TARGET_OS_WATCH + NSData *archiveData = archiver.encodedData; +#endif // TARGET_OS_WATCH + + // Save the user object's encoded value. + success = [_keychainServices setData:archiveData forKey:userKey error:outError]; + } + } else { + if (!user) { + success = + [self.storedUserManager removeStoredUserForAccessGroup:self.userAccessGroup + shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices + projectIdentifier:self.app.options.APIKey + error:outError]; + } else { + success = [self.storedUserManager setStoredUser:user + forAccessGroup:self.userAccessGroup + shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices + projectIdentifier:self.app.options.APIKey + error:outError]; + } + } + + return success; +} + +/** @fn getUser:error: + @brief Retrieves the saved user associated, if one exists, from the keychain. + @param outUser An out parameter which is populated with the saved user, if one exists. + @param error Return value for any error which occurs. + @return YES if the operation was a success (irrespective of whether or not a saved user existed + for the given @c firebaseAppId,) NO if an error occurred. + */ +- (BOOL)getUser:(FIRUser *_Nullable *)outUser error:(NSError *_Nullable *_Nullable)error { + if (!self.userAccessGroup) { + NSString *userKey = [NSString stringWithFormat:kUserKey, _firebaseAppName]; + + NSError *keychainError; + NSData *encodedUserData = [_keychainServices dataForKey:userKey error:&keychainError]; + if (keychainError) { + if (error) { + *error = keychainError; + } + return NO; + } + if (!encodedUserData) { + *outUser = nil; + return YES; + } +#if TARGET_OS_WATCH + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedUserData error:error]; + if (error && *error) { + return NO; + } +#else +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedUserData]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + FIRUser *user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:userKey]; + user.auth = self; + *outUser = user; + + return YES; + } else { + FIRUser *user = + [self.storedUserManager getStoredUserForAccessGroup:self.userAccessGroup + shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices + projectIdentifier:self.app.options.APIKey + error:error]; + user.auth = self; + *outUser = user; + if (user) { + return YES; + } else { + if (error && *error) { + return NO; + } else { + return YES; + } + } + } +} + +#pragma mark - Interoperability + ++ (nonnull NSArray *)componentsToRegister { + FIRComponentCreationBlock authCreationBlock = + ^id _Nullable(FIRComponentContainer *_Nonnull container, BOOL *_Nonnull isCacheable) { + *isCacheable = YES; + return [[FIRAuth alloc] initWithApp:container.app]; + }; + FIRComponent *authInterop = [FIRComponent componentWithProtocol:@protocol(FIRAuthInterop) + instantiationTiming:FIRInstantiationTimingAlwaysEager + dependencies:@[] + creationBlock:authCreationBlock]; + return @[ authInterop ]; +} + +#pragma mark - FIRComponentLifecycleMaintainer + +- (void)appWillBeDeleted:(nonnull FIRApp *)app { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + // This doesn't stop any request already issued, see b/27704535 . + NSString *keychainServiceName = [FIRAuth keychainServiceNameForAppName:app.name]; + if (keychainServiceName) { + [[self class] deleteKeychainServiceNameForAppName:app.name]; + FIRAuthKeychainServices *keychain = + [[FIRAuthKeychainServices alloc] initWithService:keychainServiceName]; + NSString *userKey = [NSString stringWithFormat:kUserKey, app.name]; + [keychain removeDataForKey:userKey error:NULL]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + // TODO: Move over to fire an event instead, once ready. + [[NSNotificationCenter defaultCenter] postNotificationName:FIRAuthStateDidChangeNotification + object:nil]; + }); + }); +} + +#pragma mark - FIRAuthInterop + +- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(FIRTokenCallback)callback { + __weak FIRAuth *weakSelf = self; + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuth *strongSelf = weakSelf; + // Enable token auto-refresh if not aleady enabled. + if (strongSelf && !strongSelf->_autoRefreshTokens) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000002", @"Token auto-refresh enabled."); + strongSelf->_autoRefreshTokens = YES; + [strongSelf scheduleAutoTokenRefresh]; + +#if TARGET_OS_IOS || TARGET_OS_TV // TODO: Is a similar mechanism needed on macOS? + strongSelf->_applicationDidBecomeActiveObserver = [[NSNotificationCenter defaultCenter] + addObserverForName:UIApplicationDidBecomeActiveNotification + object:nil + queue:nil + usingBlock:^(NSNotification *notification) { + FIRAuth *strongSelf = weakSelf; + if (strongSelf) { + strongSelf->_isAppInBackground = NO; + if (!strongSelf->_autoRefreshScheduled) { + [weakSelf scheduleAutoTokenRefresh]; + } + } + }]; + strongSelf->_applicationDidEnterBackgroundObserver = [[NSNotificationCenter defaultCenter] + addObserverForName:UIApplicationDidEnterBackgroundNotification + object:nil + queue:nil + usingBlock:^(NSNotification *notification) { + FIRAuth *strongSelf = weakSelf; + if (strongSelf) { + strongSelf->_isAppInBackground = YES; + } + }]; +#endif + } + // Call back with 'nil' if there is no current user. + if (!strongSelf || !strongSelf->_currentUser) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(nil, nil); + }); + return; + } + // Call back with current user token. + [strongSelf->_currentUser + internalGetTokenForcingRefresh:forceRefresh + callback:^(NSString *_Nullable token, NSError *_Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(token, error); + }); + }]; + }); +} + +- (nullable NSString *)getUserID { + return _currentUser.uid; +} + +#pragma mark - Keychain sharing + +- (BOOL)internalUseUserAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError { + BOOL success; + success = [self.storedUserManager setStoredUserAccessGroup:accessGroup error:outError]; + if (!success) { + return NO; + } + + FIRUser *user = [self getStoredUserForAccessGroup:accessGroup error:outError]; + if (!user && outError && *outError) { + return NO; + } + success = [self updateCurrentUser:user byForce:NO savingToDisk:NO error:outError]; + if (!success) { + return NO; + } + + if (_userAccessGroup == nil && accessGroup != nil) { + NSString *userKey = [NSString stringWithFormat:kUserKey, _firebaseAppName]; + [_keychainServices removeDataForKey:userKey error:outError]; + } + _userAccessGroup = accessGroup; + self->_lastNotifiedUserToken = user.rawAccessToken; + + return YES; +} + +- (BOOL)useUserAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError { + // self.storedUserManager is initialized asynchronously. Make sure it is done. + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + }); + return [self internalUseUserAccessGroup:accessGroup error:outError]; +} + +- (nullable FIRUser *)getStoredUserForAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError { + FIRUser *user; + if (!accessGroup) { + NSString *userKey = [NSString stringWithFormat:kUserKey, _firebaseAppName]; + NSData *encodedUserData = [_keychainServices dataForKey:userKey error:outError]; + if (!encodedUserData) { + return nil; + } + +#if TARGET_OS_WATCH + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedUserData error:outError]; + if (outError && *outError) { + return nil; + } +#else +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedUserData]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:userKey]; + } else { + user = [self.storedUserManager getStoredUserForAccessGroup:accessGroup + shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices + projectIdentifier:self.app.options.APIKey + error:outError]; + } + + user.auth = self; + return user; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult.m new file mode 100644 index 0000000..dc8d035 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult.m @@ -0,0 +1,83 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthDataResult + +/** @var kAdditionalUserInfoCodingKey + @brief The key used to encode the additionalUserInfo property for NSSecureCoding. + */ +static NSString *const kAdditionalUserInfoCodingKey = @"additionalUserInfo"; + +/** @var kUserCodingKey + @brief The key used to encode the user property for NSSecureCoding. + */ +static NSString *const kUserCodingKey = @"user"; + +/** @var kCredentialCodingKey + @brief The key used to encode the credential for NSSecureCoding. + */ +static NSString *const kCredentialCodingKey = @"credential"; + +- (nullable instancetype)initWithUser:(FIRUser *)user + additionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo { + return [self initWithUser:user additionalUserInfo:additionalUserInfo credential:nil]; +} + +- (nullable instancetype)initWithUser:(FIRUser *)user + additionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo + credential:(nullable FIROAuthCredential *)credential { + self = [super init]; + if (self) { + _additionalUserInfo = additionalUserInfo; + _user = user; + _credential = credential; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + FIRUser *user = [aDecoder decodeObjectOfClass:[FIRUser class] forKey:kUserCodingKey]; + FIRAdditionalUserInfo *additionalUserInfo = + [aDecoder decodeObjectOfClass:[FIRAdditionalUserInfo class] + forKey:kAdditionalUserInfoCodingKey]; + FIROAuthCredential *credential = [aDecoder decodeObjectOfClass:[FIROAuthCredential class] + forKey:kCredentialCodingKey]; + return [self initWithUser:user additionalUserInfo:additionalUserInfo credential:credential]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_user forKey:kUserCodingKey]; + [aCoder encodeObject:_additionalUserInfo forKey:kAdditionalUserInfoCodingKey]; + [aCoder encodeObject:_credential forKey:kCredentialCodingKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h new file mode 100644 index 0000000..ff5f4c2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h" + +@class FIROAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthDataResult () + +/** @fn initWithUser:additionalUserInfo: + @brief Designated initializer. + @param user The signed in user reference. + @param additionalUserInfo The additional user info if available. + */ +- (nullable instancetype)initWithUser:(FIRUser *)user + additionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo; + +/** @fn initWithUser:additionalUserInfo: + @brief Designated initializer. + @param user The signed in user reference. + @param additionalUserInfo The additional user info if available. + @param credential The updated OAuth credential if available. + */ +- (nullable instancetype)initWithUser:(FIRUser *)user + additionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo + credential:(nullable FIROAuthCredential *)credential + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h new file mode 100644 index 0000000..2c5839b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h @@ -0,0 +1,63 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthDispatcherImplBlock + @brief The type of block which can be set as the implementation for @c + dispatchAfterDelay:queue:callback: . + + @param delay The delay in seconds after which the task will be scheduled to execute. + @param queue The dispatch queue on which the task will be submitted. + @param task The task (block) to be scheduled for future execution. + */ +typedef void (^FIRAuthDispatcherImplBlock)(NSTimeInterval delay, + dispatch_queue_t queue, + void (^task)(void)); + +/** @class FIRAuthDispatchAfter + @brief A utility class used to facilitate scheduling tasks to be executed in the future. + */ +@interface FIRAuthDispatcher : NSObject + +/** @property dispatchAfterImplementation + @brief Allows custom implementation of dispatchAfterDelay:queue:callback:. + @remarks Set to nil to restore default implementation. + */ +@property(nonatomic, nullable, copy) FIRAuthDispatcherImplBlock dispatchAfterImplementation; + +/** @fn dispatchAfterDelay:queue:callback: + @brief Schedules task in the future after a specified delay. + + @param delay The delay in seconds after which the task will be scheduled to execute. + @param queue The dispatch queue on which the task will be submitted. + @param task The task (block) to be scheduled for future execution. + */ +- (void)dispatchAfterDelay:(NSTimeInterval)delay + queue:(dispatch_queue_t)queue + task:(void (^)(void))task; + +/** @fn sharedInstance + @brief Gets the shared instance of this class. + @returns The shared instance of this clss + */ ++ (instancetype)sharedInstance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.m new file mode 100644 index 0000000..e5e32c3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.m @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthDispatcher + +@synthesize dispatchAfterImplementation = _dispatchAfterImplementation; + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static FIRAuthDispatcher *sharedInstance; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + +- (void)dispatchAfterDelay:(NSTimeInterval)delay + queue:(dispatch_queue_t)queue + task:(void (^)(void))task { + if (_dispatchAfterImplementation) { + _dispatchAfterImplementation(delay, queue, task); + return; + } + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), queue, task); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h new file mode 100644 index 0000000..55bb1a7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h @@ -0,0 +1,31 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @fn FIRAuthGlobalWorkQueue + @brief Retrieves the global serial work queue for Firebase Auth. + @return The global serial dispatch queue. + @remarks To ensure thread safety, all auth code must be executed in either this global work + queue, or a serial queue that has its target queue set to this work queue. All public method + implementations that may involve contested code shall dispatch to this work queue as the + first thing they do. + */ +extern dispatch_queue_t FIRAuthGlobalWorkQueue(void); + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.m new file mode 100644 index 0000000..bfe263a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.m @@ -0,0 +1,30 @@ +/* + * 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 "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" + +NS_ASSUME_NONNULL_BEGIN + +dispatch_queue_t FIRAuthGlobalWorkQueue() { + static dispatch_once_t once; + static dispatch_queue_t queue; + dispatch_once(&once, ^{ + queue = dispatch_queue_create("com.google.firebase.auth.globalWorkQueue", NULL); + }); + return queue; +} + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthOperationType.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthOperationType.h new file mode 100644 index 0000000..62d6cd1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthOperationType.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 + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief Indicates the type of operation performed for RPCs that support the operation + parameter. + */ +typedef NS_ENUM(NSInteger, FIRAuthOperationType) { + /** Indicates that the operation type is uspecified. + */ + FIRAuthOperationTypeUnspecified = 0, + + /** Indicates that the operation type is sign in or sign up. + */ + FIRAuthOperationTypeSignUpOrSignIn = 1, + + /** Indicates that the operation type is reauthentication. + */ + FIRAuthOperationTypeReauth = 2, + + /** Indicates that the operation type is update. + */ + FIRAuthOperationTypeUpdate = 3, + + /** Indicates that the operation type is link. + */ + FIRAuthOperationTypeLink = 4, +}; + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h new file mode 100644 index 0000000..cdae046 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h @@ -0,0 +1,50 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthSerialTaskCompletionBlock + @brief The type of method a @c FIRAuthSerialTask must call when it is complete. + */ +typedef void (^FIRAuthSerialTaskCompletionBlock)(void); + +/** @typedef FIRAuthSerialTask + @brief Represents a unit of work submitted to a task queue. + @param complete The task MUST call the complete method when done. + */ +typedef void (^FIRAuthSerialTask)(FIRAuthSerialTaskCompletionBlock complete); + +/** @class FIRAuthSerialTaskQueue + @brief An easy to use serial task queue which supports a callback-based completion notification + system for easy asyncronous call chaining. + */ +@interface FIRAuthSerialTaskQueue : NSObject + +/** @fn enqueueTask: + @brief Enqueues a task for serial execution in the queue. + @remarks The task MUST call the complete method when done. This method is thread-safe. + The task block won't be executed concurrently with any other blocks in other task queues or + the global work queue as returned by @c FIRAuthGlobalWorkQueue , but an uncompleted task + (e.g. task block finished executation before complete method is called at a later time) + does not affect other task queues or the global work queue. + */ +- (void)enqueueTask:(FIRAuthSerialTask)task; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.m new file mode 100644 index 0000000..4bded78 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.m @@ -0,0 +1,56 @@ +/* + * 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 "FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthSerialTaskQueue { + /** @var _dispatchQueue + @brief The asyncronous dispatch queue into which tasks are enqueued and processed + serially. + */ + dispatch_queue_t _dispatchQueue; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _dispatchQueue = dispatch_queue_create("com.google.firebase.auth.serialTaskQueue", NULL); + dispatch_set_target_queue(_dispatchQueue, FIRAuthGlobalWorkQueue()); + } + return self; +} + +- (void)enqueueTask:(FIRAuthSerialTask)task { + // This dispatch queue will run tasks serially in FIFO order, as long as it's not suspended. + dispatch_async(self->_dispatchQueue, ^{ + // But as soon as a task is started, stop other tasks from running until the task calls it's + // completion handler, which allows the queue to resume processing of tasks. This allows the + // task to perform other asyncronous actions on other dispatch queues and "get back to us" when + // all of their sub-tasks are complete. + dispatch_suspend(self->_dispatchQueue); + task(^{ + dispatch_resume(self->_dispatchQueue); + }); + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSettings.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSettings.m new file mode 100644 index 0000000..8715897 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSettings.m @@ -0,0 +1,40 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthSettings + +- (instancetype)init { + self = [super init]; + if (self) { + _appVerificationDisabledForTesting = NO; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *__unused _Nullable)zone { + // Auth settings are mutable, so always return a copy. + FIRAuthSettings *newSettings = [[FIRAuthSettings alloc] init]; + newSettings.appVerificationDisabledForTesting = self.isAppVerificationDisabledForTesting; + return newSettings; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult.m new file mode 100644 index 0000000..fd857e3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult.m @@ -0,0 +1,166 @@ +/* + * 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 "FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kExpirationDateKey + @brief The key used to encode the expirationDate property for NSSecureCoding. + */ +static NSString *const kExpirationDateKey = @"expiratinDate"; + +/** @var kTokenKey + @brief The key used to encode the token property for NSSecureCoding. + */ +static NSString *const kTokenKey = @"token"; + +/** @var kAuthDateKey + @brief The key used to encode the authDate property for NSSecureCoding. + */ +static NSString *const kAuthDateKey = @"authDate"; + +/** @var kIssuedDateKey + @brief The key used to encode the issuedDate property for NSSecureCoding. + */ +static NSString *const kIssuedDateKey = @"issuedDate"; + +/** @var kSignInProviderKey + @brief The key used to encode the signInProvider property for NSSecureCoding. + */ +static NSString *const kSignInProviderKey = @"signInProvider"; + +/** @var kSignInSecondFactorKey + @brief The key used to encode the signInSecondFactor property for NSSecureCoding. + */ +static NSString *const kSignInSecondFactorKey = @"signInSecondFactor"; + +/** @var kClaimsKey + @brief The key used to encode the claims property for NSSecureCoding. + */ +static NSString *const kClaimsKey = @"claims"; + +@implementation FIRAuthTokenResult + +- (instancetype)initWithToken:(NSString *)token + expirationDate:(NSDate *)expirationDate + authDate:(NSDate *)authDate + issuedAtDate:(NSDate *)issuedAtDate + signInProvider:(NSString *)signInProvider + signInSecondFactor:(NSString *)signInSecondFactor + claims:(NSDictionary *)claims { + self = [super init]; + if (self) { + _token = token; + _expirationDate = expirationDate; + _authDate = authDate; + _issuedAtDate = issuedAtDate; + _signInProvider = signInProvider; + _signInSecondFactor = signInSecondFactor; + _claims = claims; + } + return self; +} + ++ (nullable FIRAuthTokenResult *)tokenResultWithToken:(NSString *)token { + NSArray *tokenStringArray = [token componentsSeparatedByString:@"."]; + + // The JWT should have three parts, though we only use the second in this method. + if (tokenStringArray.count != 3) { + return nil; + } + + // The token payload is always the second index of the array. + NSString *IDToken = tokenStringArray[1]; + + // Convert the base64URL encoded string to a base64 encoded string. + // Replace "_" with "/" + NSMutableString *tokenPayload = [[IDToken stringByReplacingOccurrencesOfString:@"_" + withString:@"/"] mutableCopy]; + + // Replace "-" with "+" + [tokenPayload replaceOccurrencesOfString:@"-" + withString:@"+" + options:kNilOptions + range:NSMakeRange(0, tokenPayload.length)]; + + // Pad the token payload with "=" signs if the payload's length is not a multiple of 4. + while ((tokenPayload.length % 4) != 0) { + [tokenPayload appendFormat:@"="]; + } + NSData *decodedTokenPayloadData = + [[NSData alloc] initWithBase64EncodedString:tokenPayload + options:NSDataBase64DecodingIgnoreUnknownCharacters]; + if (!decodedTokenPayloadData) { + return nil; + } + NSError *jsonError = nil; + NSJSONReadingOptions options = NSJSONReadingMutableContainers | NSJSONReadingAllowFragments; + NSDictionary *tokenPayloadDictionary = + [NSJSONSerialization JSONObjectWithData:decodedTokenPayloadData + options:options + error:&jsonError]; + if (jsonError != nil) { + return nil; + } + + if (!tokenPayloadDictionary) { + return nil; + } + + // These are dates since 00:00:00 January 1 1970, as described by the Terminology section in + // the JWT spec. https://tools.ietf.org/html/rfc7519 + NSDate *expirationDate = + [NSDate dateWithTimeIntervalSince1970:[tokenPayloadDictionary[@"exp"] doubleValue]]; + NSDate *authDate = + [NSDate dateWithTimeIntervalSince1970:[tokenPayloadDictionary[@"auth_time"] doubleValue]]; + NSDate *issuedAtDate = + [NSDate dateWithTimeIntervalSince1970:[tokenPayloadDictionary[@"iat"] doubleValue]]; + + NSDictionary *firebaseTokenPayloadDictionary = tokenPayloadDictionary[@"firebase"]; + NSString *signInProvider = firebaseTokenPayloadDictionary[@"sign_in_provider"]; + NSString *signInSecondFactor = firebaseTokenPayloadDictionary[@"sign_in_second_factor"]; + + FIRAuthTokenResult *tokenResult = + [[FIRAuthTokenResult alloc] initWithToken:token + expirationDate:expirationDate + authDate:authDate + issuedAtDate:issuedAtDate + signInProvider:signInProvider + signInSecondFactor:signInSecondFactor + claims:tokenPayloadDictionary]; + return tokenResult; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *token = [aDecoder decodeObjectOfClass:[NSDate class] forKey:kTokenKey]; + return [FIRAuthTokenResult tokenResultWithToken:token]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_token forKey:kTokenKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h new file mode 100644 index 0000000..6a5f7ad --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h @@ -0,0 +1,36 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @extension FIRAuthAPNSTokenResult + @brief An internal class used to expose internal methods of FIRAuthAPNSTokenResult. + */ +@interface FIRAuthTokenResult () + +/** @fn tokenResultWithToken: + @brief Parse a token string to a structured token. + @param token The token string to parse. + @return A structured token result. +*/ ++ (nullable FIRAuthTokenResult *)tokenResultWithToken:(NSString *)token; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h new file mode 100644 index 0000000..718f3eb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h @@ -0,0 +1,152 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" +#import "FirebaseCore/Sources/Private/FIRLogger.h" +#import "Interop/Auth/Public/FIRAuthInterop.h" + +@class FIRAuthRequestConfiguration; +@class FIRAuthURLPresenter; + +#if TARGET_OS_IOS +@class FIRAuthAPNSTokenManager; +@class FIRAuthAppCredentialManager; +@class FIRAuthNotificationManager; +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuth () + +/** @property requestConfiguration + @brief The configuration object comprising of paramters needed to make a request to Firebase + Auth's backend. + */ +@property(nonatomic, copy, readonly) FIRAuthRequestConfiguration *requestConfiguration; + +#if TARGET_OS_IOS + +/** @property tokenManager + @brief The manager for APNs tokens used by phone number auth. + */ +@property(nonatomic, strong, readonly) FIRAuthAPNSTokenManager *tokenManager; + +/** @property appCredentailManager + @brief The manager for app credentials used by phone number auth. + */ +@property(nonatomic, strong, readonly) FIRAuthAppCredentialManager *appCredentialManager; + +/** @property notificationManager + @brief The manager for remote notifications used by phone number auth. + */ +@property(nonatomic, strong, readonly) FIRAuthNotificationManager *notificationManager; + +#endif // TARGET_OS_IOS + +/** @property authURLPresenter + @brief An object that takes care of presenting URLs via the auth instance. + */ +@property(nonatomic, strong, readonly) FIRAuthURLPresenter *authURLPresenter; + +/** @fn initWithAPIKey:appName: + @brief Designated initializer. + @param APIKey The Google Developers Console API key for making requests from your app. + @param appName The name property of the previously created @c FIRApp instance. + */ +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey + appName:(NSString *)appName NS_DESIGNATED_INITIALIZER; + +/** @fn getUserID + @brief Gets the identifier of the current user, if any. + @return The identifier of the current user, or nil if there is no current user. + */ +- (nullable NSString *)getUserID; + +/** @fn updateKeychainWithUser:error: + @brief Updates the keychain for the given user. + @param user The user to be updated. + @param error The error caused the method to fail if the method returns NO. + @return Whether updating keychain has succeeded or not. + @remarks Called by @c FIRUser when user info or token changes occur. + */ +- (BOOL)updateKeychainWithUser:(FIRUser *)user error:(NSError *_Nullable *_Nullable)error; + +/** @fn internalSignInWithCredential:callback: + @brief Convenience method for @c internalSignInAndRetrieveDataWithCredential:callback: + This method doesn't return additional identity provider data. +*/ +- (void)internalSignInWithCredential:(FIRAuthCredential *)credential + callback:(FIRAuthResultCallback)callback; + +/** @fn internalSignInAndRetrieveDataWithCredential:callback: + @brief Asynchronously signs in Firebase with the given 3rd party credentials (e.g. a Facebook + login Access Token, a Google ID Token/Access Token pair, etc.) and returns additional + identity provider data. + @param credential The credential supplied by the IdP. + @param isReauthentication Indicates whether or not the current invocation originated from an + attempt to reauthenticate. + @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the auth global work queue in the future. + @remarks This is the internal counterpart of this method, which uses a callback that does not + update the current user. + */ +- (void)internalSignInAndRetrieveDataWithCredential:(FIRAuthCredential *)credential + isReauthentication:(BOOL)isReauthentication + callback:(nullable FIRAuthDataResultCallback)callback; + +/** @fn signOutByForceWithUserID:error: + @brief Signs out the current user. + @param userID The ID of the user to force sign out. + @param error An optional out parameter for error results. + @return @YES when the sign out request was successful. @NO otherwise. + */ +- (BOOL)signOutByForceWithUserID:(NSString *)userID error:(NSError *_Nullable *_Nullable)error; + +/** @fn completeSignInWithTokenService:callback: + @brief Completes a sign-in flow once we have access and refresh tokens for the user. + @param accessToken The STS access token. + @param accessTokenExpirationDate The approximate expiration date of the access token. + @param refreshToken The STS refresh token. + @param anonymous Whether or not the user is anonymous. + @param callback Called when the user has been signed in or when an error occurred. Invoked + asynchronously on the global auth work queue in the future. +*/ +- (void)completeSignInWithAccessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(nullable NSString *)refreshToken + anonymous:(BOOL)anonymous + callback:(FIRAuthResultCallback)callback; + +/** @fn signInFlowAuthResultCallbackByDecoratingCallback: + @brief Creates a FIRAuthResultCallback block which wraps another FIRAuthResultCallback; trying + to update the current user before forwarding it's invocations along to a subject block + @param callback Called when the user has been updated or when an error has occurred. Invoked + asynchronously on the main thread in the future. + @return Returns a block that updates the current user. + @remarks Typically invoked as part of the complete sign-in flow. For any other uses please + consider alternative ways of updating the current user. +*/ +- (FIRAuthDataResultCallback)signInFlowAuthDataResultCallbackByDecoratingCallback: + (nullable FIRAuthDataResultCallback)callback; + +@end + +/// Logger Service String + +extern FIRLoggerService kFIRLoggerAuth; + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailAuthProvider.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailAuthProvider.m new file mode 100644 index 0000000..731e79b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailAuthProvider.m @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIREmailAuthProvider + +- (instancetype)init { + @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer." + reason:@"This class is not meant to be initialized." + userInfo:nil]; +} + ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password { + return [[FIREmailPasswordAuthCredential alloc] initWithEmail:email password:password]; +} + ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email link:(NSString *)link { + return [[FIREmailPasswordAuthCredential alloc] initWithEmail:email link:link]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h new file mode 100644 index 0000000..df683e6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h @@ -0,0 +1,61 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIREmailPasswordAuthCredential + @brief Internal implementation of FIRAuthCredential for Email/Password credentials. + */ +@interface FIREmailPasswordAuthCredential : FIRAuthCredential + +/** @property email + @brief The user's email address. + */ +@property(nonatomic, readonly) NSString *email; + +/** @property password + @brief The user's password. + */ +@property(nonatomic, readonly) NSString *password; + +/** @property link + @brief The email sign-in link. + */ +@property(nonatomic, readonly) NSString *link; + +/** @fn initWithEmail:password: + @brief Designated initializer. + @param email The user's email address. + @param password The user's password. + */ +- (nullable instancetype)initWithEmail:(NSString *)email + password:(NSString *)password NS_DESIGNATED_INITIALIZER; + +/** @fn initWithEmail:link: + @brief Designated initializer. + @param email The user's email address. + @param link The email sign-in link. + */ +- (nullable instancetype)initWithEmail:(NSString *)email + link:(NSString *)link NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.m new file mode 100644 index 0000000..a427f5d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.m @@ -0,0 +1,92 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIREmailPasswordAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIREmailPasswordAuthCredential + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithEmail:(NSString *)email password:(NSString *)password { + self = [super initWithProvider:FIREmailAuthProviderID]; + if (self) { + _email = [email copy]; + _password = [password copy]; + } + return self; +} + +- (nullable instancetype)initWithEmail:(NSString *)email link:(NSString *)link { + self = [super initWithProvider:FIREmailAuthProviderID]; + if (self) { + _email = [email copy]; + _link = [link copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason: + @"Attempt to call prepareVerifyAssertionRequest: on a FIREmailPasswordAuthCredential."]; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *email = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"email"]; + NSString *password = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"password"]; + NSString *link = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"link"]; + if (email.length && password.length) { + self = [self initWithEmail:email password:password]; + } else if (email.length && link.length) { + self = [self initWithEmail:email link:link]; + } else { + self = nil; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.email forKey:@"email"]; + [aCoder encodeObject:self.password forKey:@"password"]; + [aCoder encodeObject:self.link forKey:@"link"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential.m new file mode 100644 index 0000000..2f633f7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential.m @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthCredential + +- (instancetype)init { + @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer." + reason:@"This class is an abstract base class. It's init method " + "should not be called directly." + userInfo:nil]; +} + +- (nullable instancetype)initWithProvider:(NSString *)provider { + self = [super init]; + if (self) { + _provider = [provider copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + @throw [NSException exceptionWithName:@"Attempt to call virtual method." + reason:@"This method must be overridden by a subclass." + userInfo:nil]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h new file mode 100644 index 0000000..41f3c90 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h" + +@class FIRVerifyAssertionRequest; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthCredential () + +/** @fn initWithProvider: + @brief Designated initializer. + @remarks This is the designated initializer for internal/friend subclasses. + @param provider The provider name. + */ +- (nullable instancetype)initWithProvider:(NSString *)provider NS_DESIGNATED_INITIALIZER; + +/** @fn prepareVerifyAssertionRequest: + @brief Called immediately before a request to the verifyAssertion endpoint is made. Implementers + should update the passed request instance with their credentials. + @param request The request to be updated with credentials. + */ +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthProvider.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthProvider.m new file mode 100644 index 0000000..6192ad6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthProvider.m @@ -0,0 +1,66 @@ +/* + * 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 + +#pragma mark - Provider ID constants + +// Declared 'extern' in FIRGoogleAuthProvider.h +NSString *const FIRGoogleAuthProviderID = @"google.com"; + +// Declared 'extern' in FIRFacebookAuthProvider.h +NSString *const FIRFacebookAuthProviderID = @"facebook.com"; + +// Declared 'extern' in FIREmailAuthProvider.h +NSString *const FIREmailAuthProviderID = @"password"; + +// Declared 'extern' in FIRTwitterAuthProvider.h +NSString *const FIRTwitterAuthProviderID = @"twitter.com"; + +// Declared 'extern' in FIRGitHubAuthProvider.h +NSString *const FIRGitHubAuthProviderID = @"github.com"; + +// Declared 'extern' in FIRPhoneAuthProvider.h +NSString *const FIRPhoneAuthProviderID = @"phone"; + +// Declared 'extern' in FIRGameCenterAuthProvider.h +NSString *const FIRGameCenterAuthProviderID = @"gc.apple.com"; + +#pragma mark - sign-in methods constants + +// Declared 'extern' in FIRGoogleAuthProvider.h +NSString *const FIRGoogleAuthSignInMethod = @"google.com"; + +// Declared 'extern' in FIREmailAuthProvider.h +NSString *const FIREmailPasswordAuthSignInMethod = @"password"; + +// Declared 'extern' in FIREmailAuthProvider.h +NSString *const FIREmailLinkAuthSignInMethod = @"emailLink"; + +// Declared 'extern' in FIRTwitterAuthProvider.h +NSString *const FIRTwitterAuthSignInMethod = @"twitter.com"; + +// Declared 'extern' in FIRFacebookAuthProvider.h +NSString *const FIRFacebookAuthSignInMethod = @"facebook.com"; + +// Declared 'extern' in FIRGitHubAuthProvider.h +NSString *const FIRGitHubAuthSignInMethod = @"github.com"; + +// Declared 'extern' in FIRPhoneAuthProvider.h +NSString *const FIRPhoneAuthSignInMethod = @"phone"; + +// Declared 'extern' in FIRGameCenterAuthProvider.h +NSString *const FIRGameCenterAuthSignInMethod = @"gc.apple.com"; diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h new file mode 100644 index 0000000..646ddba --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h @@ -0,0 +1,36 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRFacebookAuthCredential + @brief Internal implementation of FIRAuthCredential for the Facebook IdP. + */ +@interface FIRFacebookAuthCredential : FIRAuthCredential + +/** @fn initWithAccessToken: + @brief Designated initializer. + @param accessToken The Access Token obtained from Facebook. + */ +- (nullable instancetype)initWithAccessToken:(NSString *)accessToken NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.m new file mode 100644 index 0000000..c2ba6f1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.m @@ -0,0 +1,72 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFacebookAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIRFacebookAuthCredential { + NSString *_accessToken; +} + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithAccessToken:(NSString *)accessToken { + self = [super initWithProvider:FIRFacebookAuthProviderID]; + if (self) { + _accessToken = [accessToken copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + request.providerAccessToken = _accessToken; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"accessToken"]; + self = [self initWithAccessToken:accessToken]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_accessToken forKey:@"accessToken"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthProvider.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthProvider.m new file mode 100644 index 0000000..afdbb93 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthProvider.m @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +// FIRFacebookAuthProviderID is defined in FIRAuthProvider.m. + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRFacebookAuthProvider + +- (instancetype)init { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"This class is not meant to be initialized."]; + return nil; +} + ++ (FIRAuthCredential *)credentialWithAccessToken:(NSString *)accessToken { + return [[FIRFacebookAuthCredential alloc] initWithAccessToken:accessToken]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h new file mode 100644 index 0000000..70d4188 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h @@ -0,0 +1,80 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGameCenterAuthCredential + @brief Internal implementation of FIRAuthCredential for Game Center credentials. + */ +@interface FIRGameCenterAuthCredential : FIRAuthCredential + +/** @property playerID + @brief The ID of the Game Center local player. + */ +@property(nonatomic, readonly) NSString *playerID; + +/** @property publicKeyURL + @brief The URL for the public encryption key. + */ +@property(nonatomic, readonly) NSURL *publicKeyURL; + +/** @property signature + @brief The verification signature data generated. + */ +@property(nonatomic, readonly) NSData *signature; + +/** @property salt + @brief A random string used to compute the hash and keep it randomized. + */ +@property(nonatomic, readonly) NSData *salt; + +/** @property timestamp + @brief The date and time that the signature was created. + */ +@property(nonatomic, readonly) uint64_t timestamp; + +/** @property displayName + @brief The display name of the local Game Center player. + */ +@property(nonatomic, readonly) NSString *displayName; + +/** @fn initWithPlayerID:publicKeyURL:signature:salt:timestamp:displayName: + @brief Designated initializer. + @param publicKeyURL The URL for the public encryption key. + @param signature The verification signature generated. + @param salt A random string used to compute the hash and keep it randomized. + @param timestamp The date and time that the signature was created. + @param displayName The display name of the Game Center player. + */ +- (nullable instancetype)initWithPlayerID:(NSString *)playerID + publicKeyURL:(NSURL *)publicKeyURL + signature:(NSData *)signature + salt:(NSData *)salt + timestamp:(uint64_t)timestamp + displayName:(NSString *)displayName NS_DESIGNATED_INITIALIZER; + +/** @fn initWithProvider: + @brief Initializer with a provider name. + @param provider The provider name. + */ +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.m new file mode 100644 index 0000000..b6c2326 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.m @@ -0,0 +1,92 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGameCenterAuthCredential + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithPlayerID:(NSString *)playerID + publicKeyURL:(NSURL *)publicKeyURL + signature:(NSData *)signature + salt:(NSData *)salt + timestamp:(uint64_t)timestamp + displayName:(NSString *)displayName { + self = [super initWithProvider:FIRGameCenterAuthProviderID]; + if (self) { + _playerID = [playerID copy]; + _publicKeyURL = [publicKeyURL copy]; + _signature = [signature copy]; + _salt = [salt copy]; + _timestamp = timestamp; + _displayName = [displayName copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason: + @"Attempt to call prepareVerifyAssertionRequest: on a FIRGameCenterAuthCredential."]; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *playerID = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"playerID"]; + NSURL *publicKeyURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:@"publicKeyURL"]; + NSData *signature = [aDecoder decodeObjectOfClass:[NSData class] forKey:@"signature"]; + NSData *salt = [aDecoder decodeObjectOfClass:[NSData class] forKey:@"salt"]; + NSNumber *timestamp = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:@"timestamp"]; + NSString *displayName = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"displayName"]; + self = [self initWithPlayerID:playerID + publicKeyURL:publicKeyURL + signature:signature + salt:salt + timestamp:timestamp.unsignedLongLongValue + displayName:displayName]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.playerID forKey:@"playerID"]; + [aCoder encodeObject:self.publicKeyURL forKey:@"publicKeyURL"]; + [aCoder encodeObject:self.signature forKey:@"signature"]; + [aCoder encodeObject:self.salt forKey:@"salt"]; + [aCoder encodeObject:[NSNumber numberWithUnsignedLongLong:self.timestamp] forKey:@"timestamp"]; + [aCoder encodeObject:self.displayName forKey:@"displayName"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m new file mode 100644 index 0000000..cb53fe7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m @@ -0,0 +1,92 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h" +#import + +#import "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGameCenterAuthProvider + +- (instancetype)init { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"This class is not meant to be initialized."]; + return nil; +} + ++ (void)getCredentialWithCompletion:(FIRGameCenterCredentialCallback)completion { + /** + Linking GameKit.framework without using it on macOS results in App Store rejection. + Thus we don't link GameKit.framework to our SDK directly. `optionalLocalPlayer` is used for + checking whether the APP that consuming our SDK has linked GameKit.framework. If not, a + `GameKitNotLinkedError` will be raised. + **/ + GKLocalPlayer *_Nullable optionalLocalPlayer = [[NSClassFromString(@"GKLocalPlayer") alloc] init]; + + if (!optionalLocalPlayer) { + if (completion) { + completion(nil, [FIRAuthErrorUtils gameKitNotLinkedError]); + } + return; + } + + __weak GKLocalPlayer *localPlayer = [[optionalLocalPlayer class] localPlayer]; + if (!localPlayer.isAuthenticated) { + if (completion) { + completion(nil, [FIRAuthErrorUtils localPlayerNotAuthenticatedError]); + } + return; + } + + [localPlayer generateIdentityVerificationSignatureWithCompletionHandler:^( + NSURL *publicKeyURL, NSData *signature, NSData *salt, uint64_t timestamp, + NSError *error) { + if (error) { + if (completion) { + completion(nil, error); + } + } else { + if (completion) { + /** + @c `localPlayer.alias` is actually the displayname needed, instead of + `localPlayer.displayname`. For more information, check + https://developer.apple.com/documentation/gamekit/gkplayer + **/ + NSString *displayName = localPlayer.alias; +// iOS 13 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + FIRGameCenterAuthCredential *credential = + [[FIRGameCenterAuthCredential alloc] initWithPlayerID:localPlayer.playerID + publicKeyURL:publicKeyURL + signature:signature + salt:salt + timestamp:timestamp + displayName:displayName]; +#pragma clang diagnostic pop + completion(credential, nil); + } + } + }]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h new file mode 100644 index 0000000..f6765c4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h @@ -0,0 +1,41 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGitHubAuthCredential + @brief Internal implementation of FIRAuthCredential for GitHub credentials. + */ +@interface FIRGitHubAuthCredential : FIRAuthCredential + +/** @property token + @brief The GitHub OAuth access token. + */ +@property(nonatomic, readonly) NSString *token; + +/** @fn initWithToken: + @brief Designated initializer. + @param token The GitHub OAuth access token. + */ +- (nullable instancetype)initWithToken:(NSString *)token NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.m new file mode 100644 index 0000000..c752e20 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.m @@ -0,0 +1,70 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRGitHubAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIRGitHubAuthCredential + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithToken:(NSString *)token { + self = [super initWithProvider:FIRGitHubAuthProviderID]; + if (self) { + _token = [token copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + request.providerAccessToken = _token; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *token = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"token"]; + self = [self initWithToken:token]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.token forKey:@"token"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthProvider.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthProvider.m new file mode 100644 index 0000000..1f853d8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthProvider.m @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +// FIRGitHubAuthProviderID is defined in FIRAuthProvider.m. + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGitHubAuthProvider + +- (instancetype)init { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"This class is not meant to be initialized."]; + return nil; +} + ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token { + return [[FIRGitHubAuthCredential alloc] initWithToken:token]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h new file mode 100644 index 0000000..6d205c1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h @@ -0,0 +1,38 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGoogleAuthCredential + @brief Internal implementation of FIRAuthCredential for the Google IdP. + */ +@interface FIRGoogleAuthCredential : FIRAuthCredential + +/** @fn initWithIDToken:accessToken: + @brief Designated initializer. + @param IDToken The ID Token obtained from Google. + @param accessToken The Access Token obtained from Google. + */ +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + accessToken:(NSString *)accessToken NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.m new file mode 100644 index 0000000..149445d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.m @@ -0,0 +1,77 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRGoogleAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIRGoogleAuthCredential { + NSString *_IDToken; + NSString *_accessToken; +} + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken accessToken:(NSString *)accessToken { + self = [super initWithProvider:FIRGoogleAuthProviderID]; + if (self) { + _IDToken = [IDToken copy]; + _accessToken = [accessToken copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + request.providerIDToken = _IDToken; + request.providerAccessToken = _accessToken; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *IDToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"IDToken"]; + NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"accessToken"]; + self = [self initWithIDToken:IDToken accessToken:accessToken]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_IDToken forKey:@"IDToken"]; + [aCoder encodeObject:_accessToken forKey:@"accessToken"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthProvider.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthProvider.m new file mode 100644 index 0000000..51e2fc8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthProvider.m @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +// FIRGoogleAuthProviderID is defined in FIRAuthProvider.m. + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGoogleAuthProvider + +- (instancetype)init { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"This class is not meant to be initialized."]; + return nil; +} + ++ (FIRAuthCredential *)credentialWithIDToken:(NSString *)IDToken + accessToken:(NSString *)accessToken { + return [[FIRGoogleAuthCredential alloc] initWithIDToken:IDToken accessToken:accessToken]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m new file mode 100644 index 0000000..3c88a26 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m @@ -0,0 +1,130 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h" + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIROAuthCredential () + +@property(nonatomic, nullable) NSString *rawNonce; + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIROAuthCredential + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (instancetype)initWithProviderID:(NSString *)providerID + IDToken:(nullable NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce + accessToken:(nullable NSString *)accessToken + secret:(nullable NSString *)secret + pendingToken:(nullable NSString *)pendingToken { + self = [super initWithProvider:providerID]; + if (self) { + _IDToken = IDToken; + _rawNonce = rawNonce; + _accessToken = accessToken; + _pendingToken = pendingToken; + _secret = secret; + } + return self; +} + +- (instancetype)initWithProviderID:(NSString *)providerID + sessionID:(NSString *)sessionID + OAuthResponseURLString:(NSString *)OAuthResponseURLString { + self = [self initWithProviderID:providerID + IDToken:nil + rawNonce:nil + accessToken:nil + secret:nil + pendingToken:nil]; + if (self) { + _OAuthResponseURLString = OAuthResponseURLString; + _sessionID = sessionID; + } + return self; +} + +- (nullable instancetype)initWithVerifyAssertionResponse:(FIRVerifyAssertionResponse *)response { + if (response.oauthIDToken.length || response.oauthAccessToken.length || + response.oauthSecretToken.length) { + return [self initWithProviderID:response.providerID + IDToken:response.oauthIDToken + rawNonce:nil + accessToken:response.oauthAccessToken + secret:response.oauthSecretToken + pendingToken:response.pendingToken]; + } + return nil; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + request.providerIDToken = _IDToken; + request.providerRawNonce = _rawNonce; + request.providerAccessToken = _accessToken; + request.requestURI = _OAuthResponseURLString; + request.sessionID = _sessionID; + request.providerOAuthTokenSecret = _secret; + request.pendingToken = _pendingToken; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *IDToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"IDToken"]; + NSString *rawNonce = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"rawNonce"]; + NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"accessToken"]; + NSString *pendingToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"pendingToken"]; + NSString *secret = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"secret"]; + self = [self initWithProviderID:self.provider + IDToken:IDToken + rawNonce:rawNonce + accessToken:accessToken + secret:secret + pendingToken:pendingToken]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.IDToken forKey:@"IDToken"]; + [aCoder encodeObject:self.rawNonce forKey:@"rawNonce"]; + [aCoder encodeObject:self.accessToken forKey:@"accessToken"]; + [aCoder encodeObject:self.pendingToken forKey:@"pendingToken"]; + [aCoder encodeObject:self.secret forKey:@"secret"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h new file mode 100644 index 0000000..9f07601 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h @@ -0,0 +1,78 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h" + +@class FIRVerifyAssertionResponse; + +NS_ASSUME_NONNULL_BEGIN + +/** @extension FIROAuthCredential + @brief Internal implementation of FIRAuthCredential for generic credentials. + */ +@interface FIROAuthCredential () + +/** @property OAuthResponseURLString + @brief A string representation of the response URL corresponding to this OAuthCredential. + */ +@property(nonatomic, readonly, nullable) NSString *OAuthResponseURLString; + +/** @property sessionID + @brief The session ID used when completing the headful-lite flow. + */ +@property(nonatomic, readonly, nullable) NSString *sessionID; + +/** @property pendingToken + @brief The pending token used when completing the headful-lite flow. + */ +@property(nonatomic, readonly, nullable) NSString *pendingToken; + +/** @fn initWithProviderId:IDToken:accessToken:secret:pendingToken + @brief Designated initializer. + @param providerID The provider ID associated with the credential being created. + @param IDToken The ID Token associated with the credential being created. + @param rawNonce The raw nonce associated with the Auth credential being created. + @param accessToken The access token associated with the credential being created. + @param secret The secret associated with the credential being created. + @param pendingToken The pending token associated with the credential being created. + */ +- (instancetype)initWithProviderID:(NSString *)providerID + IDToken:(nullable NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce + accessToken:(nullable NSString *)accessToken + secret:(nullable NSString *)secret + pendingToken:(nullable NSString *)pendingToken NS_DESIGNATED_INITIALIZER; + +/** @fn initWithProviderId:sessionID:OAuthResponseURLString: + @brief Intitializer which takes a sessionID and an OAuthResponseURLString. + @param providerID The provider ID associated with the credential being created. + @param sessionID The session ID used when completing the headful-lite flow. + @param OAuthResponseURLString The error that occurred if any. + */ +- (instancetype)initWithProviderID:(NSString *)providerID + sessionID:(NSString *)sessionID + OAuthResponseURLString:(NSString *)OAuthResponseURLString; + +/** @fn initWithVerifyAssertionResponse + @brief Intitializer which takes an verifyAssertion response. + @param response The verifyAssertion Response to create the credential instance. + */ +- (nullable instancetype)initWithVerifyAssertionResponse:(FIRVerifyAssertionResponse *)response; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m new file mode 100644 index 0000000..53b376c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m @@ -0,0 +1,445 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h" +#include +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRHeadfulLiteURLCallBack + @brief The callback invoked at the end of the flow to fetch a headful-lite URL. + @param headfulLiteURL The headful lite URL. + @param error The error that occurred while fetching the headful-lite, if any. + */ +typedef void (^FIRHeadfulLiteURLCallBack)(NSURL *_Nullable headfulLiteURL, + NSError *_Nullable error); + +/** @var kHeadfulLiteURLStringFormat + @brief The format of the URL used to open the headful lite page during sign-in. + */ +NSString *const kHeadfulLiteURLStringFormat = @"https://%@/__/auth/handler?%@"; + +/** @var kHeadfulLiteEmulatorURLStringFormat + @brief The format of the URL used to open the emulated headful lite page during sign-in. + */ +NSString *const kHeadfulLiteEmulatorURLStringFormat = @"http://%@/emulator/auth/handler?%@"; + +/** @var kauthTypeSignInWithRedirect + @brief The auth type to be specified in the sign-in request with redirect request and response. + */ +static NSString *const kAuthTypeSignInWithRedirect = @"signInWithRedirect"; + +/** @var kCustomUrlSchemePrefix + @brief The prefix to append to the Firebase app ID custom callback scheme.. + */ +static NSString *const kCustomUrlSchemePrefix = @"app-"; + +@implementation FIROAuthProvider { + /** @var _auth + @brief The auth instance used for launching the URL presenter. + */ + FIRAuth *_auth; + + /** @var _callbackScheme + @brief The callback URL scheme used for headful-lite sign-in. + */ + NSString *_callbackScheme; + + /** @var _usingClientIDScheme + @brief True if the reverse client ID is registered as a custom URL scheme, and false + otherwise. + */ + BOOL _usingClientIDScheme; +} + ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + accessToken:(nullable NSString *)accessToken { + return [[FIROAuthCredential alloc] initWithProviderID:providerID + IDToken:IDToken + rawNonce:nil + accessToken:accessToken + secret:nil + pendingToken:nil]; +} + ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + accessToken:(NSString *)accessToken { + return [[FIROAuthCredential alloc] initWithProviderID:providerID + IDToken:nil + rawNonce:nil + accessToken:accessToken + secret:nil + pendingToken:nil]; +} + ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce + accessToken:(nullable NSString *)accessToken { + return [[FIROAuthCredential alloc] initWithProviderID:providerID + IDToken:IDToken + rawNonce:rawNonce + accessToken:accessToken + secret:nil + pendingToken:nil]; +} + ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce { + return [[FIROAuthCredential alloc] initWithProviderID:providerID + IDToken:IDToken + rawNonce:rawNonce + accessToken:nil + secret:nil + pendingToken:nil]; +} + ++ (instancetype)providerWithProviderID:(NSString *)providerID { + return [[self alloc] initWithProviderID:providerID auth:[FIRAuth auth]]; +} + ++ (instancetype)providerWithProviderID:(NSString *)providerID auth:(FIRAuth *)auth { + return [[self alloc] initWithProviderID:providerID auth:auth]; +} + +#if TARGET_OS_IOS +- (void)getCredentialWithUIDelegate:(nullable id)UIDelegate + completion:(nullable FIRAuthCredentialCallback)completion { + if (![FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:self->_callbackScheme]) { + [NSException raise:NSInternalInconsistencyException + format:@"Please register custom URL scheme '%@' in the app's Info.plist file.", + self->_callbackScheme]; + } + __weak __typeof__(self) weakSelf = self; + __weak FIRAuth *weakAuth = _auth; + __weak NSString *weakProviderID = _providerID; + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthCredentialCallback callbackOnMainThread = + ^(FIRAuthCredential *_Nullable credential, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(credential, error); + }); + } + }; + NSString *eventID = [FIRAuthWebUtils randomStringWithLength:10]; + NSString *sessionID = [FIRAuthWebUtils randomStringWithLength:10]; + __strong __typeof__(self) strongSelf = weakSelf; + [strongSelf + getHeadFulLiteURLWithEventID:eventID + sessionID:sessionID + completion:^(NSURL *_Nullable headfulLiteURL, NSError *_Nullable error) { + if (error) { + callbackOnMainThread(nil, error); + return; + } + FIRAuthURLCallbackMatcher callbackMatcher = + ^BOOL(NSURL *_Nullable callbackURL) { + return [FIRAuthWebUtils + isExpectedCallbackURL:callbackURL + eventID:eventID + authType:kAuthTypeSignInWithRedirect + callbackScheme:strongSelf->_callbackScheme]; + }; + __strong FIRAuth *strongAuth = weakAuth; + [strongAuth.authURLPresenter + presentURL:headfulLiteURL + UIDelegate:UIDelegate + callbackMatcher:callbackMatcher + completion:^(NSURL *_Nullable callbackURL, + NSError *_Nullable error) { + if (error) { + callbackOnMainThread(nil, error); + return; + } + NSString *OAuthResponseURLString = + [strongSelf OAuthResponseForURL:callbackURL + error:&error]; + if (error) { + callbackOnMainThread(nil, error); + return; + } + __strong NSString *strongProviderID = weakProviderID; + FIROAuthCredential *credential = [[FIROAuthCredential alloc] + initWithProviderID:strongProviderID + sessionID:sessionID + OAuthResponseURLString:OAuthResponseURLString]; + callbackOnMainThread(credential, nil); + }]; + }]; + }); +} +#endif // TARGET_OS_IOS + +#pragma mark - Internal Methods + +/** @fn initWithProviderID:auth: + @brief returns an instance of @c FIROAuthProvider associated with the provided auth instance. + @param auth The Auth instance to be associated with the OAuthProvider instance. + @return An Instance of @c FIROAuthProvider. + */ +- (nullable instancetype)initWithProviderID:(NSString *)providerID auth:(FIRAuth *)auth { + if (!auth.requestConfiguration.emulatorHostAndPort) { + NSAssert(![providerID isEqual:FIRFacebookAuthProviderID], + @"Sign in with Facebook is not supported via generic IDP; the Facebook TOS " + "dictate that you must use the Facebook iOS SDK for Facebook login."); + NSAssert(![providerID isEqual:@"apple.com"], + @"Sign in with Apple is not supported via generic IDP; You must use the Apple iOS SDK" + " for Sign in with Apple."); + } + self = [super init]; + if (self) { + _auth = auth; + _providerID = providerID; + if (_auth.app.options.clientID) { + NSString *reverseClientIDScheme = + [[[_auth.app.options.clientID componentsSeparatedByString:@"."] + reverseObjectEnumerator].allObjects componentsJoinedByString:@"."]; + if ([FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:reverseClientIDScheme]) { + _callbackScheme = reverseClientIDScheme; + _usingClientIDScheme = YES; + } + } + + if (!_usingClientIDScheme) { + _callbackScheme = [kCustomUrlSchemePrefix + stringByAppendingString:[_auth.app.options.googleAppID + stringByReplacingOccurrencesOfString:@":" + withString:@"-"]]; + } + } + return self; +} + +/** @fn OAuthResponseForURL:error: + @brief Parses the redirected URL and returns a string representation of the OAuth response URL. + @param URL The url to be parsed for an OAuth response URL. + @param error The error that occurred if any. + @return The OAuth response if successful. + */ +- (nullable NSString *)OAuthResponseForURL:(NSURL *)URL error:(NSError *_Nullable *_Nullable)error { + NSDictionary *URLQueryItems = + [FIRAuthWebUtils dictionaryWithHttpArgumentsString:URL.query]; + NSURL *deepLinkURL = [NSURL URLWithString:URLQueryItems[@"deep_link_id"]]; + URLQueryItems = [FIRAuthWebUtils dictionaryWithHttpArgumentsString:deepLinkURL.query]; + NSString *queryItemLink = URLQueryItems[@"link"]; + if (queryItemLink) { + return queryItemLink; + } + if (!error) { + return nil; + } + NSData *errorData = [URLQueryItems[@"firebaseError"] dataUsingEncoding:NSUTF8StringEncoding]; + NSError *jsonError; + NSDictionary *errorDict = [NSJSONSerialization JSONObjectWithData:errorData + options:0 + error:&jsonError]; + if (jsonError) { + *error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:jsonError]; + return nil; + } + *error = [FIRAuthErrorUtils URLResponseErrorWithCode:errorDict[@"code"] + message:errorDict[@"message"]]; + if (!*error) { + NSString *reason; + if (errorDict[@"code"] && errorDict[@"message"]) { + reason = [NSString stringWithFormat:@"[%@] - %@", errorDict[@"code"], errorDict[@"message"]]; + } + *error = [FIRAuthErrorUtils webSignInUserInteractionFailureWithReason:reason]; + } + return nil; +} + +/** @fn getHeadFulLiteURLWithEventID:completion: + @brief Constructs a URL used for opening a headful-lite flow using a given event + ID and session ID. + @param eventID The event ID used for this purpose. + @param sessionID The session ID used when completing the headful lite flow. + @param completion The callback invoked after the URL has been constructed or an error + has been encountered. + */ +- (void)getHeadFulLiteURLWithEventID:(NSString *)eventID + sessionID:(NSString *)sessionID + completion:(FIRHeadfulLiteURLCallBack)completion { + __weak __typeof__(self) weakSelf = self; + [FIRAuthWebUtils + fetchAuthDomainWithRequestConfiguration:_auth.requestConfiguration + completion:^(NSString *_Nullable authDomain, + NSError *_Nullable error) { + if (error) { + if (completion) { + completion(nil, error); + } + return; + } + __strong __typeof__(self) strongSelf = weakSelf; + NSString *bundleID = [NSBundle mainBundle].bundleIdentifier; + NSString *clientID = strongSelf->_auth.app.options.clientID; + NSString *appID = strongSelf->_auth.app.options.googleAppID; + NSString *apiKey = + strongSelf->_auth.requestConfiguration.APIKey; + NSMutableDictionary *urlArguments = [@{ + @"apiKey" : apiKey, + @"authType" : kAuthTypeSignInWithRedirect, + @"ibi" : bundleID ?: @"", + @"sessionId" : [strongSelf hashforString:sessionID], + @"v" : [FIRAuthBackend authUserAgent], + @"eventId" : eventID, + @"providerId" : strongSelf->_providerID, + } mutableCopy]; + if (strongSelf->_usingClientIDScheme) { + urlArguments[@"clientId"] = clientID; + } else { + urlArguments[@"appId"] = appID; + } + if (strongSelf.scopes.count) { + urlArguments[@"scopes"] = + [strongSelf.scopes componentsJoinedByString:@","]; + } + if (strongSelf.customParameters.count) { + NSString *customParameters = + [strongSelf customParametersStringWithError:&error]; + if (error) { + completion(nil, error); + return; + } + if (customParameters) { + urlArguments[@"customParameters"] = customParameters; + } + } + if (strongSelf->_auth.requestConfiguration.languageCode) { + urlArguments[@"hl"] = + strongSelf->_auth.requestConfiguration.languageCode; + } + NSString *argumentsString = [strongSelf + httpArgumentsStringForArgsDictionary:urlArguments]; + NSString *URLString; + if (strongSelf->_auth.requestConfiguration + .emulatorHostAndPort) { + URLString = [NSString + stringWithFormat:kHeadfulLiteEmulatorURLStringFormat, + authDomain, argumentsString]; + } else { + URLString = + [NSString stringWithFormat:kHeadfulLiteURLStringFormat, + authDomain, argumentsString]; + } + if (completion) { + NSCharacterSet *set = + [NSCharacterSet URLFragmentAllowedCharacterSet]; + completion( + [NSURL + URLWithString: + [URLString + stringByAddingPercentEncodingWithAllowedCharacters: + set]], + nil); + } + }]; +} + +/** @fn customParametersString + @brief Returns a JSON string representation of the custom parameters dictionary corresponding + to the OAuthProvider. + @return The JSON string representation of the custom parameters dictionary corresponding + to the OAuthProvider. + */ +- (nullable NSString *)customParametersStringWithError:(NSError *_Nullable *_Nullable)error { + if (!_customParameters.count) { + return nil; + } + + if (!error) { + return nil; + } + NSError *jsonError; + NSData *customParametersJSONData = [NSJSONSerialization dataWithJSONObject:_customParameters + options:0 + error:&jsonError]; + if (jsonError) { + *error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:jsonError]; + return nil; + } + + NSString *customParamsRawJSON = [[NSString alloc] initWithData:customParametersJSONData + encoding:NSUTF8StringEncoding]; + return customParamsRawJSON; +} + +/** @fn hashforString: + @brief Returns the SHA256 hash representation of a given string object. + @param string The string for which a SHA256 hash is desired. + @return An hexadecimal string representation of the SHA256 hash. + */ +- (NSString *)hashforString:(NSString *)string { + NSData *sessionIDData = [string dataUsingEncoding:NSUTF8StringEncoding]; + NSMutableData *hashOutputData = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH]; + if (CC_SHA256(sessionIDData.bytes, (CC_LONG)[sessionIDData length], + hashOutputData.mutableBytes)) { + } + return [self hexStringFromData:hashOutputData]; + ; +} + +/** @fn hexStringFromData: + @brief Returns the hexadecimal string representation of an NSData object. + @param data The NSData object for which a hexadecical string is desired. + @return The hexadecimal string representation of the supplied NSData object. + */ +- (NSString *)hexStringFromData:(NSData *)data { + const unsigned char *dataBuffer = (const unsigned char *)[data bytes]; + NSMutableString *string = [[NSMutableString alloc] init]; + for (unsigned int i = 0; i < data.length; i++) { + [string appendFormat:@"%02lx", (unsigned long)dataBuffer[i]]; + } + return [string copy]; +} + +- (NSString *)httpArgumentsStringForArgsDictionary:(NSDictionary *)argsDictionary { + NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:argsDictionary.count]; + NSString *key; + for (key in argsDictionary) { + NSString *description = [argsDictionary[key] description]; + [arguments + addObject:[NSString + stringWithFormat:@"%@=%@", + [FIRAuthWebUtils stringByUnescapingFromURLArgument:key], + [FIRAuthWebUtils + stringByUnescapingFromURLArgument:description]]]; + } + return [arguments componentsJoinedByString:@"&"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential.m new file mode 100644 index 0000000..4c197bd --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential.m @@ -0,0 +1,107 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h" + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRPhoneAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIRPhoneAuthCredential + +- (instancetype)initWithTemporaryProof:(NSString *)temporaryProof + phoneNumber:(NSString *)phoneNumber + providerID:(NSString *)providerID { + self = [super initWithProvider:providerID]; + if (self) { + _temporaryProof = [temporaryProof copy]; + _phoneNumber = [phoneNumber copy]; + } + return self; +} + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (instancetype)initWithProviderID:(NSString *)providerID + verificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode { + self = [super initWithProvider:providerID]; + if (self) { + _verificationID = [verificationID copy]; + _verificationCode = [verificationCode copy]; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *verificationID = [aDecoder decodeObjectOfClass:[NSString class] + forKey:@"verificationID"]; + NSString *verificationCode = [aDecoder decodeObjectOfClass:[NSString class] + forKey:@"verificationCode"]; + NSString *temporaryProof = [aDecoder decodeObjectOfClass:[NSString class] + forKey:@"temporaryProof"]; + NSString *phoneNumber = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"phoneNumber"]; + if (temporaryProof.length && phoneNumber.length) { + self = [self initWithTemporaryProof:temporaryProof + phoneNumber:phoneNumber + providerID:self.provider]; + } else if (verificationID.length && verificationCode.length) { + self = [self initWithProviderID:self.provider + verificationID:verificationID + verificationCode:verificationCode]; + } else { + self = nil; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.verificationID forKey:@"verificationID"]; + [aCoder encodeObject:self.verificationCode forKey:@"verificationCode"]; + [aCoder encodeObject:self.temporaryProof forKey:@"temporaryProof"]; + [aCoder encodeObject:self.phoneNumber forKey:@"phoneNumber"]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h new file mode 100644 index 0000000..78c1b74 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h @@ -0,0 +1,73 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @extension FIRPhoneAuthCredential + @brief Internal implementation of FIRAuthCredential for Phone Auth credentials. + */ +@interface FIRPhoneAuthCredential () + +/** @var verificationID + @brief The verification ID obtained from invoking @c verifyPhoneNumber:completion: + */ +@property(nonatomic, readonly, nonnull) NSString *verificationID; + +/** @var verificationCode + @brief The verification code provided by the user. + */ +@property(nonatomic, readonly, nonnull) NSString *verificationCode; + +/** @var temporaryProof + @brief The a temporary proof code perftaining to this credential, returned from the backend. + */ +@property(nonatomic, readonly, nonnull) NSString *temporaryProof; + +/** @var phoneNumber + @brief The a phone number pertaining to this credential, returned from the backend. + */ +@property(nonatomic, readonly, nonnull) NSString *phoneNumber; + +/** @var initWithTemporaryProof:phoneNumber: + @brief Designated Initializer. + @param providerID The provider ID associated with the phone auth credential being created. + */ +- (instancetype)initWithTemporaryProof:(NSString *)temporaryProof + phoneNumber:(NSString *)phoneNumber + providerID:(NSString *)providerID NS_DESIGNATED_INITIALIZER; + +/** @var initWithProviderID:verificationID:verificationCode: + @brief Designated Initializer. + @param providerID The provider ID associated with the phone auth credential being created. + @param verificationID The verification ID associated witht Phone Auth credential being created. + @param verificationCode The verification code associated witht Phone Auth credential being + created. + */ +- (instancetype)initWithProviderID:(NSString *)providerID + verificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthProvider.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthProvider.m new file mode 100644 index 0000000..401a83d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthProvider.m @@ -0,0 +1,754 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRReCAPTCHAURLCallBack + @brief The callback invoked at the end of the flow to fetch a reCAPTCHA URL. + @param reCAPTCHAURL The reCAPTCHA URL. + @param error The error that occurred while fetching the reCAPTCHAURL, if any. + */ +typedef void (^FIRReCAPTCHAURLCallBack)(NSURL *_Nullable reCAPTCHAURL, NSError *_Nullable error); + +/** @typedef FIRVerifyClientCallback + @brief The callback invoked at the end of a client verification flow. + @param appCredential credential that proves the identity of the app during a phone + authentication flow. + @param error The error that occurred while verifying the app, if any. + */ +typedef void (^FIRVerifyClientCallback)(FIRAuthAppCredential *_Nullable appCredential, + NSString *_Nullable reCAPTCHAToken, + NSError *_Nullable error); + +/** @typedef FIRFetchAuthDomainCallback + @brief The callback invoked at the end of the flow to fetch the Auth domain. + @param authDomain The Auth domain. + @param error The error that occurred while fetching the auth domain, if any. + */ +typedef void (^FIRFetchAuthDomainCallback)(NSString *_Nullable authDomain, + NSError *_Nullable error); + +/** @var kauthTypeVerifyApp + @brief The auth type to be specified in the app verification request. + */ +static NSString *const kAuthTypeVerifyApp = @"verifyApp"; + +/** @var kCustomUrlSchemePrefix + @brief The prefix to append to the Firebase app ID custom callback scheme.. + */ +static NSString *const kCustomUrlSchemePrefix = @"app-"; + +/** @var kReCAPTCHAURLStringFormat + @brief The format of the URL used to open the reCAPTCHA page during app verification. + */ +NSString *const kReCAPTCHAURLStringFormat = @"https://%@/__/auth/handler?"; + +extern NSString *const FIRPhoneMultiFactorID; + +@implementation FIRPhoneAuthProvider { + /** @var _auth + @brief The auth instance used for verifying the phone number. + */ + FIRAuth *_auth; + + /** @var _callbackScheme + @brief The callback URL scheme used for reCAPTCHA fallback. + */ + NSString *_callbackScheme; + + /** @var _usingClientIDScheme + @brief True if the reverse client ID is registered as a custom URL scheme, and false + otherwise. + */ + BOOL _usingClientIDScheme; +} + +/** @fn initWithAuth: + @brief returns an instance of @c FIRPhoneAuthProvider associated with the provided auth + instance. + @return An Instance of @c FIRPhoneAuthProvider. + */ +- (nullable instancetype)initWithAuth:(FIRAuth *)auth { + self = [super init]; + if (self) { + _auth = auth; + if (_auth.app.options.clientID) { + NSString *reverseClientIDScheme = + [[[_auth.app.options.clientID componentsSeparatedByString:@"."] + reverseObjectEnumerator].allObjects componentsJoinedByString:@"."]; + if ([FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:reverseClientIDScheme]) { + _callbackScheme = reverseClientIDScheme; + _usingClientIDScheme = YES; + } + } + if (!_usingClientIDScheme) { + _callbackScheme = [kCustomUrlSchemePrefix + stringByAppendingString:[_auth.app.options.googleAppID + stringByReplacingOccurrencesOfString:@":" + withString:@"-"]]; + } + } + return self; +} + +- (void)verifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRVerificationResultCallback)completion { + if (![FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:_callbackScheme]) { + [NSException raise:NSInternalInconsistencyException + format:@"Please register custom URL scheme '%@' in the app's Info.plist file.", + _callbackScheme]; + } + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRVerificationResultCallback callBackOnMainThread = + ^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(verificationID, error); + }); + } + }; + [self + internalVerifyPhoneNumber:phoneNumber + UIDelegate:UIDelegate + completion:^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (!error) { + callBackOnMainThread(verificationID, nil); + return; + } else { + callBackOnMainThread(nil, error); + return; + } + }]; + }); +} + +- (void)verifyPhoneNumberWithMultiFactorInfo:(FIRPhoneMultiFactorInfo *)phoneMultiFactorInfo + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + completion:(nullable FIRVerificationResultCallback)completion { + session.multiFactorInfo = phoneMultiFactorInfo; + [self verifyPhoneNumber:phoneMultiFactorInfo.phoneNumber + UIDelegate:UIDelegate + multiFactorSession:session + completion:completion]; +} + +- (void)verifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + completion:(nullable FIRVerificationResultCallback)completion { + if (!session) { + [self verifyPhoneNumber:phoneNumber UIDelegate:UIDelegate completion:completion]; + return; + } + + if (![FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:_callbackScheme]) { + [NSException raise:NSInternalInconsistencyException + format:@"Please register custom URL scheme '%@' in the app's Info.plist file.", + _callbackScheme]; + } + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRVerificationResultCallback callBackOnMainThread = + ^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(verificationID, error); + }); + } + }; + [self + internalVerifyPhoneNumber:phoneNumber + UIDelegate:UIDelegate + multiFactorSession:session + completion:^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (!error) { + callBackOnMainThread(verificationID, nil); + return; + } else { + callBackOnMainThread(nil, error); + return; + } + }]; + }); +} + +- (FIRPhoneAuthCredential *)credentialWithVerificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode { + return [[FIRPhoneAuthCredential alloc] initWithProviderID:FIRPhoneAuthProviderID + verificationID:verificationID + verificationCode:verificationCode]; +} + ++ (instancetype)provider { + return [[self alloc] initWithAuth:[FIRAuth auth]]; +} + ++ (instancetype)providerWithAuth:(FIRAuth *)auth { + return [[self alloc] initWithAuth:auth]; +} + +#pragma mark - Internal Methods + +/** @fn reCAPTCHATokenForURL:error: + @brief Parses the reCAPTCHA URL and returns the reCAPTCHA token. + @param URL The url to be parsed for a reCAPTCHA token. + @param error The error that occurred if any. + @return The reCAPTCHA token if successful. + */ +- (nullable NSString *)reCAPTCHATokenForURL:(NSURL *)URL error:(NSError **_Nonnull)error { + NSURLComponents *actualURLComponents = [NSURLComponents componentsWithURL:URL + resolvingAgainstBaseURL:NO]; + NSArray *queryItems = [actualURLComponents queryItems]; + NSString *deepLinkURL = [FIRAuthWebUtils queryItemValue:@"deep_link_id" from:queryItems]; + NSData *errorData; + if (deepLinkURL) { + actualURLComponents = [NSURLComponents componentsWithString:deepLinkURL]; + queryItems = [actualURLComponents queryItems]; + NSString *recaptchaToken = [FIRAuthWebUtils queryItemValue:@"recaptchaToken" from:queryItems]; + if (recaptchaToken) { + return recaptchaToken; + } + NSString *firebaseError = [FIRAuthWebUtils queryItemValue:@"firebaseError" from:queryItems]; + errorData = [firebaseError dataUsingEncoding:NSUTF8StringEncoding]; + } else { + errorData = nil; + } + if (error != NULL && errorData != nil) { + NSError *jsonError; + NSDictionary *errorDict = [NSJSONSerialization JSONObjectWithData:errorData + options:0 + error:&jsonError]; + if (jsonError) { + *error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:jsonError]; + return nil; + } + *error = [FIRAuthErrorUtils URLResponseErrorWithCode:errorDict[@"code"] + message:errorDict[@"message"]]; + if (!*error) { + NSString *reason; + if (errorDict[@"code"] && errorDict[@"message"]) { + reason = + [NSString stringWithFormat:@"[%@] - %@", errorDict[@"code"], errorDict[@"message"]]; + } else { + reason = [NSString stringWithFormat:@"An unknown error occurred with the following " + "response: %@", + deepLinkURL]; + } + *error = [FIRAuthErrorUtils appVerificationUserInteractionFailureWithReason:reason]; + } + } + return nil; +} + +/** @fn internalVerifyPhoneNumber:completion: + @brief Starts the phone number authentication flow by sending a verifcation code to the + specified phone number. + @param phoneNumber The phone number to be verified. + @param completion The callback to be invoked when the verification flow is finished. + */ + +- (void)internalVerifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRVerificationResultCallback)completion { + if (!phoneNumber.length) { + completion(nil, [FIRAuthErrorUtils missingPhoneNumberErrorWithMessage:nil]); + return; + } + [_auth.notificationManager + checkNotificationForwardingWithCallback:^(BOOL isNotificationBeingForwarded) { + if (!isNotificationBeingForwarded) { + completion(nil, [FIRAuthErrorUtils notificationNotForwardedError]); + return; + } + FIRVerificationResultCallback callback = + ^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (completion) { + completion(verificationID, error); + } + }; + [self verifyClientAndSendVerificationCodeToPhoneNumber:phoneNumber + retryOnInvalidAppCredential:YES + UIDelegate:UIDelegate + callback:callback]; + }]; +} + +- (void)internalVerifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + completion:(nullable FIRVerificationResultCallback)completion { + if (!phoneNumber.length) { + if (completion) { + completion(nil, [FIRAuthErrorUtils missingPhoneNumberErrorWithMessage:nil]); + } + return; + } + [_auth.notificationManager + checkNotificationForwardingWithCallback:^(BOOL isNotificationBeingForwarded) { + if (!isNotificationBeingForwarded) { + if (completion) { + completion(nil, [FIRAuthErrorUtils notificationNotForwardedError]); + } + return; + } + FIRVerificationResultCallback callback = + ^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (completion) { + completion(verificationID, error); + } + }; + [self verifyClientAndSendVerificationCodeToPhoneNumber:phoneNumber + retryOnInvalidAppCredential:YES + UIDelegate:UIDelegate + multiFactorSession:session + callback:callback]; + }]; +} + +/** @fn verifyClientAndSendVerificationCodeToPhoneNumber:retryOnInvalidAppCredential:callback: + @brief Starts the flow to verify the client via silent push notification. + @param retryOnInvalidAppCredential Whether of not the flow should be retried if an + FIRAuthErrorCodeInvalidAppCredential error is returned from the backend. + @param phoneNumber The phone number to be verified. + @param callback The callback to be invoked on the global work queue when the flow is + finished. + */ +- (void)verifyClientAndSendVerificationCodeToPhoneNumber:(NSString *)phoneNumber + retryOnInvalidAppCredential:(BOOL)retryOnInvalidAppCredential + UIDelegate:(nullable id)UIDelegate + callback:(FIRVerificationResultCallback)callback { + if (_auth.settings.isAppVerificationDisabledForTesting) { + FIRSendVerificationCodeRequest *request = + [[FIRSendVerificationCodeRequest alloc] initWithPhoneNumber:phoneNumber + appCredential:nil + reCAPTCHAToken:nil + requestConfiguration:_auth.requestConfiguration]; + [FIRAuthBackend sendVerificationCode:request + callback:^(FIRSendVerificationCodeResponse *_Nullable response, + NSError *_Nullable error) { + callback(response.verificationID, error); + }]; + return; + } + [self + verifyClientWithUIDelegate:UIDelegate + completion:^(FIRAuthAppCredential *_Nullable appCredential, + NSString *_Nullable reCAPTCHAToken, NSError *_Nullable error) { + if (error) { + callback(nil, error); + return; + } + FIRSendVerificationCodeRequest *_Nullable request; + if (appCredential) { + request = [[FIRSendVerificationCodeRequest alloc] + initWithPhoneNumber:phoneNumber + appCredential:appCredential + reCAPTCHAToken:nil + requestConfiguration:self->_auth.requestConfiguration]; + } else if (reCAPTCHAToken) { + request = [[FIRSendVerificationCodeRequest alloc] + initWithPhoneNumber:phoneNumber + appCredential:nil + reCAPTCHAToken:reCAPTCHAToken + requestConfiguration:self->_auth.requestConfiguration]; + } + if (request) { + [FIRAuthBackend + sendVerificationCode:request + callback:^( + FIRSendVerificationCodeResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (error.code == + FIRAuthErrorCodeInvalidAppCredential) { + if (retryOnInvalidAppCredential) { + [self->_auth + .appCredentialManager clearCredential]; + [self + verifyClientAndSendVerificationCodeToPhoneNumber: + phoneNumber + retryOnInvalidAppCredential: + NO + UIDelegate: + UIDelegate + callback: + callback]; + return; + } + callback( + nil, + [FIRAuthErrorUtils + unexpectedResponseWithDeserializedResponse: + nil + underlyingError: + error]); + return; + } + callback(nil, error); + return; + } + callback(response.verificationID, nil); + }]; + } + }]; +} + +- (void)verifyClientAndSendVerificationCodeToPhoneNumber:(NSString *)phoneNumber + retryOnInvalidAppCredential:(BOOL)retryOnInvalidAppCredential + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + callback:(FIRVerificationResultCallback)callback { + if (_auth.settings.isAppVerificationDisabledForTesting) { + FIRSendVerificationCodeRequest *request = + [[FIRSendVerificationCodeRequest alloc] initWithPhoneNumber:phoneNumber + appCredential:nil + reCAPTCHAToken:nil + requestConfiguration:_auth.requestConfiguration]; + [FIRAuthBackend sendVerificationCode:request + callback:^(FIRSendVerificationCodeResponse *_Nullable response, + NSError *_Nullable error) { + callback(response.verificationID, error); + }]; + return; + } + + [self + verifyClientWithUIDelegate:UIDelegate + completion:^(FIRAuthAppCredential *_Nullable appCredential, + NSString *_Nullable reCAPTCHAToken, NSError *_Nullable error) { + if (error) { + if (callback) { + callback(nil, error); + } + return; + } + + NSString *IDToken = session.IDToken; + FIRAuthProtoStartMFAPhoneRequestInfo *startMFARequestInfo = + [[FIRAuthProtoStartMFAPhoneRequestInfo alloc] + initWithPhoneNumber:phoneNumber + appCredential:appCredential + reCAPTCHAToken:reCAPTCHAToken]; + if (session.IDToken) { + FIRStartMFAEnrollmentRequest *request = + [[FIRStartMFAEnrollmentRequest alloc] + initWithIDToken:IDToken + enrollmentInfo:startMFARequestInfo + requestConfiguration:self->_auth.requestConfiguration]; + [FIRAuthBackend + startMultiFactorEnrollment:request + callback:^(FIRStartMFAEnrollmentResponse + *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (error.code == + FIRAuthErrorCodeInvalidAppCredential) { + if (retryOnInvalidAppCredential) { + [self->_auth.appCredentialManager + clearCredential]; + [self + verifyClientAndSendVerificationCodeToPhoneNumber: + phoneNumber + retryOnInvalidAppCredential: + NO + UIDelegate: + UIDelegate + multiFactorSession: + session + callback: + callback]; + return; + } + if (callback) { + callback( + nil, + [FIRAuthErrorUtils + unexpectedResponseWithDeserializedResponse: + nil + underlyingError: + error]); + } + return; + } else { + if (callback) { + callback(nil, error); + } + } + } else { + if (callback) { + callback( + response.enrollmentResponse.sessionInfo, + nil); + } + } + }]; + } else { + FIRStartMFASignInRequest *request = [[FIRStartMFASignInRequest alloc] + initWithMFAPendingCredential:session.MFAPendingCredential + MFAEnrollmentID:session.multiFactorInfo.UID + signInInfo:startMFARequestInfo + requestConfiguration:self->_auth.requestConfiguration]; + [FIRAuthBackend + startMultiFactorSignIn:request + callback:^( + FIRStartMFASignInResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (error.code == + FIRAuthErrorCodeInvalidAppCredential) { + if (retryOnInvalidAppCredential) { + [self->_auth + .appCredentialManager clearCredential]; + [self + verifyClientAndSendVerificationCodeToPhoneNumber: + phoneNumber + retryOnInvalidAppCredential: + NO + UIDelegate: + UIDelegate + multiFactorSession: + session + callback: + callback]; + return; + } + if (callback) { + callback( + nil, + [FIRAuthErrorUtils + unexpectedResponseWithDeserializedResponse: + nil + underlyingError: + error]); + } + return; + } else { + if (callback) { + callback(nil, error); + } + } + } else { + if (callback) { + callback(response.responseInfo.sessionInfo, nil); + } + } + }]; + } + }]; +} + +/** @fn verifyClientWithCompletion:completion: + @brief Continues the flow to verify the client via silent push notification. + @param completion The callback to be invoked when the client verification flow is finished. + */ +- (void)verifyClientWithUIDelegate:(nullable id)UIDelegate + completion:(FIRVerifyClientCallback)completion { + if (_auth.appCredentialManager.credential) { + completion(_auth.appCredentialManager.credential, nil, nil); + return; + } + [_auth.tokenManager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, + NSError *_Nullable error) { + if (!token) { + [self reCAPTCHAFlowWithUIDelegate:UIDelegate completion:completion]; + return; + } + FIRVerifyClientRequest *request = + [[FIRVerifyClientRequest alloc] initWithAppToken:token.string + isSandbox:token.type == FIRAuthAPNSTokenTypeSandbox + requestConfiguration:self->_auth.requestConfiguration]; + [FIRAuthBackend + verifyClient:request + callback:^(FIRVerifyClientResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + NSError *underlyingError = error.userInfo[NSUnderlyingErrorKey]; + BOOL isInvalidAppCredential = + error.code == FIRAuthErrorCodeInternalError && + underlyingError.code == FIRAuthErrorCodeInvalidAppCredential; + if (error.code != FIRAuthErrorCodeMissingAppToken && !isInvalidAppCredential) { + completion(nil, nil, error); + return; + } else { + [self reCAPTCHAFlowWithUIDelegate:UIDelegate completion:completion]; + return; + } + } + NSTimeInterval timeout = [response.suggestedTimeOutDate timeIntervalSinceNow]; + [self->_auth.appCredentialManager + didStartVerificationWithReceipt:response.receipt + timeout:timeout + callback:^(FIRAuthAppCredential *credential) { + if (!credential.secret) { + FIRLogWarning(kFIRLoggerAuth, @"I-AUT000014", + @"Failed to receive remote notification " + @"to verify app identity within " + @"%.0f second(s), falling back to " + @"reCAPTCHA verification.", + timeout); + [self reCAPTCHAFlowWithUIDelegate:UIDelegate + completion:completion]; + return; + } + completion(credential, nil, nil); + }]; + }]; + }]; +} + +- (void)reCAPTCHAFlowWithUIDelegate:(nullable id)UIDelegate + completion:(FIRVerifyClientCallback)completion { + NSString *eventID = [FIRAuthWebUtils randomStringWithLength:10]; + [self + reCAPTCHAURLWithEventID:eventID + completion:^(NSURL *_Nullable reCAPTCHAURL, NSError *_Nullable error) { + if (error) { + completion(nil, nil, error); + return; + } + FIRAuthURLCallbackMatcher callbackMatcher = + ^BOOL(NSURL *_Nullable callbackURL) { + return [FIRAuthWebUtils isExpectedCallbackURL:callbackURL + eventID:eventID + authType:kAuthTypeVerifyApp + callbackScheme:self->_callbackScheme]; + }; + [self->_auth.authURLPresenter + presentURL:reCAPTCHAURL + UIDelegate:UIDelegate + callbackMatcher:callbackMatcher + completion:^(NSURL *_Nullable callbackURL, NSError *_Nullable error) { + if (error) { + completion(nil, nil, error); + return; + } + NSError *reCAPTCHAError; + NSString *reCAPTCHAToken = + [self reCAPTCHATokenForURL:callbackURL error:&reCAPTCHAError]; + if (!reCAPTCHAToken) { + completion(nil, nil, reCAPTCHAError); + return; + } else { + completion(nil, reCAPTCHAToken, nil); + return; + } + }]; + }]; +} + +/** @fn reCAPTCHAURLWithEventID:completion: + @brief Constructs a URL used for opening a reCAPTCHA app verification flow using a given event + ID. + @param eventID The event ID used for this purpose. + @param completion The callback invoked after the URL has been constructed or an error + has been encountered. + */ +- (void)reCAPTCHAURLWithEventID:(NSString *)eventID completion:(FIRReCAPTCHAURLCallBack)completion { + [FIRAuthWebUtils + fetchAuthDomainWithRequestConfiguration:_auth.requestConfiguration + completion:^(NSString *_Nullable authDomain, + NSError *_Nullable error) { + if (error) { + if (completion) { + completion(nil, error); + return; + } + } + NSString *bundleID = [NSBundle mainBundle].bundleIdentifier; + NSString *clientID = self->_auth.app.options.clientID; + NSString *appID = self->_auth.app.options.googleAppID; + NSString *apiKey = self->_auth.requestConfiguration.APIKey; + NSMutableArray *queryItems = [@[ + [NSURLQueryItem queryItemWithName:@"apiKey" value:apiKey], + [NSURLQueryItem queryItemWithName:@"authType" + value:kAuthTypeVerifyApp], + [NSURLQueryItem queryItemWithName:@"ibi" + value:bundleID ?: @""], + [NSURLQueryItem + queryItemWithName:@"v" + value:[FIRAuthBackend authUserAgent]], + [NSURLQueryItem queryItemWithName:@"eventId" value:eventID] + ] mutableCopy]; + if (self->_usingClientIDScheme) { + [queryItems + addObject:[NSURLQueryItem queryItemWithName:@"clientId" + value:clientID]]; + } else { + [queryItems + addObject:[NSURLQueryItem queryItemWithName:@"appId" + value:appID]]; + } + + if (self->_auth.requestConfiguration.languageCode) { + [queryItems + addObject:[NSURLQueryItem + queryItemWithName:@"hl" + value:self->_auth + .requestConfiguration + .languageCode]]; + } + NSURLComponents *components = [[NSURLComponents alloc] + initWithString: + [NSString stringWithFormat:kReCAPTCHAURLStringFormat, + authDomain]]; + [components setQueryItems:queryItems]; + if (completion) { + completion([components URL], nil); + } + }]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h new file mode 100644 index 0000000..ad25dc6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h @@ -0,0 +1,48 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRTwitterAuthCredential + @brief Internal implementation of FIRAuthCredential for Twitter credentials. + */ +@interface FIRTwitterAuthCredential : FIRAuthCredential + +/** @property token + @brief The Twitter OAuth token. + */ +@property(nonatomic, readonly) NSString *token; + +/** @property secret + @brief The Twitter OAuth secret. + */ +@property(nonatomic, readonly) NSString *secret; + +/** @fn initWithToken:secret: + @brief Designated initializer. + @param token The Twitter OAuth token. + @param secret The Twitter OAuth secret. + */ +- (nullable instancetype)initWithToken:(NSString *)token + secret:(NSString *)secret NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.m new file mode 100644 index 0000000..255e344 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.m @@ -0,0 +1,74 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRTwitterAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIRTwitterAuthCredential + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithToken:(NSString *)token secret:(NSString *)secret { + self = [super initWithProvider:FIRTwitterAuthProviderID]; + if (self) { + _token = [token copy]; + _secret = [secret copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + request.providerAccessToken = _token; + request.providerOAuthTokenSecret = _secret; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *token = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"token"]; + NSString *secret = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"secret"]; + self = [self initWithToken:token secret:secret]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.token forKey:@"token"]; + [aCoder encodeObject:self.secret forKey:@"secret"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthProvider.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthProvider.m new file mode 100644 index 0000000..27483e0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthProvider.m @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +// FIRTwitterAuthProviderID is defined in FIRAuthProvider.m. + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRTwitterAuthProvider + +- (instancetype)init { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"This class is not meant to be initialized."]; + return nil; +} + ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token secret:(NSString *)secret { + return [[FIRTwitterAuthCredential alloc] initWithToken:token secret:secret]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h new file mode 100644 index 0000000..8ed6253 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h @@ -0,0 +1,125 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRStartMFAEnrollmentResponseCallback + @brief The type of block used to return the result of a call to the startMFAEnroll endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. +*/ +typedef void (^FIRStartMFAEnrollmentResponseCallback)( + FIRStartMFAEnrollmentResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRFinalizeMFAEnrollmentResponseCallback + @brief The type of block used to return the result of a call to the finalizeMFAEnroll endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. +*/ +typedef void (^FIRFinalizeMFAEnrollmentResponseCallback)( + FIRFinalizeMFAEnrollmentResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRStartMFASignInResponseCallback + @brief The type of block used to return the result of a call to the startMFASignIn endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. +*/ +typedef void (^FIRStartMFASignInResponseCallback)(FIRStartMFASignInResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRFinalizeMFASignInResponseCallback + @brief The type of block used to return the result of a call to the finalizeMFASignIn endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. +*/ +typedef void (^FIRFinalizeMFASignInResponseCallback)( + FIRFinalizeMFASignInResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRWithdrawMFAResponseCallback + @brief The type of block used to return the result of a call to the MFAUnenroll endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. +*/ +typedef void (^FIRWithdrawMFAResponseCallback)(FIRWithdrawMFAResponse *_Nullable response, + NSError *_Nullable error); + +@interface FIRAuthBackend (MultiFactor) + +/** @fn startMultiFactorEnrollment:callback: + @brief Calls the startMFAEnrollment endpoint. + @param request The request parameters. + @param callback The callback. +*/ ++ (void)startMultiFactorEnrollment:(FIRStartMFAEnrollmentRequest *)request + callback:(FIRStartMFAEnrollmentResponseCallback)callback; + +/** @fn finalizeMultiFactorEnrollment:callback: + @brief Calls the finalizeMultiFactorEnrollment endpoint. + @param request The request parameters. + @param callback The callback. +*/ ++ (void)finalizeMultiFactorEnrollment:(FIRFinalizeMFAEnrollmentRequest *)request + callback:(FIRFinalizeMFAEnrollmentResponseCallback)callback; + +/** @fn startMultiFactorSignIn:callback: + @brief Calls the startMultiFactorSignIn endpoint. + @param request The request parameters. + @param callback The callback. +*/ ++ (void)startMultiFactorSignIn:(FIRStartMFASignInRequest *)request + callback:(FIRStartMFASignInResponseCallback)callback; + +/** @fn finalizeMultiFactorSignIn:callback: + @brief Calls the finalizeMultiFactorSignIn endpoint. + @param request The request parameters. + @param callback The callback. +*/ ++ (void)finalizeMultiFactorSignIn:(FIRFinalizeMFASignInRequest *)request + callback:(FIRFinalizeMFASignInResponseCallback)callback; + +/** @fn withdrawMultiFactor:callback: + @brief Calls the withdrawMultiFactor endpoint. + @param request The request parameters. + @param callback The callback. +*/ ++ (void)withdrawMultiFactor:(FIRWithdrawMFARequest *)request + callback:(FIRWithdrawMFAResponseCallback)callback; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.m new file mode 100644 index 0000000..7c305a4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.m @@ -0,0 +1,96 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h" + +@implementation FIRAuthBackend (MultiFactor) + ++ (void)startMultiFactorEnrollment:(FIRStartMFAEnrollmentRequest *)request + callback:(FIRStartMFAEnrollmentResponseCallback)callback { + FIRStartMFAEnrollmentResponse *response = [[FIRStartMFAEnrollmentResponse alloc] init]; + [[self implementation] postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + ++ (void)finalizeMultiFactorEnrollment:(FIRFinalizeMFAEnrollmentRequest *)request + callback:(FIRFinalizeMFAEnrollmentResponseCallback)callback { + FIRFinalizeMFAEnrollmentResponse *response = [[FIRFinalizeMFAEnrollmentResponse alloc] init]; + [[self implementation] postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + ++ (void)startMultiFactorSignIn:(FIRStartMFASignInRequest *)request + callback:(FIRStartMFASignInResponseCallback)callback { + FIRStartMFASignInResponse *response = [[FIRStartMFASignInResponse alloc] init]; + [[self implementation] postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + ++ (void)finalizeMultiFactorSignIn:(FIRFinalizeMFASignInRequest *)request + callback:(FIRFinalizeMFASignInResponseCallback)callback { + FIRFinalizeMFASignInResponse *response = [[FIRFinalizeMFASignInResponse alloc] init]; + [[self implementation] postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + ++ (void)withdrawMultiFactor:(FIRWithdrawMFARequest *)request + callback:(FIRWithdrawMFAResponseCallback)callback { + FIRWithdrawMFAResponse *response = [[FIRWithdrawMFAResponse alloc] init]; + [[self implementation] postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +@end + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.h new file mode 100644 index 0000000..d3e9bca --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.h @@ -0,0 +1,620 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +@class FIRAuthRequestConfiguration; +@class FIRCreateAuthURIRequest; +@class FIRCreateAuthURIResponse; +@class FIRDeleteAccountRequest; +@class FIRDeleteAccountResponse; +@class FIREmailLinkSignInRequest; +@class FIREmailLinkSignInResponse; +@class FIRGetAccountInfoRequest; +@class FIRGetAccountInfoResponse; +@class FIRGetProjectConfigRequest; +@class FIRGetProjectConfigResponse; +@class FIRGetOOBConfirmationCodeRequest; +@class FIRGetOOBConfirmationCodeResponse; +@class FIRResetPasswordRequest; +@class FIRResetPasswordResponse; +@class FIRSecureTokenRequest; +@class FIRSecureTokenResponse; +@class FIRSetAccountInfoRequest; +@class FIRSetAccountInfoResponse; +@class FIRVerifyAssertionRequest; +@class FIRVerifyAssertionResponse; +@class FIRVerifyClientRequest; +@class FIRVerifyClientResponse; +@class FIRVerifyCustomTokenRequest; +@class FIRVerifyCustomTokenResponse; +@class FIRVerifyPasswordRequest; +@class FIRVerifyPasswordResponse; +@class FIRVerifyPhoneNumberRequest; +@class FIRVerifyPhoneNumberResponse; +@class FIRSendVerificationCodeRequest; +@class FIRSendVerificationCodeResponse; +@class FIRSignInWithGameCenterRequest; +@class FIRSignInWithGameCenterResponse; +@class FIRSignUpNewUserRequest; +@class FIRSignUpNewUserResponse; + +@protocol FIRAuthBackendImplementation; +@protocol FIRAuthBackendRPCIssuer; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthBackendRPCIssuerCompletionHandler + @brief The type of block used to return the result of a call to an endpoint. + @param data The HTTP response body. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRAuthBackendRPCIssuerCompletionHandler)(NSData *_Nullable data, + NSError *_Nullable error); + +/** @typedef FIRCreateAuthURIResponseCallback + @brief The type of block used to return the result of a call to the createAuthURI + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRCreateAuthURIResponseCallback)(FIRCreateAuthURIResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRGetAccountInfoResponseCallback + @brief The type of block used to return the result of a call to the getAccountInfo + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRGetAccountInfoResponseCallback)(FIRGetAccountInfoResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRGetProjectConfigResponseCallback + @brief The type of block used to return the result of a call to the getProjectInfo + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRGetProjectConfigResponseCallback)(FIRGetProjectConfigResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRSetAccountInfoResponseCallback + @brief The type of block used to return the result of a call to the setAccountInfo + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRSetAccountInfoResponseCallback)(FIRSetAccountInfoResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRSecureTokenResponseCallback + @brief The type of block used to return the result of a call to the token endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRSecureTokenResponseCallback)(FIRSecureTokenResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRVerifyAssertionResponseCallback + @brief The type of block used to return the result of a call to the verifyAssertion + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRVerifyAssertionResponseCallback)(FIRVerifyAssertionResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRVerifyPasswordResponseCallback + @brief The type of block used to return the result of a call to the verifyPassword + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRVerifyPasswordResponseCallback)(FIRVerifyPasswordResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIREmailLinkSigninResponseCallback + @brief The type of block used to return the result of a call to the emailLinkSignin + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIREmailLinkSigninResponseCallback)(FIREmailLinkSignInResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRVerifyCustomTokenResponseCallback + @brief The type of block used to return the result of a call to the verifyCustomToken + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRVerifyCustomTokenResponseCallback)( + FIRVerifyCustomTokenResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRDeleteCallBack + @brief The type of block called when a request delete account has finished. + @param error The error which occurred, or nil if the request was successful. + */ +typedef void (^FIRDeleteCallBack)(NSError *_Nullable error); + +/** @typedef FIRGetOOBConfirmationCodeResponseCallback + @brief The type of block used to return the result of a call to the getOOBConfirmationCode + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRGetOOBConfirmationCodeResponseCallback)( + FIRGetOOBConfirmationCodeResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRSignupNewUserCallback + @brief The type of block used to return the result of a call to the signupNewUser endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRSignupNewUserCallback)(FIRSignUpNewUserResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRResetPasswordCallback + @brief The type of block used to return the result of a call to the resetPassword endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRResetPasswordCallback)(FIRResetPasswordResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRSendVerificationCodeResponseCallback + @brief The type of block used to return the result of a call to the sendVerificationCode + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRSendVerificationCodeResponseCallback)( + FIRSendVerificationCodeResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRVerifyPhoneNumberResponseCallback + @brief The type of block used to return the result of a call to the verifyPhoneNumber endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRVerifyPhoneNumberResponseCallback)( + FIRVerifyPhoneNumberResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRVerifyClientResponseCallback + @brief The type of block used to return the result of a call to the verifyClient endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRVerifyClientResponseCallback)(FIRVerifyClientResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRSignInWithGameCenterResponseCallback + @brief The type of block used to return the result of a call to the SignInWithGameCenter + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRSignInWithGameCenterResponseCallback)( + FIRSignInWithGameCenterResponse *_Nullable response, NSError *_Nullable error); + +/** @class FIRAuthBackend + @brief Simple static class with methods representing the backend RPCs. + @remarks All callback blocks passed as method parameters are invoked asynchronously on the + global work queue in the future. See + https://github.com/firebase/firebase-ios-sdk/tree/master/FirebaseAuth/Docs/threading.md + */ +@interface FIRAuthBackend : NSObject + +/** @fn authUserAgent + @brief Retrieves the Firebase Auth user agent. + @return The Firebase Auth user agent. + */ ++ (NSString *)authUserAgent; + ++ (id)implementation; + +/** @fn setBackendImplementation: + @brief Changes the default backend implementation to something else. + @param backendImplementation The backend implementation to use. + @remarks This is not, generally, safe to call in a scenario where other backend requests may + be occuring. This is specifically to help mock the backend for testing purposes. + */ ++ (void)setBackendImplementation:(id)backendImplementation; + +/** @fn setDefaultBackendImplementationWithRPCIssuer: + @brief Uses the default backend implementation, but with a custom RPC issuer. + @param RPCIssuer The RPC issuer to use. If @c nil, will use the default implementation. + @remarks This is not, generally, safe to call in a scenario where other backend requests may + be occuring. This is specifically to help test the backend interfaces (requests, responses, + and shared FIRAuthBackend logic.) + */ ++ (void)setDefaultBackendImplementationWithRPCIssuer: + (nullable id)RPCIssuer; + +/** @fn createAuthURI:callback: + @brief Calls the createAuthURI endpoint, which is responsible for creating the URI used by the + IdP to authenticate the user. + @param request The request parameters. + @param callback The callback. + */ ++ (void)createAuthURI:(FIRCreateAuthURIRequest *)request + callback:(FIRCreateAuthURIResponseCallback)callback; + +/** @fn getAccountInfo:callback: + @brief Calls the getAccountInfo endpoint, which returns account info for a given account. + @param request The request parameters. + @param callback The callback. + */ ++ (void)getAccountInfo:(FIRGetAccountInfoRequest *)request + callback:(FIRGetAccountInfoResponseCallback)callback; + +/** @fn getProjectConfig:callback: + @brief Calls the getProjectConfig endpoint, which returns configuration information for a given + project. + @param request An object wrapping the backend get request. + @param callback The callback. + */ ++ (void)getProjectConfig:(FIRGetProjectConfigRequest *)request + callback:(FIRGetProjectConfigResponseCallback)callback; + +/** @fn setAccountInfo:callback: + @brief Calls the setAccountInfo endpoint, which is responsible for setting account info for a + user, for example, to sign up a new user with email and password. + @param request The request parameters. + @param callback The callback. + */ ++ (void)setAccountInfo:(FIRSetAccountInfoRequest *)request + callback:(FIRSetAccountInfoResponseCallback)callback; + +/** @fn verifyAssertion:callback: + @brief Calls the verifyAssertion endpoint, which is responsible for authenticating a + user who has IDP-related credentials (an ID Token, an Access Token, etc.) + @param request The request parameters. + @param callback The callback. + */ ++ (void)verifyAssertion:(FIRVerifyAssertionRequest *)request + callback:(FIRVerifyAssertionResponseCallback)callback; + +/** @fn verifyCustomToken:callback: + @brief Calls the verifyCustomToken endpoint, which is responsible for authenticating a + user who has BYOAuth credentials (a self-signed token using their BYOAuth private key.) + @param request The request parameters. + @param callback The callback. + */ ++ (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request + callback:(FIRVerifyCustomTokenResponseCallback)callback; + +/** @fn verifyPassword:callback: + @brief Calls the verifyPassword endpoint, which is responsible for authenticating a + user who has email and password credentials. + @param request The request parameters. + @param callback The callback. + */ ++ (void)verifyPassword:(FIRVerifyPasswordRequest *)request + callback:(FIRVerifyPasswordResponseCallback)callback; + +/** @fn emailLinkSignin:callback: + @brief Calls the emailLinkSignin endpoint, which is responsible for authenticating a + user through passwordless sign-in. + @param request The request parameters. + @param callback The callback. + */ ++ (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback; + +/** @fn secureToken:callback: + @brief Calls the token endpoint, which is responsible for performing STS token exchanges and + token refreshes. + @param request The request parameters. + @param callback The callback. + */ ++ (void)secureToken:(FIRSecureTokenRequest *)request + callback:(FIRSecureTokenResponseCallback)callback; + +/** @fn getOOBConfirmationCode:callback: + @brief Calls the getOOBConfirmationCode endpoint, which is responsible for sending email change + request emails, and password reset emails. + @param request The request parameters. + @param callback The callback. + */ ++ (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request + callback:(FIRGetOOBConfirmationCodeResponseCallback)callback; + +/** @fn signUpNewUser: + @brief Calls the signUpNewUser endpoint, which is responsible anonymously signing up a user + or signing in a user anonymously. + @param request The request parameters. + @param callback The callback. + */ ++ (void)signUpNewUser:(FIRSignUpNewUserRequest *)request + callback:(FIRSignupNewUserCallback)callback; + +/** @fn resetPassword:callback + @brief Calls the resetPassword endpoint, which is responsible for resetting a user's password + given an OOB code and new password. + @param request The request parameters. + @param callback The callback. + */ ++ (void)resetPassword:(FIRResetPasswordRequest *)request + callback:(FIRResetPasswordCallback)callback; + +/** @fn deleteAccount: + @brief Calls the DeleteAccount endpoint, which is responsible for deleting a user. + @param request The request parameters. + @param callback The callback. + */ ++ (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback; + +/** @fn SignInWithGameCenter:callback: + @brief Calls the SignInWithGameCenter endpoint, which is responsible for authenticating a user + who has Game Center credentials. + @param request The request parameters. + @param callback The callback. + */ ++ (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request + callback:(FIRSignInWithGameCenterResponseCallback)callback; + +#if TARGET_OS_IOS +/** @fn sendVerificationCode:callback: + @brief Calls the sendVerificationCode endpoint, which is responsible for sending the + verification code to a phone number specified in the request parameters. + @param request The request parameters. + @param callback The callback. + */ ++ (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request + callback:(FIRSendVerificationCodeResponseCallback)callback; + +/** @fn verifyPhoneNumber:callback: + @brief Calls the verifyPhoneNumber endpoint, which is responsible for sending the verification + code to a phone number specified in the request parameters. + @param request The request parameters. + @param callback The callback. + */ ++ (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request + callback:(FIRVerifyPhoneNumberResponseCallback)callback; + +/** @fn verifyClient:callback: + @brief Calls the verifyClient endpoint, which is responsible for sending the silent push + notification used for app validation to the device provided in the request parameters. + @param request The request parameters. + @param callback The callback. + */ ++ (void)verifyClient:(FIRVerifyClientRequest *)request + callback:(FIRVerifyClientResponseCallback)callback; +#endif + +@end + +/** @protocol FIRAuthBackendRPCIssuer + @brief Used to make FIRAuthBackend + */ +@protocol FIRAuthBackendRPCIssuer + +/** @fn asyncPostToURLWithRequestConfiguration:URL:body:contentType:completionHandler: + @brief Asynchronously seXnds a POST request. + @param requestConfiguration The request to be made. + @param URL The request URL. + @param body Request body. + @param contentType Content type of the body. + @param handler provided that handles POST response. Invoked asynchronously on the auth global + work queue in the future. + */ +- (void)asyncPostToURLWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + URL:(NSURL *)URL + body:(nullable NSData *)body + contentType:(NSString *)contentType + completionHandler:(FIRAuthBackendRPCIssuerCompletionHandler)handler; + +@end + +/** @protocol FIRAuthBackendImplementation + @brief Used to make FIRAuthBackend provide a layer of indirection to an actual RPC-based backend + or a mock backend. + */ +@protocol FIRAuthBackendImplementation + +/** @fn createAuthURI:callback: + @brief Calls the createAuthURI endpoint, which is responsible for creating the URI used by the + IdP to authenticate the user. + @param request The request parameters. + @param callback The callback. + */ +- (void)createAuthURI:(FIRCreateAuthURIRequest *)request + callback:(FIRCreateAuthURIResponseCallback)callback; + +/** @fn getAccountInfo:callback: + @brief Calls the getAccountInfo endpoint, which returns account info for a given account. + @param request The request parameters. + @param callback The callback. + */ +- (void)getAccountInfo:(FIRGetAccountInfoRequest *)request + callback:(FIRGetAccountInfoResponseCallback)callback; + +/** @fn getProjectConfig:callback: + @brief Calls the getProjectInfo endpoint, which returns configuration information for a given + project. + @param request The request parameters. + @param callback The callback. + */ +- (void)getProjectConfig:(FIRGetProjectConfigRequest *)request + callback:(FIRGetProjectConfigResponseCallback)callback; + +/** @fn setAccountInfo:callback: + @brief Calls the setAccountInfo endpoint, which is responsible for setting account info for a + user, for example, to sign up a new user with email and password. + @param request The request parameters. + @param callback The callback. + */ +- (void)setAccountInfo:(FIRSetAccountInfoRequest *)request + callback:(FIRSetAccountInfoResponseCallback)callback; + +/** @fn verifyAssertion:callback: + @brief Calls the verifyAssertion endpoint, which is responsible for authenticating a + user who has IDP-related credentials (an ID Token, an Access Token, etc.) + @param request The request parameters. + @param callback The callback. + */ +- (void)verifyAssertion:(FIRVerifyAssertionRequest *)request + callback:(FIRVerifyAssertionResponseCallback)callback; + +/** @fn verifyCustomToken:callback: + @brief Calls the verifyCustomToken endpoint, which is responsible for authenticating a + user who has BYOAuth credentials (a self-signed token using their BYOAuth private key.) + @param request The request parameters. + @param callback The callback. + */ +- (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request + callback:(FIRVerifyCustomTokenResponseCallback)callback; + +/** @fn verifyPassword:callback: + @brief Calls the verifyPassword endpoint, which is responsible for authenticating a + user who has email and password credentials. + @param request The request parameters. + @param callback The callback. + */ +- (void)verifyPassword:(FIRVerifyPasswordRequest *)request + callback:(FIRVerifyPasswordResponseCallback)callback; + +/** @fn emailLinkSignin:callback: + @brief Calls the emailLinkSignin endpoint, which is responsible for authenticating a + user through passwordless sign-in. + @param request The request parameters. + @param callback The callback. + */ +- (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback; + +/** @fn secureToken:callback: + @brief Calls the token endpoint, which is responsible for performing STS token exchanges and + token refreshes. + @param request The request parameters. + @param callback The callback. + */ +- (void)secureToken:(FIRSecureTokenRequest *)request + callback:(FIRSecureTokenResponseCallback)callback; + +/** @fn getOOBConfirmationCode:callback: + @brief Calls the getOOBConfirmationCode endpoint, which is responsible for sending email change + request emails, email sign-in link emails, and password reset emails. + @param request The request parameters. + @param callback The callback. + */ +- (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request + callback:(FIRGetOOBConfirmationCodeResponseCallback)callback; + +/** @fn signUpNewUser: + @brief Calls the signUpNewUser endpoint, which is responsible anonymously signing up a user + or signing in a user anonymously. + @param request The request parameters. + @param callback The callback. + */ +- (void)signUpNewUser:(FIRSignUpNewUserRequest *)request + callback:(FIRSignupNewUserCallback)callback; + +/** @fn deleteAccount: + @brief Calls the DeleteAccount endpoint, which is responsible for deleting a user. + @param request The request parameters. + @param callback The callback. + */ +- (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback; + +#if TARGET_OS_IOS +/** @fn sendVerificationCode:callback: + @brief Calls the sendVerificationCode endpoint, which is responsible for sending the + verification code to a phone number specified in the request parameters. + @param request The request parameters. + @param callback The callback. + */ +- (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request + callback:(FIRSendVerificationCodeResponseCallback)callback; + +/** @fn verifyPhoneNumber:callback: + @brief Calls the verifyPhoneNumber endpoint, which is responsible for sending the verification + code to a phone number specified in the request parameters. + @param request The request parameters. + @param callback The callback. + */ +- (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request + callback:(FIRVerifyPhoneNumberResponseCallback)callback; + +/** @fn verifyClient:callback: + @brief Calls the verifyClient endpoint, which is responsible for sending the silent push + notification used for app validation to the device provided in the request parameters. + @param request The request parameters. + @param callback The callback. + */ +- (void)verifyClient:(FIRVerifyClientRequest *)request + callback:(FIRVerifyClientResponseCallback)callback; +#endif + +/** @fn SignInWithGameCenter:callback: + @brief Calls the SignInWithGameCenter endpoint, which is responsible for authenticating a user + who has Game Center credentials. + @param request The request parameters. + @param callback The callback. + */ +- (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request + callback:(FIRSignInWithGameCenterResponseCallback)callback; + +/** @fn resetPassword:callback + @brief Calls the resetPassword endpoint, which is responsible for resetting a user's password + given an OOB code and new password. + @param request The request parameters. + @param callback The callback. + */ +- (void)resetPassword:(FIRResetPasswordRequest *)request + callback:(FIRResetPasswordCallback)callback; + +/** @fn postWithRequest:response:callback: + @brief Calls the RPC using HTTP POST. + @remarks Possible error responses: + @see FIRAuthInternalErrorCodeRPCRequestEncodingError + @see FIRAuthInternalErrorCodeJSONSerializationError + @see FIRAuthInternalErrorCodeNetworkError + @see FIRAuthInternalErrorCodeUnexpectedErrorResponse + @see FIRAuthInternalErrorCodeUnexpectedResponse + @see FIRAuthInternalErrorCodeRPCResponseDecodingError + @param request The request. + @param response The empty response to be filled. + @param callback The callback for both success and failure. +*/ +- (void)postWithRequest:(id)request + response:(id)response + callback:(void (^)(NSError *_Nullable error))callback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.m new file mode 100644 index 0000000..9359e58 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.m @@ -0,0 +1,1453 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" + +#if SWIFT_PACKAGE +@import GTMSessionFetcherCore; +#else +#import +#import +#endif + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** @var kClientVersionHeader + @brief HTTP header name for the client version. + */ +static NSString *const kClientVersionHeader = @"X-Client-Version"; + +/** @var kIosBundleIdentifierHeader + @brief HTTP header name for iOS bundle ID. + */ +static NSString *const kIosBundleIdentifierHeader = @"X-Ios-Bundle-Identifier"; + +/** @var kFirebaseLocalHeader + @brief HTTP header name for the firebase locale. + */ +static NSString *const kFirebaseLocalHeader = @"X-Firebase-Locale"; + +/** @var kFirebaseAuthCoreFrameworkMarker + @brief The marker in the HTTP header that indicates the request comes from Firebase Auth Core. + */ +static NSString *const kFirebaseAuthCoreFrameworkMarker = @"FirebaseCore-iOS"; + +/** @var kJSONContentType + @brief The value of the HTTP content-type header for JSON payloads. + */ +static NSString *const kJSONContentType = @"application/json"; + +/** @var kErrorDataKey + @brief Key for error data in NSError returned by @c GTMSessionFetcher. + */ +static NSString *const kErrorDataKey = @"data"; + +/** @var kErrorKey + @brief The key for the "error" value in JSON responses from the server. + */ +static NSString *const kErrorKey = @"error"; + +/** @var kErrorsKey + @brief The key for the "errors" value in JSON responses from the server. + */ +static NSString *const kErrorsKey = @"errors"; + +/** @var kReasonKey + @brief The key for the "reason" value in JSON responses from the server. + */ +static NSString *const kReasonKey = @"reason"; + +/** @var kInvalidKeyReasonValue + @brief The value for the "reason" key indicating an invalid API Key was received by the server. + */ +static NSString *const kInvalidKeyReasonValue = @"keyInvalid"; + +/** @var kAppNotAuthorizedReasonValue + @brief The value for the "reason" key indicating the App is not authorized to use Firebase + Authentication. + */ +static NSString *const kAppNotAuthorizedReasonValue = @"ipRefererBlocked"; + +/** @var kErrorMessageKey + @brief The key for an error's "message" value in JSON responses from the server. + */ +static NSString *const kErrorMessageKey = @"message"; + +/** @var kReturnIDPCredentialErrorMessageKey + @brief The key for "errorMessage" value in JSON responses from the server, In case + returnIDPCredential of a verifyAssertion request is set to @YES. + */ +static NSString *const kReturnIDPCredentialErrorMessageKey = @"errorMessage"; + +/** @var kUserNotFoundErrorMessage + @brief This is the error message returned when the user is not found, which means the user + account has been deleted given the token was once valid. + */ +static NSString *const kUserNotFoundErrorMessage = @"USER_NOT_FOUND"; + +/** @var kUserDeletedErrorMessage + @brief This is the error message the server will respond with if the user entered an invalid + email address. + */ +static NSString *const kUserDeletedErrorMessage = @"EMAIL_NOT_FOUND"; + +/** @var kInvalidLocalIDErrorMessage + @brief This is the error message the server responds with if the user local id in the id token + does not exit. + */ +static NSString *const kInvalidLocalIDErrorMessage = @"INVALID_LOCAL_ID"; + +/** @var kUserTokenExpiredErrorMessage + @brief The error returned by the server if the token issue time is older than the account's + valid_since time. + */ +static NSString *const kUserTokenExpiredErrorMessage = @"TOKEN_EXPIRED"; + +/** @var kTooManyRequestsErrorMessage + @brief This is the error message the server will respond with if too many requests were made to + a server method. + */ +static NSString *const kTooManyRequestsErrorMessage = @"TOO_MANY_ATTEMPTS_TRY_LATER"; + +/** @var kInvalidCustomTokenErrorMessage + @brief This is the error message the server will respond with if there is a validation error + with the custom token. + */ +static NSString *const kInvalidCustomTokenErrorMessage = @"INVALID_CUSTOM_TOKEN"; + +/** @var kCustomTokenMismatch + @brief This is the error message the server will respond with if the service account and API key + belong to different projects. + */ +static NSString *const kCustomTokenMismatch = @"CREDENTIAL_MISMATCH"; + +/** @var kInvalidCredentialErrorMessage + @brief This is the error message the server responds with if the IDP token or requestUri is + invalid. + */ +static NSString *const kInvalidCredentialErrorMessage = @"INVALID_IDP_RESPONSE"; + +/** @var kUserDisabledErrorMessage + @brief The error returned by the server if the user account is diabled. + */ +static NSString *const kUserDisabledErrorMessage = @"USER_DISABLED"; + +/** @var kOperationNotAllowedErrorMessage + @brief This is the error message the server will respond with if Admin disables IDP specified by + provider. + */ +static NSString *const kOperationNotAllowedErrorMessage = @"OPERATION_NOT_ALLOWED"; + +/** @var kPasswordLoginDisabledErrorMessage + @brief This is the error message the server responds with if password login is disabled. + */ +static NSString *const kPasswordLoginDisabledErrorMessage = @"PASSWORD_LOGIN_DISABLED"; + +/** @var kEmailAlreadyInUseErrorMessage + @brief This is the error message the server responds with if the email address already exists. + */ +static NSString *const kEmailAlreadyInUseErrorMessage = @"EMAIL_EXISTS"; + +/** @var kInvalidEmailErrorMessage + @brief The error returned by the server if the email is invalid. + */ +static NSString *const kInvalidEmailErrorMessage = @"INVALID_EMAIL"; + +/** @var kInvalidIdentifierErrorMessage + @brief The error returned by the server if the identifier is invalid. + */ +static NSString *const kInvalidIdentifierErrorMessage = @"INVALID_IDENTIFIER"; + +/** @var kWrongPasswordErrorMessage + @brief This is the error message the server will respond with if the user entered a wrong + password. + */ +static NSString *const kWrongPasswordErrorMessage = @"INVALID_PASSWORD"; + +/** @var kCredentialTooOldErrorMessage + @brief This is the error message the server responds with if account change is attempted 5 + minutes after signing in. + */ +static NSString *const kCredentialTooOldErrorMessage = @"CREDENTIAL_TOO_OLD_LOGIN_AGAIN"; + +/** @var kFederatedUserIDAlreadyLinkedMessage + @brief This is the error message the server will respond with if the federated user ID has been + already linked with another account. + */ +static NSString *const kFederatedUserIDAlreadyLinkedMessage = @"FEDERATED_USER_ID_ALREADY_LINKED"; + +/** @var kInvalidUserTokenErrorMessage + @brief This is the error message the server responds with if user's saved auth credential is + invalid, and the user needs to sign in again. + */ +static NSString *const kInvalidUserTokenErrorMessage = @"INVALID_ID_TOKEN"; + +/** @var kWeakPasswordErrorMessagePrefix + @brief This is the prefix for the error message the server responds with if user's new password + to be set is too weak. + */ +static NSString *const kWeakPasswordErrorMessagePrefix = @"WEAK_PASSWORD"; + +/** @var kExpiredActionCodeErrorMessage + @brief This is the error message the server will respond with if the action code is expired. + */ +static NSString *const kExpiredActionCodeErrorMessage = @"EXPIRED_OOB_CODE"; + +/** @var kInvalidActionCodeErrorMessage + @brief This is the error message the server will respond with if the action code is invalid. + */ +static NSString *const kInvalidActionCodeErrorMessage = @"INVALID_OOB_CODE"; + +/** @var kMissingEmailErrorMessage + @brief This is the error message the server will respond with if the email address is missing + during a "send password reset email" attempt. + */ +static NSString *const kMissingEmailErrorMessage = @"MISSING_EMAIL"; + +/** @var kInvalidSenderEmailErrorMessage + @brief This is the error message the server will respond with if the sender email is invalid + during a "send password reset email" attempt. + */ +static NSString *const kInvalidSenderEmailErrorMessage = @"INVALID_SENDER"; + +/** @var kInvalidMessagePayloadErrorMessage + @brief This is the error message the server will respond with if there are invalid parameters in + the payload during a "send password reset email" attempt. + */ +static NSString *const kInvalidMessagePayloadErrorMessage = @"INVALID_MESSAGE_PAYLOAD"; + +/** @var kInvalidRecipientEmailErrorMessage + @brief This is the error message the server will respond with if the recipient email is invalid. + */ +static NSString *const kInvalidRecipientEmailErrorMessage = @"INVALID_RECIPIENT_EMAIL"; + +/** @var kMissingIosBundleIDErrorMessage + @brief This is the error message the server will respond with if iOS bundle ID is missing but + the iOS App store ID is provided. + */ +static NSString *const kMissingIosBundleIDErrorMessage = @"MISSING_IOS_BUNDLE_ID"; + +/** @var kMissingAndroidPackageNameErrorMessage + @brief This is the error message the server will respond with if Android Package Name is missing + but the flag indicating the app should be installed is set to true. + */ +static NSString *const kMissingAndroidPackageNameErrorMessage = @"MISSING_ANDROID_PACKAGE_NAME"; + +/** @var kUnauthorizedDomainErrorMessage + @brief This is the error message the server will respond with if the domain of the continue URL + specified is not allowlisted in the Firebase console. + */ +static NSString *const kUnauthorizedDomainErrorMessage = @"UNAUTHORIZED_DOMAIN"; + +/** @var kInvalidProviderIDErrorMessage + @brief This is the error message the server will respond with if the provider id given for the + web operation is invalid. + */ +static NSString *const kInvalidProviderIDErrorMessage = @"INVALID_PROVIDER_ID"; + +/** @var kInvalidDynamicLinkDomainErrorMessage + @brief This is the error message the server will respond with if the dynamic link domain + provided in the request is invalid. + */ +static NSString *const kInvalidDynamicLinkDomainErrorMessage = @"INVALID_DYNAMIC_LINK_DOMAIN"; + +/** @var kInvalidContinueURIErrorMessage + @brief This is the error message the server will respond with if the continue URL provided in + the request is invalid. + */ +static NSString *const kInvalidContinueURIErrorMessage = @"INVALID_CONTINUE_URI"; + +/** @var kMissingContinueURIErrorMessage + @brief This is the error message the server will respond with if there was no continue URI + present in a request that required one. + */ +static NSString *const kMissingContinueURIErrorMessage = @"MISSING_CONTINUE_URI"; + +/** @var kInvalidPhoneNumberErrorMessage + @brief This is the error message the server will respond with if an incorrectly formatted phone + number is provided. + */ +static NSString *const kInvalidPhoneNumberErrorMessage = @"INVALID_PHONE_NUMBER"; + +/** @var kInvalidVerificationCodeErrorMessage + @brief This is the error message the server will respond with if an invalid verification code is + provided. + */ +static NSString *const kInvalidVerificationCodeErrorMessage = @"INVALID_CODE"; + +/** @var kInvalidSessionInfoErrorMessage + @brief This is the error message the server will respond with if an invalid session info + (verification ID) is provided. + */ +static NSString *const kInvalidSessionInfoErrorMessage = @"INVALID_SESSION_INFO"; + +/** @var kSessionExpiredErrorMessage + @brief This is the error message the server will respond with if the SMS code has expired before + it is used. + */ +static NSString *const kSessionExpiredErrorMessage = @"SESSION_EXPIRED"; + +/** @var kMissingOrInvalidNonceErrorMessage + @brief This is the error message the server will respond with if the nonce is missing or + invalid. + */ +static NSString *const kMissingOrInvalidNonceErrorMessage = @"MISSING_OR_INVALID_NONCE"; + +/** @var kMissingAppTokenErrorMessage + @brief This is the error message the server will respond with if the APNS token is missing in a + verifyClient request. + */ +static NSString *const kMissingAppTokenErrorMessage = @"MISSING_IOS_APP_TOKEN"; + +/** @var kMissingAppCredentialErrorMessage + @brief This is the error message the server will respond with if the app token is missing in a + sendVerificationCode request. + */ +static NSString *const kMissingAppCredentialErrorMessage = @"MISSING_APP_CREDENTIAL"; + +/** @var kInvalidAppCredentialErrorMessage + @brief This is the error message the server will respond with if the app credential in a + sendVerificationCode request is invalid. + */ +static NSString *const kInvalidAppCredentialErrorMessage = @"INVALID_APP_CREDENTIAL"; + +/** @var kQuoutaExceededErrorMessage + @brief This is the error message the server will respond with if the quota for SMS text messages + has been exceeded for the project. + */ +static NSString *const kQuoutaExceededErrorMessage = @"QUOTA_EXCEEDED"; + +/** @var kAppNotVerifiedErrorMessage + @brief This is the error message the server will respond with if Firebase could not verify the + app during a phone authentication flow. + */ +static NSString *const kAppNotVerifiedErrorMessage = @"APP_NOT_VERIFIED"; + +/** @var kMissingClientIdentifier + @brief This is the error message the server will respond with if Firebase could not verify the + app during a phone authentication flow when a real phone number is used and app verification + is disabled for testing. + */ +static NSString *const kMissingClientIdentifier = @"MISSING_CLIENT_IDENTIFIER"; + +/** @var kCaptchaCheckFailedErrorMessage + @brief This is the error message the server will respond with if the reCAPTCHA token provided is + invalid. + */ +static NSString *const kCaptchaCheckFailedErrorMessage = @"CAPTCHA_CHECK_FAILED"; + +/** @var kTenantIDMismatch + @brief This is the error message the server will respond with if the tenant id mismatches. + */ +static NSString *const kTenantIDMismatch = @"TENANT_ID_MISMATCH"; + +/** @var kUnsupportedTenantOperation + @brief This is the error message the server will respond with if the operation does not support + multi-tenant. + */ +static NSString *const kUnsupportedTenantOperation = @"UNSUPPORTED_TENANT_OPERATION"; + +/** @var kMissingMFAPendingCredentialErrorMessage + @brief This is the error message the server will respond with if the MFA pending credential is + missing. + */ +static NSString *const kMissingMFAPendingCredentialErrorMessage = @"MISSING_MFA_PENDING_CREDENTIAL"; + +/** @var kMissingMFAEnrollmentIDErrorMessage + @brief This is the error message the server will respond with if the MFA enrollment ID is missing. + */ +static NSString *const kMissingMFAEnrollmentIDErrorMessage = @"MISSING_MFA_ENROLLMENT_ID"; + +/** @var kInvalidMFAPendingCredentialErrorMessage + @brief This is the error message the server will respond with if the MFA pending credential is + invalid. + */ +static NSString *const kInvalidMFAPendingCredentialErrorMessage = @"INVALID_MFA_PENDING_CREDENTIAL"; + +/** @var kMFAEnrollmentNotFoundErrorMessage + @brief This is the error message the server will respond with if the MFA enrollment info is not + found. + */ +static NSString *const kMFAEnrollmentNotFoundErrorMessage = @"MFA_ENROLLMENT_NOT_FOUND"; + +/** @var kAdminOnlyOperationErrorMessage + @brief This is the error message the server will respond with if the operation is admin only. + */ +static NSString *const kAdminOnlyOperationErrorMessage = @"ADMIN_ONLY_OPERATION"; + +/** @var kUnverifiedEmailErrorMessage + @brief This is the error message the server will respond with if the email is unverified. + */ +static NSString *const kUnverifiedEmailErrorMessage = @"UNVERIFIED_EMAIL"; + +/** @var kSecondFactorExistsErrorMessage + @brief This is the error message the server will respond with if the second factor already exsists. + */ +static NSString *const kSecondFactorExistsErrorMessage = @"SECOND_FACTOR_EXISTS"; + +/** @var kSecondFactorLimitExceededErrorMessage + @brief This is the error message the server will respond with if the number of second factor + reaches the limit. + */ +static NSString *const kSecondFactorLimitExceededErrorMessage = @"SECOND_FACTOR_LIMIT_EXCEEDED"; + +/** @var kUnsupportedFirstFactorErrorMessage + @brief This is the error message the server will respond with if the first factor doesn't support + MFA. + */ +static NSString *const kUnsupportedFirstFactorErrorMessage = @"UNSUPPORTED_FIRST_FACTOR"; + +/** @var kEmailChangeNeedsVerificationErrorMessage + @brief This is the error message the server will respond with if changing an unverified email. + */ +static NSString *const kEmailChangeNeedsVerificationErrorMessage = + @"EMAIL_CHANGE_NEEDS_VERIFICATION"; + +/** @var kInvalidPendingToken + @brief Generic IDP error codes. + */ +static NSString *const kInvalidPendingToken = @"INVALID_PENDING_TOKEN"; + +/** @var gBackendImplementation + @brief The singleton FIRAuthBackendImplementation instance to use. + */ +static id gBackendImplementation; + +/** @class FIRAuthBackendRPCImplementation + @brief The default RPC-based backend implementation. + */ +@interface FIRAuthBackendRPCImplementation : NSObject + +/** @property RPCIssuer + @brief An instance of FIRAuthBackendRPCIssuer for making RPC requests. Allows the RPC + requests/responses to be easily faked. + */ +@property(nonatomic, strong) id RPCIssuer; + +@end + +@implementation FIRAuthBackend + ++ (id)implementation { + if (!gBackendImplementation) { + gBackendImplementation = [[FIRAuthBackendRPCImplementation alloc] init]; + } + return gBackendImplementation; +} + ++ (void)setBackendImplementation:(id)backendImplementation { + gBackendImplementation = backendImplementation; +} + ++ (void)setDefaultBackendImplementationWithRPCIssuer: + (nullable id)RPCIssuer { + FIRAuthBackendRPCImplementation *defaultImplementation = + [[FIRAuthBackendRPCImplementation alloc] init]; + if (RPCIssuer) { + defaultImplementation.RPCIssuer = RPCIssuer; + } + gBackendImplementation = defaultImplementation; +} + ++ (void)createAuthURI:(FIRCreateAuthURIRequest *)request + callback:(FIRCreateAuthURIResponseCallback)callback { + [[self implementation] createAuthURI:request callback:callback]; +} + ++ (void)getAccountInfo:(FIRGetAccountInfoRequest *)request + callback:(FIRGetAccountInfoResponseCallback)callback { + [[self implementation] getAccountInfo:request callback:callback]; +} + ++ (void)getProjectConfig:(FIRGetProjectConfigRequest *)request + callback:(FIRGetProjectConfigResponseCallback)callback { + [[self implementation] getProjectConfig:request callback:callback]; +} + ++ (void)setAccountInfo:(FIRSetAccountInfoRequest *)request + callback:(FIRSetAccountInfoResponseCallback)callback { + [[self implementation] setAccountInfo:request callback:callback]; +} + ++ (void)verifyAssertion:(FIRVerifyAssertionRequest *)request + callback:(FIRVerifyAssertionResponseCallback)callback { + [[self implementation] verifyAssertion:request callback:callback]; +} + ++ (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request + callback:(FIRVerifyCustomTokenResponseCallback)callback { + [[self implementation] verifyCustomToken:request callback:callback]; +} + ++ (void)verifyPassword:(FIRVerifyPasswordRequest *)request + callback:(FIRVerifyPasswordResponseCallback)callback { + [[self implementation] verifyPassword:request callback:callback]; +} + ++ (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback { + [[self implementation] emailLinkSignin:request callback:callback]; +} + ++ (void)secureToken:(FIRSecureTokenRequest *)request + callback:(FIRSecureTokenResponseCallback)callback { + [[self implementation] secureToken:request callback:callback]; +} + ++ (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request + callback:(FIRGetOOBConfirmationCodeResponseCallback)callback { + [[self implementation] getOOBConfirmationCode:request callback:callback]; +} + ++ (void)signUpNewUser:(FIRSignUpNewUserRequest *)request + callback:(FIRSignupNewUserCallback)callback { + [[self implementation] signUpNewUser:request callback:callback]; +} + ++ (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback { + [[self implementation] deleteAccount:request callback:callback]; +} + ++ (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request + callback:(FIRSignInWithGameCenterResponseCallback)callback { + [[self implementation] signInWithGameCenter:request callback:callback]; +} + +#if TARGET_OS_IOS ++ (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request + callback:(FIRSendVerificationCodeResponseCallback)callback { + [[self implementation] sendVerificationCode:request callback:callback]; +} + ++ (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request + callback:(FIRVerifyPhoneNumberResponseCallback)callback { + [[self implementation] verifyPhoneNumber:request callback:callback]; +} + ++ (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callback { + [[self implementation] verifyClient:request callback:callback]; +} +#endif + ++ (void)resetPassword:(FIRResetPasswordRequest *)request + callback:(FIRResetPasswordCallback)callback { + [[self implementation] resetPassword:request callback:callback]; +} + ++ (NSString *)authUserAgent { + return [NSString stringWithFormat:@"FirebaseAuth.iOS/%@ %@", FIRFirebaseVersion(), + GTMFetcherStandardUserAgentString(nil)]; +} + +@end + +@interface FIRAuthBackendRPCIssuerImplementation : NSObject +@end + +@implementation FIRAuthBackendRPCIssuerImplementation { + /** @var The session fetcher service. + */ + GTMSessionFetcherService *_fetcherService; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _fetcherService = [[GTMSessionFetcherService alloc] init]; + _fetcherService.userAgent = [FIRAuthBackend authUserAgent]; + _fetcherService.callbackQueue = FIRAuthGlobalWorkQueue(); + + // Avoid reusing the session to prevent + // https://github.com/firebase/firebase-ios-sdk/issues/1261 + _fetcherService.reuseSession = NO; + } + return self; +} + +- (void)asyncPostToURLWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + URL:(NSURL *)URL + body:(nullable NSData *)body + contentType:(NSString *)contentType + completionHandler: + (void (^)(NSData *_Nullable, NSError *_Nullable))handler { + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + [request setValue:contentType forHTTPHeaderField:@"Content-Type"]; + NSString *additionalFrameworkMarker = + requestConfiguration.additionalFrameworkMarker ?: kFirebaseAuthCoreFrameworkMarker; + NSString *clientVersion = [NSString + stringWithFormat:@"iOS/FirebaseSDK/%@/%@", FIRFirebaseVersion(), additionalFrameworkMarker]; + [request setValue:clientVersion forHTTPHeaderField:kClientVersionHeader]; + NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; + [request setValue:bundleID forHTTPHeaderField:kIosBundleIdentifierHeader]; + + NSArray *preferredLocalizations = [NSBundle mainBundle].preferredLocalizations; + if (preferredLocalizations.count) { + NSString *acceptLanguage = preferredLocalizations.firstObject; + [request setValue:acceptLanguage forHTTPHeaderField:@"Accept-Language"]; + } + NSString *languageCode = requestConfiguration.languageCode; + if (languageCode.length) { + [request setValue:languageCode forHTTPHeaderField:kFirebaseLocalHeader]; + } + GTMSessionFetcher *fetcher = [_fetcherService fetcherWithRequest:request]; + NSString *emulatorHostAndPort = requestConfiguration.emulatorHostAndPort; + if (emulatorHostAndPort) { + fetcher.allowLocalhostRequest = YES; + fetcher.allowedInsecureSchemes = @[ @"http" ]; + } + fetcher.bodyData = body; + [fetcher beginFetchWithCompletionHandler:handler]; +} + +@end + +@implementation FIRAuthBackendRPCImplementation + +- (instancetype)init { + self = [super init]; + if (self) { + _RPCIssuer = [[FIRAuthBackendRPCIssuerImplementation alloc] init]; + } + return self; +} + +- (void)createAuthURI:(FIRCreateAuthURIRequest *)request + callback:(FIRCreateAuthURIResponseCallback)callback { + FIRCreateAuthURIResponse *response = [[FIRCreateAuthURIResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)getAccountInfo:(FIRGetAccountInfoRequest *)request + callback:(FIRGetAccountInfoResponseCallback)callback { + FIRGetAccountInfoResponse *response = [[FIRGetAccountInfoResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)getProjectConfig:(FIRGetProjectConfigRequest *)request + callback:(FIRGetProjectConfigResponseCallback)callback { + FIRGetProjectConfigResponse *response = [[FIRGetProjectConfigResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)setAccountInfo:(FIRSetAccountInfoRequest *)request + callback:(FIRSetAccountInfoResponseCallback)callback { + FIRSetAccountInfoResponse *response = [[FIRSetAccountInfoResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)verifyAssertion:(FIRVerifyAssertionRequest *)request + callback:(FIRVerifyAssertionResponseCallback)callback { + FIRVerifyAssertionResponse *response = [[FIRVerifyAssertionResponse alloc] init]; + [self + postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + if (!response.IDToken && response.MFAInfo) { +#if TARGET_OS_IOS + NSMutableArray *multiFactorInfo = [NSMutableArray array]; + for (FIRAuthProtoMFAEnrollment *MFAEnrollment in response.MFAInfo) { + FIRPhoneMultiFactorInfo *info = + [[FIRPhoneMultiFactorInfo alloc] initWithProto:MFAEnrollment]; + [multiFactorInfo addObject:info]; + } + NSError *multiFactorRequiredError = [FIRAuthErrorUtils + secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential + hints:multiFactorInfo]; + callback(nil, multiFactorRequiredError); +#endif + } else { + callback(response, nil); + } + } + }]; +} + +- (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request + callback:(FIRVerifyCustomTokenResponseCallback)callback { + FIRVerifyCustomTokenResponse *response = [[FIRVerifyCustomTokenResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)verifyPassword:(FIRVerifyPasswordRequest *)request + callback:(FIRVerifyPasswordResponseCallback)callback { + FIRVerifyPasswordResponse *response = [[FIRVerifyPasswordResponse alloc] init]; + [self + postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + if (!response.IDToken && response.MFAInfo) { +#if TARGET_OS_IOS + NSMutableArray *multiFactorInfo = [NSMutableArray array]; + for (FIRAuthProtoMFAEnrollment *MFAEnrollment in response.MFAInfo) { + FIRPhoneMultiFactorInfo *info = + [[FIRPhoneMultiFactorInfo alloc] initWithProto:MFAEnrollment]; + [multiFactorInfo addObject:info]; + } + NSError *multiFactorRequiredError = [FIRAuthErrorUtils + secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential + hints:multiFactorInfo]; + callback(nil, multiFactorRequiredError); +#endif + } else { + callback(response, nil); + } + } + }]; +} + +- (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback { + FIREmailLinkSignInResponse *response = [[FIREmailLinkSignInResponse alloc] init]; + [self + postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + if (!response.IDToken && response.MFAInfo) { +#if TARGET_OS_IOS + NSMutableArray *multiFactorInfo = [NSMutableArray array]; + for (FIRAuthProtoMFAEnrollment *MFAEnrollment in response.MFAInfo) { + FIRPhoneMultiFactorInfo *info = + [[FIRPhoneMultiFactorInfo alloc] initWithProto:MFAEnrollment]; + [multiFactorInfo addObject:info]; + } + NSError *multiFactorRequiredError = [FIRAuthErrorUtils + secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential + hints:multiFactorInfo]; + callback(nil, multiFactorRequiredError); +#endif + } else { + callback(response, nil); + } + } + }]; +} + +- (void)secureToken:(FIRSecureTokenRequest *)request + callback:(FIRSecureTokenResponseCallback)callback { + FIRSecureTokenResponse *response = [[FIRSecureTokenResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request + callback:(FIRGetOOBConfirmationCodeResponseCallback)callback { + FIRGetOOBConfirmationCodeResponse *response = [[FIRGetOOBConfirmationCodeResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)signUpNewUser:(FIRSignUpNewUserRequest *)request + callback:(FIRSignupNewUserCallback)callback { + FIRSignUpNewUserResponse *response = [[FIRSignUpNewUserResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback { + FIRDeleteAccountResponse *response = [[FIRDeleteAccountResponse alloc] init]; + [self postWithRequest:request response:response callback:callback]; +} + +#if TARGET_OS_IOS +- (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request + callback:(FIRSendVerificationCodeResponseCallback)callback { + FIRSendVerificationCodeResponse *response = [[FIRSendVerificationCodeResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, error); + } + }]; +} + +- (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request + callback:(FIRVerifyPhoneNumberResponseCallback)callback { + FIRVerifyPhoneNumberResponse *response = [[FIRVerifyPhoneNumberResponse alloc] init]; + [self + postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + return; + } + // Check whether or not the successful response is actually the special case phone + // auth flow that returns a temporary proof and phone number. + if (response.phoneNumber.length && response.temporaryProof.length) { + FIRPhoneAuthCredential *credential = + [[FIRPhoneAuthCredential alloc] initWithTemporaryProof:response.temporaryProof + phoneNumber:response.phoneNumber + providerID:FIRPhoneAuthProviderID]; + callback(nil, [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:nil + credential:credential + email:nil]); + return; + } + callback(response, nil); + }]; +} + +- (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callback { + FIRVerifyClientResponse *response = [[FIRVerifyClientResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + return; + } + callback(response, nil); + }]; +} +#endif + +- (void)resetPassword:(FIRResetPasswordRequest *)request + callback:(FIRResetPasswordCallback)callback { + FIRResetPasswordResponse *response = [[FIRResetPasswordResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + return; + } + callback(response, nil); + }]; +} + +- (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request + callback:(FIRSignInWithGameCenterResponseCallback)callback { + FIRSignInWithGameCenterResponse *response = [[FIRSignInWithGameCenterResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + if (callback) { + callback(nil, error); + } + } else { + if (callback) { + callback(response, nil); + } + } + }]; +} + +#pragma mark - Generic RPC handling methods + +/** @fn postWithRequest:response:callback: + @brief Calls the RPC using HTTP POST. + @remarks Possible error responses: + @see FIRAuthInternalErrorCodeRPCRequestEncodingError + @see FIRAuthInternalErrorCodeJSONSerializationError + @see FIRAuthInternalErrorCodeNetworkError + @see FIRAuthInternalErrorCodeUnexpectedErrorResponse + @see FIRAuthInternalErrorCodeUnexpectedResponse + @see FIRAuthInternalErrorCodeRPCResponseDecodingError + @param request The request. + @param response The empty response to be filled. + @param callback The callback for both success and failure. + */ +- (void)postWithRequest:(id)request + response:(id)response + callback:(void (^)(NSError *_Nullable error))callback { + NSError *error; + NSData *bodyData; + if ([request containsPostBody]) { + id postBody = [request unencodedHTTPRequestBodyWithError:&error]; + if (!postBody) { + callback([FIRAuthErrorUtils RPCRequestEncodingErrorWithUnderlyingError:error]); + return; + } + + NSJSONWritingOptions JSONWritingOptions = 0; +#if DEBUG + JSONWritingOptions |= NSJSONWritingPrettyPrinted; +#endif + + if ([NSJSONSerialization isValidJSONObject:postBody]) { + bodyData = [NSJSONSerialization dataWithJSONObject:postBody + options:JSONWritingOptions + error:&error]; + if (!bodyData) { + // This is an untested case. This happens exclusively when there is an error in the + // framework implementation of dataWithJSONObject:options:error:. This shouldn't normally + // occur as isValidJSONObject: should return NO in any case we should encounter an error. + error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:error]; + } + } else { + error = [FIRAuthErrorUtils JSONSerializationErrorForUnencodableType]; + } + if (!bodyData) { + callback(error); + return; + } + } + + [_RPCIssuer + asyncPostToURLWithRequestConfiguration:[request requestConfiguration] + URL:[request requestURL] + body:bodyData + contentType:kJSONContentType + completionHandler:^(NSData *data, NSError *error) { + // If there is an error with no body data at all, then this must be a + // network error. + if (error && !data) { + callback([FIRAuthErrorUtils networkErrorWithUnderlyingError:error]); + return; + } + + // Try to decode the HTTP response data which may contain either a + // successful response or error message. + NSError *jsonError; + NSDictionary *dictionary = + [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:&jsonError]; + if (!dictionary) { + if (error) { + // We have an error, but we couldn't decode the body, so we have no + // additional information other than the raw response and the + // original NSError (the jsonError is infered by the error code + // (FIRAuthErrorCodeUnexpectedHTTPResponse, and is irrelevant.) + callback([FIRAuthErrorUtils + unexpectedErrorResponseWithData:data + underlyingError:error]); + } else { + // This is supposed to be a "successful" response, but we couldn't + // deserialize the body. + callback([FIRAuthErrorUtils unexpectedResponseWithData:data + underlyingError:jsonError]); + } + return; + } + if (![dictionary isKindOfClass:[NSDictionary class]]) { + if (error) { + callback([FIRAuthErrorUtils + unexpectedErrorResponseWithDeserializedResponse:dictionary + underlyingError:error]); + } else { + callback([FIRAuthErrorUtils + unexpectedResponseWithDeserializedResponse:dictionary]); + } + return; + } + + // At this point we either have an error with successfully decoded + // details in the body, or we have a response which must pass further + // validation before we know it's truly successful. We deal with the + // case where we have an error with successfully decoded error details + // first: + if (error) { + NSDictionary *errorDictionary = dictionary[kErrorKey]; + if ([errorDictionary isKindOfClass:[NSDictionary class]]) { + id errorMessage = errorDictionary[kErrorMessageKey]; + if ([errorMessage isKindOfClass:[NSString class]]) { + NSString *errorMessageString = (NSString *)errorMessage; + + // Contruct client error. + NSError *clientError = [[self class] + clientErrorWithServerErrorMessage:errorMessageString + errorDictionary:errorDictionary + response:response]; + if (clientError) { + callback(clientError); + return; + } + } + // Not a message we know, return the message directly. + if (errorMessage) { + NSError *unexpecterErrorResponse = [FIRAuthErrorUtils + unexpectedErrorResponseWithDeserializedResponse: + errorDictionary + underlyingError:error]; + callback(unexpecterErrorResponse); + return; + } + } + // No error message at all, return the decoded response. + callback([FIRAuthErrorUtils + unexpectedErrorResponseWithDeserializedResponse:dictionary + underlyingError:error]); + return; + } + + // Finally, we try to populate the response object with the JSON + // values. + if (![response setWithDictionary:dictionary error:&error]) { + callback([FIRAuthErrorUtils + RPCResponseDecodingErrorWithDeserializedResponse:dictionary + underlyingError:error]); + return; + } + // In case returnIDPCredential of a verifyAssertion request is set to + // @YES, the server may return a 200 with a response that may contain a + // server error. + if ([request isKindOfClass:[FIRVerifyAssertionRequest class]]) { + FIRVerifyAssertionRequest *verifyAssertionRequest = + (FIRVerifyAssertionRequest *)request; + if (verifyAssertionRequest.returnIDPCredential) { + NSString *errorMessage = + dictionary[kReturnIDPCredentialErrorMessageKey]; + if ([errorMessage isKindOfClass:[NSString class]]) { + NSString *errorString = (NSString *)errorMessage; + NSError *clientError = + [[self class] clientErrorWithServerErrorMessage:errorString + errorDictionary:@{} + response:response]; + if (clientError) { + callback(clientError); + return; + } + } + } + } + // Success! The response object originally passed in can be used by the + // caller. + callback(nil); + }]; +} + +/** @fn clientErrorWithServerErrorMessage:errorDictionary: + @brief Translates known server errors to client errors. + @param serverErrorMessage The error message from the server. + @param errorDictionary The error part of the response from the server. + @param response The response from the server RPC. + @return A client error, if any. + */ ++ (nullable NSError *)clientErrorWithServerErrorMessage:(NSString *)serverErrorMessage + errorDictionary:(NSDictionary *)errorDictionary + response:(id)response { + NSString *shortErrorMessage = serverErrorMessage; + NSString *serverDetailErrorMessage; + NSRange colonRange = [serverErrorMessage rangeOfString:@":"]; + if (colonRange.location != NSNotFound) { + shortErrorMessage = [serverErrorMessage substringToIndex:colonRange.location]; + shortErrorMessage = + [shortErrorMessage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + serverDetailErrorMessage = [serverErrorMessage substringFromIndex:colonRange.location + 1]; + serverDetailErrorMessage = [serverDetailErrorMessage + stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + } + + // Delegate the responsibility for constructing the client error to the response object, + // if possible. + SEL clientErrorWithServerErrorMessageSelector = @selector(clientErrorWithShortErrorMessage: + detailErrorMessage:); + if ([response respondsToSelector:clientErrorWithServerErrorMessageSelector]) { + NSError *error = [response clientErrorWithShortErrorMessage:shortErrorMessage + detailErrorMessage:serverDetailErrorMessage]; + if (error) { + return error; + } + } + + if ([shortErrorMessage isEqualToString:kUserNotFoundErrorMessage]) { + return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUserDeletedErrorMessage]) { + return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidLocalIDErrorMessage]) { + // This case shouldn't be necessary but it is for now: b/27908364 . + return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUserTokenExpiredErrorMessage]) { + return [FIRAuthErrorUtils userTokenExpiredErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kTooManyRequestsErrorMessage]) { + return [FIRAuthErrorUtils tooManyRequestsErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidCustomTokenErrorMessage]) { + return [FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kCustomTokenMismatch]) { + return [FIRAuthErrorUtils customTokenMistmatchErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidCredentialErrorMessage] || + [shortErrorMessage isEqualToString:kInvalidPendingToken]) { + return [FIRAuthErrorUtils invalidCredentialErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUserDisabledErrorMessage]) { + return [FIRAuthErrorUtils userDisabledErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kOperationNotAllowedErrorMessage]) { + return [FIRAuthErrorUtils operationNotAllowedErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kPasswordLoginDisabledErrorMessage]) { + return [FIRAuthErrorUtils operationNotAllowedErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kEmailAlreadyInUseErrorMessage]) { + return [FIRAuthErrorUtils emailAlreadyInUseErrorWithEmail:nil]; + } + + if ([shortErrorMessage isEqualToString:kInvalidEmailErrorMessage]) { + return [FIRAuthErrorUtils invalidEmailErrorWithMessage:serverDetailErrorMessage]; + } + + // "INVALID_IDENTIFIER" can be returned by createAuthURI RPC. Considering email addresses are + // currently the only identifiers, we surface the FIRAuthErrorCodeInvalidEmail error code in this + // case. + if ([shortErrorMessage isEqualToString:kInvalidIdentifierErrorMessage]) { + return [FIRAuthErrorUtils invalidEmailErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kWrongPasswordErrorMessage]) { + return [FIRAuthErrorUtils wrongPasswordErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kCredentialTooOldErrorMessage]) { + return [FIRAuthErrorUtils requiresRecentLoginErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidUserTokenErrorMessage]) { + return [FIRAuthErrorUtils invalidUserTokenErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kFederatedUserIDAlreadyLinkedMessage]) { + FIROAuthCredential *credential; + NSString *email; + if ([response isKindOfClass:[FIRVerifyAssertionResponse class]]) { + FIRVerifyAssertionResponse *verifyAssertion = (FIRVerifyAssertionResponse *)response; + credential = [[FIROAuthCredential alloc] initWithVerifyAssertionResponse:verifyAssertion]; + email = verifyAssertion.email; + } + return [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:serverDetailErrorMessage + credential:credential + email:email]; + } + + if ([shortErrorMessage isEqualToString:kWeakPasswordErrorMessagePrefix]) { + return [FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kExpiredActionCodeErrorMessage]) { + return [FIRAuthErrorUtils expiredActionCodeErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidActionCodeErrorMessage]) { + return [FIRAuthErrorUtils invalidActionCodeErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingEmailErrorMessage]) { + return [FIRAuthErrorUtils missingEmailErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidSenderEmailErrorMessage]) { + return [FIRAuthErrorUtils invalidSenderErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidMessagePayloadErrorMessage]) { + return [FIRAuthErrorUtils invalidMessagePayloadErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidRecipientEmailErrorMessage]) { + return [FIRAuthErrorUtils invalidRecipientEmailErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingIosBundleIDErrorMessage]) { + return [FIRAuthErrorUtils missingIosBundleIDErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingAndroidPackageNameErrorMessage]) { + return [FIRAuthErrorUtils missingAndroidPackageNameErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUnauthorizedDomainErrorMessage]) { + return [FIRAuthErrorUtils unauthorizedDomainErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidContinueURIErrorMessage]) { + return [FIRAuthErrorUtils invalidContinueURIErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidProviderIDErrorMessage]) { + return [FIRAuthErrorUtils invalidProviderIDErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidDynamicLinkDomainErrorMessage]) { + return [FIRAuthErrorUtils invalidDynamicLinkDomainErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingContinueURIErrorMessage]) { + return [FIRAuthErrorUtils missingContinueURIErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidPhoneNumberErrorMessage]) { + return [FIRAuthErrorUtils invalidPhoneNumberErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidSessionInfoErrorMessage]) { + return [FIRAuthErrorUtils invalidVerificationIDErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidVerificationCodeErrorMessage]) { + return [FIRAuthErrorUtils invalidVerificationCodeErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kSessionExpiredErrorMessage]) { + return [FIRAuthErrorUtils sessionExpiredErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingAppTokenErrorMessage]) { + return [FIRAuthErrorUtils missingAppTokenErrorWithUnderlyingError:nil]; + } + + if ([shortErrorMessage isEqualToString:kMissingAppCredentialErrorMessage]) { + return [FIRAuthErrorUtils missingAppCredentialWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidAppCredentialErrorMessage]) { + return [FIRAuthErrorUtils invalidAppCredentialWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kQuoutaExceededErrorMessage]) { + return [FIRAuthErrorUtils quotaExceededErrorWithMessage:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kAppNotVerifiedErrorMessage]) { + return [FIRAuthErrorUtils appNotVerifiedErrorWithMessage:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingClientIdentifier]) { + return [FIRAuthErrorUtils missingClientIdentifierErrorWithMessage:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kCaptchaCheckFailedErrorMessage]) { + return [FIRAuthErrorUtils captchaCheckFailedErrorWithMessage:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingOrInvalidNonceErrorMessage]) { + return [FIRAuthErrorUtils missingOrInvalidNonceErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingMFAPendingCredentialErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMissingMultiFactorSession + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingMFAEnrollmentIDErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMissingMultiFactorInfo + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidMFAPendingCredentialErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeInvalidMultiFactorSession + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMFAEnrollmentNotFoundErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMultiFactorInfoNotFound + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kAdminOnlyOperationErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeAdminRestrictedOperation + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUnverifiedEmailErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeUnverifiedEmail + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kSecondFactorExistsErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeSecondFactorAlreadyEnrolled + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kSecondFactorLimitExceededErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMaximumSecondFactorCountExceeded + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUnsupportedFirstFactorErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeUnsupportedFirstFactor + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kEmailChangeNeedsVerificationErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeEmailChangeNeedsVerification + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kTenantIDMismatch]) { + return [FIRAuthErrorUtils tenantIDMismatchError]; + } + + if ([shortErrorMessage isEqualToString:kUnsupportedTenantOperation]) { + return [FIRAuthErrorUtils unsupportedTenantOperationError]; + } + + // In this case we handle an error that might be specified in the underlying errors dictionary, + // the error message in determined based on the @c reason key in the dictionary. + if (errorDictionary[kErrorsKey]) { + // Check for underlying error with reason = keyInvalid; + id underlyingErrors = errorDictionary[kErrorsKey]; + if ([underlyingErrors isKindOfClass:[NSArray class]]) { + NSArray *underlyingErrorsArray = (NSArray *)underlyingErrors; + for (id underlyingError in underlyingErrorsArray) { + if ([underlyingError isKindOfClass:[NSDictionary class]]) { + NSDictionary *underlyingErrorDictionary = (NSDictionary *)underlyingError; + NSString *reason = underlyingErrorDictionary[kReasonKey]; + if ([reason hasPrefix:kInvalidKeyReasonValue]) { + return [FIRAuthErrorUtils invalidAPIKeyError]; + } + if ([reason isEqualToString:kAppNotAuthorizedReasonValue]) { + return [FIRAuthErrorUtils appNotAuthorizedError]; + } + } + } + } + } + return nil; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h new file mode 100644 index 0000000..9ca4f44 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h @@ -0,0 +1,57 @@ +/* + * 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 + +@class FIRAuthRequestConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/** @protocol FIRAuthRPCRequest + @brief The generic interface for an RPC request needed by @c FIRAuthBackend. + */ +@protocol FIRAuthRPCRequest + +/** @fn requestURL + @brief Gets the request's full URL. + */ +- (NSURL *)requestURL; + +@optional + +/** @fn containsPostBody + @brief Returns whether the request contains a post body or not. Requests without a post body + are get requests. + @remarks The default implementation returns YES. + */ +- (BOOL)containsPostBody; + +/** @fn UnencodedHTTPRequestBodyWithError: + @brief Creates unencoded HTTP body representing the request. + @param error An out field for an error which occurred constructing the request. + @return The HTTP body data representing the request before any encoding, or nil for error. + */ +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error; + +/** @fn requestConfiguration + @brief Obtains the request configurations if available. + @return Returns the request configurations. + */ +- (FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h new file mode 100644 index 0000000..0fe981a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h @@ -0,0 +1,48 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @protocol FIRAuthRPCResponse + @brief The generic interface for an RPC response needed by @c FIRAuthBackend. + */ +@protocol FIRAuthRPCResponse + +/** @fn setFieldsWithDictionary:error: + @brief Sets the response instance from the decoded JSON response. + @param dictionary The dictionary decoded from HTTP JSON response. + @param error An out field for an error which occurred constructing the request. + @return Whether the operation was successful or not. + */ +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error; + +@optional + +/** @fn clientErrorWithshortErrorMessage:detailErrorMessage + @brief This optional method allows response classes to create client errors given a short error + message and a detail error message from the server. + @param shortErrorMessage The short error message from the server. + @param detailErrorMessage The detailed error message from the server. + @return A client error, if any. + */ +- (nullable NSError *)clientErrorWithShortErrorMessage:(NSString *)shortErrorMessage + detailErrorMessage:(nullable NSString *)detailErrorMessage; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h new file mode 100644 index 0000000..46a42c5 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h @@ -0,0 +1,57 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthRequestConfiguration + @brief Defines configurations to be added to a request to Firebase Auth's backend. + */ +@interface FIRAuthRequestConfiguration : NSObject + +/** @property APIKey + @brief The Firebase Auth API key used in the request. + */ +@property(nonatomic, copy, readonly) NSString *APIKey; + +/** @property LanguageCode + @brief The language code used in the request. + */ +@property(nonatomic, copy, nullable) NSString *languageCode; + +/** @property additionalFrameworkMarker + @brief Additional framework marker that will be added as part of the header of every request. + */ +@property(nonatomic, copy, nullable) NSString *additionalFrameworkMarker; + +/** @property emulatorHostAndPort + @brief If set, the local emulator host and port to point to instead of the remote backend. + */ +@property(nonatomic, copy, nullable) NSString *emulatorHostAndPort; + +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithRequestClass:APIKey:authLanguage: + @brief Designated initializer. + @param APIKey The API key to be used in the request. + */ +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey NS_DESIGNATED_INITIALIZER; +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.m new file mode 100644 index 0000000..40996e5 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" + +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthRequestConfiguration + +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey { + self = [super init]; + if (self) { + _APIKey = [APIKey copy]; + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h new file mode 100644 index 0000000..b021d53 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h @@ -0,0 +1,76 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" + +@class FIRAuthRequestConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRIdentityToolkitRequest + @brief Represents a request to an identity toolkit endpoint. + */ +@interface FIRIdentityToolkitRequest : NSObject + +/** @property endpoint + @brief Gets the RPC's endpoint. + */ +@property(nonatomic, copy, readonly) NSString *endpoint; + +/** @property APIKey + @brief Gets the client's API key used for the request. + */ +@property(nonatomic, copy, readonly) NSString *APIKey; + +/** @property tenantID + @brief The tenant ID of the request. nil if none is available. + */ +@property(nonatomic, copy, readonly, nullable) NSString *tenantID; + +/** @fn init + @brief Please use initWithEndpoint:APIKey: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithEndpoint:APIKey: + @brief Designated initializer. + @param endpoint The endpoint name. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + useIdentityPlatform:(BOOL)useIdentityPlatform + useStaging:(BOOL)useStaging; + +/** @fn requestURL + @brief Gets the request's full URL. + */ +- (NSURL *)requestURL; + +/** @fn requestConfiguration + @brief Gets the request's configuration. + */ +- (FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.m new file mode 100644 index 0000000..a98ebbf --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.m @@ -0,0 +1,140 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" + +NS_ASSUME_NONNULL_BEGIN + +static NSString *const kHttpsProtocol = @"https:"; +static NSString *const kHttpProtocol = @"http:"; + +static NSString *const kFirebaseAuthAPIURLFormat = + @"%@//%@/identitytoolkit/v3/relyingparty/%@?key=%@"; +static NSString *const kIdentityPlatformAPIURLFormat = @"%@//%@/v2/%@?key=%@"; +static NSString *const kEmulatorHostAndPrefixFormat = @"%@/%@"; + +static NSString *gAPIHost = @"www.googleapis.com"; + +static NSString *kFirebaseAuthAPIHost = @"www.googleapis.com"; +static NSString *kIdentityPlatformAPIHost = @"identitytoolkit.googleapis.com"; + +static NSString *kFirebaseAuthStagingAPIHost = @"staging-www.sandbox.googleapis.com"; +static NSString *kIdentityPlatformStagingAPIHost = + @"staging-identitytoolkit.sandbox.googleapis.com"; + +@implementation FIRIdentityToolkitRequest { + FIRAuthRequestConfiguration *_requestConfiguration; + + BOOL _useIdentityPlatform; + + BOOL _useStaging; +} + +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super init]; + if (self) { + _APIKey = [requestConfiguration.APIKey copy]; + _endpoint = [endpoint copy]; + _requestConfiguration = requestConfiguration; + _useIdentityPlatform = NO; + _useStaging = NO; + + // Automatically set the tenant ID. If the request is initialized before FIRAuth is configured, + // set tenant ID to nil. + @try { + _tenantID = [FIRAuth auth].tenantID; + } @catch (NSException *e) { + _tenantID = nil; + } + } + return self; +} + +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + useIdentityPlatform:(BOOL)useIdentityPlatform + useStaging:(BOOL)useStaging { + self = [self initWithEndpoint:endpoint requestConfiguration:requestConfiguration]; + if (self) { + _useIdentityPlatform = useIdentityPlatform; + _useStaging = useStaging; + } + return self; +} + +- (BOOL)containsPostBody { + return YES; +} + +- (NSURL *)requestURL { + NSString *apiURLFormat; + NSString *apiProtocol; + NSString *apiHostAndPathPrefix; + + NSString *emulatorHostAndPort = _requestConfiguration.emulatorHostAndPort; + + if (_useIdentityPlatform) { + apiURLFormat = kIdentityPlatformAPIURLFormat; + apiProtocol = kHttpsProtocol; + if (emulatorHostAndPort) { + apiProtocol = kHttpProtocol; + apiHostAndPathPrefix = + [NSString stringWithFormat:kEmulatorHostAndPrefixFormat, emulatorHostAndPort, + kIdentityPlatformAPIHost]; + } else if (_useStaging) { + apiHostAndPathPrefix = kIdentityPlatformStagingAPIHost; + } else { + apiHostAndPathPrefix = kIdentityPlatformAPIHost; + } + } else { + apiURLFormat = kFirebaseAuthAPIURLFormat; + apiProtocol = kHttpsProtocol; + if (emulatorHostAndPort) { + apiProtocol = kHttpProtocol; + apiHostAndPathPrefix = [NSString + stringWithFormat:kEmulatorHostAndPrefixFormat, emulatorHostAndPort, kFirebaseAuthAPIHost]; + } else if (_useStaging) { + apiHostAndPathPrefix = kFirebaseAuthStagingAPIHost; + } else { + apiHostAndPathPrefix = kFirebaseAuthAPIHost; + } + } + NSString *URLString = [NSString + stringWithFormat:apiURLFormat, apiProtocol, apiHostAndPathPrefix, _endpoint, _APIKey]; + NSURL *URL = [NSURL URLWithString:URLString]; + return URL; +} + +- (FIRAuthRequestConfiguration *)requestConfiguration { + return _requestConfiguration; +} + +#pragma mark - Internal API for development + ++ (NSString *)host { + return gAPIHost; +} + ++ (void)setHost:(NSString *)host { + gAPIHost = host; +} + +NS_ASSUME_NONNULL_END + +@end diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h new file mode 100644 index 0000000..633ffa9 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h @@ -0,0 +1,88 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRCreateAuthURIRequest + @brief Represents the parameters for the createAuthUri endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/createAuthUri + */ +@interface FIRCreateAuthURIRequest : FIRIdentityToolkitRequest + +/** @property identifier + @brief The email or federated ID of the user. + */ +@property(nonatomic, copy) NSString *identifier; + +/** @property continueURI + @brief The URI to which the IDP redirects the user after the federated login flow. + */ +@property(nonatomic, copy) NSString *continueURI; + +/** @property openIDRealm + @brief Optional realm for OpenID protocol. The sub string "scheme://domain:port" of the param + "continueUri" is used if this is not set. + */ +@property(nonatomic, copy, nullable) NSString *openIDRealm; + +/** @property providerID + @brief The IdP ID. For white listed IdPs it's a short domain name e.g. google.com, aol.com, + live.net and yahoo.com. For other OpenID IdPs it's the OP identifier. + */ +@property(nonatomic, copy, nullable) NSString *providerID; + +/** @property clientID + @brief The relying party OAuth client ID. + */ +@property(nonatomic, copy, nullable) NSString *clientID; + +/** @property context + @brief The opaque value used by the client to maintain context info between the authentication + request and the IDP callback. + */ +@property(nonatomic, copy, nullable) NSString *context; + +/** @property appID + @brief The iOS client application's bundle identifier. + */ +@property(nonatomic, copy, nullable) NSString *appID; + +/** @fn initWithEndpoint:requestConfiguration:requestConfiguration. + @brief Please use initWithIdentifier:continueURI:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithIdentifier:continueURI:requestConfiguration: + @brief Designated initializer. + @param identifier The email or federated ID of the user. + @param continueURI The URI to which the IDP redirects the user after the federated login flow. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithIdentifier:(NSString *)identifier + continueURI:(NSString *)continueURI + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.m new file mode 100644 index 0000000..8a7baa6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.m @@ -0,0 +1,105 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kCreateAuthURIEndpoint + @brief The "createAuthUri" endpoint. + */ +static NSString *const kCreateAuthURIEndpoint = @"createAuthUri"; + +/** @var kProviderIDKey + @brief The key for the "providerId" value in the request. + */ +static NSString *const kProviderIDKey = @"providerId"; + +/** @var kIdentifierKey + @brief The key for the "identifier" value in the request. + */ +static NSString *const kIdentifierKey = @"identifier"; + +/** @var kContinueURIKey + @brief The key for the "continueUri" value in the request. + */ +static NSString *const kContinueURIKey = @"continueUri"; + +/** @var kOpenIDRealmKey + @brief The key for the "openidRealm" value in the request. + */ +static NSString *const kOpenIDRealmKey = @"openidRealm"; + +/** @var kClientIDKey + @brief The key for the "clientId" value in the request. + */ +static NSString *const kClientIDKey = @"clientId"; + +/** @var kContextKey + @brief The key for the "context" value in the request. + */ +static NSString *const kContextKey = @"context"; + +/** @var kAppIDKey + @brief The key for the "appId" value in the request. + */ +static NSString *const kAppIDKey = @"appId"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRCreateAuthURIRequest + +- (nullable instancetype)initWithIdentifier:(NSString *)identifier + continueURI:(NSString *)continueURI + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kCreateAuthURIEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _identifier = [identifier copy]; + _continueURI = [continueURI copy]; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = + [@{kIdentifierKey : _identifier, kContinueURIKey : _continueURI} mutableCopy]; + if (_providerID) { + postBody[kProviderIDKey] = _providerID; + } + if (_openIDRealm) { + postBody[kOpenIDRealmKey] = _openIDRealm; + } + if (_clientID) { + postBody[kClientIDKey] = _clientID; + } + if (_context) { + postBody[kContextKey] = _context; + } + if (_appID) { + postBody[kAppIDKey] = _appID; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h new file mode 100644 index 0000000..79c5ea7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h @@ -0,0 +1,61 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRCreateAuthURIResponse + @brief Represents the parameters for the createAuthUri endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/createAuthUri + */ +@interface FIRCreateAuthURIResponse : NSObject + +/** @property authUri + @brief The URI used by the IDP to authenticate the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *authURI; + +/** @property registered + @brief Whether the user is registered if the identifier is an email. + */ +@property(nonatomic, assign, readonly) BOOL registered; + +/** @property providerId + @brief The provider ID of the auth URI. + */ +@property(nonatomic, strong, readonly, nullable) NSString *providerID; + +/** @property forExistingProvider + @brief True if the authUri is for user's existing provider. + */ +@property(nonatomic, assign, readonly) BOOL forExistingProvider; + +/** @property allProviders + @brief A list of provider IDs the passed @c identifier could use to sign in with. + */ +@property(nonatomic, copy, readonly, nullable) NSArray *allProviders; + +/** @property signinMethods + @brief A list of sign-in methods available for the passed @c identifier. + */ +@property(nonatomic, copy, readonly, nullable) NSArray *signinMethods; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.m new file mode 100644 index 0000000..bf422c9 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRCreateAuthURIResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _providerID = [dictionary[@"providerId"] copy]; + _authURI = [dictionary[@"authUri"] copy]; + _registered = [dictionary[@"registered"] boolValue]; + _forExistingProvider = [dictionary[@"forExistingProvider"] boolValue]; + _allProviders = [dictionary[@"allProviders"] copy]; + _signinMethods = [dictionary[@"signinMethods"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h new file mode 100644 index 0000000..b6b6e40 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h @@ -0,0 +1,50 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRDeleteAccountRequest + @brief Represents the parameters for the deleteAccount endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/deleteAccount + */ +@interface FIRDeleteAccountRequest : FIRIdentityToolkitRequest + +/** @fn initWithEndpoint:requestConfiguration:requestConfiguration. + @brief Please use initWitLocalID:accessToken:requestConfiguration instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWitLocalID:accessToken:requestConfiguration. + @brief Designated initializer. + @param localID The local ID. + @param accessToken The access token. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWitLocalID:(NSString *)localID + accessToken:(NSString *)accessToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.m new file mode 100644 index 0000000..8bc6c52 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.m @@ -0,0 +1,69 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kCreateAuthURIEndpoint + @brief The "deleteAccount" endpoint. + */ +static NSString *const kDeleteAccountEndpoint = @"deleteAccount"; + +/** @var kIDTokenKey + @brief The key for the "idToken" value in the request. This is actually the STS Access Token, + despite it's confusing (backwards compatiable) parameter name. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kLocalIDKey + @brief The key for the "localID" value in the request. + */ +static NSString *const kLocalIDKey = @"localId"; + +@implementation FIRDeleteAccountRequest { + /** @var _accessToken + @brief The STS Access Token of the authenticated user. + */ + NSString *_accessToken; + + /** @var _localID + @brief The localID of the user. + */ + NSString *_localID; +} + +- (nullable instancetype)initWitLocalID:(NSString *)localID + accessToken:(NSString *)accessToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kDeleteAccountEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _localID = [localID copy]; + _accessToken = [accessToken copy]; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + postBody[kIDTokenKey] = _accessToken; + postBody[kLocalIDKey] = _localID; + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h new file mode 100644 index 0000000..bc4d0d9 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h @@ -0,0 +1,30 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRDeleteAccountResponse + @brief Represents the response from the deleteAccount endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/deleteAccount + */ +@interface FIRDeleteAccountResponse : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.m new file mode 100644 index 0000000..fba1b6b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.m @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRDeleteAccountResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h new file mode 100644 index 0000000..752ffb4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h @@ -0,0 +1,66 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIREmailLinkSignInRequest + @brief Represents the parameters for the emailLinkSignin endpoint. + */ +@interface FIREmailLinkSignInRequest : FIRIdentityToolkitRequest + +#pragma mark - Components of "postBody" + +/** @property email + @brief The email identifier used to complete the email link sign-in. + */ +@property(nonatomic, copy, readonly) NSString *email; + +/** @property oobCode + @brief The OOB code used to complete the email link sign-in flow. + */ +@property(nonatomic, copy, readonly) NSString *oobCode; + +/** @property IDToken + @brief The ID Token code potentially used to complete the email link sign-in flow. + */ +@property(nonatomic, copy) NSString *IDToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithProviderID:requestConfifuration instead. + */ +- (instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration NS_UNAVAILABLE; + +/** @fn initWithProviderID:requestConfifuration + @brief Designated initializer. + @param email The email identifier used to complete hte email link sign-in flow. + @param oobCode The OOB code used to complete the email link sign-in flow. + @param requestConfiguration An object containing configurations to be added to the request. + + */ +- (instancetype)initWithEmail:(NSString *)email + oobCode:(NSString *)oobCode + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.m new file mode 100644 index 0000000..5ce4522 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.m @@ -0,0 +1,82 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kEmailLinkSigninEndpoint + @brief The "EmailLinkSignin" endpoint. + */ +static NSString *const kEmailLinkSigninEndpoint = @"emailLinkSignin"; + +/** @var kEmailKey + @brief The key for the "identifier" value in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kEmailLinkKey + @brief The key for the "emailLink" value in the request. + */ +static NSString *const kOOBCodeKey = @"oobCode"; + +/** @var kIDTokenKey + @brief The key for the "IDToken" value in the request. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kPostBodyKey + @brief The key for the "postBody" value in the request. + */ +static NSString *const kPostBodyKey = @"postBody"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIREmailLinkSignInRequest + +- (instancetype)initWithEmail:(NSString *)email + oobCode:(NSString *)oobCode + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kEmailLinkSigninEndpoint + requestConfiguration:requestConfiguration]; + if (self) { + _email = email; + _oobCode = oobCode; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [@{ + kEmailKey : _email, + kOOBCodeKey : _oobCode, + } mutableCopy]; + + if (_IDToken) { + postBody[kIDTokenKey] = _IDToken; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h new file mode 100644 index 0000000..767ec5f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h @@ -0,0 +1,71 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyAssertionResponse + @brief Represents the response from the emailLinkSignin endpoint. + */ +@interface FIREmailLinkSignInResponse : NSObject + +/** @property IDToken + @brief The ID token in the email link sign-in response. + */ +@property(nonatomic, copy, readonly) NSString *IDToken; + +/** @property email + @brief The email returned by the IdP. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property refreshToken + @brief The refreshToken returned by the server. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property localID + @brief The Firebase Auth user ID. + */ +@property(nonatomic, strong, readonly, nullable) NSString *localID; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property isNewUser + @brief Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +/** @property MFAPendingCredential + @brief An opaque string that functions as proof that the user has successfully passed the first + factor check. +*/ +@property(nonatomic, strong, readonly, nullable) NSString *MFAPendingCredential; + +/** @property MFAInfo + @brief Info on which multi-factor authentication providers are enabled. +*/ +@property(nonatomic, strong, readonly, nullable) NSArray *MFAInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.m new file mode 100644 index 0000000..5ca8882 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.m @@ -0,0 +1,50 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIREmailLinkSignInResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _localID = [dictionary[@"localId"] copy]; + _email = [dictionary[@"email"] copy]; + _IDToken = [dictionary[@"idToken"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + if (dictionary[@"mfaInfo"] != nil) { + NSMutableArray *MFAInfo = [NSMutableArray array]; + NSArray *MFAInfoDataArray = dictionary[@"mfaInfo"]; + for (NSDictionary *MFAInfoData in MFAInfoDataArray) { + FIRAuthProtoMFAEnrollment *MFAEnrollment = + [[FIRAuthProtoMFAEnrollment alloc] initWithDictionary:MFAInfoData]; + [MFAInfo addObject:MFAEnrollment]; + } + _MFAInfo = MFAInfo; + } + _MFAPendingCredential = [dictionary[@"mfaPendingCredential"] copy]; + + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h new file mode 100644 index 0000000..7d78500 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h @@ -0,0 +1,53 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGetAccountInfoRequest + @brief Represents the parameters for the getAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo + */ +@interface FIRGetAccountInfoRequest : FIRIdentityToolkitRequest + +/** @property accessToken + @brief The STS Access Token for the authenticated user. + */ +@property(nonatomic, copy) NSString *accessToken; + +/** @fn initWithEndpoint:requestConfiguration:requestConfiguration + @brief Please use initWithAccessToken:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithAccessToken:requestConfiguration + @brief Designated initializer. + @param accessToken The Access Token of the authenticated user. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithAccessToken:(NSString *)accessToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.m new file mode 100644 index 0000000..db86f93 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.m @@ -0,0 +1,49 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kGetAccountInfoEndpoint + @brief The "getAccountInfo" endpoint. + */ +static NSString *const kGetAccountInfoEndpoint = @"getAccountInfo"; + +/** @var kIDTokenKey + @brief The key for the "idToken" value in the request. This is actually the STS Access Token, + despite it's confusing (backwards compatiable) parameter name. + */ +static NSString *const kIDTokenKey = @"idToken"; + +@implementation FIRGetAccountInfoRequest + +- (nullable instancetype)initWithAccessToken:(NSString *)accessToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kGetAccountInfoEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _accessToken = [accessToken copy]; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + return @{kIDTokenKey : _accessToken}; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h new file mode 100644 index 0000000..14e7f88 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h @@ -0,0 +1,158 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGetAccountInfoResponseProviderUserInfo + @brief Represents the provider user info part of the response from the getAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo + */ +@interface FIRGetAccountInfoResponseProviderUserInfo : NSObject + +/** @property providerID + @brief The ID of the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *providerID; + +/** @property displayName + @brief The user's display name at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property photoURL + @brief The user's photo URL at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSURL *photoURL; + +/** @property federatedID + @brief The user's identifier at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *federatedID; + +/** @property email + @brief The user's email at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property phoneNumber + @brief A phone number associated with the user. + */ +@property(nonatomic, readonly, nullable) NSString *phoneNumber; + +/** @fn init + @brief Please use initWithDictionary: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithAPIKey: + @brief Designated initializer. + @param dictionary The provider user info data from endpoint. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER; + +@end + +/** @class FIRGetAccountInfoResponseUser + @brief Represents the firebase user info part of the response from the getAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo + */ +@interface FIRGetAccountInfoResponseUser : NSObject + +/** @property localID + @brief The ID of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *localID; + +/** @property email + @brief The email or the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property emailVerified + @brief Whether the email has been verified. + */ +@property(nonatomic, assign, readonly) BOOL emailVerified; + +/** @property displayName + @brief The display name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property photoURL + @brief The user's photo URL. + */ +@property(nonatomic, strong, readonly, nullable) NSURL *photoURL; + +/** @property creationDate + @brief The user's creation date. + */ +@property(nonatomic, strong, readonly, nullable) NSDate *creationDate; + +/** @property lastSignInDate + @brief The user's last login date. + */ +@property(nonatomic, strong, readonly, nullable) NSDate *lastLoginDate; + +/** @property providerUserInfo + @brief The user's profiles at the associated identity providers. + */ +@property(nonatomic, strong, readonly, nullable) + NSArray *providerUserInfo; + +/** @property passwordHash + @brief Information about user's password. + @remarks This is not necessarily the hash of user's actual password. + */ +@property(nonatomic, strong, readonly, nullable) NSString *passwordHash; + +/** @property phoneNumber + @brief A phone number associated with the user. + */ +@property(nonatomic, readonly, nullable) NSString *phoneNumber; + +@property(nonatomic, strong, readonly, nullable) + NSArray *MFAEnrollments; + +/** @fn init + @brief Please use initWithDictionary: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithAPIKey: + @brief Designated initializer. + @param dictionary The provider user info data from endpoint. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER; + +@end + +/** @class FIRGetAccountInfoResponse + @brief Represents the response from the setAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo + */ +@interface FIRGetAccountInfoResponse : NSObject + +/** @property providerUserInfo + @brief The requested users' profiles. + */ +@property(nonatomic, strong, readonly, nullable) NSArray *users; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.m new file mode 100644 index 0000000..6b812bd --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.m @@ -0,0 +1,117 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h" + +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kErrorKey + @brief The key for the "error" value in JSON responses from the server. + */ +static NSString *const kErrorKey = @"error"; + +@implementation FIRGetAccountInfoResponseProviderUserInfo + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + _providerID = [dictionary[@"providerId"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + NSString *photoURL = dictionary[@"photoUrl"]; + if (photoURL) { + _photoURL = [NSURL URLWithString:photoURL]; + } + _federatedID = [dictionary[@"federatedId"] copy]; + _email = [dictionary[@"email"] copy]; + _phoneNumber = [dictionary[@"phoneNumber"] copy]; + } + return self; +} + +@end + +@implementation FIRGetAccountInfoResponseUser + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + NSArray *providerUserInfoData = dictionary[@"providerUserInfo"]; + if (providerUserInfoData) { + NSMutableArray *providerUserInfoArray = + [NSMutableArray arrayWithCapacity:providerUserInfoData.count]; + for (NSDictionary *dictionary in providerUserInfoData) { + [providerUserInfoArray addObject:[[FIRGetAccountInfoResponseProviderUserInfo alloc] + initWithDictionary:dictionary]]; + } + _providerUserInfo = [providerUserInfoArray copy]; + } + _localID = [dictionary[@"localId"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + _email = [dictionary[@"email"] copy]; + NSString *photoURL = dictionary[@"photoUrl"]; + if (photoURL) { + _photoURL = [NSURL URLWithString:photoURL]; + } + if ([dictionary[@"createdAt"] isKindOfClass:[NSString class]]) { + // Divide by 1000 in order to convert miliseconds to seconds. + NSTimeInterval creationDateTimeInterval = [dictionary[@"createdAt"] doubleValue] / 1000; + _creationDate = [NSDate dateWithTimeIntervalSince1970:creationDateTimeInterval]; + } + if ([dictionary[@"lastLoginAt"] isKindOfClass:[NSString class]]) { + // Divide by 1000 in order to convert miliseconds to seconds + NSTimeInterval creationDateTimeInterval = [dictionary[@"lastLoginAt"] doubleValue] / 1000; + _lastLoginDate = [NSDate dateWithTimeIntervalSince1970:creationDateTimeInterval]; + } + _emailVerified = [dictionary[@"emailVerified"] boolValue]; + _passwordHash = [dictionary[@"passwordHash"] copy]; + _phoneNumber = [dictionary[@"phoneNumber"] copy]; + NSArray *MFAEnrollmentData = dictionary[@"mfaInfo"]; + if (MFAEnrollmentData) { + NSMutableArray *MFAEnrollments = + [NSMutableArray arrayWithCapacity:MFAEnrollmentData.count]; + for (NSDictionary *dictionary in MFAEnrollmentData) { + [MFAEnrollments + addObject:[[FIRAuthProtoMFAEnrollment alloc] initWithDictionary:dictionary]]; + } + _MFAEnrollments = [MFAEnrollments copy]; + } + } + return self; +} + +@end + +@implementation FIRGetAccountInfoResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + NSArray *usersData = dictionary[@"users"]; + // The client side never sends a getAccountInfo request with multiple localID, so only one user + // data is expected in the response. + if (![usersData isKindOfClass:[NSArray class]] || usersData.count != 1) { + if (error) { + *error = [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary]; + } + return NO; + } + _users = @[ [[FIRGetAccountInfoResponseUser alloc] initWithDictionary:usersData.firstObject] ]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h new file mode 100644 index 0000000..dc48a3e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h @@ -0,0 +1,178 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +@class FIRActionCodeSettings; + +NS_ASSUME_NONNULL_BEGIN + +/** @enum FIRGetOOBConfirmationCodeRequestType + @brief Types of OOB Confirmation Code requests. + */ +typedef NS_ENUM(NSInteger, FIRGetOOBConfirmationCodeRequestType) { + /** @var FIRGetOOBConfirmationCodeRequestTypePasswordReset + @brief Requests a password reset code. + */ + FIRGetOOBConfirmationCodeRequestTypePasswordReset, + + /** @var FIRGetOOBConfirmationCodeRequestTypeVerifyEmail + @brief Requests an email verification code. + */ + FIRGetOOBConfirmationCodeRequestTypeVerifyEmail, + + /** @var FIRGetOOBConfirmationCodeRequestTypeEmailLink + @brief Requests an email sign-in link. + */ + FIRGetOOBConfirmationCodeRequestTypeEmailLink, + + /** @var FIRGetOOBConfirmationCodeRequestTypeVerifyBeforeUpdateEmail + @brief Requests an verify before update email. + */ + FIRGetOOBConfirmationCodeRequestTypeVerifyBeforeUpdateEmail, +}; + +/** @enum FIRGetOOBConfirmationCodeRequest + @brief Represents the parameters for the getOOBConfirmationCode endpoint. + */ +@interface FIRGetOOBConfirmationCodeRequest : FIRIdentityToolkitRequest + +/** @property requestType + @brief The types of OOB Confirmation Code to request. + */ +@property(nonatomic, assign, readonly) FIRGetOOBConfirmationCodeRequestType requestType; + +/** @property email + @brief The email of the user. + @remarks For password reset. + */ +@property(nonatomic, copy, nullable, readonly) NSString *email; + +/** @property updatedEmail + @brief The new email to be updated. + @remarks For verifyBeforeUpdateEmail. + */ +@property(nonatomic, copy, nullable, readonly) NSString *updatedEmail; + +/** @property accessToken + @brief The STS Access Token of the authenticated user. + @remarks For email change. + */ +@property(nonatomic, copy, nullable, readonly) NSString *accessToken; + +/** @property continueURL + @brief This URL represents the state/Continue URL in the form of a universal link. + */ +@property(nonatomic, copy, nullable, readonly) NSString *continueURL; + +/** @property iOSBundleID + @brief The iOS bundle Identifier, if available. + */ +@property(nonatomic, copy, nullable, readonly) NSString *iOSBundleID; + +/** @property androidPackageName + @brief The Android package name, if available. + */ +@property(nonatomic, copy, nullable, readonly) NSString *androidPackageName; + +/** @property androidMinimumVersion + @brief The minimum Android version supported, if available. + */ +@property(nonatomic, copy, nullable, readonly) NSString *androidMinimumVersion; + +/** @property androidInstallIfNotAvailable + @brief Indicates whether or not the Android app should be installed if not already available. + */ +@property(nonatomic, assign, readonly) BOOL androidInstallApp; + +/** @property handleCodeInApp + @brief Indicates whether the action code link will open the app directly or after being + redirected from a Firebase owned web widget. + */ +@property(assign, nonatomic) BOOL handleCodeInApp; + +/** @property dynamicLinkDomain + @brief The Firebase Dynamic Link domain used for out of band code flow. + */ +@property(copy, nonatomic, nullable) NSString *dynamicLinkDomain; + +/** @fn passwordResetRequestWithEmail:actionCodeSettings:requestConfiguration: + @brief Creates a password reset request. + @param email The user's email address. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the password reset request. + @param requestConfiguration An object containing configurations to be added to the request. + @return A password reset request. + */ ++ (nullable FIRGetOOBConfirmationCodeRequest *) + passwordResetRequestWithEmail:(NSString *)email + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn verifyEmailRequestWithAccessToken:actionCodeSettings:requestConfiguration: + @brief Creates a password reset request. + @param accessToken The user's STS Access Token. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the email verification request. + @param requestConfiguration An object containing configurations to be added to the request. + @return A password reset request. + */ ++ (nullable FIRGetOOBConfirmationCodeRequest *) + verifyEmailRequestWithAccessToken:(NSString *)accessToken + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn signInWithEmailLinkRequest:actionCodeSettings:requestConfiguration: + @brief Creates a sign-in with email link. + @param email The user's email address. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the email sign-in link. + @param requestConfiguration An object containing configurations to be added to the request. + @return An email sign-in link request. + */ ++ (nullable FIRGetOOBConfirmationCodeRequest *) + signInWithEmailLinkRequest:(NSString *)email + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn verifyBeforeUpdateEmailWithAccessToken:newEmail:actionCodeSettings:requestConfiguration: + @brief Creates a verifyBeforeUpdateEmail request. + @param accessToken The user's STS Access Token. + @param newEmail The user's email address to be updated. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the password reset request. + @param requestConfiguration An object containing configurations to be added to the request. + @return A verifyBeforeUpdateEmail request. + */ ++ (nullable FIRGetOOBConfirmationCodeRequest *) + verifyBeforeUpdateEmailWithAccessToken:(NSString *)accessToken + newEmail:(NSString *)newEmail + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn init + @brief Please use a factory method. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.m new file mode 100644 index 0000000..a749a54 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.m @@ -0,0 +1,296 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kEndpoint + @brief The getOobConfirmationCode endpoint name. + */ +static NSString *const kGetOobConfirmationCodeEndpoint = @"getOobConfirmationCode"; + +/** @var kRequestTypeKey + @brief The name of the required "requestType" property in the request. + */ +static NSString *const kRequestTypeKey = @"requestType"; + +/** @var kEmailKey + @brief The name of the "email" property in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kNewEmailKey + @brief The name of the "newEmail" property in the request. + */ +static NSString *const kNewEmailKey = @"newEmail"; + +/** @var kIDTokenKey + @brief The key for the "idToken" value in the request. This is actually the STS Access Token, + despite it's confusing (backwards compatiable) parameter name. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kContinueURLKey + @brief The key for the "continue URL" value in the request. + */ +static NSString *const kContinueURLKey = @"continueUrl"; + +/** @var kIosBundeIDKey + @brief The key for the "iOS Bundle Identifier" value in the request. + */ +static NSString *const kIosBundleIDKey = @"iOSBundleId"; + +/** @var kAndroidPackageNameKey + @brief The key for the "Android Package Name" value in the request. + */ +static NSString *const kAndroidPackageNameKey = @"androidPackageName"; + +/** @var kAndroidInstallAppKey + @brief The key for the request parameter indicating whether the android app should be installed + or not. + */ +static NSString *const kAndroidInstallAppKey = @"androidInstallApp"; + +/** @var kAndroidMinimumVersionKey + @brief The key for the "minimum Android version supported" value in the request. + */ +static NSString *const kAndroidMinimumVersionKey = @"androidMinimumVersion"; + +/** @var kCanHandleCodeInAppKey + @brief The key for the request parameter indicating whether the action code can be handled in + the app or not. + */ +static NSString *const kCanHandleCodeInAppKey = @"canHandleCodeInApp"; + +/** @var kDynamicLinkDomainKey + @brief The key for the "dynamic link domain" value in the request. + */ +static NSString *const kDynamicLinkDomainKey = @"dynamicLinkDomain"; + +/** @var kPasswordResetRequestTypeValue + @brief The value for the "PASSWORD_RESET" request type. + */ +static NSString *const kPasswordResetRequestTypeValue = @"PASSWORD_RESET"; + +/** @var kEmailLinkSignInTypeValue + @brief The value for the "EMAIL_SIGNIN" request type. + */ +static NSString *const kEmailLinkSignInTypeValue = @"EMAIL_SIGNIN"; + +/** @var kVerifyEmailRequestTypeValue + @brief The value for the "VERIFY_EMAIL" request type. + */ +static NSString *const kVerifyEmailRequestTypeValue = @"VERIFY_EMAIL"; + +/** @var kVerifyBeforeUpdateEmailRequestTypeValue + @brief The value for the "VERIFY_AND_CHANGE_EMAIL" request type. + */ +static NSString *const kVerifyBeforeUpdateEmailRequestTypeValue = @"VERIFY_AND_CHANGE_EMAIL"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@interface FIRGetOOBConfirmationCodeRequest () + +/** @fn initWithRequestType:email:APIKey: + @brief Designated initializer. + @param requestType The types of OOB Confirmation Code to request. + @param email The email of the user. + @param newEmail The email of the user to be updated. + @param accessToken The STS Access Token of the currently signed in user. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the OOB code request. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithRequestType:(FIRGetOOBConfirmationCodeRequestType)requestType + email:(nullable NSString *)email + newEmail:(nullable NSString *)newEmail + accessToken:(nullable NSString *)accessToken + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +@implementation FIRGetOOBConfirmationCodeRequest + +/** @var requestTypeStringValueForRequestType: + @brief Returns the string equivilent for an @c FIRGetOOBConfirmationCodeRequestType value. + */ ++ (NSString *)requestTypeStringValueForRequestType: + (FIRGetOOBConfirmationCodeRequestType)requestType { + switch (requestType) { + case FIRGetOOBConfirmationCodeRequestTypePasswordReset: + return kPasswordResetRequestTypeValue; + case FIRGetOOBConfirmationCodeRequestTypeVerifyEmail: + return kVerifyEmailRequestTypeValue; + case FIRGetOOBConfirmationCodeRequestTypeEmailLink: + return kEmailLinkSignInTypeValue; + case FIRGetOOBConfirmationCodeRequestTypeVerifyBeforeUpdateEmail: + return kVerifyBeforeUpdateEmailRequestTypeValue; + // No default case so that we get a compiler warning if a new value was added to the enum. + } +} + ++ (nullable FIRGetOOBConfirmationCodeRequest *) + passwordResetRequestWithEmail:(NSString *)email + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + return [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypePasswordReset + email:email + newEmail:nil + accessToken:nil + actionCodeSettings:actionCodeSettings + requestConfiguration:requestConfiguration]; +} + ++ (nullable FIRGetOOBConfirmationCodeRequest *) + verifyEmailRequestWithAccessToken:(NSString *)accessToken + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + return [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypeVerifyEmail + email:nil + newEmail:nil + accessToken:accessToken + actionCodeSettings:actionCodeSettings + requestConfiguration:requestConfiguration]; +} + ++ (nullable FIRGetOOBConfirmationCodeRequest *) + signInWithEmailLinkRequest:(NSString *)email + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + return [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypeEmailLink + email:email + newEmail:nil + accessToken:nil + actionCodeSettings:actionCodeSettings + requestConfiguration:requestConfiguration]; +} + ++ (nullable FIRGetOOBConfirmationCodeRequest *) + verifyBeforeUpdateEmailWithAccessToken:(NSString *)accessToken + newEmail:(NSString *)newEmail + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + return + [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypeVerifyBeforeUpdateEmail + email:nil + newEmail:newEmail + accessToken:accessToken + actionCodeSettings:actionCodeSettings + requestConfiguration:requestConfiguration]; +} + +- (nullable instancetype)initWithRequestType:(FIRGetOOBConfirmationCodeRequestType)requestType + email:(nullable NSString *)email + newEmail:(nullable NSString *)newEmail + accessToken:(nullable NSString *)accessToken + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kGetOobConfirmationCodeEndpoint + requestConfiguration:requestConfiguration]; + if (self) { + _requestType = requestType; + _email = email; + _updatedEmail = newEmail; + _accessToken = accessToken; + _continueURL = actionCodeSettings.URL.absoluteString; + _iOSBundleID = actionCodeSettings.iOSBundleID; + _androidPackageName = actionCodeSettings.androidPackageName; + _androidMinimumVersion = actionCodeSettings.androidMinimumVersion; + _androidInstallApp = actionCodeSettings.androidInstallIfNotAvailable; + _handleCodeInApp = actionCodeSettings.handleCodeInApp; + _dynamicLinkDomain = actionCodeSettings.dynamicLinkDomain; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *body = + [@{kRequestTypeKey : [[self class] requestTypeStringValueForRequestType:_requestType]} + mutableCopy]; + + // For password reset requests, we only need an email address in addition to the already required + // fields. + if (_requestType == FIRGetOOBConfirmationCodeRequestTypePasswordReset) { + body[kEmailKey] = _email; + } + + // For verify email requests, we only need an STS Access Token in addition to the already required + // fields. + if (_requestType == FIRGetOOBConfirmationCodeRequestTypeVerifyEmail) { + body[kIDTokenKey] = _accessToken; + } + + // For email sign-in link requests, we only need an email address in addition to the already + // required fields. + if (_requestType == FIRGetOOBConfirmationCodeRequestTypeEmailLink) { + body[kEmailKey] = _email; + } + + // For email sign-in link requests, we only need an STS Access Token, a new email address in + // addition to the already required fields. + if (_requestType == FIRGetOOBConfirmationCodeRequestTypeVerifyBeforeUpdateEmail) { + body[kNewEmailKey] = _updatedEmail; + body[kIDTokenKey] = _accessToken; + } + + if (_continueURL) { + body[kContinueURLKey] = _continueURL; + } + + if (_iOSBundleID) { + body[kIosBundleIDKey] = _iOSBundleID; + } + + if (_androidPackageName) { + body[kAndroidPackageNameKey] = _androidPackageName; + } + + if (_androidMinimumVersion) { + body[kAndroidMinimumVersionKey] = _androidMinimumVersion; + } + + if (_androidInstallApp) { + body[kAndroidInstallAppKey] = @YES; + } + + if (_handleCodeInApp) { + body[kCanHandleCodeInAppKey] = @YES; + } + + if (_dynamicLinkDomain) { + body[kDynamicLinkDomainKey] = _dynamicLinkDomain; + } + if (self.tenantID) { + body[kTenantIDKey] = self.tenantID; + } + + return body; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h new file mode 100644 index 0000000..9ea445e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h @@ -0,0 +1,35 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGetOOBConfirmationCodeResponse + @brief Represents the response from the getOobConfirmationCode endpoint. + */ +@interface FIRGetOOBConfirmationCodeResponse : NSObject + +/** @property OOBCode + @brief The OOB code returned by the server in some cases. + */ +@property(nonatomic, copy, readonly, nullable) NSString *OOBCode; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.m new file mode 100644 index 0000000..7eef688 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kOOBCodeKey + @brief The name of the field in the response JSON for the OOB code. + */ +static NSString *const kOOBCodeKey = @"oobCode"; + +@implementation FIRGetOOBConfirmationCodeResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _OOBCode = [dictionary[kOOBCodeKey] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h new file mode 100644 index 0000000..cfaefcc --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRGetProjectConfigRequest : FIRIdentityToolkitRequest + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithRequestConfiguration: + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithTemporaryProof:phoneNumberAPIKey + @brief Designated initializer. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.m new file mode 100644 index 0000000..402f220 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.m @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kGetProjectConfigEndPoint + @brief The "getProjectConfig" endpoint. + */ +static NSString *const kGetProjectConfigEndPoint = @"getProjectConfig"; + +@implementation FIRGetProjectConfigRequest + +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + return [super initWithEndpoint:kGetProjectConfigEndPoint + requestConfiguration:requestConfiguration]; +} + +- (BOOL)containsPostBody { + return NO; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h new file mode 100644 index 0000000..71f79c9 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGetProjectConfigResponse + @brief Represents the response from the getProjectConfig endpoint. + */ +@interface FIRGetProjectConfigResponse : NSObject + +/** @property projectID + @brief The unique ID pertaining to the current project. + */ +@property(nonatomic, strong, readonly, nullable) NSString *projectID; + +/** @property authorizedDomains + @brief A list of domains allowlisted for the current project. + */ +@property(nonatomic, strong, readonly, nullable) NSArray *authorizedDomains; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.m new file mode 100644 index 0000000..38a3ba0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.m @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGetProjectConfigResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _projectID = [dictionary[@"projectId"] copy]; + id authorizedDomains = dictionary[@"authorizedDomains"]; + if ([authorizedDomains isKindOfClass:[NSString class]]) { + NSData *data = [authorizedDomains dataUsingEncoding:NSUTF8StringEncoding]; + authorizedDomains = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:nil]; + } + if ([authorizedDomains isKindOfClass:[NSArray class]]) { + _authorizedDomains = [[NSArray alloc] initWithArray:authorizedDomains copyItems:YES]; + } + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h new file mode 100644 index 0000000..1b918f5 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h @@ -0,0 +1,55 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRResetPasswordRequest : FIRIdentityToolkitRequest + +/** @property oobCode + @brief The oobCode sent in the request. + */ +@property(nonatomic, copy, readonly) NSString *oobCode; + +/** @property updatedPassword + @brief The new password sent in the request. + */ +@property(nonatomic, copy, readonly) NSString *updatedPassword; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithOobCode:newPassword:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithOobCode:newPassword:requestConfiguration: + @brief Designated initializer. + @param oobCode The OOB Code. + @param newPassword The new password. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithOobCode:(NSString *)oobCode + newPassword:(nullable NSString *)newPassword + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.m new file mode 100644 index 0000000..7579b29 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.m @@ -0,0 +1,68 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kResetPasswordEndpoint + @brief The "resetPassword" endpoint. + */ +static NSString *const kResetPasswordEndpoint = @"resetPassword"; + +/** @var kOOBCodeKey + @brief The "resetPassword" key. + */ +static NSString *const kOOBCodeKey = @"oobCode"; + +/** @var kCurrentPasswordKey + @brief The "newPassword" key. + */ +static NSString *const kCurrentPasswordKey = @"newPassword"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRResetPasswordRequest + +- (nullable instancetype)initWithOobCode:(NSString *)oobCode + newPassword:(nullable NSString *)newPassword + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kResetPasswordEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _oobCode = oobCode; + _updatedPassword = newPassword; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + postBody[kOOBCodeKey] = _oobCode; + if (_updatedPassword) { + postBody[kCurrentPasswordKey] = _updatedPassword; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h new file mode 100644 index 0000000..3e8c560 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h @@ -0,0 +1,52 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthResetPasswordResponse + @brief Represents the response from the resetPassword endpoint. + @remarks Possible error codes: + - FIRAuthErrorCodeWeakPassword + - FIRAuthErrorCodeUserDisabled + - FIRAuthErrorCodeOperationNotAllowed + - FIRAuthErrorCodeExpiredActionCode + - FIRAuthErrorCodeInvalidActionCode + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/resetPassword + */ +@interface FIRResetPasswordResponse : NSObject + +/** @property email + @brief The email address corresponding to the reset password request. + */ +@property(nonatomic, strong, readonly) NSString *email; + +/** @property verifiedEmail + @brief The verified email returned from the backend. + */ +@property(nonatomic, strong, readonly) NSString *verifiedEmail; + +/** @property requestType + @brief The tpye of request as returned by the backend. + */ +@property(nonatomic, strong, readonly) NSString *requestType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.m new file mode 100644 index 0000000..5ad1e36 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.m @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRResetPasswordResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _email = [dictionary[@"email"] copy]; + _requestType = [dictionary[@"requestType"] copy]; + _verifiedEmail = [dictionary[@"newEmail"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h new file mode 100644 index 0000000..c17a237 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h @@ -0,0 +1,113 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @enum FIRSecureTokenRequestGrantType + @brief Represents the possible grant types for a token request. + */ +typedef NS_ENUM(NSUInteger, FIRSecureTokenRequestGrantType) { + /** @var FIRSecureTokenRequestGrantTypeAuthorizationCode + @brief Indicates an authorization code request. + @remarks Exchanges a Gitkit "ID Token" for an STS Access Token and Refresh Token. + */ + FIRSecureTokenRequestGrantTypeAuthorizationCode, + + /** @var FIRSecureTokenRequestGrantTypeRefreshToken + @brief Indicates an refresh token request. + @remarks Uses an existing Refresh Token to create a new Access Token. + */ + FIRSecureTokenRequestGrantTypeRefreshToken, +}; + +/** @class FIRSecureTokenRequest + @brief Represents the parameters for the token endpoint. + */ +@interface FIRSecureTokenRequest : NSObject + +/** @property grantType + @brief The type of grant requested. + @see FIRSecureTokenRequestGrantType + */ +@property(nonatomic, assign, readonly) FIRSecureTokenRequestGrantType grantType; + +/** @property scope + @brief The scopes requested (a comma-delimited list of scope strings.) + */ +@property(nonatomic, copy, readonly, nullable) NSString *scope; + +/** @property refreshToken + @brief The client's refresh token. + */ +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +/** @property code + @brief The client's authorization code (legacy Gitkit "ID Token"). + */ +@property(nonatomic, copy, readonly, nullable) NSString *code; + +/** @property APIKey + @brief The client's API Key. + */ +@property(nonatomic, copy, readonly) NSString *APIKey; + +/** @fn authCodeRequestWithCode: + @brief Creates an authorization code request with the given code (legacy Gitkit "ID Token"). + @param code The authorization code (legacy Gitkit "ID Token"). + @param requestConfiguration An object containing configurations to be added to the request. + @return An authorization request. + */ ++ (FIRSecureTokenRequest *)authCodeRequestWithCode:(NSString *)code + requestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn refreshRequestWithCode: + @brief Creates a refresh request with the given refresh token. + @param refreshToken The refresh token. + @param requestConfiguration An object containing configurations to be added to the request. + @return A refresh request. + */ ++ (FIRSecureTokenRequest *)refreshRequestWithRefreshToken:(NSString *)refreshToken + requestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn init + @brief Please use initWithGrantType:scope:refreshToken:code: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithGrantType:scope:refreshToken:code:APIKey: + @brief Designated initializer. + @param grantType The type of request. + @param scope The scopes requested. + @param refreshToken The client's refresh token (for refresh requests.) + @param code The client's authorization code (Gitkit ID Token) (for authorization code requests.) + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithGrantType:(FIRSecureTokenRequestGrantType)grantType + scope:(nullable NSString *)scope + refreshToken:(nullable NSString *)refreshToken + code:(nullable NSString *)code + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.m new file mode 100644 index 0000000..da9470f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.m @@ -0,0 +1,177 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h" + +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kFIRSecureTokenServiceGetTokenURLFormat + @brief The format of the secure token service URLs. Requires string format substitution with + the client's API Key. + */ +static NSString *const kFIRSecureTokenServiceGetTokenURLFormat = @"https://%@/v1/token?key=%@"; + +/** @var kFIREmulatorURLFormat + @brief The format of the emulated secure token service URLs. Requires string format substitution + with the emulator host, the gAPIHost, and the client's API Key. + */ +static NSString *const kFIREmulatorURLFormat = @"http://%@/%@/v1/token?key=%@"; + +/** @var kFIRSecureTokenServiceGrantTypeRefreshToken + @brief The string value of the @c FIRSecureTokenRequestGrantTypeRefreshToken request type. + */ +static NSString *const kFIRSecureTokenServiceGrantTypeRefreshToken = @"refresh_token"; + +/** @var kFIRSecureTokenServiceGrantTypeAuthorizationCode + @brief The string value of the @c FIRSecureTokenRequestGrantTypeAuthorizationCode request type. + */ +static NSString *const kFIRSecureTokenServiceGrantTypeAuthorizationCode = @"authorization_code"; + +/** @var kGrantTypeKey + @brief The key for the "grantType" parameter in the request. + */ +static NSString *const kGrantTypeKey = @"grantType"; + +/** @var kScopeKey + @brief The key for the "scope" parameter in the request. + */ +static NSString *const kScopeKey = @"scope"; + +/** @var kRefreshTokenKey + @brief The key for the "refreshToken" parameter in the request. + */ +static NSString *const kRefreshTokenKey = @"refreshToken"; + +/** @var kCodeKey + @brief The key for the "code" parameter in the request. + */ +static NSString *const kCodeKey = @"code"; + +/** @var gAPIHost + @brief Host for server API calls. + */ +static NSString *gAPIHost = @"securetoken.googleapis.com"; + +@implementation FIRSecureTokenRequest { + /** @var _requestConfiguration + @brief Contains configuration relevant to the request. + */ + FIRAuthRequestConfiguration *_requestConfiguration; +} + ++ (FIRSecureTokenRequest *)authCodeRequestWithCode:(NSString *)code + requestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + return [[self alloc] initWithGrantType:FIRSecureTokenRequestGrantTypeAuthorizationCode + scope:nil + refreshToken:nil + code:code + requestConfiguration:requestConfiguration]; +} + ++ (FIRSecureTokenRequest *)refreshRequestWithRefreshToken:(NSString *)refreshToken + requestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + return [[self alloc] initWithGrantType:FIRSecureTokenRequestGrantTypeRefreshToken + scope:nil + refreshToken:refreshToken + code:nil + requestConfiguration:requestConfiguration]; +} + +/** @fn grantTypeStringWithGrantType: + @brief Converts a @c FIRSecureTokenRequestGrantType to it's @c NSString equivilent. + */ ++ (NSString *)grantTypeStringWithGrantType:(FIRSecureTokenRequestGrantType)grantType { + switch (grantType) { + case FIRSecureTokenRequestGrantTypeAuthorizationCode: + return kFIRSecureTokenServiceGrantTypeAuthorizationCode; + case FIRSecureTokenRequestGrantTypeRefreshToken: + return kFIRSecureTokenServiceGrantTypeRefreshToken; + // No Default case so we will notice if new grant types are added to the enum. + } +} + +- (nullable instancetype)initWithGrantType:(FIRSecureTokenRequestGrantType)grantType + scope:(nullable NSString *)scope + refreshToken:(nullable NSString *)refreshToken + code:(nullable NSString *)code + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super init]; + if (self) { + _grantType = grantType; + _scope = [scope copy]; + _refreshToken = [refreshToken copy]; + _code = [code copy]; + _APIKey = [requestConfiguration.APIKey copy]; + _requestConfiguration = requestConfiguration; + } + return self; +} + +- (FIRAuthRequestConfiguration *)requestConfiguration { + return _requestConfiguration; +} + +- (NSURL *)requestURL { + NSString *URLString; + + NSString *emulatorHostAndPort = _requestConfiguration.emulatorHostAndPort; + if (emulatorHostAndPort) { + URLString = + [NSString stringWithFormat:kFIREmulatorURLFormat, emulatorHostAndPort, gAPIHost, _APIKey]; + } else { + URLString = + [NSString stringWithFormat:kFIRSecureTokenServiceGetTokenURLFormat, gAPIHost, _APIKey]; + } + NSURL *URL = [NSURL URLWithString:URLString]; + return URL; +} + +- (BOOL)containsPostBody { + return YES; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = + [@{kGrantTypeKey : [[self class] grantTypeStringWithGrantType:_grantType]} mutableCopy]; + if (_scope) { + postBody[kScopeKey] = _scope; + } + if (_refreshToken) { + postBody[kRefreshTokenKey] = _refreshToken; + } + if (_code) { + postBody[kCodeKey] = _code; + } + return [postBody copy]; +} + +#pragma mark - Internal API for development + ++ (NSString *)host { + return gAPIHost; +} + ++ (void)setHost:(NSString *)host { + gAPIHost = host; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h new file mode 100644 index 0000000..a45f9ad --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h @@ -0,0 +1,50 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRSecureTokenResponse + @brief Represents the response from the token endpoint. + */ +@interface FIRSecureTokenResponse : NSObject + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token. (Possibly an updated one for refresh requests.) + */ +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +/** @property accessToken + @brief The new access token. + */ +@property(nonatomic, copy, readonly, nullable) NSString *accessToken; + +/** @property IDToken + @brief The new ID Token. + */ +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.m new file mode 100644 index 0000000..5d4c00a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.m @@ -0,0 +1,73 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h" + +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kExpiresInKey + @brief The key for the number of seconds till the access token expires. + */ +static NSString *const kExpiresInKey = @"expires_in"; + +/** @var kRefreshTokenKey + @brief The key for the refresh token. + */ +static NSString *const kRefreshTokenKey = @"refresh_token"; + +/** @var kAccessTokenKey + @brief The key for the access token. + */ +static NSString *const kAccessTokenKey = @"access_token"; + +/** @var kIDTokenKey + @brief The key for the "id_token" value in the response. + */ +static NSString *const kIDTokenKey = @"id_token"; + +@implementation FIRSecureTokenResponse + +- (nullable NSString *)expectedKind { + return nil; +} + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _refreshToken = dictionary[kRefreshTokenKey]; + _accessToken = dictionary[kAccessTokenKey]; + _IDToken = dictionary[kIDTokenKey]; + if (!_accessToken.length) { + if (error) { + *error = [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary]; + } + return NO; + } + id expiresIn = dictionary[kExpiresInKey]; + if (![expiresIn isKindOfClass:[NSString class]]) { + if (error) { + *error = [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary]; + } + return NO; + } + + _approximateExpirationDate = [NSDate dateWithTimeIntervalSinceNow:[expiresIn doubleValue]]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h new file mode 100644 index 0000000..974eb6a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h @@ -0,0 +1,64 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +@class FIRAuthAppCredential; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRSendVerificationCodeRequest : FIRIdentityToolkitRequest + +/** @property phoneNumber + @brief The phone number to which the verification code should be sent. + */ +@property(nonatomic, strong, readonly) NSString *phoneNumber; + +/** @property appCredential + @brief The credential to prove the identity of the app in order to send the verification code. + */ +@property(nonatomic, strong, readonly, nullable) FIRAuthAppCredential *appCredential; + +/** @property reCAPTCHAToken + @brief The reCAPTCHA token to prove the identity of the app in order to send the verification + code. + */ +@property(nonatomic, strong, readonly, nullable) NSString *reCAPTCHAToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithPhoneNumber:appCredentials:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithPhoneNumber:appCredentials:requestConfiguration: + @brief Designated initializer. + @param phoneNumber The phone number to which the verification code is to be sent. + @param appCredential The credential that proves the identity of the app. + @param reCAPTCHAToken The reCAPTCHA token that proves the identity of the app. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithPhoneNumber:(NSString *)phoneNumber + appCredential:(nullable FIRAuthAppCredential *)appCredential + reCAPTCHAToken:(nullable NSString *)reCAPTCHAToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.m new file mode 100644 index 0000000..15e2681 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.m @@ -0,0 +1,92 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h" + +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kSendVerificationCodeEndPoint + @brief The "sendVerificationCodeEnd" endpoint. + */ +static NSString *const kSendVerificationCodeEndPoint = @"sendVerificationCode"; + +/** @var kPhoneNumberKey + @brief The key for the Phone Number parameter in the request. + */ +static NSString *const kPhoneNumberKey = @"phoneNumber"; + +/** @var kReceiptKey + @brief The key for the receipt parameter in the request. + */ +static NSString *const kReceiptKey = @"iosReceipt"; + +/** @var kSecretKey + @brief The key for the Secret parameter in the request. + */ +static NSString *const kSecretKey = @"iosSecret"; + +/** @var kreCAPTCHATokenKey + @brief The key for the reCAPTCHAToken parameter in the request. + */ +static NSString *const kreCAPTCHATokenKey = @"recaptchaToken"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRSendVerificationCodeRequest { +} + +- (nullable instancetype)initWithPhoneNumber:(NSString *)phoneNumber + appCredential:(nullable FIRAuthAppCredential *)appCredential + reCAPTCHAToken:(nullable NSString *)reCAPTCHAToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kSendVerificationCodeEndPoint + requestConfiguration:requestConfiguration]; + if (self) { + _phoneNumber = [phoneNumber copy]; + _appCredential = appCredential; + _reCAPTCHAToken = [reCAPTCHAToken copy]; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_phoneNumber) { + postBody[kPhoneNumberKey] = _phoneNumber; + } + if (_appCredential.receipt) { + postBody[kReceiptKey] = _appCredential.receipt; + } + if (_appCredential.secret) { + postBody[kSecretKey] = _appCredential.secret; + } + if (_reCAPTCHAToken) { + postBody[kreCAPTCHATokenKey] = _reCAPTCHAToken; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h new file mode 100644 index 0000000..605f3f4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h @@ -0,0 +1,32 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRSendVerificationCodeResponse : NSObject + +/** @property verificationID + @brief Encrypted session information returned by the backend. + */ +@property(nonatomic, readonly) NSString *verificationID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.m new file mode 100644 index 0000000..6e8598c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRSendVerificationCodeResponse + +// TODO: remove when resolving b/37169084 . +- (nullable NSString *)expectedKind { + return nil; +} + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _verificationID = [dictionary[@"sessionInfo"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h new file mode 100644 index 0000000..5ba22ba --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h @@ -0,0 +1,151 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +@class FIRGetAccountInfoResponse; + +NS_ASSUME_NONNULL_BEGIN + +/** @var FIRSetAccountInfoUserAttributeEmail + @brief Constant for email attribute used in "deleteAttributes". + */ +extern NSString *const FIRSetAccountInfoUserAttributeEmail; + +/** @var FIRSetAccountInfoUserAttributeDisplayName + @brief Constant for displayName attribute used in "deleteAttributes". + */ +extern NSString *const FIRSetAccountInfoUserAttributeDisplayName; + +/** @var FIRSetAccountInfoUserAttributeProvider + @brief Constant for provider attribute used in "deleteAttributes". + */ +extern NSString *const FIRSetAccountInfoUserAttributeProvider; + +/** @var FIRSetAccountInfoUserAttributePhotoURL + @brief Constant for photoURL attribute used in "deleteAttributes". + */ +extern NSString *const FIRSetAccountInfoUserAttributePhotoURL; + +/** @var FIRSetAccountInfoUserAttributePassword + @brief Constant for password attribute used in "deleteAttributes". + */ +extern NSString *const FIRSetAccountInfoUserAttributePassword; + +/** @class FIRSetAccountInfoRequest + @brief Represents the parameters for the setAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/setAccountInfo + */ +@interface FIRSetAccountInfoRequest : FIRIdentityToolkitRequest + +/** @property accessToken + @brief The STS Access Token of the authenticated user. + */ +@property(nonatomic, copy, nullable) NSString *accessToken; + +/** @property displayName + @brief The name of the user. + */ +@property(nonatomic, copy, nullable) NSString *displayName; + +/** @property localID + @brief The local ID of the user. + */ +@property(nonatomic, copy, nullable) NSString *localID; + +/** @property email + @brief The email of the user. + */ +@property(nonatomic, copy, nullable) NSString *email; + +/** @property photoURL + @brief The photoURL of the user. + */ +@property(nonatomic, copy, nullable) NSURL *photoURL; + +/** @property password + @brief The new password of the user. + */ +@property(nonatomic, copy, nullable) NSString *password; + +/** @property providers + @brief The associated identity providers of the user. + */ +@property(nonatomic, copy, nullable) NSArray *providers; + +/** @property OOBCode + @brief The out-of-band code of the change email request. + */ +@property(nonatomic, copy, nullable) NSString *OOBCode; + +/** @property emailVerified + @brief Whether to mark the email as verified or not. + */ +@property(nonatomic, assign) BOOL emailVerified; + +/** @property upgradeToFederatedLogin + @brief Whether to mark the user to upgrade to federated login. + */ +@property(nonatomic, assign) BOOL upgradeToFederatedLogin; + +/** @property captchaChallenge + @brief The captcha challenge. + */ +@property(nonatomic, copy, nullable) NSString *captchaChallenge; + +/** @property captchaResponse + @brief Response to the captcha. + */ +@property(nonatomic, copy, nullable) NSString *captchaResponse; + +/** @property deleteAttributes + @brief The list of user attributes to delete. + @remarks Every element of the list must be one of the predefined constant starts with + "FIRSetAccountInfoUserAttribute". + */ +@property(nonatomic, copy, nullable) NSArray *deleteAttributes; + +/** @property deleteProviders + @brief The list of identity providers to delete. + */ +@property(nonatomic, copy, nullable) NSArray *deleteProviders; + +/** @property returnSecureToken + @brief Whether the response should return access token and refresh token directly. + @remarks The default value is @c YES . + */ +@property(nonatomic, assign) BOOL returnSecureToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithAPIKey:email:password:displayName:requestConfiguration instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithRequestConfiguration: + @brief Designated initializer. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.m new file mode 100644 index 0000000..6e7291e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.m @@ -0,0 +1,187 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +NSString *const FIRSetAccountInfoUserAttributeEmail = @"EMAIL"; + +NSString *const FIRSetAccountInfoUserAttributeDisplayName = @"DISPLAY_NAME"; + +NSString *const FIRSetAccountInfoUserAttributeProvider = @"PROVIDER"; + +NSString *const FIRSetAccountInfoUserAttributePhotoURL = @"PHOTO_URL"; + +NSString *const FIRSetAccountInfoUserAttributePassword = @"PASSWORD"; + +/** @var kCreateAuthURIEndpoint + @brief The "setAccountInfo" endpoint. + */ +static NSString *const kSetAccountInfoEndpoint = @"setAccountInfo"; + +/** @var kIDTokenKey + @brief The key for the "idToken" value in the request. This is actually the STS Access Token, + despite it's confusing (backwards compatiable) parameter name. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kDisplayNameKey + @brief The key for the "displayName" value in the request. + */ +static NSString *const kDisplayNameKey = @"displayName"; + +/** @var kLocalIDKey + @brief The key for the "localID" value in the request. + */ +static NSString *const kLocalIDKey = @"localId"; + +/** @var kEmailKey + @brief The key for the "email" value in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kPasswordKey + @brief The key for the "password" value in the request. + */ +static NSString *const kPasswordKey = @"password"; + +/** @var kPhotoURLKey + @brief The key for the "photoURL" value in the request. + */ +static NSString *const kPhotoURLKey = @"photoUrl"; + +/** @var kProvidersKey + @brief The key for the "providers" value in the request. + */ +static NSString *const kProvidersKey = @"provider"; + +/** @var kOOBCodeKey + @brief The key for the "OOBCode" value in the request. + */ +static NSString *const kOOBCodeKey = @"oobCode"; + +/** @var kEmailVerifiedKey + @brief The key for the "emailVerified" value in the request. + */ +static NSString *const kEmailVerifiedKey = @"emailVerified"; + +/** @var kUpgradeToFederatedLoginKey + @brief The key for the "upgradeToFederatedLogin" value in the request. + */ +static NSString *const kUpgradeToFederatedLoginKey = @"upgradeToFederatedLogin"; + +/** @var kCaptchaChallengeKey + @brief The key for the "captchaChallenge" value in the request. + */ +static NSString *const kCaptchaChallengeKey = @"captchaChallenge"; + +/** @var kCaptchaResponseKey + @brief The key for the "captchaResponse" value in the request. + */ +static NSString *const kCaptchaResponseKey = @"captchaResponse"; + +/** @var kDeleteAttributesKey + @brief The key for the "deleteAttribute" value in the request. + */ +static NSString *const kDeleteAttributesKey = @"deleteAttribute"; + +/** @var kDeleteProvidersKey + @brief The key for the "deleteProvider" value in the request. + */ +static NSString *const kDeleteProvidersKey = @"deleteProvider"; + +/** @var kReturnSecureTokenKey + @brief The key for the "returnSecureToken" value in the request. + */ +static NSString *const kReturnSecureTokenKey = @"returnSecureToken"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRSetAccountInfoRequest + +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kSetAccountInfoEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _returnSecureToken = YES; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_accessToken) { + postBody[kIDTokenKey] = _accessToken; + } + if (_displayName) { + postBody[kDisplayNameKey] = _displayName; + } + if (_localID) { + postBody[kLocalIDKey] = _localID; + } + if (_email) { + postBody[kEmailKey] = _email; + } + if (_password) { + postBody[kPasswordKey] = _password; + } + if (_photoURL) { + postBody[kPhotoURLKey] = _photoURL.absoluteString; + } + if (_providers) { + postBody[kProvidersKey] = _providers; + } + if (_OOBCode) { + postBody[kOOBCodeKey] = _OOBCode; + } + if (_emailVerified) { + postBody[kEmailVerifiedKey] = @YES; + } + if (_upgradeToFederatedLogin) { + postBody[kUpgradeToFederatedLoginKey] = @YES; + } + if (_captchaChallenge) { + postBody[kCaptchaChallengeKey] = _captchaChallenge; + } + if (_captchaResponse) { + postBody[kCaptchaResponseKey] = _captchaResponse; + } + if (_deleteAttributes) { + postBody[kDeleteAttributesKey] = _deleteAttributes; + } + if (_deleteProviders) { + postBody[kDeleteProvidersKey] = _deleteProviders; + } + if (_returnSecureToken) { + postBody[kReturnSecureTokenKey] = @YES; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h new file mode 100644 index 0000000..9e30930 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h @@ -0,0 +1,98 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRSetAccountInfoResponseProviderUserInfo + @brief Represents the provider user info part of the response from the setAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/setAccountInfo + */ +@interface FIRSetAccountInfoResponseProviderUserInfo : NSObject + +/** @property providerID + @brief The ID of the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *providerID; + +/** @property displayName + @brief The user's display name at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property photoURL + @brief The user's photo URL at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSURL *photoURL; + +/** @fn init + @brief Please use initWithDictionary: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithAPIKey: + @brief Designated initializer. + @param dictionary The provider user info data from endpoint. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER; + +@end + +/** @class FIRSetAccountInfoResponse + @brief Represents the response from the setAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/setAccountInfo + */ +@interface FIRSetAccountInfoResponse : NSObject + +/** @property email + @brief The email or the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property displayName + @brief The display name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property providerUserInfo + @brief The user's profiles at the associated identity providers. + */ +@property(nonatomic, strong, readonly, nullable) + NSArray *providerUserInfo; + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.m new file mode 100644 index 0000000..138fba3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.m @@ -0,0 +1,64 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRSetAccountInfoResponseProviderUserInfo + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + _providerID = [dictionary[@"providerId"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + NSString *photoURL = dictionary[@"photoUrl"]; + if (photoURL) { + _photoURL = [NSURL URLWithString:photoURL]; + } + } + return self; +} + +@end + +@implementation FIRSetAccountInfoResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _email = [dictionary[@"email"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + _IDToken = [dictionary[@"idToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + _refreshToken = [dictionary[@"refreshToken"] copy]; + NSArray *providerUserInfoData = dictionary[@"providerUserInfo"]; + if (providerUserInfoData) { + NSMutableArray *providerUserInfoArray = + [NSMutableArray arrayWithCapacity:providerUserInfoData.count]; + for (NSDictionary *dictionary in providerUserInfoData) { + [providerUserInfoArray addObject:[[FIRSetAccountInfoResponseProviderUserInfo alloc] + initWithDictionary:dictionary]]; + } + _providerUserInfo = [providerUserInfoArray copy]; + } + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h new file mode 100644 index 0000000..781d63a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRSignInWithGameCenterRequest + @brief The request to sign in with Game Center account + */ +@interface FIRSignInWithGameCenterRequest : FIRIdentityToolkitRequest + +/** @property playerID + @brief The playerID to verify. + */ +@property(nonatomic, copy) NSString *playerID; + +/** @property publicKeyURL + @brief The URL for the public encryption key. + */ +@property(nonatomic, copy) NSURL *publicKeyURL; + +/** @property signature + @brief The verification signature data generated by Game Center. + */ +@property(nonatomic, copy) NSData *signature; + +/** @property salt + @brief A random strong used to compute the hash and keep it randomized. + */ +@property(nonatomic, copy) NSData *salt; + +/** @property timestamp + @brief The date and time that the signature was created. + */ +@property(nonatomic, assign) uint64_t timestamp; + +/** @property accessToken + @brief The STS Access Token for the authenticated user, only needed for linking the user. + */ +@property(nonatomic, copy, nullable) NSString *accessToken; + +/** @property displayName + @brief The display name of the local Game Center player. + */ +@property(nonatomic, copy, nullable) NSString *displayName; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithPlayerID:publicKeyURL:signature:salt:timestamp:requestConfiguration:. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithPlayerID:publicKeyURL:signature:salt:timestamp:displayName:requestConfiguration: + @brief Designated initializer. + @param playerID The ID of the Game Center player. + @param publicKeyURL The URL for the public encryption key. + @param signature The verification signature generated. + @param salt A random string used to compute the hash and keep it randomized. + @param timestamp The date and time that the signature was created. + @param displayName The display name of the Game Center player. + */ +- (nullable instancetype)initWithPlayerID:(NSString *)playerID + publicKeyURL:(NSURL *)publicKeyURL + signature:(NSData *)signature + salt:(NSData *)salt + timestamp:(uint64_t)timestamp + displayName:(NSString *)displayName + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.m new file mode 100644 index 0000000..864b969 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.m @@ -0,0 +1,80 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h" + +#import "FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kSignInWithGameCenterEndPoint + @brief The "SignInWithGameCenter" endpoint. + */ +static NSString *const kSignInWithGameCenterEndPoint = @"signInWithGameCenter"; + +@implementation FIRSignInWithGameCenterRequest + +- (nullable instancetype)initWithPlayerID:(NSString *)playerID + publicKeyURL:(NSURL *)publicKeyURL + signature:(NSData *)signature + salt:(NSData *)salt + timestamp:(uint64_t)timestamp + displayName:(NSString *)displayName + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kSignInWithGameCenterEndPoint + requestConfiguration:requestConfiguration]; + if (self) { + _playerID = playerID; + _publicKeyURL = [publicKeyURL copy]; + _signature = [signature copy]; + _salt = [salt copy]; + _timestamp = timestamp; + _displayName = displayName; + } + return self; +} + +#pragma mark - FIRAuthRPCRequest + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_playerID) { + postBody[@"playerId"] = _playerID; + } + if (_publicKeyURL) { + postBody[@"publicKeyUrl"] = _publicKeyURL.absoluteString; + } + if (_signature) { + postBody[@"signature"] = [_signature fir_base64URLEncodedStringWithOptions:0]; + } + if (_salt) { + postBody[@"salt"] = [_salt fir_base64URLEncodedStringWithOptions:0]; + } + if (_timestamp != 0) { + postBody[@"timestamp"] = [NSNumber numberWithUnsignedLongLong:_timestamp]; + } + if (_accessToken) { + postBody[@"idToken"] = _accessToken; + } + if (_displayName) { + postBody[@"displayName"] = _displayName; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h new file mode 100644 index 0000000..ee07b3e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h @@ -0,0 +1,64 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRSignInWithGameCenterResponse : NSObject + +/** @property IDToken + @breif Either an authorization code suitable for performing an STS token exchange, or the access + token from Secure Token Service, depending on whether @c returnSecureToken is set on the + request. + */ +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +/** @property refreshToken + @breif @breif The refresh token from Secure Token Service. + */ +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +/** @property localID + @breif @breif The Firebase Auth user ID. + */ +@property(nonatomic, copy, readonly, nullable) NSString *localID; + +/** @property playerID + @breif @breif The verified player ID. + */ +@property(nonatomic, copy, readonly, nullable) NSString *playerID; + +/** @property approximateExpirationDate + @breif The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property isNewUser + @breif Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +/** @property displayName + @breif The user's Game Center display name. + */ +@property(nonatomic, copy, readonly, nullable) NSString *displayName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.m new file mode 100644 index 0000000..ebad315 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.m @@ -0,0 +1,40 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRSignInWithGameCenterResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _localID = [dictionary[@"localId"] copy]; + _approximateExpirationDate = nil; + if ([dictionary[@"expiresIn"] isKindOfClass:[NSString class]]) { + _approximateExpirationDate = + [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] integerValue]]; + } + _playerID = [dictionary[@"playerId"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + _displayName = [dictionary[@"displayName"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h new file mode 100644 index 0000000..070290d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h @@ -0,0 +1,72 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRSignUpNewUserRequest : FIRIdentityToolkitRequest + +/** @property email + @brief The email of the user. + */ +@property(nonatomic, copy, nullable) NSString *email; + +/** @property password + @brief The password inputed by the user. + */ +@property(nonatomic, copy, nullable) NSString *password; + +/** @property displayName + @brief The password inputed by the user. + */ +@property(nonatomic, copy, nullable) NSString *displayName; + +/** @property returnSecureToken + @brief Whether the response should return access token and refresh token directly. + @remarks The default value is @c YES . + */ +@property(nonatomic, assign) BOOL returnSecureToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithAPIKey:email:password:displayName:requestConfiguration instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithEndpoint:requestConfiguration: + @brief initializer for anonymous sign-in. + */ +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn initWithAPIKey:email:password:displayName:requestConfiguration + @brief Designated initializer. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithEmail:(nullable NSString *)email + password:(nullable NSString *)password + displayName:(nullable NSString *)displayName + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m new file mode 100644 index 0000000..198e450 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m @@ -0,0 +1,98 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kSignupNewUserEndpoint + @brief The "SingupNewUserEndpoint" endpoint. + */ +static NSString *const kSignupNewUserEndpoint = @"signupNewUser"; + +/** @var kEmailKey + @brief The key for the "email" value in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kPasswordKey + @brief The key for the "password" value in the request. + */ +static NSString *const kPasswordKey = @"password"; + +/** @var kDisplayNameKey + @brief The key for the "kDisplayName" value in the request. + */ +static NSString *const kDisplayNameKey = @"displayName"; + +/** @var kReturnSecureTokenKey + @brief The key for the "returnSecureToken" value in the request. + */ +static NSString *const kReturnSecureTokenKey = @"returnSecureToken"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRSignUpNewUserRequest + +- (nullable instancetype)initWithEmail:(nullable NSString *)email + password:(nullable NSString *)password + displayName:(nullable NSString *)displayName + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kSignupNewUserEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _email = [email copy]; + _password = [password copy]; + _displayName = [displayName copy]; + _returnSecureToken = YES; + } + return self; +} + +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + self = [self initWithEmail:nil + password:nil + displayName:nil + requestConfiguration:requestConfiguration]; + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_email) { + postBody[kEmailKey] = _email; + } + if (_password) { + postBody[kPasswordKey] = _password; + } + if (_displayName) { + postBody[kDisplayNameKey] = _displayName; + } + if (_returnSecureToken) { + postBody[kReturnSecureTokenKey] = @YES; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h new file mode 100644 index 0000000..f2e74f6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h @@ -0,0 +1,44 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRSignUpNewUserResponse : NSObject + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.m new file mode 100644 index 0000000..bdfa6d5 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRSignUpNewUserResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + _refreshToken = [dictionary[@"refreshToken"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h new file mode 100644 index 0000000..0a1aa37 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h @@ -0,0 +1,118 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyAssertionRequest + @brief Represents the parameters for the verifyAssertion endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyAssertion + */ +@interface FIRVerifyAssertionRequest : FIRIdentityToolkitRequest + +/** @property requestURI + @brief The URI to which the IDP redirects the user back. It may contain federated login result + params added by the IDP. + */ +@property(nonatomic, copy, nullable) NSString *requestURI; + +/** @property pendingToken + @brief The Firebase ID Token for the IDP pending to be confirmed by the user. + */ +@property(nonatomic, copy, nullable) NSString *pendingToken; + +/** @property accessToken + @brief The STS Access Token for the authenticated user, only needed for linking the user. + */ +@property(nonatomic, copy, nullable) NSString *accessToken; + +/** @property returnSecureToken + @brief Whether the response should return access token and refresh token directly. + @remarks The default value is @c YES . + */ +@property(nonatomic, assign) BOOL returnSecureToken; + +#pragma mark - Components of "postBody" + +/** @property providerID + @brief The ID of the IDP whose credentials are being presented to the endpoint. + */ +@property(nonatomic, copy, readonly) NSString *providerID; + +/** @property providerAccessToken + @brief An access token from the IDP. + */ +@property(nonatomic, copy, nullable) NSString *providerAccessToken; + +/** @property providerIDToken + @brief An ID Token from the IDP. + */ +@property(nonatomic, copy, nullable) NSString *providerIDToken; + +/** @property providerRawNonce + @brief An raw nonce from the IDP. + */ +@property(nonatomic, copy, nullable) NSString *providerRawNonce; + +/** @property returnIDPCredential + @brief Whether the response should return the IDP credential directly. + */ +@property(nonatomic, assign) BOOL returnIDPCredential; + +/** @property providerOAuthTokenSecret + @brief A session ID used to map this request to a headful-lite flow. + */ +@property(nonatomic, copy, nullable) NSString *sessionID; + +/** @property providerOAuthTokenSecret + @brief An OAuth client secret from the IDP. + */ +@property(nonatomic, copy, nullable) NSString *providerOAuthTokenSecret; + +/** @property inputEmail + @brief The originally entered email in the UI. + */ +@property(nonatomic, copy, nullable) NSString *inputEmail; + +/** @property autoCreate + @brief A flag that indicates whether or not the user should be automatically created. + */ +@property(nonatomic, assign) BOOL autoCreate; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithProviderID:requestConfifuration instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithProviderID:requestConfifuration + @brief Designated initializer. + @param providerID The auth provider's ID. + @param requestConfiguration An object containing configurations to be added to the request. + + */ +- (nullable instancetype)initWithProviderID:(NSString *)providerID + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m new file mode 100644 index 0000000..7412af8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m @@ -0,0 +1,185 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kVerifyAssertionEndpoint + @brief The "verifyAssertion" endpoint. + */ +static NSString *const kVerifyAssertionEndpoint = @"verifyAssertion"; + +/** @var kProviderIDKey + @brief The key for the "providerId" value in the request. + */ +static NSString *const kProviderIDKey = @"providerId"; + +/** @var kProviderIDTokenKey + @brief The key for the "id_token" value in the request. + */ +static NSString *const kProviderIDTokenKey = @"id_token"; + +/** @var kProviderNonceKey + @brief The key for the "nonce" value in the request. + */ +static NSString *const kProviderNonceKey = @"nonce"; + +/** @var kProviderAccessTokenKey + @brief The key for the "access_token" value in the request. + */ +static NSString *const kProviderAccessTokenKey = @"access_token"; + +/** @var kProviderOAuthTokenSecretKey + @brief The key for the "oauth_token_secret" value in the request. + */ +static NSString *const kProviderOAuthTokenSecretKey = @"oauth_token_secret"; + +/** @var kIdentifierKey + @brief The key for the "identifier" value in the request. + */ +static NSString *const kIdentifierKey = @"identifier"; + +/** @var kRequestURIKey + @brief The key for the "requestUri" value in the request. + */ +static NSString *const kRequestURIKey = @"requestUri"; + +/** @var kPostBodyKey + @brief The key for the "postBody" value in the request. + */ +static NSString *const kPostBodyKey = @"postBody"; + +/** @var kPendingTokenKey + @brief The key for the "pendingToken" value in the request. + */ +static NSString *const kPendingTokenKey = @"pendingToken"; + +/** @var kAutoCreateKey + @brief The key for the "autoCreate" value in the request. + */ +static NSString *const kAutoCreateKey = @"autoCreate"; + +/** @var kIDTokenKey + @brief The key for the "idToken" value in the request. This is actually the STS Access Token, + despite it's confusing (backwards compatiable) parameter name. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kReturnSecureTokenKey + @brief The key for the "returnSecureToken" value in the request. + */ +static NSString *const kReturnSecureTokenKey = @"returnSecureToken"; + +/** @var kReturnIDPCredentialKey + @brief The key for the "returnIdpCredential" value in the request. + */ +static NSString *const kReturnIDPCredentialKey = @"returnIdpCredential"; + +/** @var kSessionIDKey + @brief The key for the "sessionID" value in the request. + */ +static NSString *const kSessionIDKey = @"sessionId"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRVerifyAssertionRequest + +- (nullable instancetype)initWithProviderID:(NSString *)providerID + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyAssertionEndpoint + requestConfiguration:requestConfiguration]; + if (self) { + _providerID = providerID; + _returnSecureToken = YES; + _autoCreate = YES; + _returnIDPCredential = YES; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSURLComponents *components = [[NSURLComponents alloc] init]; + NSMutableArray *queryItems = + [@[ [NSURLQueryItem queryItemWithName:kProviderIDKey value:_providerID] ] mutableCopy]; + + if (_providerIDToken) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderIDTokenKey + value:_providerIDToken]]; + } + + if (_providerRawNonce) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderNonceKey + value:_providerRawNonce]]; + } + + if (_providerAccessToken) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderAccessTokenKey + value:_providerAccessToken]]; + } + + if (!_providerIDToken && !_providerAccessToken && !_pendingToken && !_requestURI) { + [NSException + raise:NSInvalidArgumentException + format:@"One of IDToken, accessToken, pendingToken, or requestURI must be supplied."]; + } + + if (_providerOAuthTokenSecret) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderOAuthTokenSecretKey + value:_providerOAuthTokenSecret]]; + } + + if (_inputEmail) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kIdentifierKey value:_inputEmail]]; + } + [components setQueryItems:queryItems]; + NSMutableDictionary *body = [@{ + kRequestURIKey : _requestURI ?: @"http://localhost", // Unused by server, but required + kPostBodyKey : [components query] + } mutableCopy]; + + if (_pendingToken) { + body[kPendingTokenKey] = _pendingToken; + } + if (_accessToken) { + body[kIDTokenKey] = _accessToken; + } + if (_returnSecureToken) { + body[kReturnSecureTokenKey] = @YES; + } + + if (_returnIDPCredential) { + body[kReturnIDPCredentialKey] = @YES; + } + + if (_sessionID) { + body[kSessionIDKey] = _sessionID; + } + if (self.tenantID) { + body[kTenantIDKey] = self.tenantID; + } + + body[kAutoCreateKey] = @(_autoCreate); + + return body; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h new file mode 100644 index 0000000..128ff99 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h @@ -0,0 +1,221 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyAssertionResponse + @brief Represents the response from the verifyAssertion endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyAssertion + */ +@interface FIRVerifyAssertionResponse : NSObject + +/** @property federatedID + @brief The unique ID identifies the IdP account. + */ +@property(nonatomic, strong, readonly, nullable) NSString *federatedID; + +/** @property providerID + @brief The IdP ID. For white listed IdPs it's a short domain name e.g. google.com, aol.com, + live.net and yahoo.com. If the "providerId" param is set to OpenID OP identifer other than + the whilte listed IdPs the OP identifier is returned. If the "identifier" param is federated + ID in the createAuthUri request. The domain part of the federated ID is returned. + */ +@property(nonatomic, strong, readonly, nullable) NSString *providerID; + +/** @property localID + @brief The RP local ID if it's already been mapped to the IdP account identified by the + federated ID. + */ +@property(nonatomic, strong, readonly, nullable) NSString *localID; + +/** @property email + @brief The email returned by the IdP. NOTE: The federated login user may not own the email. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property inputEmail + @brief It's the identifier param in the createAuthUri request if the identifier is an email. It + can be used to check whether the user input email is different from the asserted email. + */ +@property(nonatomic, strong, readonly, nullable) NSString *inputEmail; + +/** @property originalEmail + @brief The original email stored in the mapping storage. It's returned when the federated ID is + associated to a different email. + */ +@property(nonatomic, strong, readonly, nullable) NSString *originalEmail; + +/** @property oauthRequestToken + @brief The user approved request token for the OpenID OAuth extension. + */ +@property(nonatomic, strong, readonly, nullable) NSString *oauthRequestToken; + +/** @property oauthScope + @brief The scope for the OpenID OAuth extension. + */ +@property(nonatomic, strong, readonly, nullable) NSString *oauthScope; + +/** @property firstName + @brief The first name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *firstName; + +/** @property lastName + @brief The last name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *lastName; + +/** @property fullName + @brief The full name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *fullName; + +/** @property nickName + @brief The nick name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *nickName; + +/** @property displayName + @brief The display name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property action + @brief The action code. + */ +@property(nonatomic, strong, readonly, nullable) NSString *action; + +/** @property language + @brief The language preference of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *language; + +/** @property timeZone + @brief The timezone of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *timeZone; + +/** @property photoURL + @brief The URI of the public accessible profile picture. + */ +@property(nonatomic, strong, readonly, nullable) NSURL *photoURL; + +/** @property dateOfBirth + @brief The birth date of the IdP account. + */ +@property(nonatomic, strong, readonly, nullable) NSString *dateOfBirth; + +/** @property context + @brief The opaque value used by the client to maintain context info between the authentication + request and the IDP callback. + */ +@property(nonatomic, strong, readonly, nullable) NSString *context; + +/** @property verifiedProvider + @brief When action is 'map', contains the idps which can be used for confirmation. + */ +@property(nonatomic, strong, readonly, nullable) NSArray *verifiedProvider; + +/** @property needConfirmation + @brief Whether the assertion is from a non-trusted IDP and need account linking confirmation. + */ +@property(nonatomic, assign) BOOL needConfirmation; + +/** @property emailRecycled + @brief It's true if the email is recycled. + */ +@property(nonatomic, assign) BOOL emailRecycled; + +/** @property emailVerified + @brief The value is true if the IDP is also the email provider. It means the user owns the + email. + */ +@property(nonatomic, assign) BOOL emailVerified; + +/** @property isNewUser + @brief Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +/** @property profile + @brief Dictionary containing the additional IdP specific information. + */ +@property(nonatomic, readonly, nullable) NSDictionary *profile; + +/** @property username + @brief The name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *username; + +/** @property oauthIDToken + @brief The ID token for the OpenID OAuth extension. + */ +@property(nonatomic, strong, readonly, nullable) NSString *oauthIDToken; + +/** @property oauthExpirationDate + @brief The approximate expiration date of the oauth access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *oauthExpirationDate; + +/** @property oauthAccessToken + @brief The access token for the OpenID OAuth extension. + */ +@property(nonatomic, strong, readonly, nullable) NSString *oauthAccessToken; + +/** @property oauthSecretToken + @brief The secret for the OpenID OAuth extention. + */ +@property(nonatomic, readonly, nullable) NSString *oauthSecretToken; + +/** @property pendingToken + @brief The pending ID Token string. + */ +@property(nonatomic, copy, nullable) NSString *pendingToken; + +/** @property MFAPendingCredential + @brief An opaque string that functions as proof that the user has successfully passed the first + factor check. +*/ +@property(nonatomic, strong, readonly, nullable) NSString *MFAPendingCredential; + +/** @property MFAInfo + @brief Info on which multi-factor authentication providers are enabled. +*/ +@property(nonatomic, strong, readonly, nullable) NSArray *MFAInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.m new file mode 100644 index 0000000..6c605e7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.m @@ -0,0 +1,100 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRVerifyAssertionResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _federatedID = [dictionary[@"federatedId"] copy]; + _providerID = [dictionary[@"providerId"] copy]; + _localID = [dictionary[@"localId"] copy]; + _emailRecycled = [dictionary[@"emailRecycled"] boolValue]; + _emailVerified = [dictionary[@"emailVerified"] boolValue]; + _email = [dictionary[@"email"] copy]; + _inputEmail = [dictionary[@"inputEmail"] copy]; + _originalEmail = [dictionary[@"originalEmail"] copy]; + _oauthRequestToken = [dictionary[@"oauthRequestToken"] copy]; + _oauthScope = [dictionary[@"oauthScope"] copy]; + _firstName = [dictionary[@"firstName"] copy]; + _lastName = [dictionary[@"lastName"] copy]; + _fullName = [dictionary[@"fullName"] copy]; + _nickName = [dictionary[@"nickName"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + _IDToken = [dictionary[@"idToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + id rawUserInfo = dictionary[@"rawUserInfo"]; + if ([rawUserInfo isKindOfClass:[NSString class]]) { + NSData *data = [rawUserInfo dataUsingEncoding:NSUTF8StringEncoding]; + rawUserInfo = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:nil]; + } + if ([rawUserInfo isKindOfClass:[NSDictionary class]]) { + _profile = [[NSDictionary alloc] initWithDictionary:rawUserInfo copyItems:YES]; + } + _username = [dictionary[@"username"] copy]; + _action = [dictionary[@"action"] copy]; + _language = [dictionary[@"language"] copy]; + _timeZone = [dictionary[@"timeZone"] copy]; + _photoURL = dictionary[@"photoUrl"] ? [NSURL URLWithString:dictionary[@"photoUrl"]] : nil; + _dateOfBirth = [dictionary[@"dateOfBirth"] copy]; + _context = [dictionary[@"context"] copy]; + _needConfirmation = [dictionary[@"needConfirmation"] boolValue]; + id verifiedProvider = dictionary[@"verifiedProvider"]; + if ([verifiedProvider isKindOfClass:[NSString class]]) { + NSData *data = [verifiedProvider dataUsingEncoding:NSUTF8StringEncoding]; + verifiedProvider = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:nil]; + } + if ([verifiedProvider isKindOfClass:[NSArray class]]) { + _verifiedProvider = [[NSArray alloc] initWithArray:verifiedProvider copyItems:YES]; + } + _oauthIDToken = [dictionary[@"oauthIdToken"] copy]; + _oauthExpirationDate = + [dictionary[@"oauthExpireIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"oauthExpireIn"] doubleValue]] + : nil; + _oauthAccessToken = [dictionary[@"oauthAccessToken"] copy]; + _oauthSecretToken = [dictionary[@"oauthTokenSecret"] copy]; + _pendingToken = [dictionary[@"pendingToken"] copy]; + + if (dictionary[@"mfaInfo"] != nil) { + NSMutableArray *MFAInfo = [NSMutableArray array]; + NSArray *MFAInfoDataArray = dictionary[@"mfaInfo"]; + for (NSDictionary *MFAInfoData in MFAInfoDataArray) { + FIRAuthProtoMFAEnrollment *MFAEnrollment = + [[FIRAuthProtoMFAEnrollment alloc] initWithDictionary:MFAInfoData]; + [MFAInfo addObject:MFAEnrollment]; + } + _MFAInfo = MFAInfo; + } + _MFAPendingCredential = [dictionary[@"mfaPendingCredential"] copy]; + + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h new file mode 100644 index 0000000..7b4d3bc --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h @@ -0,0 +1,55 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRVerifyClientRequest : FIRIdentityToolkitRequest + +/** @property appToken + @brief The APNS device token. + */ +@property(nonatomic, readonly, nullable) NSString *appToken; + +/** @property isSandbox + @brief The flag that denotes if the appToken pertains to Sandbox or Production. + */ +@property(nonatomic, assign, readonly) BOOL isSandbox; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithToken:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithAppToken:isSandbox:requestConfiguration: + @brief Designated initializer. + @param appToken The APNS device token. + @param isSandbox The flag indicating whether or not the app token provided is for Sandbox or + Production. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithAppToken:(nullable NSString *)appToken + isSandbox:(BOOL)isSandbox + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.m new file mode 100644 index 0000000..02e984c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.m @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kVerifyClientEndpoint + @brief The endpoint for the verifyClient request. + */ +static NSString *const kVerifyClientEndpoint = @"verifyClient"; + +/** @var kAppTokenKey + @brief The key for the appToken request paramenter. + */ +static NSString *const kAPPTokenKey = @"appToken"; + +/** @var kIsSandboxKey + @brief The key for the isSandbox request parameter + */ +static NSString *const kIsSandboxKey = @"isSandbox"; + +@implementation FIRVerifyClientRequest + +- (nullable instancetype)initWithAppToken:(nullable NSString *)appToken + isSandbox:(BOOL)isSandbox + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyClientEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _appToken = appToken; + _isSandbox = isSandbox; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_appToken) { + postBody[kAPPTokenKey] = _appToken; + } + if (_isSandbox) { + postBody[kIsSandboxKey] = @YES; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h new file mode 100644 index 0000000..40e6907 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h @@ -0,0 +1,38 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRVerifyClientResponse : NSObject + +/** @property receipt + @brief Receipt that the APNS token was successfully validated with APNS. + */ +@property(nonatomic, copy, readonly, nullable) NSString *receipt; + +/** @property suggestedTimeOut + @brief The date after which delivery of the silent push notification is considered to have + failed. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *suggestedTimeOutDate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.m new file mode 100644 index 0000000..78d648c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.m @@ -0,0 +1,34 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRVerifyClientResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _receipt = dictionary[@"receipt"]; + _suggestedTimeOutDate = + [dictionary[@"suggestedTimeout"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"suggestedTimeout"] doubleValue]] + : nil; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h new file mode 100644 index 0000000..abea35a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h @@ -0,0 +1,58 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyCustomTokenRequest + @brief Represents the parameters for the verifyCustomToken endpoint. + */ +@interface FIRVerifyCustomTokenRequest : FIRIdentityToolkitRequest + +/** @property token + @brief The self-signed token from the client's BYOAuth server. + */ +@property(nonatomic, copy, readonly) NSString *token; + +/** @property returnSecureToken + @brief Whether the response should return access token and refresh token directly. + @remarks The default value is @c YES . + */ +@property(nonatomic, assign) BOOL returnSecureToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithToken:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithToken:requestConfiguration: + @brief Designated initializer. + @param token The self-signed token from the client's BYOAuth server. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithToken:(NSString *)token + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.m new file mode 100644 index 0000000..a49f53f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.m @@ -0,0 +1,67 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kVerifyCustomTokenEndpoint + @brief The "verifyPassword" endpoint. + */ +static NSString *const kVerifyCustomTokenEndpoint = @"verifyCustomToken"; + +/** @var kTokenKey + @brief The key for the "token" value in the request. + */ +static NSString *const kTokenKey = @"token"; + +/** @var kReturnSecureTokenKey + @brief The key for the "returnSecureToken" value in the request. + */ +static NSString *const kReturnSecureTokenKey = @"returnSecureToken"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRVerifyCustomTokenRequest + +- (nullable instancetype)initWithToken:(NSString *)token + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyCustomTokenEndpoint + requestConfiguration:requestConfiguration]; + if (self) { + _token = [token copy]; + _returnSecureToken = YES; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *body = [@{kTokenKey : _token} mutableCopy]; + if (_returnSecureToken) { + body[kReturnSecureTokenKey] = @YES; + } + if (self.tenantID) { + body[kTenantIDKey] = self.tenantID; + } + return body; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h new file mode 100644 index 0000000..7484a94 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h @@ -0,0 +1,52 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyCustomTokenResponse + @brief Represents the response from the verifyCustomToken endpoint. + */ +@interface FIRVerifyCustomTokenResponse : NSObject + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property isNewUser + @brief Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.m new file mode 100644 index 0000000..1bbe645 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.m @@ -0,0 +1,36 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRVerifyCustomTokenResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h new file mode 100644 index 0000000..5931578 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h @@ -0,0 +1,81 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyPasswordRequest + @brief Represents the parameters for the verifyPassword endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyPassword + */ +@interface FIRVerifyPasswordRequest : FIRIdentityToolkitRequest + +/** @property email + @brief The email of the user. + */ +@property(nonatomic, copy) NSString *email; + +/** @property password + @brief The password inputed by the user. + */ +@property(nonatomic, copy) NSString *password; + +/** @property pendingIDToken + @brief The GITKit token for the non-trusted IDP, which is to be confirmed by the user. + */ +@property(nonatomic, copy, nullable) NSString *pendingIDToken; + +/** @property captchaChallenge + @brief The captcha challenge. + */ +@property(nonatomic, copy, nullable) NSString *captchaChallenge; + +/** @property captchaResponse + @brief Response to the captcha. + */ +@property(nonatomic, copy, nullable) NSString *captchaResponse; + +/** @property returnSecureToken + @brief Whether the response should return access token and refresh token directly. + @remarks The default value is @c YES . + */ +@property(nonatomic, assign) BOOL returnSecureToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithEmail:password:requestConfiguration: + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithEmail:password:requestConfiguration: + @brief Designated initializer. + @param email The email of the user. + @param password The password inputed by the user. + @param requestConfiguration The configu + */ +- (nullable instancetype)initWithEmail:(NSString *)email + password:(NSString *)password + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.m new file mode 100644 index 0000000..97ac2a7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.m @@ -0,0 +1,103 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kVerifyPasswordEndpoint + @brief The "verifyPassword" endpoint. + */ +static NSString *const kVerifyPasswordEndpoint = @"verifyPassword"; + +/** @var kEmailKey + @brief The key for the "email" value in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kPasswordKey + @brief The key for the "password" value in the request. + */ +static NSString *const kPasswordKey = @"password"; + +/** @var kPendingIDTokenKey + @brief The key for the "pendingIdToken" value in the request. + */ +static NSString *const kPendingIDTokenKey = @"pendingIdToken"; + +/** @var kCaptchaChallengeKey + @brief The key for the "captchaChallenge" value in the request. + */ +static NSString *const kCaptchaChallengeKey = @"captchaChallenge"; + +/** @var kCaptchaResponseKey + @brief The key for the "captchaResponse" value in the request. + */ +static NSString *const kCaptchaResponseKey = @"captchaResponse"; + +/** @var kReturnSecureTokenKey + @brief The key for the "returnSecureToken" value in the request. + */ +static NSString *const kReturnSecureTokenKey = @"returnSecureToken"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRVerifyPasswordRequest + +- (nullable instancetype)initWithEmail:(NSString *)email + password:(NSString *)password + requestConfiguration:(nonnull FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyPasswordEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _email = [email copy]; + _password = [password copy]; + _returnSecureToken = YES; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_email) { + postBody[kEmailKey] = _email; + } + if (_password) { + postBody[kPasswordKey] = _password; + } + if (_pendingIDToken) { + postBody[kPendingIDTokenKey] = _pendingIDToken; + } + if (_captchaChallenge) { + postBody[kCaptchaChallengeKey] = _captchaChallenge; + } + if (_captchaResponse) { + postBody[kCaptchaResponseKey] = _captchaResponse; + } + if (_returnSecureToken) { + postBody[kReturnSecureTokenKey] = @YES; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h new file mode 100644 index 0000000..8f95da8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h @@ -0,0 +1,82 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyPasswordResponse + @brief Represents the response from the verifyPassword endpoint. + @remarks Possible error codes: + - FIRAuthInternalErrorCodeUserDisabled + - FIRAuthInternalErrorCodeEmailNotFound + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyPassword + */ +@interface FIRVerifyPasswordResponse : NSObject + +/** @property localID + @brief The RP local ID if it's already been mapped to the IdP account identified by the + federated ID. + */ +@property(nonatomic, strong, readonly, nullable) NSString *localID; + +/** @property email + @brief The email returned by the IdP. NOTE: The federated login user may not own the email. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property displayName + @brief The display name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property photoURL + @brief The URI of the public accessible profile picture. + */ +@property(nonatomic, strong, readonly, nullable) NSURL *photoURL; + +/** @property MFAPendingCredential + @brief An opaque string that functions as proof that the user has successfully passed the first + factor check. +*/ +@property(nonatomic, strong, readonly, nullable) NSString *MFAPendingCredential; + +/** @property MFAInfo + @brief Info on which multi-factor authentication providers are enabled. +*/ +@property(nonatomic, strong, readonly, nullable) NSArray *MFAInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.m new file mode 100644 index 0000000..df8208f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.m @@ -0,0 +1,52 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRVerifyPasswordResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _localID = [dictionary[@"localId"] copy]; + _email = [dictionary[@"email"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + _IDToken = [dictionary[@"idToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _photoURL = dictionary[@"photoUrl"] ? [NSURL URLWithString:dictionary[@"photoUrl"]] : nil; + + if (dictionary[@"mfaInfo"] != nil) { + NSMutableArray *MFAInfo = [NSMutableArray array]; + NSArray *MFAInfoDataArray = dictionary[@"mfaInfo"]; + for (NSDictionary *MFAInfoData in MFAInfoDataArray) { + FIRAuthProtoMFAEnrollment *MFAEnrollment = + [[FIRAuthProtoMFAEnrollment alloc] initWithDictionary:MFAInfoData]; + [MFAInfo addObject:MFAEnrollment]; + } + _MFAInfo = MFAInfo; + } + _MFAPendingCredential = [dictionary[@"mfaPendingCredential"] copy]; + + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h new file mode 100644 index 0000000..da8d4e8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h @@ -0,0 +1,90 @@ +/* + * 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 "FirebaseAuth/Sources/Auth/FIRAuthOperationType.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRVerifyPhoneNumberRequest : FIRIdentityToolkitRequest + +/** @property verificationID + @brief The verification ID obtained from the response of @c sendVerificationCode. +*/ +@property(nonatomic, readonly, nullable) NSString *verificationID; + +/** @property verificationCode + @brief The verification code provided by the user. +*/ +@property(nonatomic, readonly, nullable) NSString *verificationCode; + +/** @property accessToken + @brief The STS Access Token for the authenticated user. + */ +@property(nonatomic, copy, nullable) NSString *accessToken; + +/** @var temporaryProof + @brief The temporary proof code, previously returned from the backend. + */ +@property(nonatomic, readonly, nonnull) NSString *temporaryProof; + +/** @var phoneNumber + @brief The phone number to be verified in the request. + */ +@property(nonatomic, readonly, nonnull) NSString *phoneNumber; + +/** @var operation + @brief The type of operation triggering this verify phone number request. + */ +@property(nonatomic, assign, readonly) FIRAuthOperationType operation; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithVerificationID:verificationCode:requestConfiguration + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithTemporaryProof:phoneNumberAPIKey + @brief Designated initializer. + @param temporaryProof The temporary proof sent by the backed. + @param phoneNumber The phone number associated with the credential to be signed in. + @param operation Indicates what operation triggered the verify phone number request. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithTemporaryProof:(NSString *)temporaryProof + phoneNumber:(NSString *)phoneNumber + operation:(FIRAuthOperationType)operation + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +/** @fn initWithVerificationID:verificationCode:requestConfiguration + @brief Designated initializer. + @param verificationID The verification ID obtained from the response of @c sendVerificationCode. + @param verificationCode The verification code provided by the user. + @param operation Indicates what operation triggered the verify phone number request. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithVerificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode + operation:(FIRAuthOperationType)operation + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.m new file mode 100644 index 0000000..99cb54b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.m @@ -0,0 +1,141 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kVerifyPhoneNumberEndPoint + @brief The "verifyPhoneNumber" endpoint. + */ +static NSString *const kVerifyPhoneNumberEndPoint = @"verifyPhoneNumber"; + +/** @var kVerificationIDKey + @brief The key for the verification ID parameter in the request. + */ +static NSString *const kVerificationIDKey = @"sessionInfo"; + +/** @var kVerificationCodeKey + @brief The key for the verification code parameter in the request. + */ +static NSString *const kVerificationCodeKey = @"code"; + +/** @var kIDTokenKey + @brief The key for the "ID Token" value in the request. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kTemporaryProofKey + @brief The key for the temporary proof value in the request. + */ +static NSString *const kTemporaryProofKey = @"temporaryProof"; + +/** @var kPhoneNumberKey + @brief The key for the phone number value in the request. + */ +static NSString *const kPhoneNumberKey = @"phoneNumber"; + +/** @var kOperationKey + @brief The key for the operation value in the request. + */ +static NSString *const kOperationKey = @"operation"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRVerifyPhoneNumberRequest + +- (nullable instancetype)initWithTemporaryProof:(NSString *)temporaryProof + phoneNumber:(NSString *)phoneNumber + operation:(FIRAuthOperationType)operation + requestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyPhoneNumberEndPoint + requestConfiguration:requestConfiguration]; + if (self) { + _temporaryProof = [temporaryProof copy]; + _phoneNumber = [phoneNumber copy]; + _operation = operation; + } + return self; +} + +- (nullable instancetype)initWithVerificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode + operation:(FIRAuthOperationType)operation + requestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyPhoneNumberEndPoint + requestConfiguration:requestConfiguration]; + if (self) { + _verificationID = verificationID; + _verificationCode = verificationCode; + _operation = operation; + } + return self; +} + +/** @fn FIRAuthOperationString + @brief Returns a string object corresponding to the provided FIRAuthOperationType value. + @param operationType The value of the FIRAuthOperationType enum which will be translated to its + corresponding string value. + @return The string value corresponding to the FIRAuthOperationType argument. + */ +NSString *const FIRAuthOperationString(FIRAuthOperationType operationType) { + switch (operationType) { + case FIRAuthOperationTypeUnspecified: + return @"VERIFY_OP_UNSPECIFIED"; + case FIRAuthOperationTypeSignUpOrSignIn: + return @"SIGN_UP_OR_IN"; + case FIRAuthOperationTypeReauth: + return @"REAUTH"; + case FIRAuthOperationTypeLink: + return @"LINK"; + case FIRAuthOperationTypeUpdate: + return @"UPDATE"; + } +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_verificationID) { + postBody[kVerificationIDKey] = _verificationID; + } + if (_verificationCode) { + postBody[kVerificationCodeKey] = _verificationCode; + } + if (_accessToken) { + postBody[kIDTokenKey] = _accessToken; + } + if (_temporaryProof) { + postBody[kTemporaryProofKey] = _temporaryProof; + } + if (_phoneNumber) { + postBody[kPhoneNumberKey] = _phoneNumber; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + NSString *operation = FIRAuthOperationString(_operation); + postBody[kOperationKey] = operation; + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h new file mode 100644 index 0000000..7817ccf --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h @@ -0,0 +1,64 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRVerifyPhoneNumberResponse : NSObject + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property localID + @brief The Firebase Auth user ID. + */ +@property(nonatomic, strong, readonly, nullable) NSString *localID; + +/** @property phoneNumber + @brief The verified phone number. + */ +@property(nonatomic, strong, readonly, nullable) NSString *phoneNumber; + +/** @property temporaryProof + @brief The temporary proof code returned by the backend. + */ +@property(nonatomic, strong, readonly, nullable) NSString *temporaryProof; + +/** @property isNewUser + @brief Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.m new file mode 100644 index 0000000..902fb96 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.m @@ -0,0 +1,43 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRVerifyPhoneNumberResponse + +- (nullable NSString *)expectedKind { + return nil; +} + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + _localID = [dictionary[@"localId"] copy]; + _phoneNumber = [dictionary[@"phoneNumber"] copy]; + _temporaryProof = [dictionary[@"temporaryProof"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h new file mode 100644 index 0000000..edd8a73 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFinalizeMFAEnrollmentRequest : FIRIdentityToolkitRequest + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) NSString *displayName; + +@property(nonatomic, copy, readonly, nullable) + FIRAuthProtoFinalizeMFAPhoneRequestInfo *verificationInfo; + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + displayName:(NSString *)displayName + verificationInfo:(FIRAuthProtoFinalizeMFAPhoneRequestInfo *)verificationInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.m new file mode 100644 index 0000000..80926bd --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.m @@ -0,0 +1,63 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h" + +static NSString *const kFinalizeMFAEnrollmentEndPoint = @"accounts/mfaEnrollment:finalize"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRFinalizeMFAEnrollmentRequest + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + displayName:(NSString *)displayName + verificationInfo:(FIRAuthProtoFinalizeMFAPhoneRequestInfo *)verificationInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kFinalizeMFAEnrollmentEndPoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + _IDToken = IDToken; + _displayName = displayName; + _verificationInfo = verificationInfo; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_IDToken) { + postBody[@"idToken"] = _IDToken; + } + if (_displayName) { + postBody[@"displayName"] = _displayName; + } + if (_verificationInfo) { + if ([_verificationInfo isKindOfClass:[FIRAuthProtoFinalizeMFAPhoneRequestInfo class]]) { + postBody[@"phoneVerificationInfo"] = [_verificationInfo dictionary]; + } + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h new file mode 100644 index 0000000..aca12a1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h @@ -0,0 +1,30 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFinalizeMFAEnrollmentResponse : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.m new file mode 100644 index 0000000..1e9cac5 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.m @@ -0,0 +1,30 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h" + +@implementation FIRFinalizeMFAEnrollmentResponse + +- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary + error:(NSError *__autoreleasing _Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + return YES; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h new file mode 100644 index 0000000..62599f6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStartMFAEnrollmentRequest : FIRIdentityToolkitRequest + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) FIRAuthProtoStartMFAPhoneRequestInfo *enrollmentInfo; + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + enrollmentInfo:(FIRAuthProtoStartMFAPhoneRequestInfo *)enrollmentInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.m new file mode 100644 index 0000000..1504cc2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.m @@ -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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h" + +static NSString *const kStartMFAEnrollmentEndPoint = @"accounts/mfaEnrollment:start"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRStartMFAEnrollmentRequest + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + enrollmentInfo:(FIRAuthProtoStartMFAPhoneRequestInfo *)enrollmentInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kStartMFAEnrollmentEndPoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + _IDToken = IDToken; + _enrollmentInfo = enrollmentInfo; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_IDToken) { + postBody[@"idToken"] = _IDToken; + } + if (_enrollmentInfo) { + if ([_enrollmentInfo isKindOfClass:[FIRAuthProtoStartMFAPhoneRequestInfo class]]) { + postBody[@"phoneEnrollmentInfo"] = [_enrollmentInfo dictionary]; + } + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h new file mode 100644 index 0000000..d0d5bda --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h @@ -0,0 +1,29 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStartMFAEnrollmentResponse : NSObject + +@property(nonatomic, copy, readonly, nullable) + FIRAuthProtoStartMFAPhoneResponseInfo *enrollmentResponse; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.m new file mode 100644 index 0000000..658462c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.m @@ -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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h" + +@implementation FIRStartMFAEnrollmentResponse + +- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary + error:(NSError *__autoreleasing _Nullable *_Nullable)error { + if (dictionary[@"phoneSessionInfo"] != nil) { + NSDictionary *data = dictionary[@"phoneSessionInfo"]; + _enrollmentResponse = [[FIRAuthProtoStartMFAPhoneResponseInfo alloc] initWithDictionary:data]; + } else { + return NO; + } + return YES; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h new file mode 100644 index 0000000..155f5ea --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFinalizeMFASignInRequest : FIRIdentityToolkitRequest + +@property(nonatomic, copy, readonly, nullable) NSString *MFAPendingCredential; + +@property(nonatomic, copy, readonly, nullable) + FIRAuthProtoFinalizeMFAPhoneRequestInfo *verificationInfo; + +- (nullable instancetype) + initWithMFAPendingCredential:(NSString *)MFAPendingCredential + verificationInfo:(FIRAuthProtoFinalizeMFAPhoneRequestInfo *)verificationInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.m new file mode 100644 index 0000000..cae48ca --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.m @@ -0,0 +1,59 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h" + +static NSString *const kFinalizeMFASignInEndPoint = @"accounts/mfaSignIn:finalize"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRFinalizeMFASignInRequest + +- (nullable instancetype) + initWithMFAPendingCredential:(NSString *)MFAPendingCredential + verificationInfo:(FIRAuthProtoFinalizeMFAPhoneRequestInfo *)verificationInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kFinalizeMFASignInEndPoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + _MFAPendingCredential = MFAPendingCredential; + _verificationInfo = verificationInfo; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_MFAPendingCredential) { + postBody[@"mfaPendingCredential"] = _MFAPendingCredential; + } + if (_verificationInfo) { + if ([_verificationInfo isKindOfClass:[FIRAuthProtoFinalizeMFAPhoneRequestInfo class]]) { + postBody[@"phoneVerificationInfo"] = [_verificationInfo dictionary]; + } + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h new file mode 100644 index 0000000..5ad8bd6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h @@ -0,0 +1,30 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFinalizeMFASignInResponse : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.m new file mode 100644 index 0000000..0763880 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.m @@ -0,0 +1,28 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h" + +@implementation FIRFinalizeMFASignInResponse + +- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary + error:(NSError *__autoreleasing _Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + return YES; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h new file mode 100644 index 0000000..8a12bad --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStartMFASignInRequest : FIRIdentityToolkitRequest + +@property(nonatomic, copy, readonly, nullable) NSString *MFAPendingCredential; + +@property(nonatomic, copy, readonly, nullable) NSString *MFAEnrollmentID; + +@property(nonatomic, copy, readonly, nullable) FIRAuthProtoStartMFAPhoneRequestInfo *signInInfo; + +- (nullable instancetype) + initWithMFAPendingCredential:(NSString *)MFAPendingCredential + MFAEnrollmentID:(NSString *)MFAEnrollmentID + signInInfo:(FIRAuthProtoStartMFAPhoneRequestInfo *)signInInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.m new file mode 100644 index 0000000..dee5b2c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.m @@ -0,0 +1,64 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h" + +static NSString *const kStartMFASignInEndPoint = @"accounts/mfaSignIn:start"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRStartMFASignInRequest + +- (nullable instancetype) + initWithMFAPendingCredential:(NSString *)MFAPendingCredential + MFAEnrollmentID:(NSString *)MFAEnrollmentID + signInInfo:(FIRAuthProtoStartMFAPhoneRequestInfo *)signInInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kStartMFASignInEndPoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + _MFAPendingCredential = MFAPendingCredential; + _MFAEnrollmentID = MFAEnrollmentID; + _signInInfo = signInInfo; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_MFAPendingCredential) { + postBody[@"mfaPendingCredential"] = _MFAPendingCredential; + } + if (_MFAEnrollmentID) { + postBody[@"mfaEnrollmentId"] = _MFAEnrollmentID; + } + if (_signInInfo) { + if ([_signInInfo isKindOfClass:[FIRAuthProtoStartMFAPhoneRequestInfo class]]) { + postBody[@"phoneSignInInfo"] = [_signInInfo dictionary]; + } + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h new file mode 100644 index 0000000..bd1c372 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h @@ -0,0 +1,28 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStartMFASignInResponse : NSObject + +@property(nonatomic, copy, readonly, nullable) FIRAuthProtoStartMFAPhoneResponseInfo *responseInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.m new file mode 100644 index 0000000..7ad49f8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.m @@ -0,0 +1,32 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h" + +@implementation FIRStartMFASignInResponse + +- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary + error:(NSError *__autoreleasing _Nullable *_Nullable)error { + if (dictionary[@"phoneResponseInfo"] != nil) { + NSDictionary *data = dictionary[@"phoneResponseInfo"]; + _responseInfo = [[FIRAuthProtoStartMFAPhoneResponseInfo alloc] initWithDictionary:data]; + } else { + return NO; + } + return YES; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h new file mode 100644 index 0000000..df211f8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRWithdrawMFARequest : FIRIdentityToolkitRequest + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) NSString *MFAEnrollmentID; + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + MFAEnrollmentID:(NSString *)MFAEnrollmentID + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.m new file mode 100644 index 0000000..a7038c3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.m @@ -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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h" + +NS_ASSUME_NONNULL_BEGIN + +static NSString *const kWithdrawMFAEndPoint = @"accounts/mfaEnrollment:withdraw"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRWithdrawMFARequest + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + MFAEnrollmentID:(NSString *)MFAEnrollmentID + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kWithdrawMFAEndPoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + _IDToken = IDToken; + _MFAEnrollmentID = MFAEnrollmentID; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_IDToken) { + postBody[@"idToken"] = _IDToken; + } + if (_MFAEnrollmentID) { + postBody[@"mfaEnrollmentId"] = _MFAEnrollmentID; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h new file mode 100644 index 0000000..84adf82 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h @@ -0,0 +1,29 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRWithdrawMFAResponse : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.m new file mode 100644 index 0000000..7d1c3c7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.m @@ -0,0 +1,32 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRWithdrawMFAResponse + +- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary + error:(NSError *__autoreleasing _Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h new file mode 100644 index 0000000..5d0d861 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h @@ -0,0 +1,30 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@protocol FIRAuthProto + +@optional +- (instancetype)initWithDictionary:(NSDictionary *)dictionary; + +- (NSDictionary *)dictionary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h new file mode 100644 index 0000000..4246e62 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthProtoMFAEnrollment : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *MFAValue; + +@property(nonatomic, copy, readonly, nullable) NSString *MFAEnrollmentID; + +@property(nonatomic, copy, readonly, nullable) NSString *displayName; + +@property(nonatomic, copy, readonly, nullable) NSDate *enrolledAt; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.m new file mode 100644 index 0000000..92237e9 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.m @@ -0,0 +1,43 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthProtoMFAEnrollment + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + if (dictionary[@"phoneInfo"]) { + _MFAValue = dictionary[@"phoneInfo"]; + } + _MFAEnrollmentID = dictionary[@"mfaEnrollmentId"]; + _displayName = dictionary[@"displayName"]; + if ([dictionary[@"enrolledAt"] isKindOfClass:[NSString class]]) { + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"]; + NSDate *date = [dateFormatter dateFromString:dictionary[@"enrolledAt"]]; + _enrolledAt = date; + } + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h new file mode 100644 index 0000000..df6e39a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h @@ -0,0 +1,31 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthProtoFinalizeMFAPhoneRequestInfo : NSObject + +@property(nonatomic, strong, readonly, nullable) NSString *sessionInfo; + +@property(nonatomic, strong, readonly, nullable) NSString *code; + +- (instancetype)initWithSessionInfo:(NSString *)sessionInfo + verificationCode:(NSString *)verificationCode; +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.m new file mode 100644 index 0000000..b233a13 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.m @@ -0,0 +1,46 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthProtoFinalizeMFAPhoneRequestInfo + +- (instancetype)initWithSessionInfo:(NSString *)sessionInfo + verificationCode:(NSString *)verificationCode { + self = [super init]; + if (self) { + _sessionInfo = sessionInfo; + _code = verificationCode; + } + return self; +} + +- (NSDictionary *)dictionary { + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (_sessionInfo) { + dict[@"sessionInfo"] = _sessionInfo; + } + if (_code) { + dict[@"code"] = _code; + } + return [dict copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h new file mode 100644 index 0000000..fc9af6e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthProtoFinalizeMFAPhoneResponseInfo : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *phoneNumber; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.m new file mode 100644 index 0000000..f8f1d96 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthProtoFinalizeMFAPhoneResponseInfo + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + _phoneNumber = [dictionary[@"phoneNumber"] copy]; + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h new file mode 100644 index 0000000..e17315f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthProtoStartMFAPhoneRequestInfo : NSObject + +@property(nonatomic, strong, readonly, nullable) NSString *phoneNumber; + +@property(nonatomic, strong, readonly, nullable) FIRAuthAppCredential *appCredential; + +@property(nonatomic, strong, readonly, nullable) NSString *reCAPTCHAToken; + +- (nullable instancetype)initWithPhoneNumber:(NSString *)phoneNumber + appCredential:(nullable FIRAuthAppCredential *)appCredential + reCAPTCHAToken:(nullable NSString *)reCAPTCHAToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.m new file mode 100644 index 0000000..1c0ffea --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.m @@ -0,0 +1,74 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kPhoneNumberKey + @brief The key for the Phone Number parameter in the request. + */ +static NSString *const kPhoneNumberKey = @"phoneNumber"; + +/** @var kReceiptKey + @brief The key for the receipt parameter in the request. + */ +static NSString *const kReceiptKey = @"iosReceipt"; + +/** @var kSecretKey + @brief The key for the Secret parameter in the request. + */ +static NSString *const kSecretKey = @"iosSecret"; + +/** @var kreCAPTCHATokenKey + @brief The key for the reCAPTCHAToken parameter in the request. + */ +static NSString *const kreCAPTCHATokenKey = @"recaptchaToken"; + +@implementation FIRAuthProtoStartMFAPhoneRequestInfo + +- (nullable instancetype)initWithPhoneNumber:(NSString *)phoneNumber + appCredential:(nullable FIRAuthAppCredential *)appCredential + reCAPTCHAToken:(nullable NSString *)reCAPTCHAToken { + self = [super init]; + if (self) { + _phoneNumber = [phoneNumber copy]; + _appCredential = appCredential; + _reCAPTCHAToken = [reCAPTCHAToken copy]; + } + return self; +} + +- (NSDictionary *)dictionary { + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (_phoneNumber) { + dict[kPhoneNumberKey] = _phoneNumber; + } + if (_appCredential.receipt) { + dict[kReceiptKey] = _appCredential.receipt; + } + if (_appCredential.secret) { + dict[kSecretKey] = _appCredential.secret; + } + if (_reCAPTCHAToken) { + dict[kreCAPTCHATokenKey] = _reCAPTCHAToken; + } + return [dict copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h new file mode 100644 index 0000000..1cdb690 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthProtoStartMFAPhoneResponseInfo : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *sessionInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.m new file mode 100644 index 0000000..065e417 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthProtoStartMFAPhoneResponseInfo + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + _sessionInfo = [dictionary[@"sessionInfo"] copy]; + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h new file mode 100644 index 0000000..43bebdb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMultiFactor () + +@property(nonatomic, weak) FIRUser *user; + +/** @fn initWithMFAEnrollments: + @brief Initialize a multi factor instance with a list of MFA enrollments. +*/ +- (instancetype)initWithMFAEnrollments:(NSArray *)MFAEnrollments; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor.m new file mode 100644 index 0000000..f8f8de0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor.m @@ -0,0 +1,195 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h" +#import "FirebaseAuth/Sources/User/FIRUser_Internal.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h" + +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +static NSString *kEnrolledFactorsCodingKey = @"enrolledFactors"; + +static NSString *kUserCodingKey = @"user"; + +@implementation FIRMultiFactor + +- (void)getSessionWithCompletion:(nullable FIRMultiFactorSessionCallback)completion { + FIRMultiFactorSession *session = [FIRMultiFactorSession sessionForCurrentUser]; + if (completion) { + completion(session, nil); + } +} + +- (void)enrollWithAssertion:(FIRMultiFactorAssertion *)assertion + displayName:(nullable NSString *)displayName + completion:(nullable FIRAuthVoidErrorCallback)completion { +#if TARGET_OS_IOS + FIRPhoneMultiFactorAssertion *phoneAssertion = (FIRPhoneMultiFactorAssertion *)assertion; + FIRAuthProtoFinalizeMFAPhoneRequestInfo *finalizeMFAPhoneRequestInfo = + [[FIRAuthProtoFinalizeMFAPhoneRequestInfo alloc] + initWithSessionInfo:phoneAssertion.authCredential.verificationID + verificationCode:phoneAssertion.authCredential.verificationCode]; + FIRFinalizeMFAEnrollmentRequest *request = + [[FIRFinalizeMFAEnrollmentRequest alloc] initWithIDToken:self.user.rawAccessToken + displayName:displayName + verificationInfo:finalizeMFAPhoneRequestInfo + requestConfiguration:self.user.requestConfiguration]; + [FIRAuthBackend + finalizeMultiFactorEnrollment:request + callback:^(FIRFinalizeMFAEnrollmentResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (completion) { + completion(error); + } + } else { + [FIRAuth.auth + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:nil + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + FIRAuthDataResult *result = + [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:nil]; + FIRAuthDataResultCallback + decoratedCallback = [FIRAuth.auth + signInFlowAuthDataResultCallbackByDecoratingCallback: + ^(FIRAuthDataResult + *_Nullable authResult, + NSError *_Nullable error) { + if (completion) { + completion(error); + } + }]; + decoratedCallback(result, error); + }]; + } + }]; +#endif +} + +- (void)unenrollWithInfo:(FIRMultiFactorInfo *)factorInfo + completion:(nullable FIRAuthVoidErrorCallback)completion { + [self unenrollWithFactorUID:factorInfo.UID completion:completion]; +} + +- (void)unenrollWithFactorUID:(NSString *)factorUID + completion:(nullable FIRAuthVoidErrorCallback)completion { + FIRWithdrawMFARequest *request = + [[FIRWithdrawMFARequest alloc] initWithIDToken:self.user.rawAccessToken + MFAEnrollmentID:factorUID + requestConfiguration:self.user.requestConfiguration]; + [FIRAuthBackend + withdrawMultiFactor:request + callback:^(FIRWithdrawMFAResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + if (completion) { + completion(error); + } + } else { + [FIRAuth.auth + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:nil + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + FIRAuthDataResult *result = + [[FIRAuthDataResult alloc] initWithUser:user + additionalUserInfo:nil]; + FIRAuthDataResultCallback decoratedCallback = [FIRAuth + .auth + signInFlowAuthDataResultCallbackByDecoratingCallback: + ^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + if (error) { + [[FIRAuth auth] signOut:NULL]; + } + if (completion) { + completion(error); + } + }]; + decoratedCallback(result, error); + }]; + } + }]; +} + +#pragma mark - Internal + +- (instancetype)initWithMFAEnrollments:(NSArray *)MFAEnrollments { + self = [super init]; + + if (self) { + NSMutableArray *multiFactorInfoArray = [[NSMutableArray alloc] init]; + for (FIRAuthProtoMFAEnrollment *MFAEnrollment in MFAEnrollments) { + FIRMultiFactorInfo *multiFactorInfo = + [[FIRMultiFactorInfo alloc] initWithProto:MFAEnrollment]; + [multiFactorInfoArray addObject:multiFactorInfo]; + } + _enrolledFactors = [multiFactorInfoArray copy]; + } + + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (self) { + NSArray *enrolledFactors = + [aDecoder decodeObjectOfClass:[NSArray class] + forKey:kEnrolledFactorsCodingKey]; + _enrolledFactors = enrolledFactors; + _user = [aDecoder decodeObjectOfClass:[FIRUser class] forKey:kUserCodingKey]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_enrolledFactors forKey:kEnrolledFactorsCodingKey]; + [aCoder encodeObject:_user forKey:kUserCodingKey]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h new file mode 100644 index 0000000..1d8fd62 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h @@ -0,0 +1,33 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMultiFactorAssertion () { + @protected + NSString *_factorID; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion.m new file mode 100644 index 0000000..d5bd9b3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion.m @@ -0,0 +1,29 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRMultiFactorAssertion +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorConstants.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorConstants.m new file mode 100644 index 0000000..0c9d06b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorConstants.m @@ -0,0 +1,26 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import + +#pragma mark - Multi Factor ID constants + +NSString *const FIRPhoneMultiFactorID = @"1"; + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h new file mode 100644 index 0000000..4475f63 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMultiFactorInfo () { + @protected + NSString *_factorID; +} + +- (instancetype)initWithProto:(FIRAuthProtoMFAEnrollment *)proto; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo.m new file mode 100644 index 0000000..e38e047 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo.m @@ -0,0 +1,74 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +static NSString *kUIDCodingKey = @"uid"; + +static NSString *kDisplayNameCodingKey = @"displayName"; + +static NSString *kEnrollmentDateCodingKey = @"enrollmentDate"; + +static NSString *kFactorIDCodingKey = @"factorID"; + +@implementation FIRMultiFactorInfo + +#pragma mark - Internal + +- (instancetype)initWithProto:(FIRAuthProtoMFAEnrollment *)proto { + self = [super init]; + + if (self) { + _UID = proto.MFAEnrollmentID; + _displayName = proto.displayName; + _enrollmentDate = proto.enrolledAt; + } + + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (self) { + _UID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUIDCodingKey]; + _displayName = [aDecoder decodeObjectOfClass:[NSString class] forKey:kDisplayNameCodingKey]; + _enrollmentDate = [aDecoder decodeObjectOfClass:[NSDate class] forKey:kEnrollmentDateCodingKey]; + _factorID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kFactorIDCodingKey]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_UID forKey:kUIDCodingKey]; + [aCoder encodeObject:_displayName forKey:kDisplayNameCodingKey]; + [aCoder encodeObject:_enrollmentDate forKey:kEnrollmentDateCodingKey]; + [aCoder encodeObject:_factorID forKey:kFactorIDCodingKey]; +} + +@end + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h new file mode 100644 index 0000000..2acaebb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMultiFactorResolver () + +@property(nonatomic) NSString *MFAPendingCredential; + +- (instancetype)initWithMFAPendingCredential:(NSString *_Nullable)MFAPendingCredential + hints:(NSArray *)hints; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver.m new file mode 100644 index 0000000..b17fe99 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver.m @@ -0,0 +1,101 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h" + +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRMultiFactorResolver + +- (instancetype)initWithMFAPendingCredential:(NSString *_Nullable)MFAPendingCredential + hints:(NSArray *)hints { + self = [super init]; + if (self) { + _MFAPendingCredential = MFAPendingCredential; + _hints = hints; + _auth = [FIRAuth auth]; + _session = [[FIRMultiFactorSession alloc] init]; + _session.MFAPendingCredential = MFAPendingCredential; + } + return self; +} + +- (void)resolveSignInWithAssertion:(nonnull FIRMultiFactorAssertion *)assertion + completion:(nullable FIRAuthDataResultCallback)completion { +#if TARGET_OS_IOS + FIRPhoneMultiFactorAssertion *phoneAssertion = (FIRPhoneMultiFactorAssertion *)assertion; + FIRAuthProtoFinalizeMFAPhoneRequestInfo *finalizeMFAPhoneRequestInfo = + [[FIRAuthProtoFinalizeMFAPhoneRequestInfo alloc] + initWithSessionInfo:phoneAssertion.authCredential.verificationID + verificationCode:phoneAssertion.authCredential.verificationCode]; + FIRFinalizeMFASignInRequest *request = [[FIRFinalizeMFASignInRequest alloc] + initWithMFAPendingCredential:self.MFAPendingCredential + verificationInfo:finalizeMFAPhoneRequestInfo + requestConfiguration:self.auth.requestConfiguration]; + [FIRAuthBackend + finalizeMultiFactorSignIn:request + callback:^(FIRFinalizeMFASignInResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (completion) { + completion(nil, error); + } + } else { + [FIRAuth.auth + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:nil + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + FIRAuthDataResult *result = + [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:nil]; + FIRAuthDataResultCallback decoratedCallback = + [FIRAuth.auth + signInFlowAuthDataResultCallbackByDecoratingCallback: + completion]; + decoratedCallback(result, error); + }]; + } + }]; +#endif +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h new file mode 100644 index 0000000..7e903f4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMultiFactorSession () + +@property(nonatomic, readonly) NSString *IDToken; + +@property(nonatomic) NSString *MFAPendingCredential; + +@property(nonatomic) FIRMultiFactorInfo *multiFactorInfo; + ++ (FIRMultiFactorSession *)sessionForCurrentUser; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession.m new file mode 100644 index 0000000..6967740 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession.m @@ -0,0 +1,52 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h" + +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h" +#import "FirebaseAuth/Sources/User/FIRUser_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRMultiFactorSession + +#pragma mark - Private + +- (instancetype)initWithIDToken:(NSString *)IDToken { + self = [super init]; + if (self) { + _IDToken = IDToken; + } + return self; +} + +#pragma mark - Internal + ++ (FIRMultiFactorSession *)sessionForCurrentUser { + FIRUser *currentUser = [[FIRAuth auth] currentUser]; + NSString *IDToken = currentUser.rawAccessToken; + FIRMultiFactorSession *session = [[FIRMultiFactorSession alloc] initWithIDToken:IDToken]; + return session; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h new file mode 100644 index 0000000..e88a8ac --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h @@ -0,0 +1,33 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRPhoneMultiFactorAssertion () + +@property(nonatomic) FIRPhoneAuthCredential *authCredential; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion.m new file mode 100644 index 0000000..9004519 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion.m @@ -0,0 +1,43 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h" + +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const _Nonnull FIRPhoneMultiFactorID; + +@implementation FIRPhoneMultiFactorAssertion + +- (instancetype)init { + self = [super init]; + if (self) { + _factorID = FIRPhoneMultiFactorID; + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorGenerator.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorGenerator.m new file mode 100644 index 0000000..124dffb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorGenerator.m @@ -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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h" + +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h" + +@implementation FIRPhoneMultiFactorGenerator + ++ (FIRPhoneMultiFactorAssertion *)assertionWithCredential: + (FIRPhoneAuthCredential *)phoneAuthCredential { + FIRPhoneMultiFactorAssertion *assertion = [[FIRPhoneMultiFactorAssertion alloc] init]; + assertion.authCredential = phoneAuthCredential; + return assertion; +} + +@end + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h new file mode 100644 index 0000000..0679755 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h @@ -0,0 +1,30 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h" + +@class FIRAuthProtoMFAEnrollment; + +@interface FIRPhoneMultiFactorInfo () + +- (instancetype)initWithProto:(FIRAuthProtoMFAEnrollment *)proto; + +@end + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo.m new file mode 100644 index 0000000..af4c68c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo.m @@ -0,0 +1,41 @@ +/* + * 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h" + +extern NSString *const FIRPhoneMultiFactorID; + +@implementation FIRPhoneMultiFactorInfo + +- (instancetype)initWithProto:(FIRAuthProtoMFAEnrollment *)proto { + self = [super initWithProto:proto]; + if (self) { + _factorID = FIRPhoneMultiFactorID; + _phoneNumber = proto.MFAValue; + } + return self; +} + +@end + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h new file mode 100644 index 0000000..5024bd5 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h @@ -0,0 +1,89 @@ +/* + * 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/LICENSE2.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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRActionCodeSettings + @brief Used to set and retrieve settings related to handling action codes. + */ +NS_SWIFT_NAME(ActionCodeSettings) +@interface FIRActionCodeSettings : NSObject + +/** @property URL + @brief This URL represents the state/Continue URL in the form of a universal link. + @remarks This URL can should be constructed as a universal link that would either directly open + the app where the action code would be handled or continue to the app after the action code + is handled by Firebase. + */ +@property(nonatomic, copy, nullable) NSURL *URL; + +/** @property handleCodeInApp + @brief Indicates whether the action code link will open the app directly or after being + redirected from a Firebase owned web widget. + */ +@property(assign, nonatomic) BOOL handleCodeInApp; + +/** @property iOSBundleID + @brief The iOS bundle ID, if available. The default value is the current app's bundle ID. + */ +@property(copy, nonatomic, readonly, nullable) NSString *iOSBundleID; + +/** @property androidPackageName + @brief The Android package name, if available. + */ +@property(nonatomic, copy, readonly, nullable) NSString *androidPackageName; + +/** @property androidMinimumVersion + @brief The minimum Android version supported, if available. + */ +@property(nonatomic, copy, readonly, nullable) NSString *androidMinimumVersion; + +/** @property androidInstallIfNotAvailable + @brief Indicates whether the Android app should be installed on a device where it is not + available. + */ +@property(nonatomic, assign, readonly) BOOL androidInstallIfNotAvailable; + +/** @property dynamicLinkDomain + @brief The Firebase Dynamic Link domain used for out of band code flow. + */ +@property(copy, nonatomic, nullable) NSString *dynamicLinkDomain; + +/** @fn setIOSBundleID + @brief Sets the iOS bundle Id. + @param iOSBundleID The iOS bundle ID. + */ +- (void)setIOSBundleID:(NSString *)iOSBundleID; + +/** @fn setAndroidPackageName:installIfNotAvailable:minimumVersion: + @brief Sets the Android package name, the flag to indicate whether or not to install the app + and the minimum Android version supported. + @param androidPackageName The Android package name. + @param installIfNotAvailable Indicates whether or not the app should be installed if not + available. + @param minimumVersion The minimum version of Android supported. + @remarks If installIfNotAvailable is set to YES and the link is opened on an android device, it + will try to install the app if not already available. Otherwise the web URL is used. + */ +- (void)setAndroidPackageName:(NSString *)androidPackageName + installIfNotAvailable:(BOOL)installIfNotAvailable + minimumVersion:(nullable NSString *)minimumVersion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h new file mode 100644 index 0000000..4f6947a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h @@ -0,0 +1,57 @@ +/* + * 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 + +@class FIRVerifyAssertionResponse; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAdditionalUserInfo + @brief Represents additional user data returned from an identity provider. + */ +NS_SWIFT_NAME(AdditionalUserInfo) +@interface FIRAdditionalUserInfo : NSObject + +/** @fn init + @brief This class should not be initialized manually. `FIRAdditionalUserInfo` can be retrieved + from from an instance of `FIRAuthDataResult`. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @property providerID + @brief The provider identifier. + */ +@property(nonatomic, readonly) NSString *providerID; + +/** @property profile + @brief Dictionary containing the additional IdP specific information. + */ +@property(nonatomic, readonly, nullable) NSDictionary *profile; + +/** @property username + @brief username The name of the user. + */ +@property(nonatomic, readonly, nullable) NSString *username; + +/** @property newUser + @brief Indicates whether or not the current user was signed in for the first time. + */ +@property(nonatomic, readonly, getter=isNewUser) BOOL newUser; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h new file mode 100644 index 0000000..10ce640 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h @@ -0,0 +1,867 @@ +/* + * 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 +#import + +#import "FIRAuthAPNSTokenType.h" +#import "FIRAuthErrors.h" + +@class FIRActionCodeSettings; +@class FIRApp; +@class FIRAuth; +@class FIRAuthCredential; +@class FIRAuthDataResult; +@class FIRAuthSettings; +@class FIRUser; +@protocol FIRAuthStateListener; +@protocol FIRAuthUIDelegate; +@protocol FIRFederatedAuthProvider; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRUserUpdateCallback + @brief The type of block invoked when a request to update the current user is completed. + */ +typedef void (^FIRUserUpdateCallback)(NSError *_Nullable error) NS_SWIFT_NAME(UserUpdateCallback); + +/** @typedef FIRAuthStateDidChangeListenerHandle + @brief The type of handle returned by `FIRAuth.addAuthStateDidChangeListener:`. + */ +// clang-format off +// clang-format12 merges the next two lines. +typedef id FIRAuthStateDidChangeListenerHandle + NS_SWIFT_NAME(AuthStateDidChangeListenerHandle); +// clang-format on + +/** @typedef FIRAuthStateDidChangeListenerBlock + @brief The type of block which can be registered as a listener for auth state did change events. + + @param auth The FIRAuth object on which state changes occurred. + @param user Optionally; the current signed in user, if any. + */ +typedef void (^FIRAuthStateDidChangeListenerBlock)(FIRAuth *auth, FIRUser *_Nullable user) + NS_SWIFT_NAME(AuthStateDidChangeListenerBlock); + +/** @typedef FIRIDTokenDidChangeListenerHandle + @brief The type of handle returned by `FIRAuth.addIDTokenDidChangeListener:`. + */ +// clang-format off +// clang-format12 merges the next two lines. +typedef id FIRIDTokenDidChangeListenerHandle + NS_SWIFT_NAME(IDTokenDidChangeListenerHandle); +// clang-format on + +/** @typedef FIRIDTokenDidChangeListenerBlock + @brief The type of block which can be registered as a listener for ID token did change events. + + @param auth The FIRAuth object on which ID token changes occurred. + @param user Optionally; the current signed in user, if any. + */ +typedef void (^FIRIDTokenDidChangeListenerBlock)(FIRAuth *auth, FIRUser *_Nullable user) + NS_SWIFT_NAME(IDTokenDidChangeListenerBlock); + +/** @typedef FIRAuthDataResultCallback + @brief The type of block invoked when sign-in related events complete. + + @param authResult Optionally; Result of sign-in request containing both the user and + the additional user info associated with the user. + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRAuthDataResultCallback)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) + NS_SWIFT_NAME(AuthDataResultCallback); +/** + @brief The name of the `NSNotificationCenter` notification which is posted when the auth state + changes (for example, a new token has been produced, a user signs in or signs out). The + object parameter of the notification is the sender `FIRAuth` instance. + */ +extern const NSNotificationName FIRAuthStateDidChangeNotification NS_SWIFT_NAME(AuthStateDidChange); + +/** @typedef FIRAuthResultCallback + @brief The type of block invoked when sign-in related events complete. + + @param user Optionally; the signed in user, if any. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRAuthResultCallback)(FIRUser *_Nullable user, NSError *_Nullable error) + NS_SWIFT_NAME(AuthResultCallback); + +/** @typedef FIRProviderQueryCallback + @brief The type of block invoked when a list of identity providers for a given email address is + requested. + + @param providers Optionally; a list of provider identifiers, if any. + @see FIRGoogleAuthProviderID etc. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRProviderQueryCallback)(NSArray *_Nullable providers, + NSError *_Nullable error) + NS_SWIFT_NAME(ProviderQueryCallback); + +/** @typedef FIRSignInMethodQueryCallback + @brief The type of block invoked when a list of sign-in methods for a given email address is + requested. + */ +typedef void (^FIRSignInMethodQueryCallback)(NSArray *_Nullable, NSError *_Nullable) + NS_SWIFT_NAME(SignInMethodQueryCallback); + +/** @typedef FIRSendPasswordResetCallback + @brief The type of block invoked when sending a password reset email. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRSendPasswordResetCallback)(NSError *_Nullable error) + NS_SWIFT_NAME(SendPasswordResetCallback); + +/** @typedef FIRSendSignInLinkToEmailCallback + @brief The type of block invoked when sending an email sign-in link email. + */ +typedef void (^FIRSendSignInLinkToEmailCallback)(NSError *_Nullable error) + NS_SWIFT_NAME(SendSignInLinkToEmailCallback); + +/** @typedef FIRConfirmPasswordResetCallback + @brief The type of block invoked when performing a password reset. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRConfirmPasswordResetCallback)(NSError *_Nullable error) + NS_SWIFT_NAME(ConfirmPasswordResetCallback); + +/** @typedef FIRVerifyPasswordResetCodeCallback + @brief The type of block invoked when verifying that an out of band code should be used to + perform password reset. + + @param email Optionally; the email address of the user for which the out of band code applies. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRVerifyPasswordResetCodeCallback)(NSString *_Nullable email, + NSError *_Nullable error) + NS_SWIFT_NAME(VerifyPasswordResetCodeCallback); + +/** @typedef FIRApplyActionCodeCallback + @brief The type of block invoked when applying an action code. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRApplyActionCodeCallback)(NSError *_Nullable error) + NS_SWIFT_NAME(ApplyActionCodeCallback); + +typedef void (^FIRAuthVoidErrorCallback)(NSError *_Nullable) NS_SWIFT_NAME(AuthVoidErrorCallback); + +/** @class FIRActionCodeInfo + @brief Manages information regarding action codes. + */ +NS_SWIFT_NAME(ActionCodeInfo) +@interface FIRActionCodeInfo : NSObject + +/** + @brief Operations which can be performed with action codes. + */ +typedef NS_ENUM(NSInteger, FIRActionCodeOperation) { + /** Action code for unknown operation. */ + FIRActionCodeOperationUnknown = 0, + + /** Action code for password reset operation. */ + FIRActionCodeOperationPasswordReset = 1, + + /** Action code for verify email operation. */ + FIRActionCodeOperationVerifyEmail = 2, + + /** Action code for recover email operation. */ + FIRActionCodeOperationRecoverEmail = 3, + + /** Action code for email link operation. */ + FIRActionCodeOperationEmailLink = 4, + + /** Action code for verifing and changing email */ + FIRActionCodeOperationVerifyAndChangeEmail = 5, + + /** Action code for reverting second factor addition */ + FIRActionCodeOperationRevertSecondFactorAddition = 6, + +} NS_SWIFT_NAME(ActionCodeOperation); + +/** + @brief The operation being performed. + */ +@property(nonatomic, readonly) FIRActionCodeOperation operation; + +/** @property email + @brief The email address to which the code was sent. The new email address in the case of + FIRActionCodeOperationRecoverEmail. + */ +@property(nonatomic, nullable, readonly, copy) NSString *email; + +/** @property previousEmail + @brief The email that is being recovered in the case of FIRActionCodeOperationRecoverEmail. + */ +@property(nonatomic, nullable, readonly, copy) NSString *previousEmail; + +/** @fn init + @brief please use initWithOperation: instead. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +/** @class FIRActionCodeURL + @brief This class will allow developers to easily extract information about out of band links. + */ +NS_SWIFT_NAME(ActionCodeURL) +@interface FIRActionCodeURL : NSObject + +/** @property APIKey + @brief Returns the API key from the link. nil, if not provided. + */ +@property(nonatomic, nullable, copy, readonly) NSString *APIKey; + +/** @property operation + @brief Returns the mode of oob action. The property will be of FIRActionCodeOperation type. + It will return FIRActionCodeOperationUnknown if no oob action is provided. + */ +@property(nonatomic, readonly) FIRActionCodeOperation operation; + +/** @property code + @brief Returns the email action code from the link. nil, if not provided. + */ +@property(nonatomic, nullable, copy, readonly) NSString *code; + +/** @property continueURL + @brief Returns the continue URL from the link. nil, if not provided. + */ +@property(nonatomic, nullable, copy, readonly) NSURL *continueURL; + +/** @property languageCode + @brief Returns the language code from the link. nil, if not provided. + */ +@property(nonatomic, nullable, copy, readonly) NSString *languageCode; + +/** @fn actionCodeURLWithLink: + @brief Construct an FIRActionCodeURL from an out of band link (e.g. email link). + @param link The oob link string used to construct the action code URL. + @return The FIRActionCodeURL object constructed based on the oob link provided. + */ ++ (nullable instancetype)actionCodeURLWithLink:(NSString *)link; + +/** @fn init + @brief Please use actionCodeURLWithLink: for Objective-C or actionCodeURLWithLink(link:) for + Swift instead. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +/** @typedef FIRCheckActionCodeCallBack + @brief The type of block invoked when performing a check action code operation. + + @param info Metadata corresponding to the action code. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRCheckActionCodeCallBack)(FIRActionCodeInfo *_Nullable info, + NSError *_Nullable error) + NS_SWIFT_NAME(CheckActionCodeCallback); + +/** @class FIRAuth + @brief Manages authentication for Firebase apps. + @remarks This class is thread-safe. + */ +NS_SWIFT_NAME(Auth) +@interface FIRAuth : NSObject + +/** @fn auth + @brief Gets the auth object for the default Firebase app. + @remarks The default Firebase app must have already been configured or an exception will be + raised. + */ ++ (FIRAuth *)auth NS_SWIFT_NAME(auth()); + +/** @fn authWithApp: + @brief Gets the auth object for a `FIRApp`. + + @param app The FIRApp for which to retrieve the associated FIRAuth instance. + @return The FIRAuth instance associated with the given FIRApp. + */ ++ (FIRAuth *)authWithApp:(FIRApp *)app NS_SWIFT_NAME(auth(app:)); + +/** @property app + @brief Gets the `FIRApp` object that this auth object is connected to. + */ +@property(nonatomic, weak, readonly, nullable) FIRApp *app; + +/** @property currentUser + @brief Synchronously gets the cached current user, or null if there is none. + */ +@property(nonatomic, strong, readonly, nullable) FIRUser *currentUser; + +/** @property languageCode + @brief The current user language code. This property can be set to the app's current language by + calling `useAppLanguage`. + + @remarks The string used to set this property must be a language code that follows BCP 47. + */ +@property(nonatomic, copy, nullable) NSString *languageCode; + +/** @property settings + @brief Contains settings related to the auth object. + */ +@property(nonatomic, copy, nullable) FIRAuthSettings *settings; + +/** @property userAccessGroup + @brief The current user access group that the Auth instance is using. Default is nil. + */ +@property(readonly, nonatomic, copy, nullable) NSString *userAccessGroup; + +/** @property shareAuthStateAcrossDevices + @brief Contains shareAuthStateAcrossDevices setting related to the auth object. + @remarks If userAccessGroup is not set, setting shareAuthStateAcrossDevices will + have no effect. You should set shareAuthStateAcrossDevices to it's desired + state and then set the userAccessGroup after. + */ +@property(nonatomic) BOOL shareAuthStateAcrossDevices; + +/** @property tenantID + @brief The tenant ID of the auth instance. nil if none is available. + */ +@property(nonatomic, copy, nullable) NSString *tenantID; + +/** @property APNSToken + @brief The APNs token used for phone number authentication. The type of the token (production + or sandbox) will be attempted to be automatcially detected. + This property is available on iOS only. + @remarks If swizzling is disabled, the APNs Token must be set for phone number auth to work, + by either setting this property or by calling `setAPNSToken:type:`. + */ +@property(nonatomic, strong, nullable) NSData *APNSToken API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn init + @brief Please access auth instances using `FIRAuth.auth` and `FIRAuth.authForApp:`. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn updateCurrentUser:completion: + @brief Sets the currentUser on the calling Auth instance to the provided user object. + @param user The user object to be set as the current user of the calling Auth instance. + @param completion Optionally; a block invoked after the user of the calling Auth instance has + been updated or an error was encountered. + */ +- (void)updateCurrentUser:(FIRUser *)user + completion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn fetchSignInMethodsForEmail:completion: + @brief Fetches the list of all sign-in methods previously used for the provided email address. + + @param email The email address for which to obtain a list of sign-in methods. + @param completion Optionally; a block which is invoked when the list of sign in methods for the + specified email address is ready or an error was encountered. Invoked asynchronously on the + main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ + +- (void)fetchSignInMethodsForEmail:(NSString *)email + completion:(nullable void (^)(NSArray *_Nullable, + NSError *_Nullable))completion; + +/** @fn signInWithEmail:password:completion: + @brief Signs in using an email address and password. + + @param email The user's email address. + @param password The user's password. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates that email and password + accounts are not enabled. Enable them in the Auth section of the + Firebase console. + + `FIRAuthErrorCodeUserDisabled` - Indicates the user's account is disabled. + + `FIRAuthErrorCodeWrongPassword` - Indicates the user attempted + sign in with an incorrect password. + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)signInWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn signInWithEmail:link:completion: + @brief Signs in using an email address and email sign-in link. + + @param email The user's email address. + @param link The email sign-in link. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates that email and email sign-in link + accounts are not enabled. Enable them in the Auth section of the + Firebase console. + + `FIRAuthErrorCodeUserDisabled` - Indicates the user's account is disabled. + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is invalid. + + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ + +- (void)signInWithEmail:(NSString *)email + link:(NSString *)link + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion + API_UNAVAILABLE(watchos); + +/** @fn signInWithProvider:UIDelegate:completion: + @brief Signs in using the provided auth provider instance. + This method is available on iOS, macOS Catalyst, and tvOS only. + + @param provider An instance of an auth provider used to initiate the sign-in flow. + @param UIDelegate Optionally an instance of a class conforming to the FIRAuthUIDelegate + protocol, this is used for presenting the web context. If nil, a default FIRAuthUIDelegate + will be used. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c FIRAuthErrorCodeOperationNotAllowed - Indicates that email and password + accounts are not enabled. Enable them in the Auth section of the + Firebase console. +
  • +
  • @c FIRAuthErrorCodeUserDisabled - Indicates the user's account is disabled. +
  • +
  • @c FIRAuthErrorCodeWebNetworkRequestFailed - Indicates that a network request within a + SFSafariViewController or WKWebView failed. +
  • +
  • @c FIRAuthErrorCodeWebInternalError - Indicates that an internal error occurred within a + SFSafariViewController or WKWebView. +
  • +
  • @c FIRAuthErrorCodeWebSignInUserInteractionFailure - Indicates a general failure during + a web sign-in flow. +
  • +
  • @c FIRAuthErrorCodeWebContextAlreadyPresented - Indicates that an attempt was made to + present a new web context while one was already being presented. +
  • +
  • @c FIRAuthErrorCodeWebContextCancelled - Indicates that the URL presentation was + cancelled prematurely by the user. +
  • +
  • @c FIRAuthErrorCodeAccountExistsWithDifferentCredential - Indicates the email asserted + by the credential (e.g. the email in a Facebook access token) is already in use by an + existing account, that cannot be authenticated with this sign-in method. Call + fetchProvidersForEmail for this user’s email and then prompt them to sign in with any of + the sign-in providers returned. This error will only be thrown if the "One account per + email address" setting is enabled in the Firebase console, under Auth settings. +
  • +
+ + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ +- (void)signInWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion + API_UNAVAILABLE(macosx, watchos); + +/** @fn signInWithCredential:completion: + @brief Asynchronously signs in to Firebase with the given 3rd-party credentials (e.g. a Facebook + login Access Token, a Google ID Token/Access Token pair, etc.) and returns additional + identity provider data. + + @param credential The credential supplied by the IdP. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidCredential` - Indicates the supplied credential is invalid. + This could happen if it has expired or it is malformed. + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates that accounts + with the identity provider represented by the credential are not enabled. + Enable them in the Auth section of the Firebase console. + + `FIRAuthErrorCodeAccountExistsWithDifferentCredential` - Indicates the email asserted + by the credential (e.g. the email in a Facebook access token) is already in use by an + existing account, that cannot be authenticated with this sign-in method. Call + fetchProvidersForEmail for this user’s email and then prompt them to sign in with any of + the sign-in providers returned. This error will only be thrown if the "One account per + email address" setting is enabled in the Firebase console, under Auth settings. + + `FIRAuthErrorCodeUserDisabled` - Indicates the user's account is disabled. + + `FIRAuthErrorCodeWrongPassword` - Indicates the user attempted sign in with an + incorrect password, if credential is of the type EmailPasswordAuthCredential. + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + `FIRAuthErrorCodeMissingVerificationID` - Indicates that the phone auth credential was + created with an empty verification ID. + + `FIRAuthErrorCodeMissingVerificationCode` - Indicates that the phone auth credential + was created with an empty verification code. + + `FIRAuthErrorCodeInvalidVerificationCode` - Indicates that the phone auth credential + was created with an invalid verification Code. + + `FIRAuthErrorCodeInvalidVerificationID` - Indicates that the phone auth credential was + created with an invalid verification ID. + + `FIRAuthErrorCodeSessionExpired` - Indicates that the SMS code has expired. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods +*/ +- (void)signInWithCredential:(FIRAuthCredential *)credential + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn signInAnonymouslyWithCompletion: + @brief Asynchronously creates and becomes an anonymous user. + @param completion Optionally; a block which is invoked when the sign in finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks If there is already an anonymous user signed in, that user will be returned instead. + If there is any other existing user signed in, that user will be signed out. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates that anonymous accounts are + not enabled. Enable them in the Auth section of the Firebase console. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)signInAnonymouslyWithCompletion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn signInWithCustomToken:completion: + @brief Asynchronously signs in to Firebase with the given Auth token. + + @param token A self-signed custom auth token. + @param completion Optionally; a block which is invoked when the sign in finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidCustomToken` - Indicates a validation error with + the custom token. + + `FIRAuthErrorCodeCustomTokenMismatch` - Indicates the service account and the API key + belong to different projects. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)signInWithCustomToken:(NSString *)token + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn createUserWithEmail:password:completion: + @brief Creates and, on success, signs in a user with the given email address and password. + + @param email The user's email address. + @param password The user's desired password. + @param completion Optionally; a block which is invoked when the sign up flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + `FIRAuthErrorCodeEmailAlreadyInUse` - Indicates the email used to attempt sign up + already exists. Call fetchProvidersForEmail to check which sign-in mechanisms the user + used, and prompt the user to sign in with one of those. + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates that email and password accounts + are not enabled. Enable them in the Auth section of the Firebase console. + + `FIRAuthErrorCodeWeakPassword` - Indicates an attempt to set a password that is + considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo + dictionary object will contain more detailed explanation that can be shown to the user. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)createUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn confirmPasswordResetWithCode:newPassword:completion: + @brief Resets the password given a code sent to the user outside of the app and a new password + for the user. + + @param newPassword The new password. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeWeakPassword` - Indicates an attempt to set a password that is + considered too weak. + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates the administrator disabled sign + in with the specified identity provider. + + `FIRAuthErrorCodeExpiredActionCode` - Indicates the OOB code is expired. + + `FIRAuthErrorCodeInvalidActionCode` - Indicates the OOB code is invalid. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)confirmPasswordResetWithCode:(NSString *)code + newPassword:(NSString *)newPassword + completion:(void (^)(NSError *_Nullable error))completion; + +/** @fn checkActionCode:completion: + @brief Checks the validity of an out of band code. + + @param code The out of band code to check validity. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)checkActionCode:(NSString *)code completion:(FIRCheckActionCodeCallBack)completion; + +/** @fn verifyPasswordResetCode:completion: + @brief Checks the validity of a verify password reset code. + + @param code The password reset code to be verified. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)verifyPasswordResetCode:(NSString *)code + completion: + (void (^)(NSString *_Nullable email, NSError *_Nullable error))completion; + +/** @fn applyActionCode:completion: + @brief Applies out of band code. + + @param code The out of band code to be applied. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks This method will not work for out of band codes which require an additional parameter, + such as password reset code. + */ +- (void)applyActionCode:(NSString *)code completion:(void (^)(NSError *_Nullable error))completion; + +/** @fn sendPasswordResetWithEmail:completion: + @brief Initiates a password reset for the given email address. + + @param email The email address of the user. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `FIRAuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `FIRAuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + + */ +- (void)sendPasswordResetWithEmail:(NSString *)email + completion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn sendPasswordResetWithEmail:actionCodeSetting:completion: + @brief Initiates a password reset for the given email address and @FIRActionCodeSettings object. + + @param email The email address of the user. + @param actionCodeSettings An `FIRActionCodeSettings` object containing settings related to + handling action codes. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `FIRAuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `FIRAuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `FIRAuthErrorCodeMissingIosBundleID` - Indicates that the iOS bundle ID is missing when + `handleCodeInApp` is set to YES. + + `FIRAuthErrorCodeMissingAndroidPackageName` - Indicates that the android package name + is missing when the `androidInstallApp` flag is set to true. + + `FIRAuthErrorCodeUnauthorizedDomain` - Indicates that the domain specified in the + continue URL is not allowlisted in the Firebase console. + + `FIRAuthErrorCodeInvalidContinueURI` - Indicates that the domain specified in the + continue URI is not valid. + + + */ +- (void)sendPasswordResetWithEmail:(NSString *)email + actionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn sendSignInLinkToEmail:actionCodeSettings:completion: + @brief Sends a sign in with email link to provided email address. + + @param email The email address of the user. + @param actionCodeSettings An `FIRActionCodeSettings` object containing settings related to + handling action codes. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)sendSignInLinkToEmail:(NSString *)email + actionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion:(nullable void (^)(NSError *_Nullable error))completion + API_UNAVAILABLE(watchos); + +/** @fn signOut: + @brief Signs out the current user. + + @param error Optionally; if an error occurs, upon return contains an NSError object that + describes the problem; is nil otherwise. + @return @YES when the sign out request was successful. @NO otherwise. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeKeychainError` - Indicates an error occurred when accessing the + keychain. The `NSLocalizedFailureReasonErrorKey` field in the `NSError.userInfo` + dictionary will contain more information about the error encountered. + + */ +- (BOOL)signOut:(NSError *_Nullable *_Nullable)error; + +/** @fn isSignInWithEmailLink + @brief Checks if link is an email sign-in link. + + @param link The email sign-in link. + @return @YES when the link passed matches the expected format of an email sign-in link. + */ +- (BOOL)isSignInWithEmailLink:(NSString *)link API_UNAVAILABLE(watchos); + +/** @fn addAuthStateDidChangeListener: + @brief Registers a block as an "auth state did change" listener. To be invoked when: + + + The block is registered as a listener, + + A user with a different UID from the current user has signed in, or + + The current user has signed out. + + @param listener The block to be invoked. The block is always invoked asynchronously on the main + thread, even for it's initial invocation after having been added as a listener. + + @remarks The block is invoked immediately after adding it according to it's standard invocation + semantics, asynchronously on the main thread. Users should pay special attention to + making sure the block does not inadvertently retain objects which should not be retained by + the long-lived block. The block itself will be retained by `FIRAuth` until it is + unregistered or until the `FIRAuth` instance is otherwise deallocated. + + @return A handle useful for manually unregistering the block as a listener. + */ + +- (FIRAuthStateDidChangeListenerHandle)addAuthStateDidChangeListener: + (void (^)(FIRAuth *auth, FIRUser *_Nullable user))listener; + +/** @fn removeAuthStateDidChangeListener: + @brief Unregisters a block as an "auth state did change" listener. + + @param listenerHandle The handle for the listener. + */ +- (void)removeAuthStateDidChangeListener:(FIRAuthStateDidChangeListenerHandle)listenerHandle; + +/** @fn addIDTokenDidChangeListener: + @brief Registers a block as an "ID token did change" listener. To be invoked when: + + + The block is registered as a listener, + + A user with a different UID from the current user has signed in, + + The ID token of the current user has been refreshed, or + + The current user has signed out. + + @param listener The block to be invoked. The block is always invoked asynchronously on the main + thread, even for it's initial invocation after having been added as a listener. + + @remarks The block is invoked immediately after adding it according to it's standard invocation + semantics, asynchronously on the main thread. Users should pay special attention to + making sure the block does not inadvertently retain objects which should not be retained by + the long-lived block. The block itself will be retained by `FIRAuth` until it is + unregistered or until the `FIRAuth` instance is otherwise deallocated. + + @return A handle useful for manually unregistering the block as a listener. + */ +- (FIRIDTokenDidChangeListenerHandle)addIDTokenDidChangeListener: + (void (^)(FIRAuth *auth, FIRUser *_Nullable user))listener; + +/** @fn removeIDTokenDidChangeListener: + @brief Unregisters a block as an "ID token did change" listener. + + @param listenerHandle The handle for the listener. + */ +- (void)removeIDTokenDidChangeListener:(FIRIDTokenDidChangeListenerHandle)listenerHandle; + +/** @fn useAppLanguage + @brief Sets `languageCode` to the app's current language. + */ +- (void)useAppLanguage; + +/** @fn useEmulatorWithHost:port + @brief Configures Firebase Auth to connect to an emulated host instead of the remote backend. + */ +- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port; + +/** @fn canHandleURL: + @brief Whether the specific URL is handled by `FIRAuth` . + This method is available on iOS only. + @param URL The URL received by the application delegate from any of the openURL method. + @return Whether or the URL is handled. YES means the URL is for Firebase Auth + so the caller should ignore the URL from further processing, and NO means the + the URL is for the app (or another libaray) so the caller should continue handling + this URL as usual. + @remarks If swizzling is disabled, URLs received by the application delegate must be forwarded + to this method for phone number auth to work. + */ +- (BOOL)canHandleURL:(nonnull NSURL *)URL API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn setAPNSToken:type: + @brief Sets the APNs token along with its type. + This method is available on iOS only. + @remarks If swizzling is disabled, the APNs Token must be set for phone number auth to work, + by either setting calling this method or by setting the `APNSToken` property. + */ +- (void)setAPNSToken:(NSData *)token + type:(FIRAuthAPNSTokenType)type API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn canHandleNotification: + @brief Whether the specific remote notification is handled by `FIRAuth` . + This method is available on iOS only. + @param userInfo A dictionary that contains information related to the + notification in question. + @return Whether or the notification is handled. YES means the notification is for Firebase Auth + so the caller should ignore the notification from further processing, and NO means the + the notification is for the app (or another libaray) so the caller should continue handling + this notification as usual. + @remarks If swizzling is disabled, related remote notifications must be forwarded to this method + for phone number auth to work. + */ +- (BOOL)canHandleNotification:(NSDictionary *)userInfo API_UNAVAILABLE(macos, tvos, watchos); + +#pragma mark - User sharing + +/** @fn useUserAccessGroup:error: + @brief Switch userAccessGroup and current user to the given accessGroup and the user stored in + it. + */ +- (BOOL)useUserAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn getStoredUserForAccessGroup:error: + @brief Get the stored user in the given accessGroup. + */ +- (nullable FIRUser *)getStoredUserForAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h new file mode 100644 index 0000000..95fc2df --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h @@ -0,0 +1,41 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * @brief The APNs token type for the app. + * This enum is available on iOS, macOS Catalyst, tvOS, and watchOS only. + */ +typedef NS_ENUM(NSInteger, FIRAuthAPNSTokenType) { + + /** Unknown token type. + The actual token type will be detected from the provisioning profile in the app's bundle. + */ + FIRAuthAPNSTokenTypeUnknown, + + /** Sandbox token type. + */ + FIRAuthAPNSTokenTypeSandbox, + + /** Production token type. + */ + FIRAuthAPNSTokenTypeProd, +} NS_SWIFT_NAME(AuthAPNSTokenType) API_UNAVAILABLE(macosx); + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h new file mode 100644 index 0000000..106d844 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h @@ -0,0 +1,41 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthCredential + @brief Represents a credential. + */ +NS_SWIFT_NAME(AuthCredential) +@interface FIRAuthCredential : NSObject + +/** @property provider + @brief Gets the name of the identity provider for the credential. + */ +@property(nonatomic, copy, readonly) NSString *provider; + +/** @fn init + @brief This is an abstract base class. Concrete instances should be created via factory + methods available in the various authentication provider libraries (like the Facebook + provider or the Google provider libraries.) + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h new file mode 100644 index 0000000..93c8b3b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h @@ -0,0 +1,57 @@ +/* + * 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 + +@class FIRAdditionalUserInfo; +@class FIRAuthCredential; +@class FIRUser; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthDataResult + @brief Helper object that contains the result of a successful sign-in, link and reauthenticate + action. It contains references to a FIRUser instance and a FIRAdditionalUserInfo instance. + */ +NS_SWIFT_NAME(AuthDataResult) +@interface FIRAuthDataResult : NSObject + +/** @fn init + @brief This class should not be initialized manually. `FIRAuthDataResult` instance is + returned as part of `FIRAuthDataResultCallback`. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @property user + @brief The signed in user. + */ +@property(nonatomic, readonly) FIRUser *user; + +/** @property additionalUserInfo + @brief If available contains the additional IdP specific information about signed in user. + */ +@property(nonatomic, readonly, nullable) FIRAdditionalUserInfo *additionalUserInfo; + +/** @property credential + @brief This property will be non-nil after a successful headful-lite sign-in via + signInWithProvider:UIDelegate:. May be used to obtain the accessToken and/or IDToken + pertaining to a recently signed-in user. + */ +@property(nonatomic, readonly, nullable) FIRAuthCredential *credential; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h new file mode 100644 index 0000000..d1c7c8a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h @@ -0,0 +1,436 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthErrors + @remarks Error Codes common to all API Methods: + + + `FIRAuthErrorCodeNetworkError` + + `FIRAuthErrorCodeUserNotFound` + + `FIRAuthErrorCodeUserTokenExpired` + + `FIRAuthErrorCodeTooManyRequests` + + `FIRAuthErrorCodeInvalidAPIKey` + + `FIRAuthErrorCodeAppNotAuthorized` + + `FIRAuthErrorCodeKeychainError` + + `FIRAuthErrorCodeInternalError` + + @remarks Common error codes for `FIRUser` operations: + + + `FIRAuthErrorCodeInvalidUserToken` + + `FIRAuthErrorCodeUserDisabled` + + */ +NS_SWIFT_NAME(AuthErrors) +@interface FIRAuthErrors + +/** + @brief The Firebase Auth error domain. + */ +extern NSString *const FIRAuthErrorDomain NS_SWIFT_NAME(AuthErrorDomain); + +/** + @brief The name of the key for the error short string of an error code. + */ +extern NSString *const FIRAuthErrorUserInfoNameKey NS_SWIFT_NAME(AuthErrorUserInfoNameKey); + +/** + @brief Errors with one of the following three codes: + - `FIRAuthErrorCodeAccountExistsWithDifferentCredential` + - `FIRAuthErrorCodeCredentialAlreadyInUse` + - `FIRAuthErrorCodeEmailAlreadyInUse` + may contain an `NSError.userInfo` dictinary object which contains this key. The value + associated with this key is an NSString of the email address of the account that already + exists. + */ +extern NSString *const FIRAuthErrorUserInfoEmailKey NS_SWIFT_NAME(AuthErrorUserInfoEmailKey); + +/** + @brief The key used to read the updated Auth credential from the userInfo dictionary of the + NSError object returned. This is the updated auth credential the developer should use for + recovery if applicable. + */ +// clang-format off +// clang-format12 will merge lines and exceed 100 character limit. +extern NSString *const FIRAuthErrorUserInfoUpdatedCredentialKey + NS_SWIFT_NAME(AuthErrorUserInfoUpdatedCredentialKey); + +/** + @brief The key used to read the MFA resolver from the userInfo dictionary of the NSError object + returned when 2FA is required for sign-incompletion. + */ +extern NSString *const FIRAuthErrorUserInfoMultiFactorResolverKey + NS_SWIFT_NAME(AuthErrorUserInfoMultiFactorResolverKey); +// clang-format on + +/** + @brief Error codes used by Firebase Auth. + */ +typedef NS_ENUM(NSInteger, FIRAuthErrorCode) { + /** Indicates a validation error with the custom token. + */ + FIRAuthErrorCodeInvalidCustomToken = 17000, + + /** Indicates the service account and the API key belong to different projects. + */ + FIRAuthErrorCodeCustomTokenMismatch = 17002, + + /** Indicates the IDP token or requestUri is invalid. + */ + FIRAuthErrorCodeInvalidCredential = 17004, + + /** Indicates the user's account is disabled on the server. + */ + FIRAuthErrorCodeUserDisabled = 17005, + + /** Indicates the administrator disabled sign in with the specified identity provider. + */ + FIRAuthErrorCodeOperationNotAllowed = 17006, + + /** Indicates the email used to attempt a sign up is already in use. + */ + FIRAuthErrorCodeEmailAlreadyInUse = 17007, + + /** Indicates the email is invalid. + */ + FIRAuthErrorCodeInvalidEmail = 17008, + + /** Indicates the user attempted sign in with a wrong password. + */ + FIRAuthErrorCodeWrongPassword = 17009, + + /** Indicates that too many requests were made to a server method. + */ + FIRAuthErrorCodeTooManyRequests = 17010, + + /** Indicates the user account was not found. + */ + FIRAuthErrorCodeUserNotFound = 17011, + + /** Indicates account linking is required. + */ + FIRAuthErrorCodeAccountExistsWithDifferentCredential = 17012, + + /** Indicates the user has attemped to change email or password more than 5 minutes after + signing in. + */ + FIRAuthErrorCodeRequiresRecentLogin = 17014, + + /** Indicates an attempt to link a provider to which the account is already linked. + */ + FIRAuthErrorCodeProviderAlreadyLinked = 17015, + + /** Indicates an attempt to unlink a provider that is not linked. + */ + FIRAuthErrorCodeNoSuchProvider = 17016, + + /** Indicates user's saved auth credential is invalid, the user needs to sign in again. + */ + FIRAuthErrorCodeInvalidUserToken = 17017, + + /** Indicates a network error occurred (such as a timeout, interrupted connection, or + unreachable host). These types of errors are often recoverable with a retry. The + `NSUnderlyingError` field in the `NSError.userInfo` dictionary will contain the error + encountered. + */ + FIRAuthErrorCodeNetworkError = 17020, + + /** Indicates the saved token has expired, for example, the user may have changed account + password on another device. The user needs to sign in again on the device that made this + request. + */ + FIRAuthErrorCodeUserTokenExpired = 17021, + + /** Indicates an invalid API key was supplied in the request. + */ + FIRAuthErrorCodeInvalidAPIKey = 17023, + + /** Indicates that an attempt was made to reauthenticate with a user which is not the current + user. + */ + FIRAuthErrorCodeUserMismatch = 17024, + + /** Indicates an attempt to link with a credential that has already been linked with a + different Firebase account + */ + FIRAuthErrorCodeCredentialAlreadyInUse = 17025, + + /** Indicates an attempt to set a password that is considered too weak. + */ + FIRAuthErrorCodeWeakPassword = 17026, + + /** Indicates the App is not authorized to use Firebase Authentication with the + provided API Key. + */ + FIRAuthErrorCodeAppNotAuthorized = 17028, + + /** Indicates the OOB code is expired. + */ + FIRAuthErrorCodeExpiredActionCode = 17029, + + /** Indicates the OOB code is invalid. + */ + FIRAuthErrorCodeInvalidActionCode = 17030, + + /** Indicates that there are invalid parameters in the payload during a "send password reset + * email" attempt. + */ + FIRAuthErrorCodeInvalidMessagePayload = 17031, + + /** Indicates that the sender email is invalid during a "send password reset email" attempt. + */ + FIRAuthErrorCodeInvalidSender = 17032, + + /** Indicates that the recipient email is invalid. + */ + FIRAuthErrorCodeInvalidRecipientEmail = 17033, + + /** Indicates that an email address was expected but one was not provided. + */ + FIRAuthErrorCodeMissingEmail = 17034, + + // The enum values 17035 is reserved and should NOT be used for new error codes. + + /** Indicates that the iOS bundle ID is missing when a iOS App Store ID is provided. + */ + FIRAuthErrorCodeMissingIosBundleID = 17036, + + /** Indicates that the android package name is missing when the `androidInstallApp` flag is set + to true. + */ + FIRAuthErrorCodeMissingAndroidPackageName = 17037, + + /** Indicates that the domain specified in the continue URL is not allowlisted in the Firebase + console. + */ + FIRAuthErrorCodeUnauthorizedDomain = 17038, + + /** Indicates that the domain specified in the continue URI is not valid. + */ + FIRAuthErrorCodeInvalidContinueURI = 17039, + + /** Indicates that a continue URI was not provided in a request to the backend which requires + one. + */ + FIRAuthErrorCodeMissingContinueURI = 17040, + + /** Indicates that a phone number was not provided in a call to + `verifyPhoneNumber:completion:`. + */ + FIRAuthErrorCodeMissingPhoneNumber = 17041, + + /** Indicates that an invalid phone number was provided in a call to + `verifyPhoneNumber:completion:`. + */ + FIRAuthErrorCodeInvalidPhoneNumber = 17042, + + /** Indicates that the phone auth credential was created with an empty verification code. + */ + FIRAuthErrorCodeMissingVerificationCode = 17043, + + /** Indicates that an invalid verification code was used in the verifyPhoneNumber request. + */ + FIRAuthErrorCodeInvalidVerificationCode = 17044, + + /** Indicates that the phone auth credential was created with an empty verification ID. + */ + FIRAuthErrorCodeMissingVerificationID = 17045, + + /** Indicates that an invalid verification ID was used in the verifyPhoneNumber request. + */ + FIRAuthErrorCodeInvalidVerificationID = 17046, + + /** Indicates that the APNS device token is missing in the verifyClient request. + */ + FIRAuthErrorCodeMissingAppCredential = 17047, + + /** Indicates that an invalid APNS device token was used in the verifyClient request. + */ + FIRAuthErrorCodeInvalidAppCredential = 17048, + + // The enum values between 17048 and 17051 are reserved and should NOT be used for new error + // codes. + + /** Indicates that the SMS code has expired. + */ + FIRAuthErrorCodeSessionExpired = 17051, + + /** Indicates that the quota of SMS messages for a given project has been exceeded. + */ + FIRAuthErrorCodeQuotaExceeded = 17052, + + /** Indicates that the APNs device token could not be obtained. The app may not have set up + remote notification correctly, or may fail to forward the APNs device token to FIRAuth + if app delegate swizzling is disabled. + */ + FIRAuthErrorCodeMissingAppToken = 17053, + + /** Indicates that the app fails to forward remote notification to FIRAuth. + */ + FIRAuthErrorCodeNotificationNotForwarded = 17054, + + /** Indicates that the app could not be verified by Firebase during phone number authentication. + */ + FIRAuthErrorCodeAppNotVerified = 17055, + + /** Indicates that the reCAPTCHA token is not valid. + */ + FIRAuthErrorCodeCaptchaCheckFailed = 17056, + + /** Indicates that an attempt was made to present a new web context while one was already being + presented. + */ + FIRAuthErrorCodeWebContextAlreadyPresented = 17057, + + /** Indicates that the URL presentation was cancelled prematurely by the user. + */ + FIRAuthErrorCodeWebContextCancelled = 17058, + + /** Indicates a general failure during the app verification flow. + */ + FIRAuthErrorCodeAppVerificationUserInteractionFailure = 17059, + + /** Indicates that the clientID used to invoke a web flow is invalid. + */ + FIRAuthErrorCodeInvalidClientID = 17060, + + /** Indicates that a network request within a SFSafariViewController or WKWebView failed. + */ + FIRAuthErrorCodeWebNetworkRequestFailed = 17061, + + /** Indicates that an internal error occurred within a SFSafariViewController or WKWebView. + */ + FIRAuthErrorCodeWebInternalError = 17062, + + /** Indicates a general failure during a web sign-in flow. + */ + FIRAuthErrorCodeWebSignInUserInteractionFailure = 17063, + + /** Indicates that the local player was not authenticated prior to attempting Game Center + signin. + */ + FIRAuthErrorCodeLocalPlayerNotAuthenticated = 17066, + + /** Indicates that a non-null user was expected as an argmument to the operation but a null + user was provided. + */ + FIRAuthErrorCodeNullUser = 17067, + + /** Indicates that a Firebase Dynamic Link is not activated. + */ + FIRAuthErrorCodeDynamicLinkNotActivated = 17068, + + /** + * Represents the error code for when the given provider id for a web operation is invalid. + */ + FIRAuthErrorCodeInvalidProviderID = 17071, + + /** + * Represents the error code for when an attempt is made to update the current user with a + * tenantId that differs from the current FirebaseAuth instance's tenantId. + */ + FIRAuthErrorCodeTenantIDMismatch = 17072, + + /** + * Represents the error code for when a request is made to the backend with an associated tenant + * ID for an operation that does not support multi-tenancy. + */ + FIRAuthErrorCodeUnsupportedTenantOperation = 17073, + + /** Indicates that the Firebase Dynamic Link domain used is either not configured or is + unauthorized for the current project. + */ + FIRAuthErrorCodeInvalidDynamicLinkDomain = 17074, + + /** Indicates that the credential is rejected because it's misformed or mismatching. + */ + FIRAuthErrorCodeRejectedCredential = 17075, + + /** Indicates that the GameKit framework is not linked prior to attempting Game Center signin. + */ + FIRAuthErrorCodeGameKitNotLinked = 17076, + + /** Indicates that the second factor is required for signin. + */ + FIRAuthErrorCodeSecondFactorRequired = 17078, + + /** Indicates that the multi factor session is missing. + */ + FIRAuthErrorCodeMissingMultiFactorSession = 17081, + + /** Indicates that the multi factor info is missing. + */ + FIRAuthErrorCodeMissingMultiFactorInfo = 17082, + + /** Indicates that the multi factor session is invalid. + */ + FIRAuthErrorCodeInvalidMultiFactorSession = 17083, + + /** Indicates that the multi factor info is not found. + */ + FIRAuthErrorCodeMultiFactorInfoNotFound = 17084, + + /** Indicates that the operation is admin restricted. + */ + FIRAuthErrorCodeAdminRestrictedOperation = 17085, + + /** Indicates that the email is required for verification. + */ + FIRAuthErrorCodeUnverifiedEmail = 17086, + + /** Indicates that the second factor is already enrolled. + */ + FIRAuthErrorCodeSecondFactorAlreadyEnrolled = 17087, + + /** Indicates that the maximum second factor count is exceeded. + */ + FIRAuthErrorCodeMaximumSecondFactorCountExceeded = 17088, + + /** Indicates that the first factor is not supported. + */ + FIRAuthErrorCodeUnsupportedFirstFactor = 17089, + + /** Indicates that the a verifed email is required to changed to. + */ + FIRAuthErrorCodeEmailChangeNeedsVerification = 17090, + + /** Indicates that the nonce is missing or invalid. + */ + FIRAuthErrorCodeMissingOrInvalidNonce = 17094, + + /** Indicates an error for when the client identifier is missing. + */ + FIRAuthErrorCodeMissingClientIdentifier = 17993, + + /** Indicates an error occurred while attempting to access the keychain. + */ + FIRAuthErrorCodeKeychainError = 17995, + + /** Indicates an internal error occurred. + */ + FIRAuthErrorCodeInternalError = 17999, + + /** Raised when a JWT fails to parse correctly. May be accompanied by an underlying error + describing which step of the JWT parsing process failed. + */ + FIRAuthErrorCodeMalformedJWT = 18000, +} NS_SWIFT_NAME(AuthErrorCode); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h new file mode 100644 index 0000000..1746627 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h @@ -0,0 +1,35 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthSettings + @brief Determines settings related to an auth object. + */ +NS_SWIFT_NAME(AuthSettings) +@interface FIRAuthSettings : NSObject + +/** @property appVerificationDisabledForTesting + @brief Flag to determine whether app verification should be disabled for testing or not. + */ +@property(nonatomic, assign, getter=isAppVerificationDisabledForTesting) + BOOL appVerificationDisabledForTesting; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h new file mode 100644 index 0000000..3c98c5f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h @@ -0,0 +1,69 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthTokenResult + @brief A data class containing the ID token JWT string and other properties associated with the + token including the decoded payload claims. + */ +NS_SWIFT_NAME(AuthTokenResult) +@interface FIRAuthTokenResult : NSObject + +/** @property token + @brief Stores the JWT string of the ID token. + */ +@property(nonatomic, readonly) NSString *token; + +/** @property expirationDate + @brief Stores the ID token's expiration date. + */ +@property(nonatomic, readonly) NSDate *expirationDate; + +/** @property authDate + @brief Stores the ID token's authentication date. + @remarks This is the date the user was signed in and NOT the date the token was refreshed. + */ +@property(nonatomic, readonly) NSDate *authDate; + +/** @property issuedAtDate + @brief Stores the date that the ID token was issued. + @remarks This is the date last refreshed and NOT the last authentication date. + */ +@property(nonatomic, readonly) NSDate *issuedAtDate; + +/** @property signInProvider + @brief Stores sign-in provider through which the token was obtained. + @remarks This does not necessarily map to provider IDs. + */ +@property(nonatomic, readonly) NSString *signInProvider; + +/** @property signInSecondFactor + @brief Stores sign-in second factor through which the token was obtained. + */ +@property(nonatomic, readonly) NSString *signInSecondFactor; + +/** @property claims + @brief Stores the entire payload of claims found on the ID token. This includes the standard + reserved claims as well as custom claims set by the developer via the Admin SDK. + */ +@property(nonatomic, readonly) NSDictionary *claims; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h new file mode 100644 index 0000000..01ab83e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h @@ -0,0 +1,54 @@ +/* + * 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 + +@class UIViewController; + +NS_ASSUME_NONNULL_BEGIN + +/** @protocol FIRAuthUIDelegate + @brief A protocol to handle user interface interactions for Firebase Auth. + This protocol is available on iOS, macOS Catalyst, and tvOS only. + */ +NS_SWIFT_NAME(AuthUIDelegate) API_UNAVAILABLE(macosx, watchos) @protocol FIRAuthUIDelegate + +/** @fn presentViewController:animated:completion: + @brief If implemented, this method will be invoked when Firebase Auth needs to display a view + controller. + @param viewControllerToPresent The view controller to be presented. + @param flag Decides whether the view controller presentation should be animated or not. + @param completion The block to execute after the presentation finishes. This block has no return + value and takes no parameters. +*/ +- (void)presentViewController:(UIViewController *)viewControllerToPresent + animated:(BOOL)flag + completion:(void (^_Nullable)(void))completion; + +/** @fn dismissViewControllerAnimated:completion: + @brief If implemented, this method will be invoked when Firebase Auth needs to display a view + controller. + @param flag Decides whether removing the view controller should be animated or not. + @param completion The block to execute after the presentation finishes. This block has no return + value and takes no parameters. +*/ +- (void)dismissViewControllerAnimated:(BOOL)flag + completion:(void (^_Nullable)(void))completion + NS_SWIFT_NAME(dismiss(animated:completion:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h new file mode 100644 index 0000000..d467f23 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h @@ -0,0 +1,73 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the email & password identity provider. + */ +extern NSString *const FIREmailAuthProviderID NS_SWIFT_NAME(EmailAuthProviderID); + +/** + @brief A string constant identifying the email-link sign-in method. + */ +extern NSString *const FIREmailLinkAuthSignInMethod NS_SWIFT_NAME(EmailLinkAuthSignInMethod); + +/** + @brief A string constant identifying the email & password sign-in method. + */ +// clang-format off +// clang-format12 merges the next two lines. +extern NSString *const FIREmailPasswordAuthSignInMethod + NS_SWIFT_NAME(EmailPasswordAuthSignInMethod); +// clang-format on + +/** @class FIREmailAuthProvider + @brief A concrete implementation of `FIRAuthProvider` for Email & Password Sign In. + */ +NS_SWIFT_NAME(EmailAuthProvider) +@interface FIREmailAuthProvider : NSObject + +/** @fn credentialWithEmail:password: + @brief Creates an `FIRAuthCredential` for an email & password sign in. + + @param email The user's email address. + @param password The user's password. + @return A FIRAuthCredential containing the email & password credential. + */ ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password; + +/** @fn credentialWithEmail:Link: + @brief Creates an `FIRAuthCredential` for an email & link sign in. + + @param email The user's email address. + @param link The email sign-in link. + @return A FIRAuthCredential containing the email & link credential. + */ ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email link:(NSString *)link; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h new file mode 100644 index 0000000..75efe13 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h @@ -0,0 +1,54 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Facebook identity provider. + */ +extern NSString *const FIRFacebookAuthProviderID NS_SWIFT_NAME(FacebookAuthProviderID); + +/** + @brief A string constant identifying the Facebook sign-in method. + */ +extern NSString *const _Nonnull FIRFacebookAuthSignInMethod NS_SWIFT_NAME(FacebookAuthSignInMethod); + +/** @class FIRFacebookAuthProvider + @brief Utility class for constructing Facebook credentials. + */ +NS_SWIFT_NAME(FacebookAuthProvider) +@interface FIRFacebookAuthProvider : NSObject + +/** @fn credentialWithAccessToken: + @brief Creates an `FIRAuthCredential` for a Facebook sign in. + + @param accessToken The Access Token from Facebook. + @return A FIRAuthCredential containing the Facebook credentials. + */ ++ (FIRAuthCredential *)credentialWithAccessToken:(NSString *)accessToken; + +/** @fn init + @brief This class should not be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h new file mode 100644 index 0000000..349470d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h @@ -0,0 +1,54 @@ +/* + * 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 + +#import "FIRAuthUIDelegate.h" + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + Utility type for constructing federated auth provider credentials. + */ +NS_SWIFT_NAME(FederatedAuthProvider) +@protocol FIRFederatedAuthProvider + +/** @typedef FIRAuthCredentialCallback + @brief The type of block invoked when obtaining an auth credential. + @param credential The credential obtained. + @param error The error that occurred if any. + */ +typedef void (^FIRAuthCredentialCallback)(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error) + NS_SWIFT_NAME(AuthCredentialCallback); + +/** @fn getCredentialWithUIDelegate:completion: + @brief Used to obtain an auth credential via a mobile web flow. + This method is available on iOS only. + @param UIDelegate An optional UI delegate used to presenet the mobile web flow. + @param completion Optionally; a block which is invoked asynchronously on the main thread when + the mobile web flow is completed. + */ +- (void)getCredentialWithUIDelegate:(nullable id)UIDelegate + completion:(nullable void (^)(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error))completion + API_UNAVAILABLE(macos, tvos, watchos); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h new file mode 100644 index 0000000..8596dce --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h @@ -0,0 +1,65 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Game Center identity provider. + */ +extern NSString *const FIRGameCenterAuthProviderID NS_SWIFT_NAME(GameCenterAuthProviderID); + +/** + @brief A string constant identifying the Game Center sign-in method. + */ +extern NSString *const _Nonnull FIRGameCenterAuthSignInMethod NS_SWIFT_NAME( + GameCenterAuthSignInMethod); + +/** @typedef FIRGameCenterCredentialCallback + @brief The type of block invoked when the Game Center credential code has finished. + @param credential On success, the credential will be provided, nil otherwise. + @param error On error, the error that occurred, nil otherwise. + */ +typedef void (^FIRGameCenterCredentialCallback)(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error) + NS_SWIFT_NAME(GameCenterCredentialCallback); + +/** @class FIRGameCenterAuthProvider + @brief A concrete implementation of @c FIRAuthProvider for Game Center Sign In. Not available on + watchOS. + */ +API_UNAVAILABLE(watchos) +NS_SWIFT_NAME(GameCenterAuthProvider) +@interface FIRGameCenterAuthProvider : NSObject + +/** @fn getCredentialWithCompletion: + @brief Creates a @c FIRAuthCredential for a Game Center sign in. + */ ++ (void)getCredentialWithCompletion: + (void (^)(FIRAuthCredential *_Nullable credential, NSError *_Nullable error))completion + NS_SWIFT_NAME(getCredential(completion:)); + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h new file mode 100644 index 0000000..0577c7b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h @@ -0,0 +1,54 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the GitHub identity provider. + */ +extern NSString *const FIRGitHubAuthProviderID NS_SWIFT_NAME(GitHubAuthProviderID); + +/** + @brief A string constant identifying the GitHub sign-in method. + */ +extern NSString *const _Nonnull FIRGitHubAuthSignInMethod NS_SWIFT_NAME(GitHubAuthSignInMethod); + +/** @class FIRGitHubAuthProvider + @brief Utility class for constructing GitHub credentials. + */ +NS_SWIFT_NAME(GitHubAuthProvider) +@interface FIRGitHubAuthProvider : NSObject + +/** @fn credentialWithToken: + @brief Creates an `FIRAuthCredential` for a GitHub sign in. + + @param token The GitHub OAuth access token. + @return A FIRAuthCredential containing the GitHub credential. + */ ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h new file mode 100644 index 0000000..7d6fa22 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h @@ -0,0 +1,56 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Google identity provider. + */ +extern NSString *const FIRGoogleAuthProviderID NS_SWIFT_NAME(GoogleAuthProviderID); + +/** + @brief A string constant identifying the Google sign-in method. + */ +extern NSString *const _Nonnull FIRGoogleAuthSignInMethod NS_SWIFT_NAME(GoogleAuthSignInMethod); + +/** @class FIRGoogleAuthProvider + @brief Utility class for constructing Google Sign In credentials. + */ +NS_SWIFT_NAME(GoogleAuthProvider) +@interface FIRGoogleAuthProvider : NSObject + +/** @fn credentialWithIDToken:accessToken: + @brief Creates an `FIRAuthCredential` for a Google sign in. + + @param IDToken The ID Token from Google. + @param accessToken The Access Token from Google. + @return A FIRAuthCredential containing the Google credentials. + */ ++ (FIRAuthCredential *)credentialWithIDToken:(NSString *)IDToken + accessToken:(NSString *)accessToken; + +/** @fn init + @brief This class should not be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h new file mode 100644 index 0000000..ecad20b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h @@ -0,0 +1,89 @@ +/* + * 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/LICENSE2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRAuth.h" +#import "FIRMultiFactorAssertion.h" +#import "FIRMultiFactorInfo.h" +#import "FIRMultiFactorSession.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRMultiFactorSessionCallback + @brief The callback that triggered when a developer calls `getSessionWithCompletion`. + This type is available on iOS only. + @param session The multi factor session returned, if any. + @param error The error which occurred, if any. +*/ +typedef void (^FIRMultiFactorSessionCallback)(FIRMultiFactorSession *_Nullable session, + NSError *_Nullable error) + NS_SWIFT_NAME(MultiFactorSessionCallback) API_UNAVAILABLE(macos, tvos, watchos); + +/** + @brief The string identifier for second factors. e.g. "phone". + This constant is available on iOS only. +*/ +extern NSString *const _Nonnull FIRPhoneMultiFactorID NS_SWIFT_NAME(PhoneMultiFactorID) + API_UNAVAILABLE(macos, tvos, watchos); + +/** @class FIRMultiFactor + @brief The interface defining the multi factor related properties and operations pertaining to a + user. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(MultiFactor) API_UNAVAILABLE(macos, tvos, watchos) @interface FIRMultiFactor + : NSObject + +@property(nonatomic, readonly) NSArray *enrolledFactors; + +/** @fn getSessionWithCompletion: + @brief Get a session for a second factor enrollment operation. + @param completion A block with the session identifier for a second factor enrollment operation. + This is used to identify the current user trying to enroll a second factor. +*/ +- (void)getSessionWithCompletion:(nullable void (^)(FIRMultiFactorSession *_Nullable credential, + NSError *_Nullable error))completion; + +/** @fn enrollWithAssertion:displayName:completion: + @brief Enrolls a second factor as identified by the `FIRMultiFactorAssertion` parameter for the + current user. + @param displayName An optional display name associated with the multi factor to enroll. + @param completion The block invoked when the request is complete, or fails. +*/ +- (void)enrollWithAssertion:(FIRMultiFactorAssertion *)assertion + displayName:(nullable NSString *)displayName + completion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn unenrollWithInfo:completion: + @brief Unenroll the given multi factor. + @param completion The block invoked when the request to send the verification email is complete, + or fails. +*/ +- (void)unenrollWithInfo:(FIRMultiFactorInfo *)factorInfo + completion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn unenrollWithFactorUID:completion: + @brief Unenroll the given multi factor. + @param completion The block invoked when the request to send the verification email is complete, + or fails. +*/ +- (void)unenrollWithFactorUID:(NSString *)factorUID + completion:(nullable void (^)(NSError *_Nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h new file mode 100644 index 0000000..f3bc340 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.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/LICENSE2.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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRMultiFactorAssertion + @brief The base class for asserting ownership of a second factor. This is equivalent to the + AuthCredential class. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(MultiFactorAssertion) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRMultiFactorAssertion : NSObject + +/** + @brief The second factor identifier for this opaque object asserting a second factor. +*/ +@property(nonatomic, readonly, nonnull) NSString *factorID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h new file mode 100644 index 0000000..8c02660 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h @@ -0,0 +1,50 @@ +/* + * 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/LICENSE2.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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRMultiFactorInfo + @brief Safe public structure used to represent a second factor entity from a client perspective. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(MultiFactorInfo) API_UNAVAILABLE(macos, tvos, watchos) @interface FIRMultiFactorInfo + : NSObject + +/** + @brief The multi-factor enrollment ID. +*/ +@property(nonatomic, readonly) NSString *UID; + +/** + @brief The user friendly name of the current second factor. +*/ +@property(nonatomic, readonly, nullable) NSString *displayName; + +/** + @brief The second factor enrollment date. +*/ +@property(nonatomic, readonly) NSDate *enrollmentDate; + +/** + @brief The identifier of the second factor. +*/ +@property(nonatomic, readonly) NSString *factorID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h new file mode 100644 index 0000000..6a102c5 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h @@ -0,0 +1,56 @@ +/* + * 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/LICENSE2.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 "FIRMultiFactor.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRMultiFactorResolver + @brief The data structure used to help developers resolve 2nd factor requirements on users that + have opted in to 2 factor authentication. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(MultiFactorResolver) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRMultiFactorResolver : NSObject + +/** + @brief The opaque session identifier for the current sign-in flow. +*/ +@property(nonatomic, readonly) FIRMultiFactorSession *session; + +/** + @brief The list of hints for the second factors needed to complete the sign-in for the current + session. +*/ +@property(nonatomic, readonly) NSArray *hints NS_SWIFT_NAME(hints); + +/** + @brief The Auth reference for the current FIRMultiResolver. +*/ +@property(nonatomic, readonly) FIRAuth *auth; + +/** @fn resolveSignInWithAssertion:completion: + @brief A helper function to help users complete sign in with a second factor using an + FIRMultiFactorAssertion confirming the user successfully completed the second factor + challenge. + @param completion The block invoked when the request is complete, or fails. +*/ +- (void)resolveSignInWithAssertion:(FIRMultiFactorAssertion *)assertion + completion:(nullable FIRAuthDataResultCallback)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h new file mode 100644 index 0000000..1b64b28 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h @@ -0,0 +1,31 @@ +/* + * 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/LICENSE2.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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRMultiFactorSession + @brief Opaque object that identifies the current session to enroll a second factor or to + complete sign in when previously enrolled. + This class is available on iOS only. + */ +NS_SWIFT_NAME(MultiFactorSession) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRMultiFactorSession : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h new file mode 100644 index 0000000..94abe4f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h @@ -0,0 +1,53 @@ +/* + * 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 + +#import "FIRAuthCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIROAuthCredential + @brief Internal implementation of FIRAuthCredential for generic credentials. + */ +NS_SWIFT_NAME(OAuthCredential) +@interface FIROAuthCredential : FIRAuthCredential + +/** @property IDToken + @brief The ID Token associated with this credential. + */ +@property(nonatomic, readonly, nullable) NSString *IDToken; + +/** @property accessToken + @brief The access token associated with this credential. + */ +@property(nonatomic, readonly, nullable) NSString *accessToken; + +/** @property secret + @brief The secret associated with this credential. This will be nil for OAuth 2.0 providers. + @detail OAuthCredential already exposes a providerId getter. This will help the developer + determine whether an access token/secret pair is needed. + */ +@property(nonatomic, readonly, nullable) NSString *secret; + +/** @fn init + @brief This class is not supposed to be instantiated directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h new file mode 100644 index 0000000..db3f2b1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h @@ -0,0 +1,124 @@ +/* + * 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 + +#import "FIRFederatedAuthProvider.h" + +@class FIRAuth; +@class FIROAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIROAuthProvider + @brief A concrete implementation of `FIRAuthProvider` for generic OAuth Providers. + */ +NS_SWIFT_NAME(OAuthProvider) +@interface FIROAuthProvider : NSObject + +/** @property scopes + @brief Array used to configure the OAuth scopes. + */ +@property(nonatomic, copy, nullable) NSArray *scopes; + +/** @property customParameters + @brief Dictionary used to configure the OAuth custom parameters. + */ +@property(nonatomic, copy, nullable) NSDictionary *customParameters; + +/** @property providerID + @brief The provider ID indicating the specific OAuth provider this OAuthProvider instance + represents. + */ +@property(nonatomic, copy, readonly) NSString *providerID; + +/** @fn providerWithProviderID: + @param providerID The provider ID of the IDP for which this auth provider instance will be + configured. + @return An instance of FIROAuthProvider corresponding to the specified provider ID. + */ ++ (FIROAuthProvider *)providerWithProviderID:(NSString *)providerID; + +/** @fn providerWithProviderID:auth: + @param providerID The provider ID of the IDP for which this auth provider instance will be + configured. + @param auth The auth instance to be associated with the FIROAuthProvider instance. + @return An instance of FIROAuthProvider corresponding to the specified provider ID. + */ ++ (FIROAuthProvider *)providerWithProviderID:(NSString *)providerID auth:(FIRAuth *)auth; + +/** @fn credentialWithProviderID:IDToken:accessToken: + @brief Creates an `FIRAuthCredential` for that OAuth 2 provider identified by providerID, ID + token and access token. + + @param providerID The provider ID associated with the Auth credential being created. + @param IDToken The IDToken associated with the Auth credential being created. + @param accessToken The access token associated with the Auth credential be created, if + available. + @return A FIRAuthCredential for the specified provider ID, ID token and access token. + */ ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + accessToken:(nullable NSString *)accessToken; + +/** @fn credentialWithProviderID:accessToken: + @brief Creates an `FIRAuthCredential` for that OAuth 2 provider identified by providerID using + an ID token. + + @param providerID The provider ID associated with the Auth credential being created. + @param accessToken The access token associated with the Auth credential be created + @return A FIRAuthCredential. + */ ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + accessToken:(NSString *)accessToken; + +/** @fn credentialWithProviderID:IDToken:rawNonce:accessToken: + @brief Creates an `FIRAuthCredential` for that OAuth 2 provider identified by providerID, ID + token, raw nonce and access token. + + @param providerID The provider ID associated with the Auth credential being created. + @param IDToken The IDToken associated with the Auth credential being created. + @param rawNonce The raw nonce associated with the Auth credential being created. + @param accessToken The access token associated with the Auth credential be created, if + available. + @return A FIRAuthCredential for the specified provider ID, ID token and access token. + */ ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce + accessToken:(nullable NSString *)accessToken; + +/** @fn credentialWithProviderID:IDToken:rawNonce: + @brief Creates an `FIRAuthCredential` for that OAuth 2 provider identified by providerID using + an ID token and raw nonce. + + @param providerID The provider ID associated with the Auth credential being created. + @param IDToken The IDToken associated with the Auth credential being created. + @param rawNonce The raw nonce associated with the Auth credential being created. + @return A FIRAuthCredential. + */ ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h new file mode 100644 index 0000000..deea1dd --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h @@ -0,0 +1,37 @@ +/* + * 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 + +#import "FIRAuthCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRPhoneAuthCredential + @brief Implementation of FIRAuthCredential for Phone Auth credentials. + This class is available on iOS only. + */ +NS_SWIFT_NAME(PhoneAuthCredential) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRPhoneAuthCredential : FIRAuthCredential + +/** @fn init + @brief This class is not supposed to be instantiated directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h new file mode 100644 index 0000000..8a64c09 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h @@ -0,0 +1,144 @@ +/* + * 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 + +@class FIRAuth; +@class FIRMultiFactorSession; +@class FIRPhoneAuthCredential; +@class FIRPhoneMultiFactorInfo; +@protocol FIRAuthUIDelegate; + +NS_ASSUME_NONNULL_BEGIN + +/** @var FIRPhoneAuthProviderID + @brief A string constant identifying the phone identity provider. + This constant is available on iOS only. + */ +extern NSString *const FIRPhoneAuthProviderID NS_SWIFT_NAME(PhoneAuthProviderID) + API_UNAVAILABLE(macos, tvos, watchos); + +/** @var FIRPhoneAuthProviderID + @brief A string constant identifying the phone sign-in method. + This constant is available on iOS only. + */ +extern NSString *const _Nonnull FIRPhoneAuthSignInMethod NS_SWIFT_NAME(PhoneAuthSignInMethod) + API_UNAVAILABLE(macos, tvos, watchos); + +/** @typedef FIRVerificationResultCallback + @brief The type of block invoked when a request to send a verification code has finished. + This type is available on iOS only. + + @param verificationID On success, the verification ID provided, nil otherwise. + @param error On error, the error that occurred, nil otherwise. + */ +typedef void (^FIRVerificationResultCallback)(NSString *_Nullable verificationID, + NSError *_Nullable error) + NS_SWIFT_NAME(VerificationResultCallback) API_UNAVAILABLE(macos, tvos, watchos); + +/** @class FIRPhoneAuthProvider + @brief A concrete implementation of `FIRAuthProvider` for phone auth providers. + This class is available on iOS only. + */ +NS_SWIFT_NAME(PhoneAuthProvider) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRPhoneAuthProvider : NSObject + +/** @fn provider + @brief Returns an instance of `FIRPhoneAuthProvider` for the default `FIRAuth` object. + */ ++ (instancetype)provider NS_SWIFT_NAME(provider()); + +/** @fn providerWithAuth: + @brief Returns an instance of `FIRPhoneAuthProvider` for the provided `FIRAuth` object. + @param auth The auth object to associate with the phone auth provider instance. + */ ++ (instancetype)providerWithAuth:(FIRAuth *)auth NS_SWIFT_NAME(provider(auth:)); + +/** @fn verifyPhoneNumber:UIDelegate:completion: + @brief Starts the phone number authentication flow by sending a verification code to the + specified phone number. + @param phoneNumber The phone number to be verified. + @param UIDelegate An object used to present the SFSafariViewController. The object is retained + by this method until the completion block is executed. + @param completion The callback to be invoked when the verification flow is finished. + @remarks Possible error codes: + + + `FIRAuthErrorCodeCaptchaCheckFailed` - Indicates that the reCAPTCHA token obtained by + the Firebase Auth is invalid or has expired. + + `FIRAuthErrorCodeQuotaExceeded` - Indicates that the phone verification quota for this + project has been exceeded. + + `FIRAuthErrorCodeInvalidPhoneNumber` - Indicates that the phone number provided is + invalid. + + `FIRAuthErrorCodeMissingPhoneNumber` - Indicates that a phone number was not provided. + */ +- (void)verifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRVerificationResultCallback)completion; + +/** @fn verifyPhoneNumber:UIDelegate:multiFactorSession:completion: + @brief Verify ownership of the second factor phone number by the current user. + @param phoneNumber The phone number to be verified. + @param UIDelegate An object used to present the SFSafariViewController. The object is retained + by this method until the completion block is executed. + @param session A session to identify the MFA flow. For enrollment, this identifies the user + trying to enroll. For sign-in, this identifies that the user already passed the first + factor challenge. + @param completion The callback to be invoked when the verification flow is finished. +*/ +- (void)verifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + completion:(nullable FIRVerificationResultCallback)completion; + +/** @fn verifyPhoneNumberWithMultiFactorInfo:UIDelegate:multiFactorSession:completion: + @brief Verify ownership of the second factor phone number by the current user. + @param phoneMultiFactorInfo The phone multi factor whose number need to be verified. + @param UIDelegate An object used to present the SFSafariViewController. The object is retained + by this method until the completion block is executed. + @param session A session to identify the MFA flow. For enrollment, this identifies the user + trying to enroll. For sign-in, this identifies that the user already passed the first + factor challenge. + @param completion The callback to be invoked when the verification flow is finished. +*/ +- (void)verifyPhoneNumberWithMultiFactorInfo:(FIRPhoneMultiFactorInfo *)phoneMultiFactorInfo + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + completion: + (nullable void (^)(NSString *_Nullable verificationID, + NSError *_Nullable error))completion; + +/** @fn credentialWithVerificationID:verificationCode: + @brief Creates an `FIRAuthCredential` for the phone number provider identified by the + verification ID and verification code. + + @param verificationID The verification ID obtained from invoking + verifyPhoneNumber:completion: + @param verificationCode The verification code obtained from the user. + @return The corresponding phone auth credential for the verification ID and verification code + provided. + */ +- (FIRPhoneAuthCredential *)credentialWithVerificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode; + +/** @fn init + @brief Please use the `provider` or `providerWithAuth:` methods to obtain an instance of + `FIRPhoneAuthProvider`. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h new file mode 100644 index 0000000..13e6a42 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h @@ -0,0 +1,33 @@ +/* + * 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/LICENSE2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRMultiFactorAssertion.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRPhoneMultiFactorAssertion + @brief The subclass of base class FIRMultiFactorAssertion, used to assert ownership of a phone + second factor. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(PhoneMultiFactorAssertion) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRPhoneMultiFactorAssertion : FIRMultiFactorAssertion + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h new file mode 100644 index 0000000..355b927 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h @@ -0,0 +1,43 @@ +/* + * 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/LICENSE2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRPhoneAuthCredential.h" +#import "FIRPhoneMultiFactorAssertion.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRPhoneMultiFactorGenerator + @brief The data structure used to help initialize an assertion for a second factor entity to the + Firebase Auth/CICP server. Depending on the type of second factor, this will help generate + the assertion. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(PhoneMultiFactorGenerator) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRPhoneMultiFactorGenerator : NSObject + +/** @fn assertionWithCredential: + @brief Initializes the MFA assertion to confirm ownership of the phone second factor. Note that + this API is used for both enrolling and signing in with a phone second factor. + @param phoneAuthCredential The phone auth credential used for multi factor flows. +*/ ++ (FIRPhoneMultiFactorAssertion *)assertionWithCredential: + (FIRPhoneAuthCredential *)phoneAuthCredential; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h new file mode 100644 index 0000000..9a09dde --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h @@ -0,0 +1,38 @@ +/* + * 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/LICENSE2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRMultiFactorInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRPhoneMultiFactorInfo + @brief Extends the FIRMultiFactorInfo class for phone number second factors. + The identifier of this second factor is "phone". + This class is available on iOS only. +*/ +NS_SWIFT_NAME(PhoneMultiFactorInfo) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRPhoneMultiFactorInfo : FIRMultiFactorInfo + +/** + @brief This is the phone number associated with the current second factor. +*/ +@property(nonatomic, readonly, nonnull) NSString *phoneNumber; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h new file mode 100644 index 0000000..0f1b28d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h @@ -0,0 +1,54 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Twitter identity provider. + */ +extern NSString *const FIRTwitterAuthProviderID NS_SWIFT_NAME(TwitterAuthProviderID); +/** + @brief A string constant identifying the Twitter sign-in method. + */ +extern NSString *const _Nonnull FIRTwitterAuthSignInMethod NS_SWIFT_NAME(TwitterAuthSignInMethod); + +/** @class FIRTwitterAuthProvider + @brief Utility class for constructing Twitter credentials. + */ +NS_SWIFT_NAME(TwitterAuthProvider) +@interface FIRTwitterAuthProvider : NSObject + +/** @fn credentialWithToken:secret: + @brief Creates an `FIRAuthCredential` for a Twitter sign in. + + @param token The Twitter OAuth token. + @param secret The Twitter OAuth secret. + @return A FIRAuthCredential containing the Twitter credential. + */ ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token secret:(NSString *)secret; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h new file mode 100644 index 0000000..54bdc57 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h @@ -0,0 +1,550 @@ +/* + * 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 + +#import "FIRAuth.h" +#import "FIRAuthDataResult.h" +#import "FIRMultiFactor.h" +#import "FIRUserInfo.h" + +@class FIRAuthTokenResult; +@class FIRPhoneAuthCredential; +@class FIRUserProfileChangeRequest; +@class FIRUserMetadata; +@protocol FIRAuthUIDelegate; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthTokenCallback + @brief The type of block called when a token is ready for use. + @see FIRUser.getIDTokenWithCompletion: + @see FIRUser.getIDTokenForcingRefresh:withCompletion: + + @param token Optionally; an access token if the request was successful. + @param error Optionally; the error which occurred - or nil if the request was successful. + + @remarks One of: `token` or `error` will always be non-nil. + */ +typedef void (^FIRAuthTokenCallback)(NSString *_Nullable token, NSError *_Nullable error) + NS_SWIFT_NAME(AuthTokenCallback); + +/** @typedef FIRAuthTokenResultCallback + @brief The type of block called when a token is ready for use. + @see FIRUser.getIDTokenResultWithCompletion: + @see FIRUser.getIDTokenResultForcingRefresh:withCompletion: + + @param tokenResult Optionally; an object containing the raw access token string as well as other + useful data pertaining to the token. + @param error Optionally; the error which occurred - or nil if the request was successful. + + @remarks One of: `token` or `error` will always be non-nil. + */ +typedef void (^FIRAuthTokenResultCallback)(FIRAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error) + NS_SWIFT_NAME(AuthTokenResultCallback); + +/** @typedef FIRUserProfileChangeCallback + @brief The type of block called when a user profile change has finished. + + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRUserProfileChangeCallback)(NSError *_Nullable error) + NS_SWIFT_NAME(UserProfileChangeCallback); + +/** @typedef FIRSendEmailVerificationCallback + @brief The type of block called when a request to send an email verification has finished. + + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRSendEmailVerificationCallback)(NSError *_Nullable error) + NS_SWIFT_NAME(SendEmailVerificationCallback); + +/** @class FIRUser + @brief Represents a user. Firebase Auth does not attempt to validate users + when loading them from the keychain. Invalidated users (such as those + whose passwords have been changed on another client) are automatically + logged out when an auth-dependent operation is attempted or when the + ID token is automatically refreshed. + @remarks This class is thread-safe. + */ +NS_SWIFT_NAME(User) +@interface FIRUser : NSObject + +/** @property anonymous + @brief Indicates the user represents an anonymous user. + */ +@property(nonatomic, readonly, getter=isAnonymous) BOOL anonymous; + +/** @property emailVerified + @brief Indicates the email address associated with this user has been verified. + */ +@property(nonatomic, readonly, getter=isEmailVerified) BOOL emailVerified; + +/** @property refreshToken + @brief A refresh token; useful for obtaining new access tokens independently. + @remarks This property should only be used for advanced scenarios, and is not typically needed. + */ +@property(nonatomic, readonly, nullable) NSString *refreshToken; + +/** @property providerData + @brief Profile data for each identity provider, if any. + @remarks This data is cached on sign-in and updated when linking or unlinking. + */ +@property(nonatomic, readonly, nonnull) NSArray> *providerData; + +/** @property metadata + @brief Metadata associated with the Firebase user in question. + */ +@property(nonatomic, readonly, nonnull) FIRUserMetadata *metadata; + +/** @property tenantID + @brief The tenant ID of the current user. nil if none is available. + */ +@property(nonatomic, readonly, nullable) NSString *tenantID; + +/** @property multiFactor + @brief Multi factor object associated with the user. + This property is available on iOS only. +*/ +@property(nonatomic, readonly, nonnull) + FIRMultiFactor *multiFactor API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn init + @brief This class should not be instantiated. + @remarks To retrieve the current user, use `FIRAuth.currentUser`. To sign a user + in or out, use the methods on `FIRAuth`. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn updateEmail:completion: + @brief Updates the email address for the user. On success, the cached user profile data is + updated. + @remarks May fail if there is already an account with this email address that was created using + email and password authentication. + + @param email The email address for the user. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `FIRAuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `FIRAuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `FIRAuthErrorCodeEmailAlreadyInUse` - Indicates the email is already in use by another + account. + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + `FIRAuthErrorCodeRequiresRecentLogin` - Updating a user’s email is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + invoking reauthenticateWithCredential:completion: on FIRUser. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ +- (void)updateEmail:(NSString *)email + completion:(nullable void (^)(NSError *_Nullable error))completion + NS_SWIFT_NAME(updateEmail(to:completion:)); + +/** @fn updatePassword:completion: + @brief Updates the password for the user. On success, the cached user profile data is updated. + + @param password The new password for the user. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates the administrator disabled + sign in with the specified identity provider. + + `FIRAuthErrorCodeRequiresRecentLogin` - Updating a user’s password is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + invoking reauthenticateWithCredential:completion: on FIRUser. + + `FIRAuthErrorCodeWeakPassword` - Indicates an attempt to set a password that is + considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo + dictionary object will contain more detailed explanation that can be shown to the user. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ +- (void)updatePassword:(NSString *)password + completion:(nullable void (^)(NSError *_Nullable error))completion + NS_SWIFT_NAME(updatePassword(to:completion:)); + +/** @fn updatePhoneNumberCredential:completion: + @brief Updates the phone number for the user. On success, the cached user profile data is + updated. + This method is available on iOS only. + + @param phoneNumberCredential The new phone number credential corresponding to the phone number + to be added to the Firebase account, if a phone number is already linked to the account this + new phone number will replace it. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeRequiresRecentLogin` - Updating a user’s phone number is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + invoking reauthenticateWithCredential:completion: on FIRUser. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ +- (void)updatePhoneNumberCredential:(FIRPhoneAuthCredential *)phoneNumberCredential + completion:(nullable void (^)(NSError *_Nullable error))completion + API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn profileChangeRequest + @brief Creates an object which may be used to change the user's profile data. + + @remarks Set the properties of the returned object, then call + `FIRUserProfileChangeRequest.commitChangesWithCallback:` to perform the updates atomically. + + @return An object which may be used to change the user's profile data atomically. + */ +- (FIRUserProfileChangeRequest *)profileChangeRequest NS_SWIFT_NAME(createProfileChangeRequest()); + +/** @fn reloadWithCompletion: + @brief Reloads the user's profile data from the server. + + @param completion Optionally; the block invoked when the reload has finished. Invoked + asynchronously on the main thread in the future. + + @remarks May fail with a `FIRAuthErrorCodeRequiresRecentLogin` error code. In this case + you should call `FIRUser.reauthenticateWithCredential:completion:` before re-invoking + `FIRUser.updateEmail:completion:`. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)reloadWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn reauthenticateWithCredential:completion: + @brief Renews the user's authentication tokens by validating a fresh set of credentials supplied + by the user and returns additional identity provider data. + + @param credential A user-supplied credential, which will be validated by the server. This can be + a successful third-party identity provider sign-in, or an email address and password. + @param completion Optionally; the block invoked when the re-authentication operation has + finished. Invoked asynchronously on the main thread in the future. + + @remarks If the user associated with the supplied credential is different from the current user, + or if the validation of the supplied credentials fails; an error is returned and the current + user remains signed in. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidCredential` - Indicates the supplied credential is invalid. + This could happen if it has expired or it is malformed. + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates that accounts with the + identity provider represented by the credential are not enabled. Enable them in the + Auth section of the Firebase console. + + `FIRAuthErrorCodeEmailAlreadyInUse` - Indicates the email asserted by the credential + (e.g. the email in a Facebook access token) is already in use by an existing account, + that cannot be authenticated with this method. Call fetchProvidersForEmail for + this user’s email and then prompt them to sign in with any of the sign-in providers + returned. This error will only be thrown if the "One account per email address" + setting is enabled in the Firebase console, under Auth settings. Please note that the + error code raised in this specific situation may not be the same on Web and Android. + + `FIRAuthErrorCodeUserDisabled` - Indicates the user's account is disabled. + + `FIRAuthErrorCodeWrongPassword` - Indicates the user attempted reauthentication with + an incorrect password, if credential is of the type EmailPasswordAuthCredential. + + `FIRAuthErrorCodeUserMismatch` - Indicates that an attempt was made to + reauthenticate with a user which is not the current user. + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)reauthenticateWithCredential:(FIRAuthCredential *)credential + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn reauthenticateWithProvider:UIDelegate:completion: + @brief Renews the user's authentication using the provided auth provider instance. + This method is available on iOS, macOS Catalyst, and tvOS only. + + @param provider An instance of an auth provider used to initiate the reauthenticate flow. + @param UIDelegate Optionally an instance of a class conforming to the FIRAuthUIDelegate + protocol, this is used for presenting the web context. If nil, a default FIRAuthUIDelegate + will be used. + @param completion Optionally; a block which is invoked when the reauthenticate flow finishes, or + is canceled. Invoked asynchronously on the main thread in the future. + */ +- (void)reauthenticateWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion + NS_SWIFT_NAME(reauthenticate(with:uiDelegate:completion:))API_UNAVAILABLE(macosx, watchos); + +/** @fn getIDTokenResultWithCompletion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)getIDTokenResultWithCompletion:(nullable void (^)(FIRAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error))completion + NS_SWIFT_NAME(getIDTokenResult(completion:)); + +/** @fn getIDTokenResultForcingRefresh:completion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason + other than an expiration. + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks The authentication token will be refreshed (by making a network request) if it has + expired, or if `forceRefresh` is YES. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)getIDTokenResultForcingRefresh:(BOOL)forceRefresh + completion:(nullable void (^)(FIRAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error))completion + NS_SWIFT_NAME(getIDTokenResult(forcingRefresh:completion:)); + +/** @fn getIDTokenWithCompletion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)getIDTokenWithCompletion: + (nullable void (^)(NSString *_Nullable token, NSError *_Nullable error))completion + NS_SWIFT_NAME(getIDToken(completion:)); + +/** @fn getIDTokenForcingRefresh:completion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason + other than an expiration. + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks The authentication token will be refreshed (by making a network request) if it has + expired, or if `forceRefresh` is YES. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)getIDTokenForcingRefresh:(BOOL)forceRefresh + completion:(nullable void (^)(NSString *_Nullable token, + NSError *_Nullable error))completion; + +/** @fn linkWithCredential:completion: + @brief Associates a user account from a third-party identity provider with this user and + returns additional identity provider data. + + @param credential The credential for the identity provider. + @param completion Optionally; the block invoked when the unlinking is complete, or fails. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeProviderAlreadyLinked` - Indicates an attempt to link a provider of a + type already linked to this account. + + `FIRAuthErrorCodeCredentialAlreadyInUse` - Indicates an attempt to link with a + credential that has already been linked with a different Firebase account. + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates that accounts with the identity + provider represented by the credential are not enabled. Enable them in the Auth section + of the Firebase console. + + @remarks This method may also return error codes associated with updateEmail:completion: and + updatePassword:completion: on FIRUser. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ +- (void)linkWithCredential:(FIRAuthCredential *)credential + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn linkWithProvider:UIDelegate:completion: + @brief link the user with the provided auth provider instance. + This method is available on iOS, macOS Catalyst, and tvOS only. + + @param provider An instance of an auth provider used to initiate the link flow. + @param UIDelegate Optionally an instance of a class conforming to the FIRAuthUIDelegate + protocol, this is used for presenting the web context. If nil, a default FIRAuthUIDelegate + will be used. + @param completion Optionally; a block which is invoked when the link flow finishes, or + is canceled. Invoked asynchronously on the main thread in the future. + */ +- (void)linkWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion + NS_SWIFT_NAME(link(with:uiDelegate:completion:))API_UNAVAILABLE(macosx, watchos); + +/** @fn unlinkFromProvider:completion: + @brief Disassociates a user account from a third-party identity provider with this user. + + @param provider The provider ID of the provider to unlink. + @param completion Optionally; the block invoked when the unlinking is complete, or fails. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeNoSuchProvider` - Indicates an attempt to unlink a provider + that is not linked to the account. + + `FIRAuthErrorCodeRequiresRecentLogin` - Updating email is a security sensitive + operation that requires a recent login from the user. This error indicates the user + has not signed in recently enough. To resolve, reauthenticate the user by invoking + reauthenticateWithCredential:completion: on FIRUser. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ +- (void)unlinkFromProvider:(NSString *)provider + completion:(nullable void (^)(FIRUser *_Nullable user, + NSError *_Nullable error))completion; + +/** @fn sendEmailVerificationWithCompletion: + @brief Initiates email verification for the user. + + @param completion Optionally; the block invoked when the request to send an email verification + is complete, or fails. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `FIRAuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `FIRAuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `FIRAuthErrorCodeUserNotFound` - Indicates the user account was not found. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + */ +- (void)sendEmailVerificationWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn sendEmailVerificationWithActionCodeSettings:completion: + @brief Initiates email verification for the user. + + @param actionCodeSettings An `FIRActionCodeSettings` object containing settings related to + handling action codes. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `FIRAuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `FIRAuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `FIRAuthErrorCodeUserNotFound` - Indicates the user account was not found. + + `FIRAuthErrorCodeMissingIosBundleID` - Indicates that the iOS bundle ID is missing when + a iOS App Store ID is provided. + + `FIRAuthErrorCodeMissingAndroidPackageName` - Indicates that the android package name + is missing when the `androidInstallApp` flag is set to true. + + `FIRAuthErrorCodeUnauthorizedDomain` - Indicates that the domain specified in the + continue URL is not allowlisted in the Firebase console. + + `FIRAuthErrorCodeInvalidContinueURI` - Indicates that the domain specified in the + continue URI is not valid. + */ +- (void)sendEmailVerificationWithActionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion:(nullable void (^)(NSError *_Nullable error)) + completion; + +/** @fn deleteWithCompletion: + @brief Deletes the user account (also signs out the user, if this was the current user). + + @param completion Optionally; the block invoked when the request to delete the account is + complete, or fails. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeRequiresRecentLogin` - Updating email is a security sensitive + operation that requires a recent login from the user. This error indicates the user + has not signed in recently enough. To resolve, reauthenticate the user by invoking + reauthenticateWithCredential:completion: on FIRUser. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all FIRUser methods. + + */ +- (void)deleteWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn sendEmailVerificationBeforeUpdatingEmail:completion: + @brief Send an email to verify the ownership of the account then update to the new email. + @param email The email to be updated to. + @param completion Optionally; the block invoked when the request to send the verification + email is complete, or fails. +*/ +- (void)sendEmailVerificationBeforeUpdatingEmail:(nonnull NSString *)email + completion: + (nullable void (^)(NSError *_Nullable error))completion; + +/** @fn sendEmailVerificationBeforeUpdatingEmail:completion: + @brief Send an email to verify the ownership of the account then update to the new email. + @param email The email to be updated to. + @param actionCodeSettings An `FIRActionCodeSettings` object containing settings related to + handling action codes. + @param completion Optionally; the block invoked when the request to send the verification + email is complete, or fails. +*/ +- (void)sendEmailVerificationBeforeUpdatingEmail:(nonnull NSString *)email + actionCodeSettings:(nonnull FIRActionCodeSettings *)actionCodeSettings + completion: + (nullable void (^)(NSError *_Nullable error))completion; + +@end + +/** @class FIRUserProfileChangeRequest + @brief Represents an object capable of updating a user's profile data. + @remarks Properties are marked as being part of a profile update when they are set. Setting a + property value to nil is not the same as leaving the property unassigned. + */ +NS_SWIFT_NAME(UserProfileChangeRequest) +@interface FIRUserProfileChangeRequest : NSObject + +/** @fn init + @brief Please use `FIRUser.profileChangeRequest` + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @property displayName + @brief The user's display name. + @remarks It is an error to set this property after calling + `FIRUserProfileChangeRequest.commitChangesWithCallback:` + */ +@property(nonatomic, copy, nullable) NSString *displayName; + +/** @property photoURL + @brief The user's photo URL. + @remarks It is an error to set this property after calling + `FIRUserProfileChangeRequest.commitChangesWithCallback:` + */ +@property(nonatomic, copy, nullable) NSURL *photoURL; + +/** @fn commitChangesWithCompletion: + @brief Commits any pending changes. + @remarks This method should only be called once. Once called, property values should not be + changed. + + @param completion Optionally; the block invoked when the user profile change has been applied. + Invoked asynchronously on the main thread in the future. + */ +- (void)commitChangesWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h new file mode 100644 index 0000000..04eca49 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h @@ -0,0 +1,60 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief Represents user data returned from an identity provider. + */ +NS_SWIFT_NAME(UserInfo) +@protocol FIRUserInfo + +/** @property providerID + @brief The provider identifier. + */ +@property(nonatomic, copy, readonly) NSString *providerID; + +/** @property uid + @brief The provider's user ID for the user. + */ +@property(nonatomic, copy, readonly) NSString *uid; + +/** @property displayName + @brief The name of the user. + */ +@property(nonatomic, copy, readonly, nullable) NSString *displayName; + +/** @property photoURL + @brief The URL of the user's profile photo. + */ +@property(nonatomic, copy, readonly, nullable) NSURL *photoURL; + +/** @property email + @brief The user's email address. + */ +@property(nonatomic, copy, readonly, nullable) NSString *email; + +/** @property phoneNumber + @brief A phone number associated with the user. + @remarks This property is only available for users authenticated via phone number auth. + */ +@property(nonatomic, readonly, nullable) NSString *phoneNumber; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h new file mode 100644 index 0000000..3ceae38 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h @@ -0,0 +1,45 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRUserMetadata + @brief A data class representing the metadata corresponding to a Firebase user. + */ +NS_SWIFT_NAME(UserMetadata) +@interface FIRUserMetadata : NSObject + +/** @property lastSignInDate + @brief Stores the last sign in date for the corresponding Firebase user. + */ +@property(copy, nonatomic, readonly, nullable) NSDate *lastSignInDate; + +/** @property creationDate + @brief Stores the creation date for the corresponding Firebase user. + */ +@property(copy, nonatomic, readonly, nullable) NSDate *creationDate; + +/** @fn init + @brief This class should not be initialized manually, an instance of this class can be obtained + from a Firebase user object. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h new file mode 100644 index 0000000..3d922b2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h @@ -0,0 +1,51 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRActionCodeSettings.h" +#import "FIRAdditionalUserInfo.h" +#import "FIRAuth.h" +#import "FIRAuthCredential.h" +#import "FIRAuthDataResult.h" +#import "FIRAuthErrors.h" +#import "FIRAuthTokenResult.h" +#import "FIREmailAuthProvider.h" +#import "FIRFacebookAuthProvider.h" +#import "FIRFederatedAuthProvider.h" +#import "FIRGameCenterAuthProvider.h" +#import "FIRGitHubAuthProvider.h" +#import "FIRGoogleAuthProvider.h" +#import "FIRMultiFactor.h" +#import "FIRMultiFactorAssertion.h" +#import "FIRMultiFactorInfo.h" +#import "FIRMultiFactorResolver.h" +#import "FIRMultiFactorSession.h" +#import "FIROAuthCredential.h" +#import "FIROAuthProvider.h" +#import "FIRTwitterAuthProvider.h" +#import "FIRUser.h" +#import "FIRUserInfo.h" +#import "FIRUserMetadata.h" + +#import "FIRAuthAPNSTokenType.h" +#import "FIRAuthSettings.h" +#import "FIRAuthUIDelegate.h" +#import "FIRPhoneAuthCredential.h" +#import "FIRPhoneAuthProvider.h" +#import "FIRPhoneMultiFactorAssertion.h" +#import "FIRPhoneMultiFactorGenerator.h" +#import "FIRPhoneMultiFactorInfo.h" diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h new file mode 100644 index 0000000..ff7c05d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h @@ -0,0 +1,99 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief The protocol for permanant data storage. + */ +@protocol FIRAuthStorage + +/** @fn initWithService: + @brief Initialize a @c FIRAuthStorage instance. + @param service The name of the storage service to use. + @return An initialized @c FIRAuthStorage instance for the specified service. + */ +- (id)initWithService:(NSString *)service; + +/** @fn dataForKey:error: + @brief Gets the data for @c key in the storage. The key is set for the attribute + @c kSecAttrAccount of a generic password query. + @param key The key to use. + @param error The address to store any error that occurs during the process, if not NULL. + If the operation was successful, its content is set to @c nil . + @return The data stored in the storage for @c key, if any. + */ +- (nullable NSData *)dataForKey:(NSString *)key error:(NSError **_Nullable)error; + +/** @fn setData:forKey:error: + @brief Sets the data for @c key in the storage. The key is set for the attribute + @c kSecAttrAccount of a generic password query. + @param data The data to store. + @param key The key to use. + @param error The address to store any error that occurs during the process, if not NULL. + @return Whether the operation succeeded or not. + */ +- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError **_Nullable)error; + +/** @fn removeDataForKey:error: + @brief Removes the data for @c key in the storage. The key is set for the attribute + @c kSecAttrAccount of a generic password query. + @param key The key to use. + @param error The address to store any error that occurs during the process, if not NULL. + @return Whether the operation succeeded or not. + */ +- (BOOL)removeDataForKey:(NSString *)key error:(NSError **_Nullable)error; + +@end + +/** @class FIRAuthKeychain + @brief The utility class to manipulate data in iOS Keychain. + */ +@interface FIRAuthKeychainServices : NSObject + +/** @fn getItemWithQuery:error: + @brief Get the item from keychain by given query. + @param query The query to query the keychain. + @param outError The address to store any error that occurs during the process, if not nil. + @return The item of the given query. nil if not exsit. + */ +- (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn setItem:withQuery:error: + @brief Set the item into keychain with given query. + @param item The item to be added into keychain. + @param query The query to query the keychain. + @param outError The address to store any error that occurs during the process, if not nil. + @return Whether the operation succeed. + */ +- (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn getItemWithQuery:error: + @brief Remove the item with given queryfrom keychain. + @param query The query to query the keychain. + @param outError The address to store any error that occurs during the process, if not nil. + @return Whether the operation succeed. + */ +- (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.m new file mode 100644 index 0000000..ec657df --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.m @@ -0,0 +1,342 @@ +/* + * 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 "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" + +#import + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +/** @var kAccountPrefix + @brief The prefix string for keychain item account attribute before the key. + @remarks A number "1" is encoded in the prefix in case we need to upgrade the scheme in future. + */ +static NSString *const kAccountPrefix = @"firebase_auth_1_"; + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthKeychainServices { + /** @var _service + @brief The name of the keychain service. + */ + NSString *_service; + + /** @var _legacyItemDeletedForKey + @brief Indicates whether or not this class knows that the legacy item for a particular key has + been deleted. + @remarks This dictionary is to avoid unecessary keychain operations against legacy items. + */ + NSMutableDictionary *_legacyEntryDeletedForKey; +} + +- (id)initWithService:(NSString *)service { + self = [super init]; + if (self) { + _service = [service copy]; + _legacyEntryDeletedForKey = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (nullable NSData *)dataForKey:(NSString *)key error:(NSError **_Nullable)error { + if (!key.length) { + [NSException raise:NSInvalidArgumentException format:@"%@", @"The key cannot be nil or empty."]; + return nil; + } + NSData *data = [self itemWithQuery:[self genericPasswordQueryWithKey:key] error:error]; + if (error && *error) { + return nil; + } + if (data) { + return data; + } + // Check for legacy form. + if (_legacyEntryDeletedForKey[key]) { + return nil; + } + data = [self itemWithQuery:[self legacyGenericPasswordQueryWithKey:key] error:error]; + if (error && *error) { + return nil; + } + if (!data) { + // Mark legacy data as non-existing so we don't have to query it again. + _legacyEntryDeletedForKey[key] = @YES; + return nil; + } + // Move the data to current form. + if (![self setData:data forKey:key error:error]) { + return nil; + } + [self deleteLegacyItemWithKey:key]; + return data; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError **_Nullable)error { + if (!key.length) { + [NSException raise:NSInvalidArgumentException format:@"%@", @"The key cannot be nil or empty."]; + return NO; + } + NSDictionary *attributes = @{ + (__bridge id)kSecValueData : data, + (__bridge id)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, + }; + return [self setItemWithQuery:[self genericPasswordQueryWithKey:key] + attributes:attributes + error:error]; +} + +- (BOOL)removeDataForKey:(NSString *)key error:(NSError **_Nullable)error { + if (!key.length) { + [NSException raise:NSInvalidArgumentException format:@"%@", @"The key cannot be nil or empty."]; + return NO; + } + if (![self deleteItemWithQuery:[self genericPasswordQueryWithKey:key] error:error]) { + return NO; + } + // Legacy form item, if exists, also needs to be removed, otherwise it will be exposed when + // current form item is removed, leading to incorrect semantics. + [self deleteLegacyItemWithKey:key]; + return YES; +} + +#pragma mark - Private methods for non-sharing keychain operations + +- (nullable NSData *)itemWithQuery:(NSDictionary *)query error:(NSError **_Nullable)error { + NSMutableDictionary *returningQuery = [query mutableCopy]; + returningQuery[(__bridge id)kSecReturnData] = @YES; + returningQuery[(__bridge id)kSecReturnAttributes] = @YES; + // Using a match limit of 2 means that we can check whether there is more than one item. + // If we used a match limit of 1 we would never find out. + returningQuery[(__bridge id)kSecMatchLimit] = @2; + + CFArrayRef result = NULL; + OSStatus status = + SecItemCopyMatching((__bridge CFDictionaryRef)returningQuery, (CFTypeRef *)&result); + + if (status == noErr && result != NULL) { + NSArray *items = (__bridge_transfer NSArray *)result; + if (items.count == 0) { + if (error) { + // The keychain query returned no error, but there were no items found. + *error = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemCopyMatching" status:status]; + } + return nil; + } else if (items.count > 1) { + // More than one keychain item was found, all but the first will be ignored. + FIRLogWarning( + kFIRLoggerAuth, @"I-AUT000005", + @"Keychain query returned multiple results, all but the first will be ignored: %@", + items); + } + + if (error) { + *error = nil; + } + // Return the non-legacy item. + for (NSDictionary *item in items) { + if (item[(__bridge NSString *)kSecAttrService] != nil) { + return item[(__bridge id)kSecValueData]; + } + } + + // If they were all legacy items, just return the first one. + // This should not happen, since only one account should be + // stored. + return items[0][(__bridge id)kSecValueData]; + } + + if (status == errSecItemNotFound) { + if (error) { + *error = nil; + } + } else { + if (error) { + *error = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemCopyMatching" status:status]; + } + } + return nil; +} + +- (BOOL)setItemWithQuery:(NSDictionary *)query + attributes:(NSDictionary *)attributes + error:(NSError **_Nullable)error { + NSMutableDictionary *combined = [attributes mutableCopy]; + [combined addEntriesFromDictionary:query]; + BOOL hasItem = NO; + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)combined, NULL); + + if (status == errSecDuplicateItem) { + hasItem = YES; + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes); + } + + if (status == noErr) { + return YES; + } + if (error) { + NSString *function = hasItem ? @"SecItemUpdate" : @"SecItemAdd"; + *error = [FIRAuthErrorUtils keychainErrorWithFunction:function status:status]; + } + return NO; +} + +- (BOOL)deleteItemWithQuery:(NSDictionary *)query error:(NSError **_Nullable)error { + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); + if (status == noErr || status == errSecItemNotFound) { + return YES; + } + if (error) { + *error = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemDelete" status:status]; + } + return NO; +} + +/** @fn deleteLegacyItemsWithKey: + @brief Deletes legacy item from the keychain if it is not already known to be deleted. + @param key The key for the item. + */ +- (void)deleteLegacyItemWithKey:(NSString *)key { + if (_legacyEntryDeletedForKey[key]) { + return; + } + NSDictionary *query = [self legacyGenericPasswordQueryWithKey:key]; + SecItemDelete((__bridge CFDictionaryRef)query); + _legacyEntryDeletedForKey[key] = @YES; +} + +/** @fn genericPasswordQueryWithKey: + @brief Returns a keychain query of generic password to be used to manipulate key'ed value. + @param key The key for the value being manipulated, used as the account field in the query. + */ +- (NSDictionary *)genericPasswordQueryWithKey:(NSString *)key { + return @{ + (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrAccount : [kAccountPrefix stringByAppendingString:key], + (__bridge id)kSecAttrService : _service, + }; +} + +/** @fn legacyGenericPasswordQueryWithKey: + @brief Returns a keychain query of generic password without service field, which is used by + previous version of this class. + @param key The key for the value being manipulated, used as the account field in the query. + */ +- (NSDictionary *)legacyGenericPasswordQueryWithKey:(NSString *)key { + return @{ + (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrAccount : key, + }; +} + +#pragma mark - Private methods for shared keychain operations + +- (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *mutableQuery = [query mutableCopy]; + + mutableQuery[(__bridge id)kSecReturnData] = @YES; + mutableQuery[(__bridge id)kSecReturnAttributes] = @YES; + mutableQuery[(__bridge id)kSecMatchLimit] = @2; + + CFArrayRef result = NULL; + OSStatus status = + SecItemCopyMatching((__bridge CFDictionaryRef)mutableQuery, (CFTypeRef *)&result); + + if (status == noErr && result != NULL) { + NSArray *items = (__bridge_transfer NSArray *)result; + if (items.count != 1) { + if (outError) { + *outError = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemCopyMatching" + status:status]; + } + return nil; + } + + if (outError) { + *outError = nil; + } + NSDictionary *item = items[0]; + return item[(__bridge id)kSecValueData]; + } + + if (status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + } else { + if (outError) { + *outError = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemCopyMatching" + status:status]; + } + } + return nil; +} + +- (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSData *existingItem = [self getItemWithQuery:query error:outError]; + if (outError && *outError) { + return NO; + } + + OSStatus status; + if (!existingItem) { + NSMutableDictionary *queryWithItem = [query mutableCopy]; + [queryWithItem setObject:item forKey:(__bridge id)kSecValueData]; + status = SecItemAdd((__bridge CFDictionaryRef)queryWithItem, NULL); + } else { + NSDictionary *attributes = @{(__bridge id)kSecValueData : item}; + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes); + } + + if (status == noErr) { + if (outError) { + *outError = nil; + } + return YES; + } + + NSString *function = existingItem ? @"SecItemUpdate" : @"SecItemAdd"; + if (outError) { + *outError = [FIRAuthErrorUtils keychainErrorWithFunction:function status:status]; + } + return NO; +} + +- (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError { + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); + + if (status == noErr || status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + return YES; + } + + if (outError) { + *outError = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemDelete" status:status]; + } + return NO; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h new file mode 100644 index 0000000..dfd8aad --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h @@ -0,0 +1,36 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthUserDefaults + @brief The utility class to storage data in NSUserDefaults. + */ +@interface FIRAuthUserDefaults : NSObject + +/** @fn clear + @brief Clears all data from the storage. + @remarks This method is only supposed to be called from tests. + */ +- (void)clear; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.m new file mode 100644 index 0000000..b109450 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.m @@ -0,0 +1,74 @@ +/* + * 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 "FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h" + +NS_ASSUME_NONNULL_BEGIN + +static NSString *const kPersistentDomainNamePrefix = @"com.google.Firebase.Auth."; + +@implementation FIRAuthUserDefaults { + /** @var _persistentDomainName + @brief The name of the persistent domain in user defaults. + */ + NSString *_persistentDomainName; + + /** @var _storage + @brief The backing NSUserDefaults storage for this instance. + */ + NSUserDefaults *_storage; +} + +- (instancetype)initWithService:(NSString *)service { + self = [super init]; + if (self) { + _persistentDomainName = [kPersistentDomainNamePrefix stringByAppendingString:service]; + _storage = [[NSUserDefaults alloc] init]; + } + return self; +} + +- (nullable NSData *)dataForKey:(NSString *)key error:(NSError **_Nullable)error { + if (error) { + *error = nil; + } + NSDictionary *allData = [_storage persistentDomainForName:_persistentDomainName]; + return allData[key]; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError **_Nullable)error { + NSMutableDictionary *allData = + [([_storage persistentDomainForName:_persistentDomainName] ?: @{}) mutableCopy]; + allData[key] = data; + [_storage setPersistentDomain:allData forName:_persistentDomainName]; + return YES; +} + +- (BOOL)removeDataForKey:(NSString *)key error:(NSError **_Nullable)error { + NSMutableDictionary *allData = + [[_storage persistentDomainForName:_persistentDomainName] mutableCopy]; + [allData removeObjectForKey:key]; + [_storage setPersistentDomain:allData forName:_persistentDomainName]; + return YES; +} + +- (void)clear { + [_storage setPersistentDomain:@{} forName:_persistentDomainName]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h new file mode 100644 index 0000000..d06de11 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h @@ -0,0 +1,63 @@ +/* + * 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 +#if !TARGET_OS_OSX + +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthAPNSToken + @brief A data structure for an APNs token. + */ +@interface FIRAuthAPNSToken : NSObject + +/** @property data + @brief The APNs token data. + */ +@property(nonatomic, strong, readonly) NSData *data; + +/** @property string + @brief The uppercase hexadecimal string form of the APNs token data. + */ +@property(nonatomic, strong, readonly) NSString *string; + +/** @property type + @brief The APNs token type. + */ +@property(nonatomic, assign, readonly) FIRAuthAPNSTokenType type; + +/** @fn initWithData:type: + @brief Initializes the instance. + @param data The APNs token data. + @param type The APNs token type. + @return The initialized instance. + */ +- (instancetype)initWithData:(NSData *)data + type:(FIRAuthAPNSTokenType)type NS_DESIGNATED_INITIALIZER; + +/** @fn init + @brief Call @c initWithData:type: to get an instance of this class. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.m new file mode 100644 index 0000000..4937942 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.m @@ -0,0 +1,57 @@ +/* + * 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 +#if !TARGET_OS_OSX + +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthAPNSToken { + /** @var _string + @brief The lazy-initialized string form of the token data. + */ + NSString *_string; +} + +- (instancetype)initWithData:(NSData *)data type:(FIRAuthAPNSTokenType)type { + self = [super init]; + if (self) { + _data = [data copy]; + _type = type; + } + return self; +} + +- (NSString *)string { + if (!_string) { + NSUInteger capacity = _data.length * 2; + NSMutableString *tokenString = [NSMutableString stringWithCapacity:capacity]; + const unsigned char *tokenData = _data.bytes; + for (int idx = 0; idx < _data.length; ++idx) { + [tokenString appendFormat:@"%02X", (int)tokenData[idx]]; + } + _string = tokenString; + } + return _string; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h new file mode 100644 index 0000000..c4e2cfb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h @@ -0,0 +1,83 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import +#import + +@class FIRAuthAPNSToken; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthAPNSTokenCallback + @brief The type of block to receive an APNs token. + @param token The APNs token if one is available. + @param error The error happened if any. + @remarks Both `token` and `error` being `nil` means the request timed-out. + */ +typedef void (^FIRAuthAPNSTokenCallback)(FIRAuthAPNSToken *_Nullable token, + NSError *_Nullable error); + +/** @class FIRAuthAPNSTokenManager + @brief A class to manage APNs token in memory. + */ +@interface FIRAuthAPNSTokenManager : NSObject + +/** @property token + @brief The APNs token, if one is available. + @remarks Setting a token with FIRAuthAPNSTokenTypeUnknown will automatically converts it to + a token with the automatically detected type. + */ +@property(nonatomic, strong, nullable) FIRAuthAPNSToken *token; + +/** @property timeout + @brief The timeout for registering for remote notification. + @remarks Only tests should access this property. + */ +@property(nonatomic, assign) NSTimeInterval timeout; + +/** @fn init + @brief Call @c initWithApplication: to initialize an instance of this class. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithApplication: + @brief Initializes the instance. + @param application The @c UIApplication to request the token from. + @return The initialized instance. + */ +- (instancetype)initWithApplication:(UIApplication *)application NS_DESIGNATED_INITIALIZER; + +/** @fn getTokenWithCallback: + @brief Attempts to get the APNs token. + @param callback The block to be called either immediately or in future, either when a token + becomes available, or when timeout occurs, whichever happens earlier. + */ +- (void)getTokenWithCallback:(FIRAuthAPNSTokenCallback)callback; + +/** @fn cancelWithError: + @brief Cancels any pending `getTokenWithCallback:` request. + @param error The error to return. + */ +- (void)cancelWithError:(NSError *)error; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.m new file mode 100644 index 0000000..0daac97 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.m @@ -0,0 +1,250 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kRegistrationTimeout + @brief Timeout for registration for remote notification. + @remarks Once we start to handle `application:didFailToRegisterForRemoteNotificationsWithError:` + we probably don't have to use timeout at all. + */ +static const NSTimeInterval kRegistrationTimeout = 5; + +/** @var kLegacyRegistrationTimeout + @brief Timeout for registration for remote notification on iOS 7. + */ +static const NSTimeInterval kLegacyRegistrationTimeout = 30; + +@implementation FIRAuthAPNSTokenManager { + /** @var _application + @brief The @c UIApplication to request the token from. + */ + UIApplication *_application; + + /** @var _pendingCallbacks + @brief The list of all pending callbacks for the APNs token. + */ + NSMutableArray *_pendingCallbacks; +} + +- (instancetype)initWithApplication:(UIApplication *)application { + self = [super init]; + if (self) { + _application = application; + _timeout = [_application respondsToSelector:@selector(registerForRemoteNotifications)] + ? kRegistrationTimeout + : kLegacyRegistrationTimeout; + } + return self; +} + +- (void)getTokenWithCallback:(FIRAuthAPNSTokenCallback)callback { + if (_token) { + callback(_token, nil); + return; + } + if (_pendingCallbacks) { + [_pendingCallbacks addObject:callback]; + return; + } + _pendingCallbacks = + [[NSMutableArray alloc] initWithObjects:callback, nil]; + dispatch_async(dispatch_get_main_queue(), ^{ + if ([self->_application respondsToSelector:@selector(registerForRemoteNotifications)]) { + [self->_application registerForRemoteNotifications]; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#if TARGET_OS_IOS + [self->_application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert]; +#endif // TARGET_OS_IOS +#pragma clang diagnostic pop + } + }); + NSArray *applicableCallbacks = _pendingCallbacks; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timeout * NSEC_PER_SEC)), + FIRAuthGlobalWorkQueue(), ^{ + // Only cancel if the pending callbacks remain the same, i.e., not triggered yet. + if (applicableCallbacks == self->_pendingCallbacks) { + [self callBackWithToken:nil error:nil]; + } + }); +} + +- (void)setToken:(nullable FIRAuthAPNSToken *)token { + if (!token) { + _token = nil; + return; + } + if (token.type == FIRAuthAPNSTokenTypeUnknown) { + static FIRAuthAPNSTokenType detectedTokenType = FIRAuthAPNSTokenTypeUnknown; + if (detectedTokenType == FIRAuthAPNSTokenTypeUnknown) { + detectedTokenType = + [[self class] isProductionApp] ? FIRAuthAPNSTokenTypeProd : FIRAuthAPNSTokenTypeSandbox; + } + token = [[FIRAuthAPNSToken alloc] initWithData:token.data type:detectedTokenType]; + } + _token = token; + [self callBackWithToken:token error:nil]; +} + +- (void)cancelWithError:(NSError *)error { + [self callBackWithToken:nil error:error]; +} + +#pragma mark - Internal methods + +/** @fn callBack + @brief Calls back all pending callbacks with APNs token or error. + @param token The APNs token if one is available. + @param error The error occurred, if any. + */ +- (void)callBackWithToken:(nullable FIRAuthAPNSToken *)token error:(nullable NSError *)error { + if (!_pendingCallbacks) { + return; + } + NSArray *allCallbacks = _pendingCallbacks; + _pendingCallbacks = nil; + for (FIRAuthAPNSTokenCallback callback in allCallbacks) { + callback(token, error); + } +}; + +/** @fn isProductionApp + @brief Whether or not the app has production (versus sandbox) provisioning profile. + */ ++ (BOOL)isProductionApp { + const BOOL defaultAppTypeProd = YES; + + NSError *error = nil; + + if ([GULAppEnvironmentUtil isSimulator]) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000006", @"Assuming prod APNs token type on simulator."); + return defaultAppTypeProd; + } + + // Apps distributed via AppStore or TestFlight use the Production APNS certificates. + if ([GULAppEnvironmentUtil isFromAppStore]) { + return defaultAppTypeProd; + } + NSString *path = [[[NSBundle mainBundle] bundlePath] + stringByAppendingPathComponent:@"embedded.mobileprovision"]; + if ([GULAppEnvironmentUtil isAppStoreReceiptSandbox] && !path.length) { + // Distributed via TestFlight + return defaultAppTypeProd; + } + + NSMutableData *profileData = [NSMutableData dataWithContentsOfFile:path options:0 error:&error]; + + if (!profileData.length || error) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000007", @"Error while reading embedded mobileprovision %@", + error); + return defaultAppTypeProd; + } + + // The "embedded.mobileprovision" sometimes contains characters with value 0, which signals the + // end of a c-string and halts the ASCII parser, or with value > 127, which violates strict 7-bit + // ASCII. Replace any 0s or invalid characters in the input. + uint8_t *profileBytes = (uint8_t *)profileData.bytes; + for (int i = 0; i < profileData.length; i++) { + uint8_t currentByte = profileBytes[i]; + if (!currentByte || currentByte > 127) { + profileBytes[i] = '.'; + } + } + + NSString *embeddedProfile = [[NSString alloc] initWithBytesNoCopy:profileBytes + length:profileData.length + encoding:NSASCIIStringEncoding + freeWhenDone:NO]; + + if (error || !embeddedProfile.length) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000008", @"Error while reading embedded mobileprovision %@", + error); + return defaultAppTypeProd; + } + + NSScanner *scanner = [NSScanner scannerWithString:embeddedProfile]; + NSString *plistContents; + if ([scanner scanUpToString:@"" intoString:&plistContents]) { + plistContents = [plistContents stringByAppendingString:@""]; + } + } + + if (!plistContents.length) { + return defaultAppTypeProd; + } + + NSData *data = [plistContents dataUsingEncoding:NSUTF8StringEncoding]; + if (!data.length) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000009", + @"Couldn't read plist fetched from embedded mobileprovision"); + return defaultAppTypeProd; + } + + NSError *plistMapError; + id plistData = [NSPropertyListSerialization propertyListWithData:data + options:NSPropertyListImmutable + format:nil + error:&plistMapError]; + if (plistMapError || ![plistData isKindOfClass:[NSDictionary class]]) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000010", @"Error while converting assumed plist to dict %@", + plistMapError.localizedDescription); + return defaultAppTypeProd; + } + NSDictionary *plistMap = (NSDictionary *)plistData; + + if ([plistMap valueForKeyPath:@"ProvisionedDevices"]) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000011", + @"Provisioning profile has specifically provisioned devices, " + @"most likely a Dev profile."); + } + + NSString *apsEnvironment = [plistMap valueForKeyPath:@"Entitlements.aps-environment"]; + FIRLogDebug(kFIRLoggerAuth, @"I-AUT000012", @"APNS Environment in profile: %@", apsEnvironment); + + // No aps-environment in the profile. + if (!apsEnvironment.length) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000013", + @"No aps-environment set. If testing on a device APNS is not " + @"correctly configured. Please recheck your provisioning profiles."); + return defaultAppTypeProd; + } + + if ([apsEnvironment isEqualToString:@"development"]) { + return NO; + } + + return defaultAppTypeProd; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h new file mode 100644 index 0000000..ceb93e2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h @@ -0,0 +1,52 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthAppCredential + @brief A class represents a credential that proves the identity of the app. + */ +@interface FIRAuthAppCredential : NSObject + +/** @property receipt + @brief The server acknowledgement of receiving client's claim of identity. + */ +@property(nonatomic, strong, readonly) NSString *receipt; + +/** @property secret + @brief The secret that the client received from server via a trusted channel, if ever. + */ +@property(nonatomic, strong, readonly, nullable) NSString *secret; + +/** @fn initWithReceipt:secret: + @brief Initializes the instance. + @param receipt The server acknowledgement of receiving client's claim of identity. + @param secret The secret that the client received from server via a trusted channel, if ever. + @return The initialized instance. + */ +- (instancetype)initWithReceipt:(NSString *)receipt + secret:(nullable NSString *)secret NS_DESIGNATED_INITIALIZER; + +/** @fn init + @brief Call @c initWithReceipt:secret: to get an instance of this class. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.m new file mode 100644 index 0000000..7bf1021 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.m @@ -0,0 +1,64 @@ +/* + * 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 "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kReceiptKey + @brief The key used to encode the receipt property for NSSecureCoding. + */ +static NSString *const kReceiptKey = @"receipt"; + +/** @var kSecretKey + @brief The key used to encode the secret property for NSSecureCoding. + */ +static NSString *const kSecretKey = @"secret"; + +@implementation FIRAuthAppCredential + +- (instancetype)initWithReceipt:(NSString *)receipt secret:(nullable NSString *)secret { + self = [super init]; + if (self) { + _receipt = [receipt copy]; + _secret = [secret copy]; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *receipt = [aDecoder decodeObjectOfClass:[NSString class] forKey:kReceiptKey]; + if (!receipt) { + return nil; + } + NSString *secret = [aDecoder decodeObjectOfClass:[NSString class] forKey:kSecretKey]; + return [self initWithReceipt:receipt secret:secret]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_receipt forKey:kReceiptKey]; + [aCoder encodeObject:_secret forKey:kSecretKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h new file mode 100644 index 0000000..efbbe7a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h @@ -0,0 +1,90 @@ +/* + * 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 +#if !TARGET_OS_OSX + +#import + +#import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthAppCredentialCallback + @brief The type of block to receive an app crdential. + @param credential The best available app credential at the time. + */ +typedef void (^FIRAuthAppCredentialCallback)(FIRAuthAppCredential *credential); + +/** @class FIRAuthAppCredentialManager + @brief A class to manage app credentials backed by iOS Keychain. + */ +@interface FIRAuthAppCredentialManager : NSObject + +/** @property credential + @brief The full credential (which has a secret) to be used by the app, if one is available. + */ +@property(nonatomic, strong, readonly, nullable) FIRAuthAppCredential *credential; + +/** @property maximumNumberOfPendingReceipts + @brief The maximum (but not necessarily the minimum) number of pending receipts to be kept. + @remarks Only tests should access this property. + */ +@property(nonatomic, assign, readonly) NSUInteger maximumNumberOfPendingReceipts; + +/** @fn init + @brief Call @c initWithKeychain: to initialize an instance of this class. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithKeychain: + @brief Initializes the instance. + @param keychain The iOS Keychain storage to back up the app credential with. + @return The initialized instance. + */ +- (instancetype)initWithKeychain:(FIRAuthKeychainServices *)keychain NS_DESIGNATED_INITIALIZER; + +/** @fn didStartVerificationWithReceipt:timeout:callback: + @brief Notifies that the app verification process has started. + @param receipt The receipt for verification. + @param timeout The timeout value for how long the callback is waited to be called. + @param callback The block to be called in future either when the verification finishes, or + when timeout occurs, whichever happens earlier. + */ +- (void)didStartVerificationWithReceipt:(NSString *)receipt + timeout:(NSTimeInterval)timeout + callback:(FIRAuthAppCredentialCallback)callback; + +/** @fn canFinishVerificationWithReceipt: + @brief Attempts to finish verification. + @param receipt The receipt to match the original receipt obtained when verification started. + @param secret The secret to complete the verification. + @return Whether or not the receipt matches a pending verification, and finishes verification + if it does. + */ +- (BOOL)canFinishVerificationWithReceipt:(NSString *)receipt secret:(NSString *)secret; + +/** @fn clearCredential + @brief Clears the saved credential, to be used in the case that it is rejected by the server. + */ +- (void)clearCredential; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.m new file mode 100644 index 0000000..52673f0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.m @@ -0,0 +1,180 @@ +/* + * 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 +#if !TARGET_OS_OSX + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kKeychainDataKey + @brief The keychain key for the data. + */ +static NSString *const kKeychainDataKey = @"app_credentials"; + +/** @var kFullCredentialKey + @brief The data key for the full app credential. + */ +static NSString *const kFullCredentialKey = @"full_credential"; + +/** @var kPendingReceiptsKey + @brief The data key for the array of pending receipts. + */ +static NSString *const kPendingReceiptsKey = @"pending_receipts"; + +/** @var kMaximumNumberOfPendingReceipts + @brief The maximum number of partial credentials kept by this class. + */ +static const NSUInteger kMaximumNumberOfPendingReceipts = 32; + +@implementation FIRAuthAppCredentialManager { + /** @var _keychainServices + @brief The keychain for app credentials to load from and to save to. + */ + FIRAuthKeychainServices *_keychainServices; + + /** @var _pendingReceipts + @brief A list of pending receipts sorted in the order they were recorded. + */ + NSMutableArray *_pendingReceipts; + + /** @var _callbacksByReceipt + @brief A map from pending receipts to callbacks. + */ + NSMutableDictionary *_callbacksByReceipt; +} + +- (instancetype)initWithKeychain:(FIRAuthKeychainServices *)keychain { + self = [super init]; + if (self) { + _keychainServices = keychain; + // Load the credentials from keychain if possible. + NSError *error; + NSData *encodedData = [_keychainServices dataForKey:kKeychainDataKey error:&error]; + if (!error && encodedData) { +#if TARGET_OS_WATCH + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedData + error:&error]; +#else +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedData]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + FIRAuthAppCredential *credential = + [unarchiver decodeObjectOfClass:[FIRAuthAppCredential class] forKey:kFullCredentialKey]; + if ([credential isKindOfClass:[FIRAuthAppCredential class]] && !error) { + _credential = credential; + } + NSSet *allowedClasses = + [NSSet setWithObjects:[NSArray class], [NSString class], nil]; + NSArray *pendingReceipts = [unarchiver decodeObjectOfClasses:allowedClasses + forKey:kPendingReceiptsKey]; + if ([pendingReceipts isKindOfClass:[NSArray class]]) { + _pendingReceipts = [pendingReceipts mutableCopy]; + } + } + if (!_pendingReceipts) { + _pendingReceipts = [[NSMutableArray alloc] init]; + } + _callbacksByReceipt = + [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSUInteger)maximumNumberOfPendingReceipts { + return kMaximumNumberOfPendingReceipts; +} + +- (void)didStartVerificationWithReceipt:(NSString *)receipt + timeout:(NSTimeInterval)timeout + callback:(FIRAuthAppCredentialCallback)callback { + [_pendingReceipts removeObject:receipt]; + if (_pendingReceipts.count >= kMaximumNumberOfPendingReceipts) { + [_pendingReceipts removeObjectAtIndex:0]; + } + [_pendingReceipts addObject:receipt]; + _callbacksByReceipt[receipt] = callback; + [self saveData]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)), + FIRAuthGlobalWorkQueue(), ^{ + [self callBackWithReceipt:receipt]; + }); +} + +- (BOOL)canFinishVerificationWithReceipt:(NSString *)receipt secret:(NSString *)secret { + if (![_pendingReceipts containsObject:receipt]) { + return NO; + } + [_pendingReceipts removeObject:receipt]; + _credential = [[FIRAuthAppCredential alloc] initWithReceipt:receipt secret:secret]; + [self saveData]; + [self callBackWithReceipt:receipt]; + return YES; +} + +- (void)clearCredential { + _credential = nil; + [self saveData]; +} + +#pragma mark - Internal methods + +/** @fn saveData + @brief Save the data in memory to the keychain ignoring any errors. + */ +- (void)saveData { + NSMutableData *archiveData = [NSMutableData data]; +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiveData]; +#pragma clang diagnostic pop + [archiver encodeObject:_credential forKey:kFullCredentialKey]; + [archiver encodeObject:_pendingReceipts forKey:kPendingReceiptsKey]; + [archiver finishEncoding]; + [_keychainServices setData:archiveData forKey:kKeychainDataKey error:NULL]; +} + +/** @fn callBackWithReceipt: + @brief Calls the saved callback for the specifc receipt. + @param receipt The receipt associated with the callback. + */ +- (void)callBackWithReceipt:(NSString *)receipt { + FIRAuthAppCredentialCallback callback = _callbacksByReceipt[receipt]; + if (!callback) { + return; + } + [_callbacksByReceipt removeObjectForKey:receipt]; + if (_credential) { + callback(_credential); + } else { + callback([[FIRAuthAppCredential alloc] initWithReceipt:receipt secret:nil]); + } +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h new file mode 100644 index 0000000..12b6f3e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h @@ -0,0 +1,76 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import +#import + +@class FIRAuthAppCredentialManager; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthNotificationForwardingCallback + @brief The type of block to receive whether or not remote notifications are being forwarded. + @param isNotificationBeingForwarded Whether or not remote notifications are being forwarded. + */ +typedef void (^FIRAuthNotificationForwardingCallback)(BOOL isNotificationBeingForwarded); + +/** @class FIRAuthNotificationManager + */ +@interface FIRAuthNotificationManager : NSObject + +/** @property timeout + @brief The timeout for checking for notification forwarding. + @remarks Only tests should access this property. + */ +@property(nonatomic, assign) NSTimeInterval timeout; + +/** @fn initWithApplication:appCredentialManager: + @brief Initializes the instance. + @param application The application. + @param appCredentialManager The object to handle app credentials delivered via notification. + @return The initialized instance. + */ +- (instancetype)initWithApplication:(UIApplication *)application + appCredentialManager:(FIRAuthAppCredentialManager *)appCredentialManager + NS_DESIGNATED_INITIALIZER; + +/** @fn init + @brief please use initWithAppCredentialManager: instead. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn checkNotificationForwardingWithCallback: + @brief Checks whether or not remote notifications are being forwarded to this class. + @param callback The block to be called either immediately or in future once a result + is available. + */ +- (void)checkNotificationForwardingWithCallback:(FIRAuthNotificationForwardingCallback)callback; + +/** @fn canHandleNotification: + @brief Attempts to handle the remote notification. + @param notification The notification in question. + @return Whether or the notification has been handled. + */ +- (BOOL)canHandleNotification:(NSDictionary *)notification; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.m new file mode 100644 index 0000000..93bb17e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.m @@ -0,0 +1,189 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kNotificationKey + @brief The key to locate payload data in the remote notification. + */ +static NSString *const kNotificationDataKey = @"com.google.firebase.auth"; + +/** @var kNotificationReceiptKey + @brief The key for the receipt in the remote notification payload data. + */ +static NSString *const kNotificationReceiptKey = @"receipt"; + +/** @var kNotificationSecretKey + @brief The key for the secret in the remote notification payload data. + */ +static NSString *const kNotificationSecretKey = @"secret"; + +/** @var kNotificationProberKey + @brief The key for marking the prober in the remote notification payload data. + */ +static NSString *const kNotificationProberKey = @"warning"; + +/** @var kProbingTimeout + @brief Timeout for probing whether the app delegate forwards the remote notification to us. + */ +static const NSTimeInterval kProbingTimeout = 1; + +@implementation FIRAuthNotificationManager { + /** @var _application + @brief The application. + */ + UIApplication *_application; + + /** @var _appCredentialManager + @brief The object to handle app credentials delivered via notification. + */ + FIRAuthAppCredentialManager *_appCredentialManager; + + /** @var _hasCheckedNotificationForwarding + @brief Whether notification forwarding has been checked or not. + */ + BOOL _hasCheckedNotificationForwarding; + + /** @var _isNotificationBeingForwarded + @brief Whether or not notification is being forwarded + */ + BOOL _isNotificationBeingForwarded; + + /** @var _pendingCallbacks + @brief All pending callbacks while a check is being performed. + */ + NSMutableArray *_pendingCallbacks; +} + +- (instancetype)initWithApplication:(UIApplication *)application + appCredentialManager:(FIRAuthAppCredentialManager *)appCredentialManager { + self = [super init]; + if (self) { + _application = application; + _appCredentialManager = appCredentialManager; + _timeout = kProbingTimeout; + } + return self; +} + +- (void)checkNotificationForwardingWithCallback:(FIRAuthNotificationForwardingCallback)callback { + if (_pendingCallbacks) { + [_pendingCallbacks addObject:callback]; + return; + } + if (_hasCheckedNotificationForwarding) { + callback(_isNotificationBeingForwarded); + return; + } + _hasCheckedNotificationForwarding = YES; + _pendingCallbacks = + [[NSMutableArray alloc] initWithObjects:callback, nil]; + dispatch_async(dispatch_get_main_queue(), ^{ + NSDictionary *proberNotification = @{ + kNotificationDataKey : @{ + kNotificationProberKey : @"This fake notification should be forwarded to Firebase Auth." + } + }; + if ([self->_application.delegate + respondsToSelector:@selector(application: + didReceiveRemoteNotification:fetchCompletionHandler:)]) { + [self->_application.delegate application:self->_application + didReceiveRemoteNotification:proberNotification + fetchCompletionHandler:^(UIBackgroundFetchResult result){ + }]; +#if !TARGET_OS_TV + } else if ([self->_application.delegate + respondsToSelector:@selector(application:didReceiveRemoteNotification:)]) { +// iOS 10 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [self->_application.delegate application:self->_application + didReceiveRemoteNotification:proberNotification]; +#pragma clang diagnostic pop +#endif + } else { + FIRLogWarning(kFIRLoggerAuth, @"I-AUT000015", + @"The UIApplicationDelegate must handle remote notification for phone number " + @"authentication to work."); + } + }); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timeout * NSEC_PER_SEC)), + FIRAuthGlobalWorkQueue(), ^{ + [self callBack]; + }); +} + +- (BOOL)canHandleNotification:(NSDictionary *)notification { + NSDictionary *data = notification[kNotificationDataKey]; + if ([data isKindOfClass:[NSString class]]) { + // Deserialize in case the data is a JSON string. + NSData *JSONData = [((NSString *)data) dataUsingEncoding:NSUTF8StringEncoding]; + data = [NSJSONSerialization JSONObjectWithData:JSONData options:0 error:NULL]; + } + if (![data isKindOfClass:[NSDictionary class]]) { + return NO; + } + if (data[kNotificationProberKey]) { + if (!_pendingCallbacks) { + // The prober notification probably comes from another instance, so pass it along. + return NO; + } + _isNotificationBeingForwarded = YES; + [self callBack]; + return YES; + } + NSString *receipt = data[kNotificationReceiptKey]; + if (![receipt isKindOfClass:[NSString class]]) { + return NO; + } + NSString *secret = data[kNotificationSecretKey]; + if (![receipt isKindOfClass:[NSString class]]) { + return NO; + } + return [_appCredentialManager canFinishVerificationWithReceipt:receipt secret:secret]; +} + +#pragma mark - Internal methods + +/** @fn callBack + @brief Calls back all pending callbacks with the result of notification forwarding check. + */ +- (void)callBack { + if (!_pendingCallbacks) { + return; + } + NSArray *allCallbacks = _pendingCallbacks; + _pendingCallbacks = nil; + for (FIRAuthNotificationForwardingCallback callback in allCallbacks) { + callback(_isNotificationBeingForwarded); + } +}; + +@end +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h new file mode 100644 index 0000000..02a85b7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h @@ -0,0 +1,108 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h" + +#import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" +#import "FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthStoredUserManager : NSObject + +/** @property keychain + @brief The mediator object to access to the system Keychain services. + */ +@property(readonly, nonatomic, strong) FIRAuthKeychainServices *keychainServices; + +/** @property userDefaults + @brief The mediator object to access to the system User Defaults services. + */ +@property(readonly, nonatomic, strong) FIRAuthUserDefaults *userDefaults; + +/** @fn init + @brief The default initializer is disabled. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithServiceName: + @brief The designated initializer. + @param serviceName The service name to initialize with. + */ +- (instancetype)initWithServiceName:(NSString *)serviceName NS_DESIGNATED_INITIALIZER; + +/** @fn getStoredUserAccessGroupWithError: + @brief Get the user access group stored locally. + @param outError Return value for any error which occurs. + */ +- (nullable NSString *)getStoredUserAccessGroupWithError:(NSError *_Nullable *_Nullable)outError; + +/** @fn setStoredUserAccessGroup:error: + @brief The setter of the user access group stored locally. + @param accessGroup The access group to be set. + @param outError Return value for any error which occurs. + */ +- (BOOL)setStoredUserAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn getStoredUserForAccessGroup:projectID:error: + @brief The getter of the user stored locally. + @param accessGroup The access group to retrieve the user from. + @param shareAuthStateAcrossDevices If true, the keychain will be synced across the end-user's + iCloud. + @param projectIdentifier An identifier of the project that the user associates with. Currently, + we use API KEY. + @param outError Return value for any error which occurs. + */ +- (nullable FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn setStoredUser:forAccessGroup:projectID:error: + @brief The setter of the user stored locally. + @param user The user to be stored. + @param accessGroup The access group to store the user in. + @param shareAuthStateAcrossDevices If true, the keychain will be synced across the end-user's + iCloud. + @param projectIdentifier An identifier of the project that the user associates with. Currently, + we use API KEY. + @param outError Return value for any error which occurs. + */ +- (BOOL)setStoredUser:(FIRUser *)user + forAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn removeStoredUserForAccessGroup:projectID:error: + @brief Remove the user that stored locally. + @param accessGroup The access group to remove the user from. + @param shareAuthStateAcrossDevices If true, the keychain will be synced across the end-user's + iCloud. + @param projectIdentifier An identifier of the project that the user associates with. Currently, + we use API KEY. + @param outError Return value for any error which occurs. + */ +- (BOOL)removeStoredUserForAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m new file mode 100644 index 0000000..deae373 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m @@ -0,0 +1,175 @@ +/* + * 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 "FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h" + +#import "FirebaseAuth/Sources/User/FIRUser_Internal.h" + +/** @var kUserAccessGroupKey + @brief Key of user access group stored in user defaults. Used for retrieve the user access + group at launch. + */ +static NSString *kStoredUserAccessGroupKey = @"firebase_auth_stored_user_access_group"; + +/** @var kSharedKeychainAccountValue + @brief Default value for kSecAttrAccount of shared keychain items. + */ +static NSString *kSharedKeychainAccountValue = @"firebase_auth_firebase_user"; + +/** @var kStoredUserCoderKey + @brief The key to encode and decode the stored user. + */ +static NSString *kStoredUserCoderKey = @"firebase_auth_stored_user_coder_key"; + +@implementation FIRAuthStoredUserManager + +#pragma mark - Initializers + +- (instancetype)initWithServiceName:(NSString *)serviceName { + self = [super init]; + if (self) { + _keychainServices = [[FIRAuthKeychainServices alloc] initWithService:serviceName]; + _userDefaults = [[FIRAuthUserDefaults alloc] initWithService:serviceName]; + } + return self; +} + +#pragma mark - User Access Group + +- (NSString *_Nullable)getStoredUserAccessGroupWithError:(NSError *_Nullable *_Nullable)outError { + NSData *data = [self.userDefaults dataForKey:kStoredUserAccessGroupKey error:outError]; + if (data) { + NSString *userAccessGroup = [NSString stringWithUTF8String:data.bytes]; + return userAccessGroup; + } else { + return nil; + } +} + +- (BOOL)setStoredUserAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError { + NSData *data = [accessGroup dataUsingEncoding:NSUTF8StringEncoding]; + if (!data) { + return [self.userDefaults removeDataForKey:kStoredUserAccessGroupKey error:outError]; + } else { + return [self.userDefaults setData:data forKey:kStoredUserAccessGroupKey error:outError]; + } +} + +#pragma mark - User for Access Group + +- (FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; + query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword; + + query[(__bridge id)kSecAttrAccessGroup] = accessGroup; + query[(__bridge id)kSecAttrService] = projectIdentifier; + query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue; + if (shareAuthStateAcrossDevices) { + query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue; + } + + NSData *data = [self.keychainServices getItemWithQuery:query error:outError]; + // If there's an outError parameter and it's populated, or there's no data, return. + if ((outError && *outError) || !data) { + return nil; + } +#if TARGET_OS_WATCH + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data + error:outError]; + if (outError && *outError) { + return nil; + } +#else +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + FIRUser *user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:kStoredUserCoderKey]; + + return user; +} + +- (BOOL)setStoredUser:(FIRUser *)user + forAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; + query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword; + if (shareAuthStateAcrossDevices) { + query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock; + } else { + query[(__bridge id)kSecAttrAccessible] = + (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + } + + query[(__bridge id)kSecAttrAccessGroup] = accessGroup; + query[(__bridge id)kSecAttrService] = projectIdentifier; + query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue; + if (shareAuthStateAcrossDevices) { + query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue; + } + +#if TARGET_OS_WATCH + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false]; +#else + NSMutableData *data = [NSMutableData data]; +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + [archiver encodeObject:user forKey:kStoredUserCoderKey]; + [archiver finishEncoding]; + +#if TARGET_OS_WATCH + NSData *data = archiver.encodedData; +#endif // TARGET_OS_WATCH + + return [self.keychainServices setItem:data withQuery:query error:outError]; +} + +- (BOOL)removeStoredUserForAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; + query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword; + if (shareAuthStateAcrossDevices) { + query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock; + } else { + query[(__bridge id)kSecAttrAccessible] = + (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + } + if (shareAuthStateAcrossDevices) { + query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue; + } + + query[(__bridge id)kSecAttrAccessGroup] = accessGroup; + query[(__bridge id)kSecAttrService] = projectIdentifier; + query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue; + + return [self.keychainServices removeItemWithQuery:query error:outError]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h new file mode 100644 index 0000000..ba03b7d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h @@ -0,0 +1,99 @@ +/* + * 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 + +@class FIRAuthRequestConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRFetchAccessTokenCallback + @brief The callback used to return the value of attempting to fetch an access token. + + In the event the operation was successful @c token will be set and @c error will be @c nil. + In the event of failure @c token will be @c nil and @c error will be set. + @c tokenUpdated indicates whether either the access or the refresh token has been updated. + + The token returned should be considered ephemeral and not cached. It should be used immediately + and discarded. All operations that need this token should call fetchAccessToken and do their + work from the callback. + */ +typedef void (^FIRFetchAccessTokenCallback)(NSString *_Nullable token, + NSError *_Nullable error, + BOOL tokenUpdated); + +/** @class FIRSecureTokenService + @brief Provides services for token exchanges and refreshes. + */ +@interface FIRSecureTokenService : NSObject + +/** @property requestConfiguration + @brief The configuration for making requests to server. + */ +@property(nonatomic, strong) FIRAuthRequestConfiguration *requestConfiguration; + +/** @property rawAccessToken + @brief The cached access token. + @remarks This method is specifically for providing the access token to internal clients during + deserialization and sign-in events, and should not be used to retrieve the access token by + anyone else. + */ +@property(nonatomic, copy, readonly) NSString *rawAccessToken; + +/** @property refreshToken + @brief The refresh token for the user, or @c nil if the user has yet completed sign-in flow. + @remarks This property needs to be set manually after the instance is decoded from archive. + */ +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +/** @property accessTokenExpirationDate + @brief The expiration date of the cached access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *accessTokenExpirationDate; + +/** @fn initWithRequestConfiguration:authorizationCode: + @brief Creates a @c FIRSecureTokenService with an authroization code. + @param requestConfiguration The configuration for making requests to server. + @param authorizationCode An authorization code which needs to be exchanged for STS tokens. + */ +- (instancetype)initWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + authorizationCode:(NSString *)authorizationCode; + +/** @fn initWithRequestConfiguration:accessToken:accessTokenExpirationDate:refreshToken + @brief Creates a @c FIRSecureTokenService with access and refresh tokens. + @param requestConfiguration The configuration for making requests to server. + @param accessToken The STS access token. + @param accessTokenExpirationDate The approximate expiration date of the access token. + @param refreshToken The STS refresh token. + */ +- (instancetype)initWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + accessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(NSString *)refreshToken; + +/** @fn fetchAccessTokenForcingRefresh:callback: + @brief Fetch a fresh ephemeral access token for the ID associated with this instance. The token + received in the callback should be considered short lived and not cached. + @param forceRefresh Forces the token to be refreshed. + @param callback Callback block that will be called to return either the token or an error. + Invoked asyncronously on the auth global work queue in the future. + */ +- (void)fetchAccessTokenForcingRefresh:(BOOL)forceRefresh + callback:(FIRFetchAccessTokenCallback)callback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.m new file mode 100644 index 0000000..e432afb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.m @@ -0,0 +1,227 @@ +/* + * 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 "FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h" + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kAPIKeyCodingKey + @brief The key used to encode the APIKey for NSSecureCoding. + */ +static NSString *const kAPIKeyCodingKey = @"APIKey"; + +/** @var kRefreshTokenKey + @brief The key used to encode the refresh token for NSSecureCoding. + */ +static NSString *const kRefreshTokenKey = @"refreshToken"; + +/** @var kAccessTokenKey + @brief The key used to encode the access token for NSSecureCoding. + */ +static NSString *const kAccessTokenKey = @"accessToken"; + +/** @var kAccessTokenExpirationDateKey + @brief The key used to encode the access token expiration date for NSSecureCoding. + */ +static NSString *const kAccessTokenExpirationDateKey = @"accessTokenExpirationDate"; + +/** @var kFiveMinutes + @brief Five minutes (in seconds.) + */ +static const NSTimeInterval kFiveMinutes = 5 * 60; + +@interface FIRSecureTokenService () +- (instancetype)init NS_DESIGNATED_INITIALIZER; +@end + +@implementation FIRSecureTokenService { + /** @var _taskQueue + @brief Used to serialize all requests for access tokens. + */ + FIRAuthSerialTaskQueue *_taskQueue; + + /** @var _authorizationCode + @brief An authorization code which needs to be exchanged for Secure Token Service tokens. + */ + NSString *_Nullable _authorizationCode; + + /** @var _accessToken + @brief The currently cached access token. Or |nil| if no token is currently cached. + */ + NSString *_Nullable _accessToken; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _taskQueue = [[FIRAuthSerialTaskQueue alloc] init]; + } + return self; +} + +- (instancetype)initWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + authorizationCode:(NSString *)authorizationCode { + self = [self init]; + if (self) { + _requestConfiguration = requestConfiguration; + _authorizationCode = [authorizationCode copy]; + } + return self; +} + +- (instancetype)initWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + accessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(NSString *)refreshToken { + self = [self init]; + if (self) { + _requestConfiguration = requestConfiguration; + _accessToken = [accessToken copy]; + _accessTokenExpirationDate = [accessTokenExpirationDate copy]; + _refreshToken = [refreshToken copy]; + } + return self; +} + +- (void)fetchAccessTokenForcingRefresh:(BOOL)forceRefresh + callback:(FIRFetchAccessTokenCallback)callback { + [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock complete) { + if (!forceRefresh && [self hasValidAccessToken]) { + complete(); + callback(self->_accessToken, nil, NO); + } else { + FIRLogDebug(kFIRLoggerAuth, @"I-AUT000017", @"Fetching new token from backend."); + [self requestAccessToken:^(NSString *_Nullable token, NSError *_Nullable error, + BOOL tokenUpdated) { + complete(); + callback(token, error, tokenUpdated); + }]; + } + }]; +} + +- (NSString *)rawAccessToken { + return _accessToken; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *refreshToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:kRefreshTokenKey]; + NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:kAccessTokenKey]; + NSDate *accessTokenExpirationDate = [aDecoder decodeObjectOfClass:[NSDate class] + forKey:kAccessTokenExpirationDateKey]; + if (!refreshToken) { + return nil; + } + self = [self init]; + if (self) { + _refreshToken = refreshToken; + _accessToken = accessToken; + _accessTokenExpirationDate = accessTokenExpirationDate; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + // The API key is encoded even it is not used in decoding to be compatible with previous versions + // of the library. + [aCoder encodeObject:_requestConfiguration.APIKey forKey:kAPIKeyCodingKey]; + // Authorization code is not encoded because it is not long-lived. + [aCoder encodeObject:_refreshToken forKey:kRefreshTokenKey]; + [aCoder encodeObject:_accessToken forKey:kAccessTokenKey]; + [aCoder encodeObject:_accessTokenExpirationDate forKey:kAccessTokenExpirationDateKey]; +} + +#pragma mark - Private methods + +/** @fn requestAccessToken: + @brief Makes a request to STS for an access token. + @details This handles both the case that the token has not been granted yet and that it just + needs to be refreshed. The caller is responsible for making sure that this is occurring in + a @c _taskQueue task. + @param callback Called when the fetch is complete. Invoked asynchronously on the main thread in + the future. + @remarks Because this method is guaranteed to only be called from tasks enqueued in + @c _taskQueue, we do not need any @synchronized guards around access to _accessToken/etc. + since only one of those tasks is ever running at a time, and those tasks are the only + access to and mutation of these instance variables. + */ +- (void)requestAccessToken:(FIRFetchAccessTokenCallback)callback { + FIRSecureTokenRequest *request; + if (_refreshToken.length) { + request = [FIRSecureTokenRequest refreshRequestWithRefreshToken:_refreshToken + requestConfiguration:_requestConfiguration]; + } else { + request = [FIRSecureTokenRequest authCodeRequestWithCode:_authorizationCode + requestConfiguration:_requestConfiguration]; + } + [FIRAuthBackend + secureToken:request + callback:^(FIRSecureTokenResponse *_Nullable response, NSError *_Nullable error) { + BOOL tokenUpdated = NO; + NSString *newAccessToken = response.accessToken; + if (newAccessToken.length && ![newAccessToken isEqualToString:self->_accessToken]) { + self->_accessToken = [newAccessToken copy]; + self->_accessTokenExpirationDate = response.approximateExpirationDate; + tokenUpdated = YES; + FIRLogDebug(kFIRLoggerAuth, @"I-AUT000017", + @"Updated access token. Estimated expiration date: %@, current date: %@", + self->_accessTokenExpirationDate, [NSDate date]); + } + NSString *newRefreshToken = response.refreshToken; + if (newRefreshToken.length && ![newRefreshToken isEqualToString:self->_refreshToken]) { + self->_refreshToken = [newRefreshToken copy]; + tokenUpdated = YES; + } + callback(newAccessToken, error, tokenUpdated); + }]; +} + +- (BOOL)hasValidAccessToken { + BOOL hasValidAccessToken = + _accessToken && [_accessTokenExpirationDate timeIntervalSinceNow] > kFiveMinutes; + if (hasValidAccessToken) { + FIRLogDebug(kFIRLoggerAuth, @"I-AUT000017", + @"Has valid access token. Estimated expiration date: %@, current date: %@", + _accessTokenExpirationDate, [NSDate date]); + } else { + FIRLogDebug( + kFIRLoggerAuth, @"I-AUT000017", + @"Does not have valid access token. Estimated expiration date: %@, current date: %@", + _accessTokenExpirationDate, [NSDate date]); + } + return hasValidAccessToken; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo.m new file mode 100644 index 0000000..52f56c4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo.m @@ -0,0 +1,97 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" +#import "FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAdditionalUserInfo + +/** @var kProviderIDCodingKey + @brief The key used to encode the providerID property for NSSecureCoding. + */ +static NSString *const kProviderIDCodingKey = @"providerID"; + +/** @var kProfileCodingKey + @brief The key used to encode the profile property for NSSecureCoding. + */ +static NSString *const kProfileCodingKey = @"profile"; + +/** @var kUsernameCodingKey + @brief The key used to encode the username property for NSSecureCoding. + */ +static NSString *const kUsernameCodingKey = @"username"; + +/** @var kNewUserKey + @brief The key used to encode the newUser property for NSSecureCoding. + */ +static NSString *const kNewUserKey = @"newUser"; + ++ (nullable instancetype)userInfoWithVerifyAssertionResponse: + (FIRVerifyAssertionResponse *)verifyAssertionResponse { + return [[self alloc] initWithProviderID:verifyAssertionResponse.providerID + profile:verifyAssertionResponse.profile + username:verifyAssertionResponse.username + isNewUser:verifyAssertionResponse.isNewUser]; +} + +- (nullable instancetype)initWithProviderID:(nullable NSString *)providerID + profile:(nullable NSDictionary *)profile + username:(nullable NSString *)username + isNewUser:(BOOL)isNewUser { + self = [super init]; + if (self) { + _providerID = [providerID copy]; + if (profile) { + _profile = [[NSDictionary alloc] initWithDictionary:profile copyItems:YES]; + } + _username = [username copy]; + _newUser = isNewUser; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *providerID = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kProviderIDCodingKey]; + NSDictionary *profile = [aDecoder decodeObjectOfClass:[NSDictionary class] + forKey:kProfileCodingKey]; + NSString *username = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUsernameCodingKey]; + NSNumber *isNewUser = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:kNewUserKey]; + + return [self initWithProviderID:providerID + profile:profile + username:username + isNewUser:isNewUser.boolValue]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_providerID forKey:kProviderIDCodingKey]; + [aCoder encodeObject:_profile forKey:kProfileCodingKey]; + [aCoder encodeObject:_username forKey:kUsernameCodingKey]; + [aCoder encodeObject:[NSNumber numberWithBool:_newUser] forKey:kNewUserKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h new file mode 100644 index 0000000..d0be10c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAdditionalUserInfo () + +/** @fn userInfoWithVerifyAssertionResponse: + @brief A convenience factory method for constructing a @c FIRAdditionalUserInfo instance from + data returned by the verifyAssertion endpoint. + @param verifyAssertionResponse Data returned by the verifyAssertion endpoint. + @return A new instance of @c FIRAdditionalUserInfo using data from the verifyAssertion endpoint. + */ ++ (nullable instancetype)userInfoWithVerifyAssertionResponse: + (FIRVerifyAssertionResponse *)verifyAssertionResponse; + +/** @fn initWithProviderID:profile:username: + @brief Designated initializer. + @param providerID The provider identifier. + @param profile Dictionary containing the additional IdP specific information. + @param username The name of the user. + @param isNewUser Indicates whether or not the current user was signed in for the first time. + */ +- (nullable instancetype)initWithProviderID:(nullable NSString *)providerID + profile:(nullable NSDictionary *)profile + username:(nullable NSString *)username + isNewUser:(BOOL)isNewUser NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser.m new file mode 100644 index 0000000..e6ef146 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser.m @@ -0,0 +1,1627 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthOperationType.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h" +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h" +#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h" +#import "FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h" +#import "FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h" +#import "FirebaseAuth/Sources/User/FIRUserInfoImpl.h" +#import "FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h" +#import "FirebaseAuth/Sources/User/FIRUser_Internal.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** @var kUserIDCodingKey + @brief The key used to encode the user ID for NSSecureCoding. + */ +static NSString *const kUserIDCodingKey = @"userID"; + +/** @var kHasEmailPasswordCredentialCodingKey + @brief The key used to encode the hasEmailPasswordCredential property for NSSecureCoding. + */ +static NSString *const kHasEmailPasswordCredentialCodingKey = @"hasEmailPassword"; + +/** @var kAnonymousCodingKey + @brief The key used to encode the anonymous property for NSSecureCoding. + */ +static NSString *const kAnonymousCodingKey = @"anonymous"; + +/** @var kEmailCodingKey + @brief The key used to encode the email property for NSSecureCoding. + */ +static NSString *const kEmailCodingKey = @"email"; + +/** @var kPhoneNumberCodingKey + @brief The key used to encode the phoneNumber property for NSSecureCoding. + */ +static NSString *const kPhoneNumberCodingKey = @"phoneNumber"; + +/** @var kEmailVerifiedCodingKey + @brief The key used to encode the isEmailVerified property for NSSecureCoding. + */ +static NSString *const kEmailVerifiedCodingKey = @"emailVerified"; + +/** @var kDisplayNameCodingKey + @brief The key used to encode the displayName property for NSSecureCoding. + */ +static NSString *const kDisplayNameCodingKey = @"displayName"; + +/** @var kPhotoURLCodingKey + @brief The key used to encode the photoURL property for NSSecureCoding. + */ +static NSString *const kPhotoURLCodingKey = @"photoURL"; + +/** @var kProviderDataKey + @brief The key used to encode the providerData instance variable for NSSecureCoding. + */ +static NSString *const kProviderDataKey = @"providerData"; + +/** @var kAPIKeyCodingKey + @brief The key used to encode the APIKey instance variable for NSSecureCoding. + */ +static NSString *const kAPIKeyCodingKey = @"APIKey"; + +/** @var kTokenServiceCodingKey + @brief The key used to encode the tokenService instance variable for NSSecureCoding. + */ +static NSString *const kTokenServiceCodingKey = @"tokenService"; + +/** @var kMetadataCodingKey + @brief The key used to encode the metadata instance variable for NSSecureCoding. + */ +static NSString *const kMetadataCodingKey = @"metadata"; + +static NSString *const kMultiFactorCodingKey = @"multiFactor"; + +/** @var kTenantIDKey + @brief The key used to encode the tenantID instance variable for NSSecureCoding. + */ +static NSString *const kTenantIDCodingKey = @"tenantID"; + +/** @var kMissingUsersErrorMessage + @brief The error message when there is no users array in the getAccountInfo response. + */ +static NSString *const kMissingUsersErrorMessage = @"users"; + +/** @typedef CallbackWithError + @brief The type for a callback block that only takes an error parameter. + */ +typedef void (^CallbackWithError)(NSError *_Nullable); + +/** @typedef CallbackWithUserAndError + @brief The type for a callback block that takes a user parameter and an error parameter. + */ +typedef void (^CallbackWithUserAndError)(FIRUser *_Nullable, NSError *_Nullable); + +/** @typedef CallbackWithUserAndError + @brief The type for a callback block that takes a user parameter and an error parameter. + */ +typedef void (^CallbackWithAuthDataResultAndError)(FIRAuthDataResult *_Nullable, + NSError *_Nullable); + +/** @var kMissingPasswordReason + @brief The reason why the @c FIRAuthErrorCodeWeakPassword error is thrown. + @remarks This error message will be localized in the future. + */ +static NSString *const kMissingPasswordReason = @"Missing Password"; + +/** @fn callInMainThreadWithError + @brief Calls a callback in main thread with error. + @param callback The callback to be called in main thread. + @param error The error to pass to callback. + */ +static void callInMainThreadWithError(_Nullable CallbackWithError callback, + NSError *_Nullable error) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(error); + }); + } +} + +/** @fn callInMainThreadWithUserAndError + @brief Calls a callback in main thread with user and error. + @param callback The callback to be called in main thread. + @param user The user to pass to callback if there is no error. + @param error The error to pass to callback. + */ +static void callInMainThreadWithUserAndError(_Nullable CallbackWithUserAndError callback, + FIRUser *_Nonnull user, + NSError *_Nullable error) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(error ? nil : user, error); + }); + } +} + +/** @fn callInMainThreadWithUserAndError + @brief Calls a callback in main thread with user and error. + @param callback The callback to be called in main thread. + @param result The result to pass to callback if there is no error. + @param error The error to pass to callback. + */ +static void callInMainThreadWithAuthDataResultAndError( + _Nullable CallbackWithAuthDataResultAndError callback, + FIRAuthDataResult *_Nullable result, + NSError *_Nullable error) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(result, error); + }); + } +} + +@interface FIRUserProfileChangeRequest () + +/** @fn initWithUser: + @brief Designated initializer. + @param user The user for which we are updating profile information. + */ +- (nullable instancetype)initWithUser:(FIRUser *)user NS_DESIGNATED_INITIALIZER; + +@end + +@interface FIRUser () + +/** @property anonymous + @brief Whether the current user is anonymous. + */ +@property(nonatomic, readwrite) BOOL anonymous; + +/** @property tenantID + @brief The tenant ID of the current user. nil if none is available. + */ +@property(nonatomic, readwrite, nullable) NSString *tenantID; + +@end + +@implementation FIRUser { + /** @var _hasEmailPasswordCredential + @brief Whether or not the user can be authenticated by using Firebase email and password. + */ + BOOL _hasEmailPasswordCredential; + + /** @var _providerData + @brief Provider specific user data. + */ + NSDictionary *_providerData; + + /** @var _taskQueue + @brief Used to serialize the update profile calls. + */ + FIRAuthSerialTaskQueue *_taskQueue; + + /** @var _tokenService + @brief A secure token service associated with this user. For performing token exchanges and + refreshing access tokens. + */ + FIRSecureTokenService *_tokenService; +} + +#pragma mark - Properties + +// Explicitly @synthesize because these properties are defined in FIRUserInfo protocol. +@synthesize uid = _userID; +@synthesize displayName = _displayName; +@synthesize photoURL = _photoURL; +@synthesize email = _email; +@synthesize phoneNumber = _phoneNumber; + +#pragma mark - + ++ (void)retrieveUserWithAuth:(FIRAuth *)auth + accessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(nullable NSString *)refreshToken + anonymous:(BOOL)anonymous + callback:(FIRRetrieveUserCallback)callback { + FIRSecureTokenService *tokenService = + [[FIRSecureTokenService alloc] initWithRequestConfiguration:auth.requestConfiguration + accessToken:accessToken + accessTokenExpirationDate:accessTokenExpirationDate + refreshToken:refreshToken]; + FIRUser *user = [[self alloc] initWithTokenService:tokenService]; + user.auth = auth; + user.tenantID = auth.tenantID; + user.requestConfiguration = auth.requestConfiguration; + [user internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + callback(nil, error); + return; + } + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken + requestConfiguration:auth.requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + // No need to sign out user here for errors because the user hasn't been signed in + // yet. + callback(nil, error); + return; + } + user.anonymous = anonymous; + [user updateWithGetAccountInfoResponse:response]; + callback(user, nil); + }]; + }]; +} + +- (instancetype)initWithTokenService:(FIRSecureTokenService *)tokenService { + self = [super init]; + if (self) { + _providerData = @{}; + _taskQueue = [[FIRAuthSerialTaskQueue alloc] init]; + _tokenService = tokenService; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *userID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUserIDCodingKey]; + BOOL hasAnonymousKey = [aDecoder containsValueForKey:kAnonymousCodingKey]; + BOOL anonymous = [aDecoder decodeBoolForKey:kAnonymousCodingKey]; + BOOL hasEmailPasswordCredential = + [aDecoder decodeBoolForKey:kHasEmailPasswordCredentialCodingKey]; + NSString *displayName = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kDisplayNameCodingKey]; + NSURL *photoURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kPhotoURLCodingKey]; + NSString *email = [aDecoder decodeObjectOfClass:[NSString class] forKey:kEmailCodingKey]; + NSString *phoneNumber = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kPhoneNumberCodingKey]; + BOOL emailVerified = [aDecoder decodeBoolForKey:kEmailVerifiedCodingKey]; + NSSet *providerDataClasses = + [NSSet setWithArray:@[ [NSDictionary class], [NSString class], [FIRUserInfoImpl class] ]]; + NSDictionary *providerData = + [aDecoder decodeObjectOfClasses:providerDataClasses forKey:kProviderDataKey]; + FIRSecureTokenService *tokenService = [aDecoder decodeObjectOfClass:[FIRSecureTokenService class] + forKey:kTokenServiceCodingKey]; + FIRUserMetadata *metadata = [aDecoder decodeObjectOfClass:[FIRUserMetadata class] + forKey:kMetadataCodingKey]; + NSString *tenantID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kTenantIDCodingKey]; + NSString *APIKey = [aDecoder decodeObjectOfClass:[NSString class] forKey:kAPIKeyCodingKey]; +#if TARGET_OS_IOS + FIRMultiFactor *multiFactor = [aDecoder decodeObjectOfClass:[FIRMultiFactor class] + forKey:kMultiFactorCodingKey]; +#endif + if (!userID || !tokenService) { + return nil; + } + self = [self initWithTokenService:tokenService]; + if (self) { + _userID = userID; + // Previous version of this code didn't save 'anonymous' bit directly but deduced it from + // 'hasEmailPasswordCredential' and 'providerData' instead, so here backward compatibility is + // provided to read old format data. + _anonymous = hasAnonymousKey ? anonymous : (!hasEmailPasswordCredential && !providerData.count); + _hasEmailPasswordCredential = hasEmailPasswordCredential; + _email = email; + _emailVerified = emailVerified; + _displayName = displayName; + _photoURL = photoURL; + _providerData = providerData; + _phoneNumber = phoneNumber; + _metadata = metadata ?: [[FIRUserMetadata alloc] initWithCreationDate:nil lastSignInDate:nil]; + _tenantID = tenantID; + _requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey]; +#if TARGET_OS_IOS + _multiFactor = multiFactor ?: [[FIRMultiFactor alloc] init]; +#endif + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_userID forKey:kUserIDCodingKey]; + [aCoder encodeBool:self.anonymous forKey:kAnonymousCodingKey]; + [aCoder encodeBool:_hasEmailPasswordCredential forKey:kHasEmailPasswordCredentialCodingKey]; + [aCoder encodeObject:_providerData forKey:kProviderDataKey]; + [aCoder encodeObject:_email forKey:kEmailCodingKey]; + [aCoder encodeObject:_phoneNumber forKey:kPhoneNumberCodingKey]; + [aCoder encodeBool:_emailVerified forKey:kEmailVerifiedCodingKey]; + [aCoder encodeObject:_photoURL forKey:kPhotoURLCodingKey]; + [aCoder encodeObject:_displayName forKey:kDisplayNameCodingKey]; + [aCoder encodeObject:_metadata forKey:kMetadataCodingKey]; + [aCoder encodeObject:_tenantID forKey:kTenantIDCodingKey]; + [aCoder encodeObject:_auth.requestConfiguration.APIKey forKey:kAPIKeyCodingKey]; + [aCoder encodeObject:_tokenService forKey:kTokenServiceCodingKey]; +#if TARGET_OS_IOS + [aCoder encodeObject:_multiFactor forKey:kMultiFactorCodingKey]; +#endif +} + +#pragma mark - + +- (void)setAuth:(nullable FIRAuth *)auth { + _auth = auth; + _tokenService.requestConfiguration = auth.requestConfiguration; +} + +- (NSString *)providerID { + return @"Firebase"; +} + +- (NSArray> *)providerData { + return _providerData.allValues; +} + +/** @fn getAccountInfoRefreshingCache: + @brief Gets the users's account data from the server, updating our local values. + @param callback Invoked when the request to getAccountInfo has completed, or when an error has + been detected. Invoked asynchronously on the auth global work queue in the future. + */ +- (void)getAccountInfoRefreshingCache:(void (^)(FIRGetAccountInfoResponseUser *_Nullable user, + NSError *_Nullable error))callback { + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + callback(nil, error); + return; + } + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken + requestConfiguration:self->_auth.requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callback(nil, error); + return; + } + [self updateWithGetAccountInfoResponse:response]; + if (![self updateKeychain:&error]) { + callback(nil, error); + return; + } + callback(response.users.firstObject, nil); + }]; + }]; +} + +- (void)updateWithGetAccountInfoResponse:(FIRGetAccountInfoResponse *)response { + FIRGetAccountInfoResponseUser *user = response.users.firstObject; + _userID = user.localID; + _email = user.email; + _emailVerified = user.emailVerified; + _displayName = user.displayName; + _photoURL = user.photoURL; + _phoneNumber = user.phoneNumber; + _hasEmailPasswordCredential = user.passwordHash.length > 0; + _metadata = [[FIRUserMetadata alloc] initWithCreationDate:user.creationDate + lastSignInDate:user.lastLoginDate]; + NSMutableDictionary *providerData = + [NSMutableDictionary dictionary]; + for (FIRGetAccountInfoResponseProviderUserInfo *providerUserInfo in user.providerUserInfo) { + FIRUserInfoImpl *userInfo = + [FIRUserInfoImpl userInfoWithGetAccountInfoResponseProviderUserInfo:providerUserInfo]; + if (userInfo) { + providerData[providerUserInfo.providerID] = userInfo; + } + } + _providerData = [providerData copy]; +#if TARGET_OS_IOS + _multiFactor = [[FIRMultiFactor alloc] initWithMFAEnrollments:user.MFAEnrollments]; + _multiFactor.user = self; +#endif +} + +/** @fn executeUserUpdateWithChanges:callback: + @brief Performs a setAccountInfo request by mutating the results of a getAccountInfo response, + atomically in regards to other calls to this method. + @param changeBlock A block responsible for mutating a template @c FIRSetAccountInfoRequest + @param callback A block to invoke when the change is complete. Invoked asynchronously on the + auth global work queue in the future. + */ +- (void)executeUserUpdateWithChanges:(void (^)(FIRGetAccountInfoResponseUser *, + FIRSetAccountInfoRequest *))changeBlock + callback:(nonnull FIRUserProfileChangeCallback)callback { + [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) { + [self getAccountInfoRefreshingCache:^(FIRGetAccountInfoResponseUser *_Nullable user, + NSError *_Nullable error) { + if (error) { + complete(); + callback(error); + return; + } + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + complete(); + callback(error); + return; + } + FIRAuthRequestConfiguration *configuration = self->_auth.requestConfiguration; + // Mutate setAccountInfoRequest in block: + FIRSetAccountInfoRequest *setAccountInfoRequest = + [[FIRSetAccountInfoRequest alloc] initWithRequestConfiguration:configuration]; + setAccountInfoRequest.accessToken = accessToken; + changeBlock(user, setAccountInfoRequest); + // Execute request: + [FIRAuthBackend + setAccountInfo:setAccountInfoRequest + callback:^(FIRSetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + complete(); + callback(error); + return; + } + if (response.IDToken && response.refreshToken) { + FIRSecureTokenService *tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:configuration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + [self setTokenService:tokenService + callback:^(NSError *_Nullable error) { + complete(); + callback(error); + }]; + return; + } + complete(); + callback(nil); + }]; + }]; + }]; + }]; +} + +/** @fn updateKeychain: + @brief Updates the keychain for user token or info changes. + @param error The error if NO is returned. + @return Whether the operation is successful. + */ +- (BOOL)updateKeychain:(NSError *_Nullable *_Nullable)error { + return [_auth updateKeychainWithUser:self error:error]; +} + +/** @fn setTokenService:callback: + @brief Sets a new token service for the @c FIRUser instance. + @param tokenService The new token service object. + @param callback The block to be called in the global auth working queue once finished. + @remarks The method makes sure the token service has access and refresh token and the new tokens + are saved in the keychain before calling back. + */ +- (void)setTokenService:(FIRSecureTokenService *)tokenService + callback:(nonnull CallbackWithError)callback { + [tokenService fetchAccessTokenForcingRefresh:NO + callback:^(NSString *_Nullable token, + NSError *_Nullable error, BOOL tokenUpdated) { + if (error) { + callback(error); + return; + } + self->_tokenService = tokenService; + if (![self updateKeychain:&error]) { + callback(error); + return; + } + callback(nil); + }]; +} + +#pragma mark - + +/** @fn updateEmail:password:callback: + @brief Updates email address and/or password for the current user. + @remarks May fail if there is already an email/password-based account for the same email + address. + @param email The email address for the user, if to be updated. + @param password The new password for the user, if to be updated. + @param callback The block called when the user profile change has finished. Invoked + asynchronously on the auth global work queue in the future. + @remarks May fail with a @c FIRAuthErrorCodeRequiresRecentLogin error code. + Call @c reauthentateWithCredential:completion: beforehand to avoid this error case. + */ +- (void)updateEmail:(nullable NSString *)email + password:(nullable NSString *)password + callback:(nonnull FIRUserProfileChangeCallback)callback { + if (password && ![password length]) { + callback([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:kMissingPasswordReason]); + return; + } + BOOL hadEmailPasswordCredential = _hasEmailPasswordCredential; + [self + executeUserUpdateWithChanges:^(FIRGetAccountInfoResponseUser *user, + FIRSetAccountInfoRequest *request) { + if (email) { + request.email = email; + } + if (password) { + request.password = password; + } + } + callback:^(NSError *error) { + if (error) { + callback(error); + return; + } + if (email) { + self->_email = [email copy]; + } + if (self->_email) { + if (!hadEmailPasswordCredential) { + // The list of providers need to be updated for the newly added email-password provider. + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + callback(error); + return; + } + FIRAuthRequestConfiguration *requestConfiguration = self->_auth.requestConfiguration; + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken + requestConfiguration:requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callback(error); + return; + } + for (FIRGetAccountInfoResponseUser *userAccountInfo in response.users) { + // Set the account to non-anonymous if there are any providers, even if + // they're not email/password ones. + if (userAccountInfo.providerUserInfo.count > 0) { + self.anonymous = NO; + } + for (FIRGetAccountInfoResponseProviderUserInfo + *providerUserInfo in userAccountInfo.providerUserInfo) { + if ([providerUserInfo.providerID + isEqualToString:FIREmailAuthProviderID]) { + self->_hasEmailPasswordCredential = YES; + break; + } + } + } + [self updateWithGetAccountInfoResponse:response]; + if (![self updateKeychain:&error]) { + callback(error); + return; + } + callback(nil); + }]; + }]; + return; + } + } + if (![self updateKeychain:&error]) { + callback(error); + return; + } + callback(nil); + }]; +} + +- (void)updateEmail:(NSString *)email completion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self updateEmail:email + password:nil + callback:^(NSError *_Nullable error) { + callInMainThreadWithError(completion, error); + }]; + }); +} + +- (void)updatePassword:(NSString *)password + completion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self updateEmail:nil + password:password + callback:^(NSError *_Nullable error) { + callInMainThreadWithError(completion, error); + }]; + }); +} + +#if TARGET_OS_IOS +/** @fn internalUpdateOrLinkPhoneNumberCredential:completion: + @brief Updates the phone number for the user. On success, the cached user profile data is + updated. + + @param phoneAuthCredential The new phone number credential corresponding to the phone number + to be added to the Firebase account, if a phone number is already linked to the account this + new phone number will replace it. + @param isLinkOperation Boolean value indicating whether or not this is a link operation. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the global work queue in the future. + */ +- (void)internalUpdateOrLinkPhoneNumberCredential:(FIRPhoneAuthCredential *)phoneAuthCredential + isLinkOperation:(BOOL)isLinkOperation + completion:(FIRUserProfileChangeCallback)completion { + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + completion(error); + return; + } + FIRAuthOperationType operation = + isLinkOperation ? FIRAuthOperationTypeLink : FIRAuthOperationTypeUpdate; + FIRVerifyPhoneNumberRequest *request = [[FIRVerifyPhoneNumberRequest alloc] + initWithVerificationID:phoneAuthCredential.verificationID + verificationCode:phoneAuthCredential.verificationCode + operation:operation + requestConfiguration:self->_auth.requestConfiguration]; + request.accessToken = accessToken; + [FIRAuthBackend verifyPhoneNumber:request + callback:^(FIRVerifyPhoneNumberResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + completion(error); + return; + } + FIRAuthRequestConfiguration *requestConfiguration = + self.auth.requestConfiguration; + // Update the new token and refresh user info again. + self->_tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + // Get account info to update cached user info. + [self getAccountInfoRefreshingCache:^( + FIRGetAccountInfoResponseUser *_Nullable user, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + completion(error); + return; + } + self.anonymous = NO; + if (![self updateKeychain:&error]) { + completion(error); + return; + } + completion(nil); + }]; + }]; + }]; +} + +- (void)updatePhoneNumberCredential:(FIRPhoneAuthCredential *)phoneAuthCredential + completion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self internalUpdateOrLinkPhoneNumberCredential:phoneAuthCredential + isLinkOperation:NO + completion:^(NSError *_Nullable error) { + callInMainThreadWithError(completion, error); + }]; + }); +} +#endif + +- (FIRUserProfileChangeRequest *)profileChangeRequest { + __block FIRUserProfileChangeRequest *result; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = [[FIRUserProfileChangeRequest alloc] initWithUser:self]; + }); + return result; +} + +- (void)setDisplayName:(NSString *)displayName { + _displayName = [displayName copy]; +} + +- (void)setPhotoURL:(NSURL *)photoURL { + _photoURL = [photoURL copy]; +} + +- (NSString *)rawAccessToken { + return _tokenService.rawAccessToken; +} + +- (NSDate *)accessTokenExpirationDate { + return _tokenService.accessTokenExpirationDate; +} + +#pragma mark - + +- (void)reloadWithCompletion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self getAccountInfoRefreshingCache:^(FIRGetAccountInfoResponseUser *_Nullable user, + NSError *_Nullable error) { + callInMainThreadWithError(completion, error); + }]; + }); +} + +#pragma mark - + +- (void)reauthenticateWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self->_auth + internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:YES + callback:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + if (error) { + // If "user not found" error returned by backend, + // translate to user mismatch error which is more + // accurate. + if (error.code == FIRAuthErrorCodeUserNotFound) { + error = [FIRAuthErrorUtils userMismatchError]; + } + callInMainThreadWithAuthDataResultAndError( + completion, authResult, error); + return; + } + if (![authResult.user.uid + isEqual:[self->_auth getUserID]]) { + callInMainThreadWithAuthDataResultAndError( + completion, authResult, + [FIRAuthErrorUtils userMismatchError]); + return; + } + // Successful reauthenticate + [self + setTokenService:authResult.user->_tokenService + callback:^(NSError *_Nullable error) { + callInMainThreadWithAuthDataResultAndError( + completion, authResult, error); + }]; + }]; + }); +} + +- (void)reauthenticateWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRAuthDataResultCallback)completion { +#if TARGET_OS_IOS + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [provider getCredentialWithUIDelegate:UIDelegate + completion:^(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error) { + [self reauthenticateWithCredential:credential + completion:completion]; + }]; + }); +#endif // TARGET_OS_IOS +} + +- (nullable NSString *)refreshToken { + __block NSString *result; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = self->_tokenService.refreshToken; + }); + return result; +} + +- (void)getIDTokenWithCompletion:(nullable FIRAuthTokenCallback)completion { + // |getIDTokenForcingRefresh:completion:| is also a public API so there is no need to dispatch to + // global work queue here. + [self getIDTokenForcingRefresh:NO completion:completion]; +} + +- (void)getIDTokenForcingRefresh:(BOOL)forceRefresh + completion:(nullable FIRAuthTokenCallback)completion { + [self getIDTokenResultForcingRefresh:forceRefresh + completion:^(FIRAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(tokenResult.token, error); + }); + } + }]; +} + +- (void)getIDTokenResultWithCompletion:(nullable FIRAuthTokenResultCallback)completion { + [self getIDTokenResultForcingRefresh:NO + completion:^(FIRAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(tokenResult, error); + }); + } + }]; +} + +- (void)getIDTokenResultForcingRefresh:(BOOL)forceRefresh + completion:(nullable FIRAuthTokenResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self + internalGetTokenForcingRefresh:forceRefresh + callback:^(NSString *_Nullable token, NSError *_Nullable error) { + FIRAuthTokenResult *tokenResult; + if (token) { + tokenResult = [FIRAuthTokenResult tokenResultWithToken:token]; + FIRLogDebug(kFIRLoggerAuth, @"I-AUT000017", + @"Actual token expiration date: %@, current date: %@", + tokenResult.expirationDate, [NSDate date]); + } + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(tokenResult, error); + }); + } + }]; + }); +} + +/** @fn parseIDToken:error: + @brief Parses the provided IDToken and returns an instance of FIRAuthTokenResult containing + claims obtained from the IDToken. + + @param token The raw text of the Firebase IDToken encoded in base64. + @param error An out parameter which would contain any error that occurs during parsing. + @return An instance of FIRAuthTokenResult containing claims obtained from the IDToken. + + @remarks IDToken returned from the backend in some cases is of a length that is not a multiple + of 4. In these cases this function pads the token with as many "=" characters as needed and + then attempts to parse the token. If the token cannot be parsed an error is returned via the + "error" out parameter. + */ +- (nullable FIRAuthTokenResult *)parseIDToken:(NSString *)token error:(NSError **)error { + // Though this is an internal method, errors returned here are surfaced in user-visible + // callbacks. + if (error) { + *error = nil; + } + NSArray *tokenStringArray = [token componentsSeparatedByString:@"."]; + + // The JWT should have three parts, though we only use the second in this method. + if (tokenStringArray.count != 3) { + if (error) { + *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:nil]; + } + return nil; + } + + // The token payload is always the second index of the array. + NSString *IDToken = tokenStringArray[1]; + + // Convert the base64URL encoded string to a base64 encoded string. + // Replace "_" with "/" + NSMutableString *tokenPayload = [[IDToken stringByReplacingOccurrencesOfString:@"_" + withString:@"/"] mutableCopy]; + + // Replace "-" with "+" + [tokenPayload replaceOccurrencesOfString:@"-" + withString:@"+" + options:kNilOptions + range:NSMakeRange(0, tokenPayload.length)]; + + // Pad the token payload with "=" signs if the payload's length is not a multiple of 4. + while ((tokenPayload.length % 4) != 0) { + [tokenPayload appendFormat:@"="]; + } + NSData *decodedTokenPayloadData = + [[NSData alloc] initWithBase64EncodedString:tokenPayload + options:NSDataBase64DecodingIgnoreUnknownCharacters]; + if (!decodedTokenPayloadData) { + if (error) { + *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:nil]; + } + return nil; + } + NSError *jsonError = nil; + NSJSONReadingOptions options = NSJSONReadingMutableContainers | NSJSONReadingAllowFragments; + NSDictionary *tokenPayloadDictionary = + [NSJSONSerialization JSONObjectWithData:decodedTokenPayloadData + options:options + error:&jsonError]; + if (jsonError != nil) { + if (error) { + *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:jsonError]; + } + return nil; + } + + if (!tokenPayloadDictionary) { + if (error) { + *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:nil]; + } + return nil; + } + + FIRAuthTokenResult *result = [FIRAuthTokenResult tokenResultWithToken:token]; + return result; +} + +/** @fn internalGetTokenForcingRefresh:callback: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + @param callback The block to invoke when the token is available. Invoked asynchronously on the + global work thread in the future. + */ +- (void)internalGetTokenWithCallback:(nonnull FIRAuthTokenCallback)callback { + [self internalGetTokenForcingRefresh:NO callback:callback]; +} + +- (void)internalGetTokenForcingRefresh:(BOOL)forceRefresh + callback:(nonnull FIRAuthTokenCallback)callback { + [_tokenService fetchAccessTokenForcingRefresh:forceRefresh + callback:^(NSString *_Nullable token, + NSError *_Nullable error, BOOL tokenUpdated) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callback(nil, error); + return; + } + if (tokenUpdated) { + if (![self updateKeychain:&error]) { + callback(nil, error); + return; + } + } + callback(token, nil); + }]; +} + +- (void)sendEmailVerificationBeforeUpdatingEmail:(nonnull NSString *)email + completion:(nullable FIRAuthVoidErrorCallback)completion { + [self internalVerifyBeforeUpdateEmailWithNewEmail:email + actionCodeSettings:nil + completion:completion]; +} + +- (void)sendEmailVerificationBeforeUpdatingEmail:(nonnull NSString *)email + actionCodeSettings:(nonnull FIRActionCodeSettings *)actionCodeSettings + completion:(nullable FIRAuthVoidErrorCallback)completion { + [self internalVerifyBeforeUpdateEmailWithNewEmail:email + actionCodeSettings:actionCodeSettings + completion:completion]; +} + +- (void)internalVerifyBeforeUpdateEmailWithNewEmail:(NSString *)newEmail + actionCodeSettings: + (nullable FIRActionCodeSettings *)actionCodeSettings + completion:(FIRVerifyBeforeUpdateEmailCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self + internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + callInMainThreadWithError(completion, error); + return; + } + FIRAuthRequestConfiguration *configuration = self->_auth.requestConfiguration; + FIRActionCodeSettings *settings = actionCodeSettings; + FIRGetOOBConfirmationCodeRequest *request = [FIRGetOOBConfirmationCodeRequest + verifyBeforeUpdateEmailWithAccessToken:accessToken + newEmail:newEmail + actionCodeSettings:settings + requestConfiguration:configuration]; + [FIRAuthBackend + getOOBConfirmationCode:request + callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response, + NSError *_Nullable error) { + callInMainThreadWithError(completion, error); + }]; + }]; + }); +} + +- (void)linkWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + if (self->_providerData[credential.provider]) { + callInMainThreadWithAuthDataResultAndError(completion, nil, + [FIRAuthErrorUtils providerAlreadyLinkedError]); + return; + } + FIRAuthDataResult *result = [[FIRAuthDataResult alloc] initWithUser:self + additionalUserInfo:nil]; + if ([credential isKindOfClass:[FIREmailPasswordAuthCredential class]]) { + if (self->_hasEmailPasswordCredential) { + callInMainThreadWithAuthDataResultAndError(completion, nil, + [FIRAuthErrorUtils providerAlreadyLinkedError]); + return; + } + FIREmailPasswordAuthCredential *emailPasswordCredential = + (FIREmailPasswordAuthCredential *)credential; + if (emailPasswordCredential.password) { + [self updateEmail:emailPasswordCredential.email + password:emailPasswordCredential.password + callback:^(NSError *error) { + if (error) { + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + } else { + callInMainThreadWithAuthDataResultAndError(completion, result, nil); + } + }]; + } else { + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + NSDictionary *queryItems = + [FIRAuthWebUtils parseURL:emailPasswordCredential.link]; + if (![queryItems count]) { + NSURLComponents *urlComponents = + [NSURLComponents componentsWithString:emailPasswordCredential.link]; + queryItems = [FIRAuthWebUtils parseURL:urlComponents.query]; + } + NSString *actionCode = queryItems[@"oobCode"]; + FIRAuthRequestConfiguration *requestConfiguration = self.auth.requestConfiguration; + FIREmailLinkSignInRequest *request = + [[FIREmailLinkSignInRequest alloc] initWithEmail:emailPasswordCredential.email + oobCode:actionCode + requestConfiguration:requestConfiguration]; + request.IDToken = accessToken; + [FIRAuthBackend + emailLinkSignin:request + callback:^(FIREmailLinkSignInResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + } else { + // Update the new token and refresh user info again. + self->_tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + return; + } + + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] + initWithAccessToken:accessToken + requestConfiguration:requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callInMainThreadWithAuthDataResultAndError(completion, nil, + error); + return; + } + self.anonymous = NO; + [self updateWithGetAccountInfoResponse:response]; + if (![self updateKeychain:&error]) { + callInMainThreadWithAuthDataResultAndError(completion, nil, + error); + return; + } + callInMainThreadWithAuthDataResultAndError(completion, + result, nil); + }]; + }]; + } + }]; + }]; + } + return; + } + + if ([credential isKindOfClass:[FIRGameCenterAuthCredential class]]) { + FIRGameCenterAuthCredential *gameCenterCredential = (FIRGameCenterAuthCredential *)credential; + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + FIRAuthRequestConfiguration *requestConfiguration = self.auth.requestConfiguration; + FIRSignInWithGameCenterRequest *gameCenterRequest = [[FIRSignInWithGameCenterRequest alloc] + initWithPlayerID:gameCenterCredential.playerID + publicKeyURL:gameCenterCredential.publicKeyURL + signature:gameCenterCredential.signature + salt:gameCenterCredential.salt + timestamp:gameCenterCredential.timestamp + displayName:gameCenterCredential.displayName + requestConfiguration:requestConfiguration]; + gameCenterRequest.accessToken = accessToken; + + [FIRAuthBackend + signInWithGameCenter:gameCenterRequest + callback:^(FIRSignInWithGameCenterResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + } else { + // Update the new token and refresh user info again. + self->_tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + return; + } + + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] + initWithAccessToken:accessToken + requestConfiguration:requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callInMainThreadWithAuthDataResultAndError(completion, + nil, error); + return; + } + self.anonymous = NO; + [self updateWithGetAccountInfoResponse:response]; + if (![self updateKeychain:&error]) { + callInMainThreadWithAuthDataResultAndError(completion, + nil, error); + return; + } + callInMainThreadWithAuthDataResultAndError(completion, + result, nil); + }]; + }]; + } + }]; + }]; + return; + } + +#if TARGET_OS_IOS + if ([credential isKindOfClass:[FIRPhoneAuthCredential class]]) { + FIRPhoneAuthCredential *phoneAuthCredential = (FIRPhoneAuthCredential *)credential; + [self internalUpdateOrLinkPhoneNumberCredential:phoneAuthCredential + isLinkOperation:YES + completion:^(NSError *_Nullable error) { + if (error) { + callInMainThreadWithAuthDataResultAndError( + completion, nil, error); + } else { + callInMainThreadWithAuthDataResultAndError( + completion, result, nil); + } + }]; + return; + } +#endif + + [self->_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) { + CallbackWithAuthDataResultAndError completeWithError = + ^(FIRAuthDataResult *result, NSError *error) { + complete(); + callInMainThreadWithAuthDataResultAndError(completion, result, error); + }; + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + completeWithError(nil, error); + return; + } + FIRAuthRequestConfiguration *requestConfiguration = self->_auth.requestConfiguration; + FIRVerifyAssertionRequest *request = + [[FIRVerifyAssertionRequest alloc] initWithProviderID:credential.provider + requestConfiguration:requestConfiguration]; + [credential prepareVerifyAssertionRequest:request]; + request.accessToken = accessToken; + [FIRAuthBackend + verifyAssertion:request + callback:^(FIRVerifyAssertionResponse *response, NSError *error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + completeWithError(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [FIRAdditionalUserInfo userInfoWithVerifyAssertionResponse:response]; + FIROAuthCredential *updatedOAuthCredential = + [[FIROAuthCredential alloc] initWithVerifyAssertionResponse:response]; + FIRAuthDataResult *result = + [[FIRAuthDataResult alloc] initWithUser:self + additionalUserInfo:additionalUserInfo + credential:updatedOAuthCredential]; + // Update the new token and refresh user info again. + self->_tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + completeWithError(nil, error); + return; + } + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] + initWithAccessToken:accessToken + requestConfiguration:requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + completeWithError(nil, error); + return; + } + self.anonymous = NO; + [self updateWithGetAccountInfoResponse:response]; + if (![self updateKeychain:&error]) { + completeWithError(nil, error); + return; + } + completeWithError(result, nil); + }]; + }]; + }]; + }]; + }]; + }); +} + +- (void)linkWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRAuthDataResultCallback)completion { +#if TARGET_OS_IOS + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [provider getCredentialWithUIDelegate:UIDelegate + completion:^(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error) { + [self linkWithCredential:credential completion:completion]; + }]; + }); +#endif // TARGET_OS_IOS +} + +- (void)unlinkFromProvider:(NSString *)provider + completion:(nullable FIRAuthResultCallback)completion { + [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) { + CallbackWithError completeAndCallbackWithError = ^(NSError *error) { + complete(); + callInMainThreadWithUserAndError(completion, self, error); + }; + [self + internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + completeAndCallbackWithError(error); + return; + } + FIRAuthRequestConfiguration *requestConfiguration = self->_auth.requestConfiguration; + FIRSetAccountInfoRequest *setAccountInfoRequest = + [[FIRSetAccountInfoRequest alloc] initWithRequestConfiguration:requestConfiguration]; + setAccountInfoRequest.accessToken = accessToken; + + if (!self->_providerData[provider]) { + completeAndCallbackWithError([FIRAuthErrorUtils noSuchProviderError]); + return; + } + setAccountInfoRequest.deleteProviders = @[ provider ]; + + [FIRAuthBackend + setAccountInfo:setAccountInfoRequest + callback:^(FIRSetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + completeAndCallbackWithError(error); + return; + } + + // We can't just use the provider info objects in FIRSetAccountInfoResponse + // because they don't have localID and email fields. Remove the specific + // provider manually. + NSMutableDictionary *mutableProviderData = [self->_providerData mutableCopy]; + [mutableProviderData removeObjectForKey:provider]; + self->_providerData = [mutableProviderData copy]; + + if ([provider isEqualToString:FIREmailAuthProviderID]) { + self->_hasEmailPasswordCredential = NO; + } +#if TARGET_OS_IOS + // After successfully unlinking a phone auth provider, remove the phone number + // from the cached user info. + if ([provider isEqualToString:FIRPhoneAuthProviderID]) { + self->_phoneNumber = nil; + } +#endif + + if (response.IDToken && response.refreshToken) { + FIRSecureTokenService *tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + [self setTokenService:tokenService + callback:^(NSError *_Nullable error) { + completeAndCallbackWithError(error); + }]; + return; + } + if (![self updateKeychain:&error]) { + completeAndCallbackWithError(error); + return; + } + completeAndCallbackWithError(nil); + }]; + }]; + }]; +} + +- (void)sendEmailVerificationWithCompletion:(nullable FIRSendEmailVerificationCallback)completion { + [self sendEmailVerificationWithNullableActionCodeSettings:nil completion:completion]; +} + +- (void)sendEmailVerificationWithActionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion: + (nullable FIRSendEmailVerificationCallback)completion { + [self sendEmailVerificationWithNullableActionCodeSettings:actionCodeSettings + completion:completion]; +} + +/** @fn sendEmailVerificationWithNullableActionCodeSettings:completion: + @brief Initiates email verification for the user. + + @param actionCodeSettings Optionally, a @c FIRActionCodeSettings object containing settings + related to the handling action codes. + */ +- (void)sendEmailVerificationWithNullableActionCodeSettings: + (nullable FIRActionCodeSettings *)actionCodeSettings + completion: + (nullable FIRSendEmailVerificationCallback) + completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self + internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + callInMainThreadWithError(completion, error); + return; + } + FIRAuthRequestConfiguration *configuration = self->_auth.requestConfiguration; + FIRGetOOBConfirmationCodeRequest *request = + [FIRGetOOBConfirmationCodeRequest verifyEmailRequestWithAccessToken:accessToken + actionCodeSettings:actionCodeSettings + requestConfiguration:configuration]; + [FIRAuthBackend + getOOBConfirmationCode:request + callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response, + NSError *_Nullable error) { + [self signOutIfTokenIsInvalidWithError:error]; + callInMainThreadWithError(completion, error); + }]; + }]; + }); +} + +- (void)deleteWithCompletion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self + internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + callInMainThreadWithError(completion, error); + return; + } + FIRDeleteAccountRequest *deleteUserRequest = + [[FIRDeleteAccountRequest alloc] initWitLocalID:self->_userID + accessToken:accessToken + requestConfiguration:self->_auth.requestConfiguration]; + [FIRAuthBackend deleteAccount:deleteUserRequest + callback:^(NSError *_Nullable error) { + if (error) { + callInMainThreadWithError(completion, error); + return; + } + if (![self->_auth signOutByForceWithUserID:self->_userID + error:&error]) { + callInMainThreadWithError(completion, error); + return; + } + callInMainThreadWithError(completion, error); + }]; + }]; + }); +} + +/** @fn signOutIfTokenIsInvalidWithError: + @brief Signs out this user if the user or the token is invalid. + @param error The error from the server. + */ +- (void)signOutIfTokenIsInvalidWithError:(nullable NSError *)error { + NSInteger errorCode = error.code; + if (errorCode == FIRAuthErrorCodeUserNotFound || errorCode == FIRAuthErrorCodeUserDisabled || + errorCode == FIRAuthErrorCodeInvalidUserToken || + errorCode == FIRAuthErrorCodeUserTokenExpired) { + FIRLogNotice(kFIRLoggerAuth, @"I-AUT000016", + @"Invalid user token detected, user is automatically signed out."); + [_auth signOutByForceWithUserID:_userID error:NULL]; + } +} + +@end + +@implementation FIRUserProfileChangeRequest { + /** @var _user + @brief The user associated with the change request. + */ + FIRUser *_user; + + /** @var _displayName + @brief The display name value to set if @c _displayNameSet is YES. + */ + NSString *_displayName; + + /** @var _displayNameSet + @brief Indicates the display name should be part of the change request. + */ + BOOL _displayNameSet; + + /** @var _photoURL + @brief The photo URL value to set if @c _displayNameSet is YES. + */ + NSURL *_photoURL; + + /** @var _photoURLSet + @brief Indicates the photo URL should be part of the change request. + */ + BOOL _photoURLSet; + + /** @var _consumed + @brief Indicates the @c commitChangesWithCallback: method has already been invoked. + */ + BOOL _consumed; +} + +- (nullable instancetype)initWithUser:(FIRUser *)user { + self = [super init]; + if (self) { + _user = user; + } + return self; +} + +- (nullable NSString *)displayName { + return _displayName; +} + +- (void)setDisplayName:(nullable NSString *)displayName { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + if (self->_consumed) { + [NSException + raise:NSInternalInconsistencyException + format:@"%@", @"Invalid call to setDisplayName: after commitChangesWithCallback:."]; + return; + } + self->_displayNameSet = YES; + self->_displayName = [displayName copy]; + }); +} + +- (nullable NSURL *)photoURL { + return _photoURL; +} + +- (void)setPhotoURL:(nullable NSURL *)photoURL { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + if (self->_consumed) { + [NSException raise:NSInternalInconsistencyException + format:@"%@", @"Invalid call to setPhotoURL: after commitChangesWithCallback:."]; + return; + } + self->_photoURLSet = YES; + self->_photoURL = [photoURL copy]; + }); +} + +/** @fn hasUpdates + @brief Indicates at least one field has a value which needs to be committed. + */ +- (BOOL)hasUpdates { + return _displayNameSet || _photoURLSet; +} + +- (void)commitChangesWithCompletion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + if (self->_consumed) { + [NSException raise:NSInternalInconsistencyException + format:@"%@", @"commitChangesWithCallback: should only be called once."]; + return; + } + self->_consumed = YES; + // Return fast if there is nothing to update: + if (![self hasUpdates]) { + callInMainThreadWithError(completion, nil); + return; + } + NSString *displayName = [self->_displayName copy]; + BOOL displayNameWasSet = self->_displayNameSet; + NSURL *photoURL = [self->_photoURL copy]; + BOOL photoURLWasSet = self->_photoURLSet; + [self->_user + executeUserUpdateWithChanges:^(FIRGetAccountInfoResponseUser *user, + FIRSetAccountInfoRequest *request) { + if (photoURLWasSet) { + request.photoURL = photoURL; + } + if (displayNameWasSet) { + request.displayName = displayName; + } + } + callback:^(NSError *_Nullable error) { + if (error) { + callInMainThreadWithError(completion, error); + return; + } + if (displayNameWasSet) { + [self->_user setDisplayName:displayName]; + } + if (photoURLWasSet) { + [self->_user setPhotoURL:photoURL]; + } + if (![self->_user updateKeychain:&error]) { + callInMainThreadWithError(completion, error); + return; + } + callInMainThreadWithError(completion, nil); + }]; + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.h new file mode 100644 index 0000000..8d6b377 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.h @@ -0,0 +1,60 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h" + +@class FIRGetAccountInfoResponseProviderUserInfo; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRUserInfoImpl : NSObject + +/** @fn userInfoWithGetAccountInfoResponseProviderUserInfo: + @brief A convenience factory method for constructing a @c FIRUserInfo instance from data + returned by the getAccountInfo endpoint. + @param providerUserInfo Data returned by the getAccountInfo endpoint. + @return A new instance of @c FIRUserInfo using data from the getAccountInfo endpoint. + */ ++ (nullable instancetype)userInfoWithGetAccountInfoResponseProviderUserInfo: + (FIRGetAccountInfoResponseProviderUserInfo *)providerUserInfo; + +/** @fn init + @brief This class should not be initialized manually. + @see FIRUser.providerData + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithProviderID:userID:displayName:photoURL:email: + @brief Designated initializer. + @param providerID The provider identifier. + @param userID The unique user ID for the user (the value of the @c uid field in the token.) + @param displayName The name of the user. + @param photoURL The URL of the user's profile photo. + @param email The user's email address. + @param phoneNumber The user's phone number. + */ +- (nullable instancetype)initWithProviderID:(NSString *)providerID + userID:(NSString *)userID + displayName:(nullable NSString *)displayName + photoURL:(nullable NSURL *)photoURL + email:(nullable NSString *)email + phoneNumber:(nullable NSString *)phoneNumber + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.m new file mode 100644 index 0000000..5092606 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.m @@ -0,0 +1,131 @@ +/* + * 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 "FirebaseAuth/Sources/User/FIRUserInfoImpl.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kProviderIDCodingKey + @brief The key used to encode the providerID property for NSSecureCoding. + */ +static NSString *const kProviderIDCodingKey = @"providerID"; + +/** @var kUserIDCodingKey + @brief The key used to encode the userID property for NSSecureCoding. + */ +static NSString *const kUserIDCodingKey = @"userID"; + +/** @var kDisplayNameCodingKey + @brief The key used to encode the displayName property for NSSecureCoding. + */ +static NSString *const kDisplayNameCodingKey = @"displayName"; + +/** @var kProfileURLCodingKey + @brief The key used to encode the profileURL property for NSSecureCoding. + */ +static NSString *const kProfileURLCodingKey = @"profileURL"; + +/** @var kPhotoURLCodingKey + @brief The key used to encode the photoURL property for NSSecureCoding. + */ +static NSString *const kPhotoURLCodingKey = @"photoURL"; + +/** @var kEmailCodingKey + @brief The key used to encode the email property for NSSecureCoding. + */ +static NSString *const kEmailCodingKey = @"email"; + +/** @var kPhoneNumberCodingKey + @brief The key used to encode the phoneNumber property for NSSecureCoding. + */ +static NSString *const kPhoneNumberCodingKey = @"phoneNumber"; + +@implementation FIRUserInfoImpl + +@synthesize providerID = _providerID; +@synthesize uid = _userID; +@synthesize displayName = _displayName; +@synthesize photoURL = _photoURL; +@synthesize email = _email; +@synthesize phoneNumber = _phoneNumber; + ++ (nullable instancetype)userInfoWithGetAccountInfoResponseProviderUserInfo: + (FIRGetAccountInfoResponseProviderUserInfo *)providerUserInfo { + return [[self alloc] initWithProviderID:providerUserInfo.providerID + userID:providerUserInfo.federatedID + displayName:providerUserInfo.displayName + photoURL:providerUserInfo.photoURL + email:providerUserInfo.email + phoneNumber:providerUserInfo.phoneNumber]; +} + +- (nullable instancetype)initWithProviderID:(NSString *)providerID + userID:(NSString *)userID + displayName:(nullable NSString *)displayName + photoURL:(nullable NSURL *)photoURL + email:(nullable NSString *)email + phoneNumber:(nullable NSString *)phoneNumber { + self = [super init]; + if (self) { + _providerID = [providerID copy]; + _userID = [userID copy]; + _displayName = [displayName copy]; + _photoURL = [photoURL copy]; + _email = [email copy]; + _phoneNumber = [phoneNumber copy]; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *providerID = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kProviderIDCodingKey]; + NSString *userID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUserIDCodingKey]; + NSString *displayName = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kDisplayNameCodingKey]; + NSURL *photoURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kPhotoURLCodingKey]; + NSString *email = [aDecoder decodeObjectOfClass:[NSString class] forKey:kEmailCodingKey]; + NSString *phoneNumber = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kPhoneNumberCodingKey]; + + return [self initWithProviderID:providerID + userID:userID + displayName:displayName + photoURL:photoURL + email:email + phoneNumber:phoneNumber]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_providerID forKey:kProviderIDCodingKey]; + [aCoder encodeObject:_userID forKey:kUserIDCodingKey]; + [aCoder encodeObject:_displayName forKey:kDisplayNameCodingKey]; + [aCoder encodeObject:_photoURL forKey:kPhotoURLCodingKey]; + [aCoder encodeObject:_email forKey:kEmailCodingKey]; + [aCoder encodeObject:_phoneNumber forKey:kPhoneNumberCodingKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata.m new file mode 100644 index 0000000..ba46ebd --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata.m @@ -0,0 +1,64 @@ +/* + * 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 "FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRUserMetadata + +/** @var kCreationDateCodingKey + @brief The key used to encode the creationDate property for NSSecureCoding. + */ +static NSString *const kCreationDateCodingKey = @"creationDate"; + +/** @var kLastSignInDateCodingKey + @brief The key used to encode the lastSignInDate property for NSSecureCoding. + */ +static NSString *const kLastSignInDateCodingKey = @"lastSignInDate"; + +- (instancetype)initWithCreationDate:(nullable NSDate *)creationDate + lastSignInDate:(nullable NSDate *)lastSignInDate { + self = [super init]; + if (self) { + _creationDate = [creationDate copy]; + _lastSignInDate = [lastSignInDate copy]; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSDate *creationDate = [aDecoder decodeObjectOfClass:[NSDate class] + forKey:kCreationDateCodingKey]; + NSDate *lastSignInDate = [aDecoder decodeObjectOfClass:[NSDate class] + forKey:kLastSignInDateCodingKey]; + return [self initWithCreationDate:creationDate lastSignInDate:lastSignInDate]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_creationDate forKey:kCreationDateCodingKey]; + [aCoder encodeObject:_lastSignInDate forKey:kLastSignInDateCodingKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h new file mode 100644 index 0000000..20a19de --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h @@ -0,0 +1,37 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @extension FIRUserMetadata + @brief An internal class used to expose internal methods of FIRUserMetadata. + */ +@interface FIRUserMetadata () + +/** @fn initWithCreationDate:lastSignInDate: + @brief Designated initializer. + @param creationDate The creation date of the corresponding user. + @param lastSignInDate The date of the last recorded sign-in of the corresponding user. + */ +- (instancetype)initWithCreationDate:(nullable NSDate *)creationDate + lastSignInDate:(nullable NSDate *)lastSignInDate NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser_Internal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser_Internal.h new file mode 100644 index 0000000..54524f2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser_Internal.h @@ -0,0 +1,107 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h" + +@class FIRAuth; +@class FIRAuthRequestConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRRetrieveUserCallback + @brief The type of block that is invoked when the construction of a user succeeds or fails. + @param user The user that was constructed, or nil if user construction failed. + @param error The error which occurred, or nil if the request was successful. + */ +typedef void (^FIRRetrieveUserCallback)(FIRUser *_Nullable user, NSError *_Nullable error); + +/** @typedef FIRVerifyBeforeUpdateEmailCallback + @brief The type of block called when a request to verify before update email has finished. + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRVerifyBeforeUpdateEmailCallback)(NSError *_Nullable error); + +@interface FIRUser () + +/** @property rawAccessToken + @brief The cached access token. + @remarks This method is specifically for providing the access token to internal clients during + deserialization and sign-in events, and should not be used to retrieve the access token by + anyone else. + */ +@property(nonatomic, copy, readonly) NSString *rawAccessToken; + +/** @property auth + @brief A weak reference to a FIRAuth instance associated with this instance. + */ +@property(nonatomic, weak) FIRAuth *auth; + +/** @property auth + @brief A strong reference to a requestConfiguration instance associated with this user instance. + */ +@property(nonatomic, strong) FIRAuthRequestConfiguration *requestConfiguration; + +/** @var accessTokenExpirationDate + @brief The expiration date of the cached access token. + */ +@property(nonatomic, copy, readonly) NSDate *accessTokenExpirationDate; + +/** @fn retrieveUserWithAuth:accessToken:accessTokenExpirationDate:refreshToken:callback: + @brief Constructs a user with Secure Token Service tokens, and obtains user details from the + getAccountInfo endpoint. + @param auth The associated FIRAuth instance. + @param accessToken The Secure Token Service access token. + @param accessTokenExpirationDate The approximate expiration date of the access token. + @param refreshToken The Secure Token Service refresh token. + @param anonymous Whether or not the user is anonymous. + @param callback A block which is invoked when the construction succeeds or fails. Invoked + asynchronously on the auth global work queue in the future. + */ ++ (void)retrieveUserWithAuth:(FIRAuth *)auth + accessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(nullable NSString *)refreshToken + anonymous:(BOOL)anonymous + callback:(FIRRetrieveUserCallback)callback; + +/** @fn internalGetTokenForcingRefresh:callback: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason + other than an expiration. + @param callback The block to invoke when the token is available. Invoked asynchronously on the + global work thread in the future. + */ +- (void)internalGetTokenForcingRefresh:(BOOL)forceRefresh + callback:(nonnull FIRAuthTokenCallback)callback; + +/** @fn internalVerifyBeforeUpdateEmailWithNewEmail:actionCodeSettings:callback: + @brief Sends a verification email to newEmail. Upon redemption of the link in the email, + this user's email will be changed to newEmail and that email will be marked verified. + @param newEmail the user's new email. + @param actionCodeSettings the optional FIRActionCodeSettings object to allow linking back + to your app in the email. + @param completion The block to invoke when the call succeeds or fails. Invoked asynchronously on + the global work thread in the future. + + */ +- (void)internalVerifyBeforeUpdateEmailWithNewEmail:(NSString *)newEmail + actionCodeSettings: + (nullable FIRActionCodeSettings *)actionCodeSettings + completion:(FIRVerifyBeforeUpdateEmailCallback)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h new file mode 100644 index 0000000..4946d16 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthDefaultUIDelegate + @brief Class responsible for providing a default FIRAuthUIDelegte. + @remarks This class should be used in the case that a UIDelegate was expected and necessary to + continue a given flow, but none was provided. + */ +@interface FIRAuthDefaultUIDelegate : NSObject + +/** @fn defaultUIDelegate + @brief Unavailable. Please use @c +defaultUIDelegate: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn defaultUIDelegate + @brief Returns a default FIRAuthUIDelegate object. + @return The default FIRAuthUIDelegate object. + */ ++ (id)defaultUIDelegate; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.m new file mode 100644 index 0000000..7b421a2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.m @@ -0,0 +1,126 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import +#import + +#import "FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthDefaultUIDelegate () + +/** @fn initWithViewController: + @brief Initializes the instance with a view controller. + @param viewController The view controller as the presenting view controller in @c + FIRAuthUIDelegate. + @return The initialized instance. + */ +- (instancetype)initWithViewController:(nullable UIViewController *)viewController + NS_DESIGNATED_INITIALIZER; + +@end + +@implementation FIRAuthDefaultUIDelegate { + /** @var _viewController + @brief The presenting view controller. + */ + UIViewController *_viewController; +} + +- (instancetype)initWithViewController:(nullable UIViewController *)viewController { + self = [super init]; + if (self) { + _viewController = viewController; + } + return self; +} + +- (void)presentViewController:(UIViewController *)viewControllerToPresent + animated:(BOOL)flag + completion:(nullable void (^)(void))completion { + [_viewController presentViewController:viewControllerToPresent + animated:flag + completion:completion]; +} + +- (void)dismissViewControllerAnimated:(BOOL)flag completion:(nullable void (^)(void))completion { + [_viewController dismissViewControllerAnimated:flag completion:completion]; +} + ++ (id)defaultUIDelegate { + // iOS App extensions should not call [UIApplication sharedApplication], even if UIApplication + // responds to it. + static Class applicationClass = nil; + if (![GULAppEnvironmentUtil isAppExtension]) { + Class cls = NSClassFromString(@"UIApplication"); + if (cls && [cls respondsToSelector:NSSelectorFromString(@"sharedApplication")]) { + applicationClass = cls; + } + } + + UIViewController *topViewController; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 + if (@available(iOS 13.0, tvOS 13.0, *)) { + UIApplication *application = [applicationClass sharedApplication]; + NSSet *connectedScenes = application.connectedScenes; + for (UIScene *scene in connectedScenes) { + if ([scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene *windowScene = (UIWindowScene *)scene; + for (UIWindow *window in windowScene.windows) { + if (window.isKeyWindow) { + topViewController = window.rootViewController; + } + } + } + } + } else { + UIApplication *application = [applicationClass sharedApplication]; +// iOS 13 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + topViewController = application.keyWindow.rootViewController; +#pragma clang diagnostic pop + } +#else + UIApplication *application = [applicationClass sharedApplication]; + topViewController = application.keyWindow.rootViewController; +#endif + + while (true) { + if (topViewController.presentedViewController) { + topViewController = topViewController.presentedViewController; + } else if ([topViewController isKindOfClass:[UINavigationController class]]) { + UINavigationController *nav = (UINavigationController *)topViewController; + topViewController = nav.topViewController; + } else if ([topViewController isKindOfClass:[UITabBarController class]]) { + UITabBarController *tab = (UITabBarController *)topViewController; + topViewController = tab.selectedViewController; + } else { + break; + } + } + return [[FIRAuthDefaultUIDelegate alloc] initWithViewController:topViewController]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h new file mode 100644 index 0000000..8006e5c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h @@ -0,0 +1,610 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h" + +#import "FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h" + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthErrorUtils + @brief Utility class used to construct @c NSError instances. + */ +@interface FIRAuthErrorUtils : NSObject + ++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code message:(nullable NSString *)message; + +/** @fn RPCRequestEncodingErrorWithUnderlyingError + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeRPCRequestEncodingError + code and a populated @c NSUnderlyingErrorKey in the @c NSError.userInfo dictionary. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. + @remarks This error is used when an @c FIRAuthRPCRequest.unencodedHTTPRequestBodyWithError: + invocation returns an error. The error returned is wrapped in this internal error code. + */ ++ (NSError *)RPCRequestEncodingErrorWithUnderlyingError:(NSError *)underlyingError; + +/** @fn JSONSerializationErrorForUnencodableType + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeJSONSerializationError code. + @remarks This error is used when an @c NSJSONSerialization.isValidJSONObject: check fails, not + for when an error is returned from @c NSJSONSerialization.dataWithJSONObject:options:error:. + */ ++ (NSError *)JSONSerializationErrorForUnencodableType; + +/** @fn JSONSerializationErrorWithUnderlyingError: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeJSONSerializationError code, and the + @c underlyingError as the @c NSUnderlyingErrorKey value in the @c NSError.userInfo + dictionary. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. + @remarks This error is used when an invocation of + @c NSJSONSerialization.dataWithJSONObject:options:error: returns an error. + */ ++ (NSError *)JSONSerializationErrorWithUnderlyingError:(NSError *)underlyingError; + +/** @fn networkErrorWithUnderlyingError: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNetworkError code, and the + @c underlyingError as the @c NSUnderlyingErrorKey value in the @c NSError.userInfo + dictionary. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. Should be the error from + GTM. + @remarks This error is used when a network request results in an error, and no body data was + returned. + */ ++ (NSError *)networkErrorWithUnderlyingError:(NSError *)underlyingError; + +/** @fn unexpectedErrorResponseWithUnderlyingError: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNetworkError code, and the + @c underlyingError as the @c NSUnderlyingErrorKey value. + @param data The value of the @c FIRAuthErrorUserInfoDataKey key in the @c NSError.userInfo + dictionary. + @param underlyingError The value of the @c NSUnderlyingErrorKey key in the @c NSError.userInfo + dictionary. + @remarks This error is used when a network request results in an error, and unserializable body + data was returned. + */ ++ (NSError *)unexpectedErrorResponseWithData:(NSData *)data + underlyingError:(NSError *)underlyingError; + +/** @fn unexpectedErrorResponseWithDeserializedResponse: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedErrorResponse + code, and a populated @c FIRAuthErrorUserInfoDeserializedResponseKey key in the + @c NSError.userInfo dictionary. + @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key. + @remarks This error is used when a network request results in an error, and the body data was + deserializable as JSON, but couldn't be decoded as an error. + */ ++ (NSError *)unexpectedErrorResponseWithDeserializedResponse:(id)deserializedResponse; + +/** @fn unexpectedErrorResponseWithDeserializedResponse:underlyingError: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedErrorResponse + code, and populated @c FIRAuthErrorUserInfoDeserializedResponseKey and + @c NSUnderlyingErrorKey keys in the @c NSError.userInfo dictionary. + @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. + @remarks This error is used when a network request results in an error, and the body data was + deserializable as JSON, but couldn't be decoded as an error. + */ ++ (NSError *)unexpectedErrorResponseWithDeserializedResponse:(id)deserializedResponse + underlyingError:(NSError *)underlyingError; + +/** @fn malformedJWTErrorWithToken:underlyingError: + @brief Constructs an @c NSError with the code set to @c FIRAuthErrorCodeMalformedJWT and + populates the userInfo dictionary with an error message, the bad token, and an underlying + error that may have occurred when parsing. + @param token The token that failed to parse. + @param underlyingError The error that caused this error. If this parameter is nil, the + NSUnderlyingErrorKey value will not be set. + @remarks This error is returned when JWT parsing fails. + @returns An @c FIRAuthErrorCodeMalformedJWT error wrapping an underlying error, if available. + */ ++ (NSError *)malformedJWTErrorWithToken:(NSString *)token + underlyingError:(NSError *_Nullable)underlyingError; + +/** @fn unexpectedResponseWithData:underlyingError: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedResponse + code, and a populated @c FIRAuthErrorUserInfoDataKey key in the @c NSError.userInfo + dictionary. + @param data The value of the @c FIRAuthErrorUserInfoDataKey key in the @c NSError.userInfo + dictionary. + @param underlyingError The value of the @c NSUnderlyingErrorKey key in the @c NSError.userInfo + dictionary. + @remarks This error is used when a network request is apparently successful, but the body data + couldn't be deserialized as JSON. + */ ++ (NSError *)unexpectedResponseWithData:(NSData *)data underlyingError:(NSError *)underlyingError; +; + +/** @fn unexpectedResponseWithDeserializedResponse: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedResponse + code, and a populated @c FIRAuthErrorUserInfoDeserializedResponseKey key in the + @c NSError.userInfo dictionary. + @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key. + @remarks This error is used when a network request is apparently successful, the body data was + successfully deserialized as JSON, but the JSON wasn't a dictionary. + */ ++ (NSError *)unexpectedResponseWithDeserializedResponse:(id)deserializedResponse; + +/** @fn unexpectedResponseWithDeserializedResponse:underlyingError: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedResponse + code, and populated @c FIRAuthErrorUserInfoDeserializedResponseKey and + @c NSUnderlyingErrorKey keys in the @c NSError.userInfo dictionary. + @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. + @remarks This error is used when a network request was apparently successful, the body data was + successfully deserialized as JSON, but the data type of the response was unexpected. + */ ++ (NSError *)unexpectedResponseWithDeserializedResponse:(nullable id)deserializedResponse + underlyingError:(NSError *)underlyingError; + +/** @fn RPCResponseDecodingErrorWithDeserializedResponse:underlyingError: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeRPCResponseDecodingError + code, and populated @c FIRAuthErrorUserInfoDeserializedResponseKey and + @c NSUnderlyingErrorKey keys in the @c NSError.userInfo dictionary. + @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. + @remarks This error is used when an invocation of @c FIRAuthRPCResponse.setWithDictionary:error: + resulted in an error. + */ ++ (NSError *)RPCResponseDecodingErrorWithDeserializedResponse:(id)deserializedResponse + underlyingError:(NSError *)underlyingError; + +/** @fn emailAlreadyInUseErrorWithEmail: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeEmailExists code. + @param email The email address that is already in use. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)emailAlreadyInUseErrorWithEmail:(nullable NSString *)email; + +/** @fn userDisabledErrorWithMessageWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserDisabled code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)userDisabledErrorWithMessage:(nullable NSString *)message; + +/** @fn wrongPasswordErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeWrongPassword code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)wrongPasswordErrorWithMessage:(nullable NSString *)message; + +/** @fn tooManyRequestsErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeTooManyRequests Code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)tooManyRequestsErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidCustomTokenErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidCustomToken code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidCustomTokenErrorWithMessage:(nullable NSString *)message; + +/** @fn customTokenMistmatchErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeCustomTokenMismatch code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)customTokenMistmatchErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidCredentialErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidCredential code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidCredentialErrorWithMessage:(nullable NSString *)message; + +/** @fn requiresRecentLoginError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeRequiresRecentLogin code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)requiresRecentLoginErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidUserTokenErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidUserToken code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidUserTokenErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidEmailErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidEmail code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidEmailErrorWithMessage:(nullable NSString *)message; + +/** @fn accountExistsWithDifferentCredentialErrorWithEmail: + @brief Constructs an @c NSError with the @c FIRAuthErrorAccountExistsWithDifferentCredential + code. + @param email The email address that is already associated with an existing account + @param updatedCredential The updated credential for the existing account + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)accountExistsWithDifferentCredentialErrorWithEmail:(nullable NSString *)email + updatedCredential: + (nullable FIRAuthCredential *)updatedCredential; + +/** @fn providerAlreadyLinkedErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeProviderAlreadyLinked code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)providerAlreadyLinkedError; + +/** @fn noSuchProviderError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNoSuchProvider code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)noSuchProviderError; + +/** @fn userTokenExpiredErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserTokenExpired code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)userTokenExpiredErrorWithMessage:(nullable NSString *)message; + +/** @fn userNotFoundErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserNotFound code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)userNotFoundErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidLocalAPIKeyErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidAPIKey code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidAPIKeyError; + +/** @fn userMismatchError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserMismatch code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)userMismatchError; + +/** @fn credentialAlreadyInUseErrorWithMessage:email: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeCredentialAlreadyInUse code. + @param message Error message from the backend, if any. + @param credential Auth credential to be added to the Error User Info dictionary. + @param email Email to be added to the Error User Info dictionary. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)credentialAlreadyInUseErrorWithMessage:(nullable NSString *)message + credential:(nullable FIRAuthCredential *)credential + email:(nullable NSString *)email; +/** @fn operationNotAllowedErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeOperationNotAllowed code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)operationNotAllowedErrorWithMessage:(nullable NSString *)message; + +/** @fn weakPasswordErrorWithServerResponseReason: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeWeakPassword code. + @param serverResponseReason A more detailed explanation string from server response. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)weakPasswordErrorWithServerResponseReason:(nullable NSString *)serverResponseReason; + +/** @fn appNotAuthorizedError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeAppNotAuthorized code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)appNotAuthorizedError; + +/** @fn expiredActionCodeErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeExpiredActionCode code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)expiredActionCodeErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidActionCodeErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidActionCode code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidActionCodeErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidMessagePayloadError: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidMessagePayload code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidMessagePayloadErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidSenderErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidSender code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidSenderErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidRecipientEmailError: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidRecipientEmail code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidRecipientEmailErrorWithMessage:(nullable NSString *)message; + +/** @fn missingIosBundleIDErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingIosBundleID code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingIosBundleIDErrorWithMessage:(nullable NSString *)message; + +/** @fn missingAndroidPackageNameErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingAndroidPackageName code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingAndroidPackageNameErrorWithMessage:(nullable NSString *)message; + +/** @fn unauthorizedDomainErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUnauthorizedDomain code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)unauthorizedDomainErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidContinueURIErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidContinueURI code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidContinueURIErrorWithMessage:(nullable NSString *)message; + +/** @fn missingContinueURIErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingContinueURI code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingContinueURIErrorWithMessage:(nullable NSString *)message; + +/** @fn missingEmailErrorWithMessage + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingEmail code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingEmailErrorWithMessage:(nullable NSString *)message; + +/** @fn missingPhoneNumberErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingPhoneNumber code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingPhoneNumberErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidPhoneNumberErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidPhoneNumber code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidPhoneNumberErrorWithMessage:(nullable NSString *)message; + +/** @fn missingVerificationCodeErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingVerificationCode code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingVerificationCodeErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidVerificationCodeErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidVerificationCode code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidVerificationCodeErrorWithMessage:(nullable NSString *)message; + +/** @fn missingVerificationIDErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingVerificationID code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingVerificationIDErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidVerificationIDErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidVerificationID code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidVerificationIDErrorWithMessage:(nullable NSString *)message; + +/** @fn sessionExpiredErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeSessionExpired code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)sessionExpiredErrorWithMessage:(nullable NSString *)message; + +/** @fn missingAppCredentialWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorMissingCredential code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingAppCredentialWithMessage:(nullable NSString *)message; + +/** @fn invalidAppCredentialWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorInvalidCredential code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidAppCredentialWithMessage:(nullable NSString *)message; + +/** @fn quotaExceededErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeQuotaExceeded code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)quotaExceededErrorWithMessage:(nullable NSString *)message; + +/** @fn missingAppTokenErrorWithUnderlyingError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingAppToken code. + @param underlyingError The underlying error, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingAppTokenErrorWithUnderlyingError:(nullable NSError *)underlyingError; + +/** @fn localPlayerNotAuthenticatedError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeLocalPlayerNotAuthenticated code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)localPlayerNotAuthenticatedError; + +/** @fn gameKitNotLinkedError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeGameKitNotLinked code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)gameKitNotLinkedError; + +/** @fn notificationNotForwardedError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNotificationNotForwarded code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)notificationNotForwardedError; + +#if TARGET_OS_IOS +/** @fn secondFactorRequiredError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeSecondFactorRequired code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)secondFactorRequiredErrorWithPendingCredential:(NSString *)MFAPendingCredential + hints:(NSArray *) + multiFactorInfo; +#endif + +/** @fn appNotVerifiedErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeAppNotVerified code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)appNotVerifiedErrorWithMessage:(nullable NSString *)message; + +/** @fn missingClientIdentifierErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingClientIdentifier code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingClientIdentifierErrorWithMessage:(nullable NSString *)message; + +/** @fn captchaCheckFailedErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCaptchaCheckFailed code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)captchaCheckFailedErrorWithMessage:(nullable NSString *)message; + +/** @fn webContextAlreadyPresentedErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeWebContextAlreadyPresented code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)webContextAlreadyPresentedErrorWithMessage:(nullable NSString *)message; + +/** @fn webContextCancelledErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeWebContextCancelled code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)webContextCancelledErrorWithMessage:(nullable NSString *)message; + +/** @fn appVerificationUserInteractionFailureWithReason: + @brief Constructs an @c NSError with the @c + FIRAuthErrorCodeAppVerificationUserInteractionFailure code. + @param reason Reason for error, returned via URL response. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)appVerificationUserInteractionFailureWithReason:(NSString *)reason; + +/** @fn webSignInUserInteractionFailureWithReason: + @brief Constructs an @c NSError with the @c + FIRAuthErrorCodeWebSignInUserInteractionFailure code. + @param reason Reason for error, returned via URL response. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)webSignInUserInteractionFailureWithReason:(nullable NSString *)reason; + +/** @fn URLResponseErrorWithCode:message: + @brief Constructs an @c NSError with the code and message provided. + @param message Error message from the backend, if any. + @return The nullable NSError instance associated with the given error message, if one is found. + */ ++ (nullable NSError *)URLResponseErrorWithCode:(NSString *)code + message:(nullable NSString *)message; + +/** @fn nullUserErrorWithMessage: + @brief Constructs an @c NSError with the code and message provided. + @param message Error message from the backend, if any. + @return The nullable NSError instance associated with the given error message, if one is found. + */ ++ (NSError *)nullUserErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidProviderIDErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidProviderID code. + @param message Error message from the backend, if any. + @remarks This error indicates that the provider id given for the web operation is invalid. + */ ++ (NSError *)invalidProviderIDErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidDynamicLinkDomainErrorWithMessage: + @brief Constructs an @c NSError with the code and message provided. + @param message Error message from the backend, if any. + @return The nullable NSError instance associated with the given error message, if one is found. + */ ++ (NSError *)invalidDynamicLinkDomainErrorWithMessage:(nullable NSString *)message; + +/** @fn keychainErrorWithFunction:status: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeKeychainError code. + @param keychainFunction The keychain function which was invoked and yielded an unexpected + response. The @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo + dictionary will contain a string partially comprised of this value. + @param status The response status from the invoked keychain function. The + @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo dictionary will contain + a string partially comprised of this value. + */ ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status; + +/** @fn missingOrInvalidNonceErrorWithMessage: + @brief Constructs an @c NSError with the code and message provided. + @param message Error message from the backend, if any. + @return The nullable NSError instance associated with the given error message, if one is found. +*/ ++ (NSError *)missingOrInvalidNonceErrorWithMessage:(nullable NSString *)message; + +/** @fn tenantIDMismatchError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeTenantIDMismatch code. + @remarks This error is used when an attempt is made to update the current user with a + tenantId that differs from the current FirebaseAuth instance's tenantId. + */ ++ (NSError *)tenantIDMismatchError; + +/** @fn unsupportedTenantOperationError + @brief Constructs an @c NSError with the @c FIRUnsupportedTenantOperation code. + @remarks This error indicates the operation is not supported in a multi-tenant context. + */ ++ (NSError *)unsupportedTenantOperationError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m new file mode 100644 index 0000000..c67ed61 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m @@ -0,0 +1,1410 @@ +/* + * 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 "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h" + +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +NSString *const FIRAuthErrorDomain = @"FIRAuthErrorDomain"; + +NSString *const FIRAuthInternalErrorDomain = @"FIRAuthInternalErrorDomain"; + +NSString *const FIRAuthErrorUserInfoDeserializedResponseKey = + @"FIRAuthErrorUserInfoDeserializedResponseKey"; + +NSString *const FIRAuthErrorUserInfoDataKey = @"FIRAuthErrorUserInfoDataKey"; + +NSString *const FIRAuthErrorUserInfoEmailKey = @"FIRAuthErrorUserInfoEmailKey"; + +NSString *const FIRAuthErrorUserInfoUpdatedCredentialKey = + @"FIRAuthErrorUserInfoUpdatedCredentialKey"; + +NSString *const FIRAuthErrorUserInfoNameKey = @"FIRAuthErrorUserInfoNameKey"; + +NSString *const FIRAuthErrorUserInfoMultiFactorResolverKey = + @"FIRAuthErrorUserInfoMultiFactorResolverKey"; + +/** @var kServerErrorDetailMarker + @brief This marker indicates that the server error message contains a detail error message which + should be used instead of the hardcoded client error message. + */ +static NSString *const kServerErrorDetailMarker = @" : "; + +#pragma mark - URL response error codes + +/** @var kURLResponseErrorCodeInvalidClientID + @brief Error code that indicates that the client ID provided was invalid. + */ +static NSString *const kURLResponseErrorCodeInvalidClientID = @"auth/invalid-oauth-client-id"; + +/** @var kURLResponseErrorCodeNetworkRequestFailed + @brief Error code that indicates that a network request within the SFSafariViewController or + WKWebView failed. + */ +static NSString *const kURLResponseErrorCodeNetworkRequestFailed = @"auth/network-request-failed"; + +/** @var kURLResponseErrorCodeInternalError + @brief Error code that indicates that an internal error occurred within the + SFSafariViewController or WKWebView failed. + */ +static NSString *const kURLResponseErrorCodeInternalError = @"auth/internal-error"; + +#pragma mark - Standard Error Messages + +/** @var kFIRAuthErrorMessageInvalidCustomToken + @brief Message for @c FIRAuthErrorCodeInvalidCustomToken error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidCustomToken = + @"The custom token format is " + "incorrect. Please check the documentation."; + +/** @var kFIRAuthErrorMessageCustomTokenMismatch + @brief Message for @c FIRAuthErrorCodeCustomTokenMismatch error code. + */ +static NSString *const kFIRAuthErrorMessageCustomTokenMismatch = @"The custom token corresponds to " + "a different audience."; + +/** @var kFIRAuthErrorMessageInvalidEmail + @brief Message for @c FIRAuthErrorCodeInvalidEmail error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidEmail = @"The email address is badly formatted."; + +/** @var kFIRAuthErrorMessageInvalidCredential + @brief Message for @c FIRAuthErrorCodeInvalidCredential error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidCredential = @"The supplied auth credential is " + "malformed or has expired."; + +/** @var kFIRAuthErrorMessageUserDisabled + @brief Message for @c FIRAuthErrorCodeUserDisabled error code. + */ +static NSString *const kFIRAuthErrorMessageUserDisabled = @"The user account has been disabled by " + "an administrator."; + +/** @var kFIRAuthErrorMessageEmailAlreadyInUse + @brief Message for @c FIRAuthErrorCodeEmailAlreadyInUse error code. + */ +static NSString *const kFIRAuthErrorMessageEmailAlreadyInUse = @"The email address is already in " + "use by another account."; + +/** @var kFIRAuthErrorMessageWrongPassword + @brief Message for @c FIRAuthErrorCodeWrongPassword error code. + */ +static NSString *const kFIRAuthErrorMessageWrongPassword = @"The password is invalid or the user " + "does not have a password."; + +/** @var kFIRAuthErrorMessageTooManyRequests + @brief Message for @c FIRAuthErrorCodeTooManyRequests error code. + */ +static NSString *const kFIRAuthErrorMessageTooManyRequests = + @"We have blocked all requests from " + "this device due to unusual activity. Try again later."; + +/** @var kFIRAuthErrorMessageAccountExistsWithDifferentCredential + @brief Message for @c FIRAuthErrorCodeAccountExistsWithDifferentCredential error code. + */ +static NSString *const kFIRAuthErrorMessageAccountExistsWithDifferentCredential = + @"An account " + "already exists with the same email address but different sign-in credentials. Sign in using " + "a " + "provider associated with this email address."; + +/** @var kFIRAuthErrorMessageRequiresRecentLogin + @brief Message for @c FIRAuthErrorCodeRequiresRecentLogin error code. + */ +static NSString *const kFIRAuthErrorMessageRequiresRecentLogin = + @"This operation is sensitive and " + "requires recent authentication. Log in again before retrying this request."; + +/** @var kFIRAuthErrorMessageProviderAlreadyLinked + @brief Message for @c FIRAuthErrorCodeProviderAlreadyExists error code. + */ +static NSString *const kFIRAuthErrorMessageProviderAlreadyLinked = + @"[ERROR_PROVIDER_ALREADY_LINKED] - User can only be linked to one identity for the given " + "provider."; + +/** @var kFIRAuthErrorMessageNoSuchProvider + @brief Message for @c FIRAuthErrorCodeNoSuchProvider error code. + */ +static NSString *const kFIRAuthErrorMessageNoSuchProvider = @"User was not linked to an account " + "with the given provider."; + +/** @var kFIRAuthErrorMessageInvalidUserToken + @brief Message for @c FIRAuthErrorCodeInvalidUserToken error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidUserToken = + @"This user's credential isn't valid " + "for this project. This can happen if the user's token has been tampered with, or if the user " + "doesn’t belong to the project associated with the API key used in your request."; + +/** @var kFIRAuthErrorMessageNetworkError + @brief Message for @c FIRAuthErrorCodeNetworkError error code. + */ +static NSString *const kFIRAuthErrorMessageNetworkError = + @"Network error (such as timeout, " + "interrupted connection or unreachable host) has occurred."; + +/** @var kFIRAuthErrorMessageKeychainError + @brief Message for @c FIRAuthErrorCodeKeychainError error code. + */ +static NSString *const kFIRAuthErrorMessageKeychainError = + @"An error occurred when accessing the " + "keychain. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo dictionary " + "will contain more information about the error encountered"; + +/** @var kFIRAuthErrorMessageMissingClientIdentifier + @brief Message for @c FIRAuthErrorCodeMissingClientIdentifier error code. + */ +static NSString *const kFIRAuthErrorMessageMissingClientIdentifier = + @"The request does not contain " + "any client identifier."; + +/** @var kFIRAuthErrorMessageUserTokenExpired + @brief Message for @c FIRAuthErrorCodeTokenExpired error code. + */ +static NSString *const kFIRAuthErrorMessageUserTokenExpired = + @"The user's credential is no longer " + "valid. The user must sign in again."; + +/** @var kFIRAuthErrorMessageUserNotFound + @brief Message for @c FIRAuthErrorCodeUserNotFound error code. + */ +static NSString *const kFIRAuthErrorMessageUserNotFound = + @"There is no user record corresponding " + "to this identifier. The user may have been deleted."; + +/** @var kFIRAuthErrorMessageInvalidAPIKey + @brief Message for @c FIRAuthErrorCodeInvalidAPIKey error code. + @remarks This error is not thrown by the server. + */ +static NSString *const kFIRAuthErrorMessageInvalidAPIKey = @"An invalid API Key was supplied in " + "the request."; + +/** @var kFIRAuthErrorMessageUserMismatch. + @brief Message for @c FIRAuthErrorCodeInvalidAPIKey error code. + */ +static NSString *const FIRAuthErrorMessageUserMismatch = + @"The supplied credentials do not " + "correspond to the previously signed in user."; + +/** @var kFIRAuthErrorMessageCredentialAlreadyInUse + @brief Message for @c FIRAuthErrorCodeCredentialAlreadyInUse error code. + */ +static NSString *const kFIRAuthErrorMessageCredentialAlreadyInUse = + @"This credential is already " + "associated with a different user account."; + +/** @var kFIRAuthErrorMessageOperationNotAllowed + @brief Message for @c FIRAuthErrorCodeOperationNotAllowed error code. + */ +static NSString *const kFIRAuthErrorMessageOperationNotAllowed = + @"The given sign-in provider is " + "disabled for this Firebase project. Enable it in the Firebase console, under the sign-in " + "method tab of the Auth section."; + +/** @var kFIRAuthErrorMessageWeakPassword + @brief Message for @c FIRAuthErrorCodeWeakPassword error code. + */ +static NSString *const kFIRAuthErrorMessageWeakPassword = @"The password must be 6 characters long " + "or more."; + +/** @var kFIRAuthErrorMessageAppNotAuthorized + @brief Message for @c FIRAuthErrorCodeAppNotAuthorized error code. + */ +static NSString *const kFIRAuthErrorMessageAppNotAuthorized = + @"This app is not authorized to use " + "Firebase Authentication with the provided API key. Review your key configuration in the " + "Google API console and ensure that it accepts requests from your app's bundle ID."; + +/** @var kFIRAuthErrorMessageExpiredActionCode + @brief Message for @c FIRAuthErrorCodeExpiredActionCode error code. + */ +static NSString *const kFIRAuthErrorMessageExpiredActionCode = @"The action code has expired."; + +/** @var kFIRAuthErrorMessageInvalidActionCode + @brief Message for @c FIRAuthErrorCodeInvalidActionCode error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidActionCode = + @"The action code is invalid. This " + "can happen if the code is malformed, expired, or has already been used."; + +/** @var kFIRAuthErrorMessageInvalidMessagePayload + @brief Message for @c FIRAuthErrorCodeInvalidMessagePayload error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidMessagePayload = + @"The action code is invalid. " + "This can happen if the code is malformed, expired, or has already been used."; + +/** @var kFIRAuthErrorMessageInvalidSender + @brief Message for @c FIRAuthErrorCodeInvalidSender error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidSender = + @"The email template corresponding to " + "this action contains invalid characters in its message. Please fix by going to the Auth " + "email " + "templates section in the Firebase Console."; + +/** @var kFIRAuthErrorMessageInvalidRecipientEmail + @brief Message for @c FIRAuthErrorCodeInvalidRecipient error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidRecipientEmail = + @"The action code is invalid. " + "This can happen if the code is malformed, expired, or has already been used."; + +/** @var kFIRAuthErrorMessageMissingIosBundleID + @brief Message for @c FIRAuthErrorCodeMissingIosbundleID error code. + */ +static NSString *const kFIRAuthErrorMessageMissingIosBundleID = + @"An iOS Bundle ID must be provided if an App Store ID is provided."; + +/** @var kFIRAuthErrorMessageMissingAndroidPackageName + @brief Message for @c FIRAuthErrorCodeMissingAndroidPackageName error code. + */ +static NSString *const kFIRAuthErrorMessageMissingAndroidPackageName = + @"An Android Package Name must be provided if the Android App is required to be installed."; + +/** @var kFIRAuthErrorMessageUnauthorizedDomain + @brief Message for @c FIRAuthErrorCodeUnauthorizedDomain error code. + */ +static NSString *const kFIRAuthErrorMessageUnauthorizedDomain = + @"The domain of the continue URL " + "is not allowlisted. Please allowlist the domain in the Firebase console."; + +/** @var kFIRAuthErrorMessageInvalidContinueURI + @brief Message for @c FIRAuthErrorCodeInvalidContinueURI error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidContinueURI = + @"The continue URL provided in the request is invalid."; + +/** @var kFIRAuthErrorMessageMissingEmail + @brief Message for @c FIRAuthErrorCodeMissingEmail error code. + */ +static NSString *const kFIRAuthErrorMessageMissingEmail = @"An email address must be provided."; + +/** @var kFIRAuthErrorMessageMissingContinueURI + @brief Message for @c FIRAuthErrorCodeMissingContinueURI error code. + */ +static NSString *const kFIRAuthErrorMessageMissingContinueURI = + @"A continue URL must be provided in the request."; + +/** @var kFIRAuthErrorMessageMissingPhoneNumber + @brief Message for @c FIRAuthErrorCodeMissingPhoneNumber error code. + */ +static NSString *const kFIRAuthErrorMessageMissingPhoneNumber = + @"To send verification codes, provide a phone number for the recipient."; + +/** @var kFIRAuthErrorMessageInvalidPhoneNumber + @brief Message for @c FIRAuthErrorCodeInvalidPhoneNumber error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidPhoneNumber = + @"The format of the phone number provided is incorrect. Please enter the phone number in a " + "format that can be parsed into E.164 format. E.164 phone numbers are written in the format " + "[+][country code][subscriber number including area code]."; + +/** @var kFIRAuthErrorMessageMissingVerificationCode + @brief Message for @c FIRAuthErrorCodeMissingVerificationCode error code. + */ +static NSString *const kFIRAuthErrorMessageMissingVerificationCode = + @"The phone auth credential was created with an empty SMS verification Code."; + +/** @var kFIRAuthErrorMessageInvalidVerificationCode + @brief Message for @c FIRAuthErrorCodeInvalidVerificationCode error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidVerificationCode = + @"The SMS verification code used to create the phone auth credential is invalid. Please resend " + "the verification code SMS and be sure to use the verification code provided by the user."; + +/** @var kFIRAuthErrorMessageMissingVerificationID + @brief Message for @c FIRAuthErrorCodeInvalidVerificationID error code. + */ +static NSString *const kFIRAuthErrorMessageMissingVerificationID = + @"The phone auth credential was created with an empty verification ID."; + +/** @var kFIRAuthErrorMessageInvalidVerificationID + @brief Message for @c FIRAuthErrorCodeInvalidVerificationID error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidVerificationID = + @"The verification ID used to create the phone auth credential is invalid."; + +/** @var kFIRAuthErrorMessageLocalPlayerNotAuthenticated + @brief Message for @c FIRAuthErrorCodeLocalPlayerNotAuthenticated error code. + */ +static NSString *const kFIRAuthErrorMessageLocalPlayerNotAuthenticated = + @"The local player is not authenticated. Please log the local player in to Game Center."; + +/** @var kFIRAuthErrorMessageGameKitNotLinked + @brief Message for @c kFIRAuthErrorMessageGameKitNotLinked error code. + */ +static NSString *const kFIRAuthErrorMessageGameKitNotLinked = + @"The GameKit framework is not linked. Please turn on the Game Center capability."; + +/** @var kFIRAuthErrorMessageSessionExpired + @brief Message for @c FIRAuthErrorCodeSessionExpired error code. + */ +static NSString *const kFIRAuthErrorMessageSessionExpired = + @"The SMS code has expired. Please " + @"re-send the verification code to try again."; + +/** @var kFIRAuthErrorMessageMissingAppCredential + @brief Message for @c FIRAuthErrorCodeMissingAppCredential error code. + */ +static NSString *const kFIRAuthErrorMessageMissingAppCredential = + @"The phone verification request " + "is missing an APNs Device token. Firebase Auth automatically detects APNs Device Tokens, " + "however, if method swizzling is disabled, the APNs token must be set via the APNSToken " + "property on FIRAuth or by calling setAPNSToken:type on FIRAuth."; + +/** @var kFIRAuthErrorMessageInvalidAppCredential + @brief Message for @c FIRAuthErrorCodeInvalidAppCredential error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidAppCredential = + @"The APNs device token provided " + "is either incorrect or does not match the private certificate uploaded to the Firebase " + "Console."; + +/** @var kFIRAuthErrorMessageQuotaExceeded + @brief Message for @c FIRAuthErrorCodeQuotaExceeded error code. + */ +static NSString *const kFIRAuthErrorMessageQuotaExceeded = @"The quota for this operation " + "has been exceeded."; + +/** @var kFIRAuthErrorMessageMissingAppToken + @brief Message for @c FIRAuthErrorCodeMissingAppToken error code. + */ +static NSString *const kFIRAuthErrorMessageMissingAppToken = + @"There seems to be a problem with " + "your project's Firebase phone number authentication set-up, please make sure to follow the " + "instructions found at https://firebase.google.com/docs/auth/ios/phone-auth"; + +/** @var kFIRAuthErrorMessageMissingAppToken + @brief Message for @c FIRAuthErrorCodeMissingAppToken error code. + */ +static NSString *const kFIRAuthErrorMessageNotificationNotForwarded = + @"If app delegate swizzling " + "is disabled, remote notifications received by UIApplicationDelegate need to be forwarded to " + "FIRAuth's canHandleNotificaton: method."; + +/** @var kFIRAuthErrorMessageAppNotVerified + @brief Message for @c FIRAuthErrorCodeMissingAppToken error code. + */ +static NSString *const kFIRAuthErrorMessageAppNotVerified = + @"Firebase could not retrieve the " + "silent push notification and therefore could not verify your app. Ensure that you configured " + "your app correctly to receive push notifications."; + +/** @var kFIRAuthErrorMessageCaptchaCheckFailed + @brief Message for @c FIRAuthErrorCodeCaptchaCheckFailed error code. + */ +static NSString *const kFIRAuthErrorMessageCaptchaCheckFailed = + @"The reCAPTCHA response token " + "provided is either invalid, expired or already"; + +/** @var kFIRAuthErrorMessageWebContextAlreadyPresented + @brief Message for @c FIRAuthErrorCodeWebContextAlreadyPresented error code. + */ +static NSString *const kFIRAuthErrorMessageWebContextAlreadyPresented = + @"User interaction is " + "still ongoing, another view cannot be presented."; + +/** @var kFIRAuthErrorMessageWebContextCancelled + @brief Message for @c FIRAuthErrorCodeWebContextCancelled error code. + */ +static NSString *const kFIRAuthErrorMessageWebContextCancelled = @"The interaction was cancelled " + "by the user."; + +/** @var kFIRAuthErrorMessageInvalidClientID + @brief Message for @c FIRAuthErrorCodeInvalidClientID error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidClientID = + @"The OAuth client ID provided is " + "either invalid or does not match the specified API key."; + +/** @var kFIRAuthErrorMessageWebRequestFailed + @brief Message for @c FIRAuthErrorCodeWebRequestFailed error code. + */ +static NSString *const kFIRAuthErrorMessageWebRequestFailed = + @"A network error (such as timeout, " + "interrupted connection, or unreachable host) has occurred within the web context."; + +/** @var kFIRAuthErrorMessageWebInternalError + @brief Message for @c FIRAuthErrorCodeWebInternalError error code. + */ +static NSString *const kFIRAuthErrorMessageWebInternalError = + @"An internal error has occurred " + "within the SFSafariViewController or WKWebView."; + +/** @var kFIRAuthErrorMessageAppVerificationUserInteractionFailure + @brief Message for @c FIRAuthErrorCodeInvalidClientID error code. + */ +static NSString *const kFIRAuthErrorMessageAppVerificationUserInteractionFailure = + @"The app " + "verification process has failed, print and inspect the error details for more information"; + +/** @var kFIRAuthErrorMessageNullUser + @brief Message for @c FIRAuthErrorCodeNullUser error code. + */ +static NSString *const kFIRAuthErrorMessageNullUser = + @"A null user object was provided as the " + "argument for an operation which requires a non-null user object."; + +/** @var kFIRAuthErrorMessageInvalidProviderID + @brief Message for @c FIRAuthErrorCodeInvalidProviderID error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidProviderID = + @"The provider ID provided for the " + "attempted web operation is invalid."; + +/** @var kFIRAuthErrorMessageInvalidDynamicLinkDomain + @brief Message for @c kFIRAuthErrorMessageInvalidDynamicLinkDomain error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidDynamicLinkDomain = + @"The " + "Firebase Dynamic Link domain used is either not configured or is unauthorized " + "for the current project."; + +/** @var kFIRAuthErrorMessageInternalError + @brief Message for @c FIRAuthErrorCodeInternalError error code. + */ +static NSString *const kFIRAuthErrorMessageInternalError = + @"An internal error has occurred, " + "print and inspect the error details for more information."; + +/** @var kFIRAuthErrorMessageMalformedJWT + @brief Error message constant describing @c FIRAuthErrorCodeMalformedJWT errors. + */ +static NSString *const kFIRAuthErrorMessageMalformedJWT = + @"Failed to parse JWT. Check the userInfo dictionary for the full token."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const kFIRAuthErrorMessageSecondFactorRequired = + @"Please complete a second factor challenge to finish signing into this account."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageMissingMultiFactorSession = + @"The request is missing proof of first factor successful sign-in."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageMissingMultiFactorInfo = + @"No second factor identifier is provided."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageInvalidMultiFactorSession = + @"The request does not contain a valid proof of first factor successful sign-in."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageMultiFactorInfoNotFound = + @"The user does not have a second factor matching the identifier provided."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageAdminRestrictedOperation = + @"This operation is restricted to administrators only."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageUnverifiedEmail = + @"The operation requires a verified email."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageSecondFactorAlreadyEnrolled = + @"The second factor is already enrolled on this account."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageMaximumSecondFactorCountExceeded = + @"The maximum allowed number of second factors on a user has been exceeded."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageUnsupportedFirstFactor = + @"Enrolling a second factor or signing in with a multi-factor account requires sign-in with a " + @"supported first factor."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageEmailChangeNeedsVerification = + @"Multi-factor users must always have a verified email."; + +/** @var kFIRAuthErrorMessageDynamicLinkNotActivated + @brief Error message constant describing @c FIRAuthErrorCodeDynamicLinkNotActivated errors. + */ +static NSString *const kFIRAuthErrorMessageDynamicLinkNotActivated = + @"Please activate Dynamic Links in the Firebase Console and agree to the terms and conditions."; + +/** @var kFIRAuthErrorMessageRejectedCredential + @brief Error message constant describing @c FIRAuthErrorCodeRejectedCredential errors. + */ +static NSString *const kFIRAuthErrorMessageRejectedCredential = + @"The request contains malformed or mismatching credentials."; + +/** @var kFIRAuthErrorMessageMissingOrInvalidNonce + @brief Error message constant describing @c FIRAuthErrorCodeMissingOrInvalidNonce errors. + */ +static NSString *const kFIRAuthErrorMessageMissingOrInvalidNonce = + @"The request contains malformed or mismatched credentials."; + +/** @var kFIRAuthErrorMessageTenantIDMismatch. + @brief Message for @c FIRAuthErrorCodeTenantIDMismatch error code. + */ +static NSString *const kFIRAuthErrorMessageTenantIDMismatch = + @"The provided user's tenant ID does" + "not match the Auth instance's tenant ID."; + +/** @var kFIRAuthErrorMessageUnsupportedTenantOperation + @brief Message for @c FIRAuthErrorCodeUnsupportedTenantOperation error code. + */ +static NSString *const kFIRAuthErrorMessageUnsupportedTenantOperation = + @"This operation is not" + "supported in a multi-tenant context."; + +/** @var FIRAuthErrorDescription + @brief The error descrioption, based on the error code. + @remarks No default case so that we get a compiler warning if a new value was added to the enum. + */ +static NSString *FIRAuthErrorDescription(FIRAuthErrorCode code) { + switch (code) { + case FIRAuthErrorCodeInvalidCustomToken: + return kFIRAuthErrorMessageInvalidCustomToken; + case FIRAuthErrorCodeCustomTokenMismatch: + return kFIRAuthErrorMessageCustomTokenMismatch; + case FIRAuthErrorCodeInvalidEmail: + return kFIRAuthErrorMessageInvalidEmail; + case FIRAuthErrorCodeInvalidCredential: + return kFIRAuthErrorMessageInvalidCredential; + case FIRAuthErrorCodeUserDisabled: + return kFIRAuthErrorMessageUserDisabled; + case FIRAuthErrorCodeEmailAlreadyInUse: + return kFIRAuthErrorMessageEmailAlreadyInUse; + case FIRAuthErrorCodeWrongPassword: + return kFIRAuthErrorMessageWrongPassword; + case FIRAuthErrorCodeTooManyRequests: + return kFIRAuthErrorMessageTooManyRequests; + case FIRAuthErrorCodeAccountExistsWithDifferentCredential: + return kFIRAuthErrorMessageAccountExistsWithDifferentCredential; + case FIRAuthErrorCodeRequiresRecentLogin: + return kFIRAuthErrorMessageRequiresRecentLogin; + case FIRAuthErrorCodeProviderAlreadyLinked: + return kFIRAuthErrorMessageProviderAlreadyLinked; + case FIRAuthErrorCodeNoSuchProvider: + return kFIRAuthErrorMessageNoSuchProvider; + case FIRAuthErrorCodeInvalidUserToken: + return kFIRAuthErrorMessageInvalidUserToken; + case FIRAuthErrorCodeNetworkError: + return kFIRAuthErrorMessageNetworkError; + case FIRAuthErrorCodeKeychainError: + return kFIRAuthErrorMessageKeychainError; + case FIRAuthErrorCodeMissingClientIdentifier: + return kFIRAuthErrorMessageMissingClientIdentifier; + case FIRAuthErrorCodeUserTokenExpired: + return kFIRAuthErrorMessageUserTokenExpired; + case FIRAuthErrorCodeUserNotFound: + return kFIRAuthErrorMessageUserNotFound; + case FIRAuthErrorCodeInvalidAPIKey: + return kFIRAuthErrorMessageInvalidAPIKey; + case FIRAuthErrorCodeCredentialAlreadyInUse: + return kFIRAuthErrorMessageCredentialAlreadyInUse; + case FIRAuthErrorCodeInternalError: + return kFIRAuthErrorMessageInternalError; + case FIRAuthErrorCodeUserMismatch: + return FIRAuthErrorMessageUserMismatch; + case FIRAuthErrorCodeOperationNotAllowed: + return kFIRAuthErrorMessageOperationNotAllowed; + case FIRAuthErrorCodeWeakPassword: + return kFIRAuthErrorMessageWeakPassword; + case FIRAuthErrorCodeAppNotAuthorized: + return kFIRAuthErrorMessageAppNotAuthorized; + case FIRAuthErrorCodeExpiredActionCode: + return kFIRAuthErrorMessageExpiredActionCode; + case FIRAuthErrorCodeInvalidActionCode: + return kFIRAuthErrorMessageInvalidActionCode; + case FIRAuthErrorCodeInvalidSender: + return kFIRAuthErrorMessageInvalidSender; + case FIRAuthErrorCodeInvalidMessagePayload: + return kFIRAuthErrorMessageInvalidMessagePayload; + case FIRAuthErrorCodeInvalidRecipientEmail: + return kFIRAuthErrorMessageInvalidRecipientEmail; + case FIRAuthErrorCodeMissingIosBundleID: + return kFIRAuthErrorMessageMissingIosBundleID; + case FIRAuthErrorCodeMissingAndroidPackageName: + return kFIRAuthErrorMessageMissingAndroidPackageName; + case FIRAuthErrorCodeUnauthorizedDomain: + return kFIRAuthErrorMessageUnauthorizedDomain; + case FIRAuthErrorCodeInvalidContinueURI: + return kFIRAuthErrorMessageInvalidContinueURI; + case FIRAuthErrorCodeMissingContinueURI: + return kFIRAuthErrorMessageMissingContinueURI; + case FIRAuthErrorCodeMissingEmail: + return kFIRAuthErrorMessageMissingEmail; + case FIRAuthErrorCodeMissingPhoneNumber: + return kFIRAuthErrorMessageMissingPhoneNumber; + case FIRAuthErrorCodeInvalidPhoneNumber: + return kFIRAuthErrorMessageInvalidPhoneNumber; + case FIRAuthErrorCodeMissingVerificationCode: + return kFIRAuthErrorMessageMissingVerificationCode; + case FIRAuthErrorCodeInvalidVerificationCode: + return kFIRAuthErrorMessageInvalidVerificationCode; + case FIRAuthErrorCodeMissingVerificationID: + return kFIRAuthErrorMessageMissingVerificationID; + case FIRAuthErrorCodeInvalidVerificationID: + return kFIRAuthErrorMessageInvalidVerificationID; + case FIRAuthErrorCodeSessionExpired: + return kFIRAuthErrorMessageSessionExpired; + case FIRAuthErrorCodeMissingAppCredential: + return kFIRAuthErrorMessageMissingAppCredential; + case FIRAuthErrorCodeInvalidAppCredential: + return kFIRAuthErrorMessageInvalidAppCredential; + case FIRAuthErrorCodeQuotaExceeded: + return kFIRAuthErrorMessageQuotaExceeded; + case FIRAuthErrorCodeMissingAppToken: + return kFIRAuthErrorMessageMissingAppToken; + case FIRAuthErrorCodeNotificationNotForwarded: + return kFIRAuthErrorMessageNotificationNotForwarded; + case FIRAuthErrorCodeAppNotVerified: + return kFIRAuthErrorMessageAppNotVerified; + case FIRAuthErrorCodeCaptchaCheckFailed: + return kFIRAuthErrorMessageCaptchaCheckFailed; + case FIRAuthErrorCodeWebContextAlreadyPresented: + return kFIRAuthErrorMessageWebContextAlreadyPresented; + case FIRAuthErrorCodeWebContextCancelled: + return kFIRAuthErrorMessageWebContextCancelled; + case FIRAuthErrorCodeInvalidClientID: + return kFIRAuthErrorMessageInvalidClientID; + case FIRAuthErrorCodeAppVerificationUserInteractionFailure: + return kFIRAuthErrorMessageAppVerificationUserInteractionFailure; + case FIRAuthErrorCodeWebNetworkRequestFailed: + return kFIRAuthErrorMessageWebRequestFailed; + case FIRAuthErrorCodeNullUser: + return kFIRAuthErrorMessageNullUser; + case FIRAuthErrorCodeInvalidProviderID: + return kFIRAuthErrorMessageInvalidProviderID; + case FIRAuthErrorCodeInvalidDynamicLinkDomain: + return kFIRAuthErrorMessageInvalidDynamicLinkDomain; + case FIRAuthErrorCodeWebInternalError: + return kFIRAuthErrorMessageWebInternalError; + case FIRAuthErrorCodeWebSignInUserInteractionFailure: + return kFIRAuthErrorMessageAppVerificationUserInteractionFailure; + case FIRAuthErrorCodeMalformedJWT: + return kFIRAuthErrorMessageMalformedJWT; + case FIRAuthErrorCodeLocalPlayerNotAuthenticated: + return kFIRAuthErrorMessageLocalPlayerNotAuthenticated; + case FIRAuthErrorCodeGameKitNotLinked: + return kFIRAuthErrorMessageGameKitNotLinked; + case FIRAuthErrorCodeSecondFactorRequired: + return kFIRAuthErrorMessageSecondFactorRequired; + case FIRAuthErrorCodeMissingMultiFactorSession: + return FIRAuthErrorMessageMissingMultiFactorSession; + case FIRAuthErrorCodeMissingMultiFactorInfo: + return FIRAuthErrorMessageMissingMultiFactorInfo; + case FIRAuthErrorCodeInvalidMultiFactorSession: + return FIRAuthErrorMessageInvalidMultiFactorSession; + case FIRAuthErrorCodeMultiFactorInfoNotFound: + return FIRAuthErrorMessageMultiFactorInfoNotFound; + case FIRAuthErrorCodeAdminRestrictedOperation: + return FIRAuthErrorMessageAdminRestrictedOperation; + case FIRAuthErrorCodeUnverifiedEmail: + return FIRAuthErrorMessageUnverifiedEmail; + case FIRAuthErrorCodeSecondFactorAlreadyEnrolled: + return FIRAuthErrorMessageSecondFactorAlreadyEnrolled; + case FIRAuthErrorCodeMaximumSecondFactorCountExceeded: + return FIRAuthErrorMessageMaximumSecondFactorCountExceeded; + case FIRAuthErrorCodeUnsupportedFirstFactor: + return FIRAuthErrorMessageUnsupportedFirstFactor; + case FIRAuthErrorCodeEmailChangeNeedsVerification: + return FIRAuthErrorMessageEmailChangeNeedsVerification; + case FIRAuthErrorCodeDynamicLinkNotActivated: + return kFIRAuthErrorMessageDynamicLinkNotActivated; + case FIRAuthErrorCodeRejectedCredential: + return kFIRAuthErrorMessageRejectedCredential; + case FIRAuthErrorCodeMissingOrInvalidNonce: + return kFIRAuthErrorMessageMissingOrInvalidNonce; + case FIRAuthErrorCodeTenantIDMismatch: + return kFIRAuthErrorMessageTenantIDMismatch; + case FIRAuthErrorCodeUnsupportedTenantOperation: + return kFIRAuthErrorMessageUnsupportedTenantOperation; + } +} + +/** @var FIRAuthErrorCodeString + @brief The the error short string, based on the error code. + @remarks No default case so that we get a compiler warning if a new value was added to the enum. + */ +static NSString *const FIRAuthErrorCodeString(FIRAuthErrorCode code) { + switch (code) { + case FIRAuthErrorCodeInvalidCustomToken: + return @"ERROR_INVALID_CUSTOM_TOKEN"; + case FIRAuthErrorCodeCustomTokenMismatch: + return @"ERROR_CUSTOM_TOKEN_MISMATCH"; + case FIRAuthErrorCodeInvalidEmail: + return @"ERROR_INVALID_EMAIL"; + case FIRAuthErrorCodeInvalidCredential: + return @"ERROR_INVALID_CREDENTIAL"; + case FIRAuthErrorCodeUserDisabled: + return @"ERROR_USER_DISABLED"; + case FIRAuthErrorCodeEmailAlreadyInUse: + return @"ERROR_EMAIL_ALREADY_IN_USE"; + case FIRAuthErrorCodeWrongPassword: + return @"ERROR_WRONG_PASSWORD"; + case FIRAuthErrorCodeTooManyRequests: + return @"ERROR_TOO_MANY_REQUESTS"; + case FIRAuthErrorCodeAccountExistsWithDifferentCredential: + return @"ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL"; + case FIRAuthErrorCodeRequiresRecentLogin: + return @"ERROR_REQUIRES_RECENT_LOGIN"; + case FIRAuthErrorCodeProviderAlreadyLinked: + return @"ERROR_PROVIDER_ALREADY_LINKED"; + case FIRAuthErrorCodeNoSuchProvider: + return @"ERROR_NO_SUCH_PROVIDER"; + case FIRAuthErrorCodeInvalidUserToken: + return @"ERROR_INVALID_USER_TOKEN"; + case FIRAuthErrorCodeNetworkError: + return @"ERROR_NETWORK_REQUEST_FAILED"; + case FIRAuthErrorCodeKeychainError: + return @"ERROR_KEYCHAIN_ERROR"; + case FIRAuthErrorCodeMissingClientIdentifier: + return @"ERROR_MISSING_CLIENT_IDENTIFIER"; + case FIRAuthErrorCodeUserTokenExpired: + return @"ERROR_USER_TOKEN_EXPIRED"; + case FIRAuthErrorCodeUserNotFound: + return @"ERROR_USER_NOT_FOUND"; + case FIRAuthErrorCodeInvalidAPIKey: + return @"ERROR_INVALID_API_KEY"; + case FIRAuthErrorCodeCredentialAlreadyInUse: + return @"ERROR_CREDENTIAL_ALREADY_IN_USE"; + case FIRAuthErrorCodeInternalError: + return @"ERROR_INTERNAL_ERROR"; + case FIRAuthErrorCodeUserMismatch: + return @"ERROR_USER_MISMATCH"; + case FIRAuthErrorCodeOperationNotAllowed: + return @"ERROR_OPERATION_NOT_ALLOWED"; + case FIRAuthErrorCodeWeakPassword: + return @"ERROR_WEAK_PASSWORD"; + case FIRAuthErrorCodeAppNotAuthorized: + return @"ERROR_APP_NOT_AUTHORIZED"; + case FIRAuthErrorCodeExpiredActionCode: + return @"ERROR_EXPIRED_ACTION_CODE"; + case FIRAuthErrorCodeInvalidActionCode: + return @"ERROR_INVALID_ACTION_CODE"; + case FIRAuthErrorCodeInvalidMessagePayload: + return @"ERROR_INVALID_MESSAGE_PAYLOAD"; + case FIRAuthErrorCodeInvalidSender: + return @"ERROR_INVALID_SENDER"; + case FIRAuthErrorCodeInvalidRecipientEmail: + return @"ERROR_INVALID_RECIPIENT_EMAIL"; + case FIRAuthErrorCodeMissingIosBundleID: + return @"ERROR_MISSING_IOS_BUNDLE_ID"; + case FIRAuthErrorCodeMissingAndroidPackageName: + return @"ERROR_MISSING_ANDROID_PKG_NAME"; + case FIRAuthErrorCodeUnauthorizedDomain: + return @"ERROR_UNAUTHORIZED_DOMAIN"; + case FIRAuthErrorCodeInvalidContinueURI: + return @"ERROR_INVALID_CONTINUE_URI"; + case FIRAuthErrorCodeMissingContinueURI: + return @"ERROR_MISSING_CONTINUE_URI"; + case FIRAuthErrorCodeMissingEmail: + return @"ERROR_MISSING_EMAIL"; + case FIRAuthErrorCodeMissingPhoneNumber: + return @"ERROR_MISSING_PHONE_NUMBER"; + case FIRAuthErrorCodeInvalidPhoneNumber: + return @"ERROR_INVALID_PHONE_NUMBER"; + case FIRAuthErrorCodeMissingVerificationCode: + return @"ERROR_MISSING_VERIFICATION_CODE"; + case FIRAuthErrorCodeInvalidVerificationCode: + return @"ERROR_INVALID_VERIFICATION_CODE"; + case FIRAuthErrorCodeMissingVerificationID: + return @"ERROR_MISSING_VERIFICATION_ID"; + case FIRAuthErrorCodeInvalidVerificationID: + return @"ERROR_INVALID_VERIFICATION_ID"; + case FIRAuthErrorCodeSessionExpired: + return @"ERROR_SESSION_EXPIRED"; + case FIRAuthErrorCodeMissingAppCredential: + return @"MISSING_APP_CREDENTIAL"; + case FIRAuthErrorCodeInvalidAppCredential: + return @"INVALID_APP_CREDENTIAL"; + case FIRAuthErrorCodeQuotaExceeded: + return @"ERROR_QUOTA_EXCEEDED"; + case FIRAuthErrorCodeMissingAppToken: + return @"ERROR_MISSING_APP_TOKEN"; + case FIRAuthErrorCodeNotificationNotForwarded: + return @"ERROR_NOTIFICATION_NOT_FORWARDED"; + case FIRAuthErrorCodeAppNotVerified: + return @"ERROR_APP_NOT_VERIFIED"; + case FIRAuthErrorCodeCaptchaCheckFailed: + return @"ERROR_CAPTCHA_CHECK_FAILED"; + case FIRAuthErrorCodeWebContextAlreadyPresented: + return @"ERROR_WEB_CONTEXT_ALREADY_PRESENTED"; + case FIRAuthErrorCodeWebContextCancelled: + return @"ERROR_WEB_CONTEXT_CANCELLED"; + case FIRAuthErrorCodeInvalidClientID: + return @"ERROR_INVALID_CLIENT_ID"; + case FIRAuthErrorCodeAppVerificationUserInteractionFailure: + return @"ERROR_APP_VERIFICATION_FAILED"; + case FIRAuthErrorCodeWebNetworkRequestFailed: + return @"ERROR_WEB_NETWORK_REQUEST_FAILED"; + case FIRAuthErrorCodeNullUser: + return @"ERROR_NULL_USER"; + case FIRAuthErrorCodeInvalidProviderID: + return @"ERROR_INVALID_PROVIDER_ID"; + case FIRAuthErrorCodeInvalidDynamicLinkDomain: + return @"ERROR_INVALID_DYNAMIC_LINK_DOMAIN"; + case FIRAuthErrorCodeWebInternalError: + return @"ERROR_WEB_INTERNAL_ERROR"; + case FIRAuthErrorCodeWebSignInUserInteractionFailure: + return @"ERROR_WEB_USER_INTERACTION_FAILURE"; + case FIRAuthErrorCodeMalformedJWT: + return @"ERROR_MALFORMED_JWT"; + case FIRAuthErrorCodeLocalPlayerNotAuthenticated: + return @"ERROR_LOCAL_PLAYER_NOT_AUTHENTICATED"; + case FIRAuthErrorCodeGameKitNotLinked: + return @"ERROR_GAME_KIT_NOT_LINKED"; + case FIRAuthErrorCodeSecondFactorRequired: + return @"ERROR_SECOND_FACTOR_REQUIRED"; + case FIRAuthErrorCodeMissingMultiFactorSession: + return @"ERROR_MISSING_MULTI_FACTOR_SESSION"; + case FIRAuthErrorCodeMissingMultiFactorInfo: + return @"ERROR_MISSING_MULTI_FACTOR_INFO"; + case FIRAuthErrorCodeInvalidMultiFactorSession: + return @"ERROR_INVALID_MULTI_FACTOR_SESSION"; + case FIRAuthErrorCodeMultiFactorInfoNotFound: + return @"ERROR_MULTI_FACTOR_INFO_NOT_FOUND"; + case FIRAuthErrorCodeAdminRestrictedOperation: + return @"ERROR_ADMIN_RESTRICTED_OPERATION"; + case FIRAuthErrorCodeUnverifiedEmail: + return @"ERROR_UNVERIFIED_EMAIL"; + case FIRAuthErrorCodeSecondFactorAlreadyEnrolled: + return @"ERROR_SECOND_FACTOR_ALREADY_ENROLLED"; + case FIRAuthErrorCodeMaximumSecondFactorCountExceeded: + return @"ERROR_MAXIMUM_SECOND_FACTOR_COUNT_EXCEEDED"; + case FIRAuthErrorCodeUnsupportedFirstFactor: + return @"ERROR_UNSUPPORTED_FIRST_FACTOR"; + case FIRAuthErrorCodeEmailChangeNeedsVerification: + return @"ERROR_EMAIL_CHANGE_NEEDS_VERIFICATION"; + case FIRAuthErrorCodeDynamicLinkNotActivated: + return @"ERROR_DYNAMIC_LINK_NOT_ACTIVATED"; + case FIRAuthErrorCodeRejectedCredential: + return @"ERROR_REJECTED_CREDENTIAL"; + case FIRAuthErrorCodeMissingOrInvalidNonce: + return @"ERROR_MISSING_OR_INVALID_NONCE"; + case FIRAuthErrorCodeTenantIDMismatch: + return @"ERROR_TENANT_ID_MISMATCH"; + case FIRAuthErrorCodeUnsupportedTenantOperation: + return @"ERROR_UNSUPPORTED_TENANT_OPERATION"; + } +} + +@implementation FIRAuthErrorUtils + ++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code { + return [self errorWithCode:code message:nil]; +} + ++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code message:(nullable NSString *)message { + NSDictionary *userInfo = nil; + if (message.length) { + userInfo = @{NSLocalizedDescriptionKey : message}; + } + return [self errorWithCode:code userInfo:userInfo]; +} + ++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code + underlyingError:(nullable NSError *)underlyingError { + NSDictionary *errorUserInfo; + if (underlyingError) { + errorUserInfo = @{NSUnderlyingErrorKey : underlyingError}; + } + return [self errorWithCode:code userInfo:errorUserInfo]; +} + ++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code + userInfo:(nullable NSDictionary *)userInfo { + BOOL isPublic = (code & FIRAuthPublicErrorCodeFlag) == FIRAuthPublicErrorCodeFlag; + if (isPublic) { + // This is a public error. Return it as a public error and add a description. + NSInteger errorCode = code & ~FIRAuthPublicErrorCodeFlag; + NSMutableDictionary *errorUserInfo = [NSMutableDictionary dictionary]; + if (userInfo) { + [errorUserInfo addEntriesFromDictionary:userInfo]; + } + if (!errorUserInfo[NSLocalizedDescriptionKey]) { + errorUserInfo[NSLocalizedDescriptionKey] = FIRAuthErrorDescription(errorCode); + } + errorUserInfo[FIRAuthErrorUserInfoNameKey] = FIRAuthErrorCodeString(errorCode); + return [NSError errorWithDomain:FIRAuthErrorDomain code:errorCode userInfo:errorUserInfo]; + } else { + // This is an internal error. Wrap it in an internal error. + NSError *error = [NSError errorWithDomain:FIRAuthInternalErrorDomain + code:code + userInfo:userInfo]; + return [self errorWithCode:FIRAuthInternalErrorCodeInternalError underlyingError:error]; + } +} + ++ (NSError *)RPCRequestEncodingErrorWithUnderlyingError:(NSError *)underlyingError { + return [self errorWithCode:FIRAuthInternalErrorCodeRPCRequestEncodingError + underlyingError:underlyingError]; +} + ++ (NSError *)JSONSerializationErrorForUnencodableType { + return [self errorWithCode:FIRAuthInternalErrorCodeJSONSerializationError]; +} + ++ (NSError *)JSONSerializationErrorWithUnderlyingError:(NSError *)underlyingError { + return [self errorWithCode:FIRAuthInternalErrorCodeJSONSerializationError + underlyingError:underlyingError]; +} + ++ (NSError *)networkErrorWithUnderlyingError:(NSError *)underlyingError { + return [self errorWithCode:FIRAuthInternalErrorCodeNetworkError underlyingError:underlyingError]; +} + ++ (NSError *)unexpectedErrorResponseWithData:(NSData *)data + underlyingError:(NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (data) { + userInfo[FIRAuthErrorUserInfoDataKey] = data; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedErrorResponse + userInfo:[userInfo copy]]; +} + ++ (NSError *)unexpectedErrorResponseWithDeserializedResponse:(id)deserializedResponse { + NSDictionary *userInfo; + if (deserializedResponse) { + userInfo = @{ + FIRAuthErrorUserInfoDeserializedResponseKey : deserializedResponse, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedErrorResponse userInfo:userInfo]; +} + ++ (NSError *)unexpectedErrorResponseWithDeserializedResponse:(id)deserializedResponse + underlyingError:(NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (deserializedResponse) { + userInfo[FIRAuthErrorUserInfoDeserializedResponseKey] = deserializedResponse; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedErrorResponse + userInfo:[userInfo copy]]; +} + ++ (NSError *)malformedJWTErrorWithToken:(NSString *)token + underlyingError:(NSError *_Nullable)underlyingError { + NSMutableDictionary *userInfo = + [NSMutableDictionary dictionaryWithObject:kFIRAuthErrorMessageMalformedJWT + forKey:NSLocalizedDescriptionKey]; + [userInfo setObject:token forKey:FIRAuthErrorUserInfoDataKey]; + if (underlyingError != nil) { + [userInfo setObject:underlyingError forKey:NSUnderlyingErrorKey]; + } + return [self errorWithCode:FIRAuthInternalErrorCodeMalformedJWT userInfo:[userInfo copy]]; +} + ++ (NSError *)unexpectedResponseWithData:(NSData *)data underlyingError:(NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (data) { + userInfo[FIRAuthErrorUserInfoDataKey] = data; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedResponse userInfo:[userInfo copy]]; +} + ++ (NSError *)unexpectedResponseWithDeserializedResponse:(id)deserializedResponse { + NSDictionary *userInfo; + if (deserializedResponse) { + userInfo = @{ + FIRAuthErrorUserInfoDeserializedResponseKey : deserializedResponse, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedResponse userInfo:userInfo]; +} + ++ (NSError *)unexpectedResponseWithDeserializedResponse:(nullable id)deserializedResponse + underlyingError:(NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (deserializedResponse) { + userInfo[FIRAuthErrorUserInfoDeserializedResponseKey] = deserializedResponse; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedResponse userInfo:[userInfo copy]]; +} + ++ (NSError *)RPCResponseDecodingErrorWithDeserializedResponse:(id)deserializedResponse + underlyingError:(NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (deserializedResponse) { + userInfo[FIRAuthErrorUserInfoDeserializedResponseKey] = deserializedResponse; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + return [self errorWithCode:FIRAuthInternalErrorCodeRPCResponseDecodingError + userInfo:[userInfo copy]]; +} + ++ (NSError *)emailAlreadyInUseErrorWithEmail:(nullable NSString *)email { + NSDictionary *userInfo; + if (email.length) { + userInfo = @{ + FIRAuthErrorUserInfoEmailKey : email, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeEmailAlreadyInUse userInfo:userInfo]; +} + ++ (NSError *)userDisabledErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeUserDisabled message:message]; +} + ++ (NSError *)wrongPasswordErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeWrongPassword message:message]; +} + ++ (NSError *)tooManyRequestsErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeTooManyRequests message:message]; +} + ++ (NSError *)invalidCustomTokenErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidCustomToken message:message]; +} + ++ (NSError *)customTokenMistmatchErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeCustomTokenMismatch message:message]; +} + ++ (NSError *)invalidCredentialErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidCredential message:message]; +} + ++ (NSError *)requiresRecentLoginErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeRequiresRecentLogin message:message]; +} + ++ (NSError *)invalidUserTokenErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidUserToken message:message]; +} + ++ (NSError *)invalidEmailErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidEmail message:message]; +} + ++ (NSError *)accountExistsWithDifferentCredentialErrorWithEmail:(nullable NSString *)email + updatedCredential: + (nullable FIRAuthCredential *)updatedCredential { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (email) { + userInfo[FIRAuthErrorUserInfoEmailKey] = email; + } + if (updatedCredential) { + userInfo[FIRAuthErrorUserInfoUpdatedCredentialKey] = updatedCredential; + } + return [self errorWithCode:FIRAuthInternalErrorCodeAccountExistsWithDifferentCredential + userInfo:userInfo]; +} + ++ (NSError *)providerAlreadyLinkedError { + return [self errorWithCode:FIRAuthInternalErrorCodeProviderAlreadyLinked]; +} + ++ (NSError *)noSuchProviderError { + return [self errorWithCode:FIRAuthInternalErrorCodeNoSuchProvider]; +} + ++ (NSError *)userTokenExpiredErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeUserTokenExpired message:message]; +} + ++ (NSError *)userNotFoundErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeUserNotFound message:message]; +} + ++ (NSError *)invalidAPIKeyError { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidAPIKey]; +} + ++ (NSError *)userMismatchError { + return [self errorWithCode:FIRAuthInternalErrorCodeUserMismatch]; +} + ++ (NSError *)credentialAlreadyInUseErrorWithMessage:(nullable NSString *)message + credential:(nullable FIRAuthCredential *)credential + email:(nullable NSString *)email { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (credential) { + userInfo[FIRAuthErrorUserInfoUpdatedCredentialKey] = credential; + } + if (email.length) { + userInfo[FIRAuthErrorUserInfoEmailKey] = email; + } + if (userInfo.count) { + return [self errorWithCode:FIRAuthInternalErrorCodeCredentialAlreadyInUse userInfo:userInfo]; + } + return [self errorWithCode:FIRAuthInternalErrorCodeCredentialAlreadyInUse message:message]; +} + ++ (NSError *)operationNotAllowedErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeOperationNotAllowed message:message]; +} + ++ (NSError *)weakPasswordErrorWithServerResponseReason:(nullable NSString *)reason { + NSDictionary *userInfo; + if (reason.length) { + userInfo = @{ + NSLocalizedFailureReasonErrorKey : reason, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeWeakPassword userInfo:userInfo]; +} + ++ (NSError *)appNotAuthorizedError { + return [self errorWithCode:FIRAuthInternalErrorCodeAppNotAuthorized]; +} + ++ (NSError *)expiredActionCodeErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeExpiredActionCode message:message]; +} + ++ (NSError *)invalidActionCodeErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidActionCode message:message]; +} + ++ (NSError *)invalidMessagePayloadErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidMessagePayload message:message]; +} + ++ (NSError *)invalidSenderErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidSender message:message]; +} + ++ (NSError *)invalidRecipientEmailErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidRecipientEmail message:message]; +} + ++ (NSError *)missingIosBundleIDErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthinternalErrorCodeMissingIosBundleID message:message]; +} + ++ (NSError *)missingAndroidPackageNameErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingAndroidPackageName message:message]; +} + ++ (NSError *)unauthorizedDomainErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeUnauthorizedDomain message:message]; +} + ++ (NSError *)invalidContinueURIErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidContinueURI message:message]; +} + ++ (NSError *)missingContinueURIErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingContinueURI message:message]; +} + ++ (NSError *)missingEmailErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingEmail message:message]; +} + ++ (NSError *)missingPhoneNumberErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingPhoneNumber message:message]; +} + ++ (NSError *)invalidPhoneNumberErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidPhoneNumber message:message]; +} + ++ (NSError *)missingVerificationCodeErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingVerificationCode message:message]; +} + ++ (NSError *)invalidVerificationCodeErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidVerificationCode message:message]; +} + ++ (NSError *)missingVerificationIDErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingVerificationID message:message]; +} + ++ (NSError *)invalidVerificationIDErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidVerificationID message:message]; +} + ++ (NSError *)sessionExpiredErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeSessionExpired message:message]; +} + ++ (NSError *)missingAppCredentialWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingAppCredential message:message]; +} + ++ (NSError *)invalidAppCredentialWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidAppCredential message:message]; +} + ++ (NSError *)quotaExceededErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeQuotaExceeded message:message]; +} + ++ (NSError *)missingAppTokenErrorWithUnderlyingError:(nullable NSError *)underlyingError { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingAppToken + underlyingError:underlyingError]; +} + ++ (NSError *)localPlayerNotAuthenticatedError { + return [self errorWithCode:FIRAuthInternalErrorCodeLocalPlayerNotAuthenticated]; +} + ++ (NSError *)gameKitNotLinkedError { + return [self errorWithCode:FIRAuthInternalErrorCodeGameKitNotLinked]; +} + +#if TARGET_OS_IOS ++ (NSError *)secondFactorRequiredErrorWithPendingCredential:(NSString *)MFAPendingCredential + hints:(NSArray *)hints { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (MFAPendingCredential && hints) { + FIRMultiFactorResolver *resolver = + [[FIRMultiFactorResolver alloc] initWithMFAPendingCredential:MFAPendingCredential + hints:hints]; + userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey] = resolver; + } + return [self errorWithCode:FIRAuthInternalErrorCodeSecondFactorRequired userInfo:userInfo]; +} +#endif + ++ (NSError *)notificationNotForwardedError { + return [self errorWithCode:FIRAuthInternalErrorCodeNotificationNotForwarded]; +} + ++ (NSError *)appNotVerifiedErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeAppNotVerified message:message]; +} + ++ (NSError *)missingClientIdentifierErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingClientIdentifier message:message]; +} + ++ (NSError *)captchaCheckFailedErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeCaptchaCheckFailed message:message]; +} + ++ (NSError *)webContextAlreadyPresentedErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeWebContextAlreadyPresented message:message]; +} + ++ (NSError *)webContextCancelledErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeWebContextCancelled message:message]; +} + ++ (NSError *)appVerificationUserInteractionFailureWithReason:(NSString *)reason { + NSDictionary *userInfo; + if (reason.length) { + userInfo = @{ + NSLocalizedFailureReasonErrorKey : reason, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeAppVerificationUserInteractionFailure + userInfo:userInfo]; +} + ++ (NSError *)webSignInUserInteractionFailureWithReason:(nullable NSString *)reason { + NSDictionary *userInfo; + if (reason.length) { + userInfo = @{ + NSLocalizedFailureReasonErrorKey : reason, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeWebSignInUserInteractionFailure + userInfo:userInfo]; +} + ++ (nullable NSError *)URLResponseErrorWithCode:(NSString *)code + message:(nullable NSString *)message { + if ([code isEqualToString:kURLResponseErrorCodeInvalidClientID]) { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidClientID message:message]; + } + if ([code isEqualToString:kURLResponseErrorCodeNetworkRequestFailed]) { + return [self errorWithCode:FIRAuthInternalErrorCodeWebNetworkRequestFailed message:message]; + } + if ([code isEqualToString:kURLResponseErrorCodeInternalError]) { + return [self errorWithCode:FIRAuthInternalErrorCodeWebInternalError message:message]; + } + return nil; +} + ++ (NSError *)nullUserErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeNullUser message:message]; +} + ++ (NSError *)invalidProviderIDErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidProviderID message:message]; +} + ++ (NSError *)invalidDynamicLinkDomainErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidDynamicLinkDomain message:message]; +} + ++ (NSError *)missingOrInvalidNonceErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingOrInvalidNonce message:message]; +} + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { + NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; + return [self errorWithCode:FIRAuthInternalErrorCodeKeychainError + userInfo:@{ + NSLocalizedFailureReasonErrorKey : failureReason, + }]; +} + ++ (NSError *)tenantIDMismatchError { + return [self errorWithCode:FIRAuthInternalErrorCodeTenantIDMismatch]; +} + ++ (NSError *)unsupportedTenantOperationError { + return [self errorWithCode:FIRAuthInternalErrorCodeUnsupportedTenantOperation]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h new file mode 100644 index 0000000..3ae9159 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h @@ -0,0 +1,41 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthExceptionUtils + @brief Utility class used to raise standardized Auth related exceptions. +*/ +@interface FIRAuthExceptionUtils : NSObject + +/** @fn raiseInvalidParameterExceptionWithReason: + @brief raises the "invalid parameter" exception + @param reason string will contain a description of the error. + */ ++ (void)raiseInvalidParameterExceptionWithReason:(nullable NSString *)reason; + +/** @fn raiseMethodNotImplementedExceptionWithReason: + @brief raises the "method not implemented" exception + @param reason string will contain a description of the error. + @see FIRMethodNotImplementedException + */ ++ (void)raiseMethodNotImplementedExceptionWithReason:(nullable NSString *)reason; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.m new file mode 100644 index 0000000..783d4a4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.m @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var FIRMethodNotImplementedException + @brief The name of the "Method Not Implemented" exception. + */ +static NSString *const FIRMethodNotImplementedException = @"FIRMethodNotImplementedException"; + +@implementation FIRAuthExceptionUtils + ++ (void)raiseInvalidParameterExceptionWithReason:(nullable NSString *)reason { + [NSException raise:NSInvalidArgumentException format:@"%@", reason]; +} + ++ (void)raiseMethodNotImplementedExceptionWithReason:(nullable NSString *)reason { + NSException *exception = [NSException exceptionWithName:FIRMethodNotImplementedException + reason:reason + userInfo:nil]; + [exception raise]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h new file mode 100644 index 0000000..d8a2970 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h @@ -0,0 +1,543 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var FIRAuthPublicErrorCodeFlag + @brief Bitmask value indicating the error represents a public error code when this bit is + zeroed. Error codes which don't contain this flag will be wrapped in an @c NSError whose + code is @c FIRAuthErrorCodeInternalError. + */ +static const NSInteger FIRAuthPublicErrorCodeFlag = 1 << 20; + +/** @var FIRAuthInternalErrorDomain + @brief The Firebase Auth error domain for internal errors. + */ +extern NSString *const FIRAuthInternalErrorDomain; + +/** @var FIRAuthErrorUserInfoDeserializedResponseKey + @brief Errors with the code @c FIRAuthErrorCodeUnexpectedResponseError, + @c FIRAuthErrorCodeUnexpectedErrorResponseError, and + @c FIRAuthInternalErrorCodeRPCResponseDecodingError may contain an @c NSError.userInfo + dictionary which contains this key. The value associated with this key is an object of + unspecified contents containing the deserialized server response. + */ +extern NSString *const FIRAuthErrorUserInfoDeserializedResponseKey; + +/** @var FIRAuthErrorUserInfoDataKey + @brief Errors with the code @c FIRAuthErrorCodeUnexpectedResponseError or + @c FIRAuthErrorCodeUnexpectedErrorResponseError may contain an @c NSError.userInfo + dictionary which contains this key. The value associated with this key is an @c NSString + which represents the response from a server to an RPC which could not be deserialized. + */ +extern NSString *const FIRAuthErrorUserInfoDataKey; + +/** @var FIRAuthInternalErrorCode + @brief Error codes used internally by Firebase Auth. + @remarks All errors are generated using an internal error code. These errors are automatically + converted to the appropriate public version of the @c NSError by the methods in + @c FIRAuthErrorUtils + */ +typedef NS_ENUM(NSInteger, FIRAuthInternalErrorCode) { + /** @var FIRAuthInternalErrorCodeNetworkError + @brief Indicates a network error occurred (such as a timeout, interrupted connection, or + unreachable host.) + @remarks These types of errors are often recoverable with a retry. + + See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details about + the network error which occurred. + */ + FIRAuthInternalErrorCodeNetworkError = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeNetworkError, + + /** @var FIRAuthInternalErrorCodeEmailAlreadyInUse + @brief The email used to attempt a sign-up already exists. + */ + FIRAuthInternalErrorCodeEmailAlreadyInUse = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeEmailAlreadyInUse, + + /** @var FIRAuthInternalErrorCodeUserDisabled + @brief Indicates the user's account is disabled on the server side. + */ + FIRAuthInternalErrorCodeUserDisabled = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeUserDisabled, + + /** @var FIRAuthInternalErrorCodeWrongPassword + @brief Indicates the user attempted sign in with a wrong password + */ + FIRAuthInternalErrorCodeWrongPassword = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeWrongPassword, + + /** @var FIRAuthInternalErrorCodeKeychainError + @brief Indicates an error occurred accessing the keychain. + @remarks The @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo dictionary + will contain more information about the error encountered. + */ + FIRAuthInternalErrorCodeKeychainError = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeKeychainError, + + /** @var FIRAuthInternalErrorCodeMissingClientIdentifier + @brief Indicates an error for when the client identifier is missing. + */ + FIRAuthInternalErrorCodeMissingClientIdentifier = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingClientIdentifier, + + /** @var FIRAuthInternalErrorCodeInternalError + @brief An internal error occurred. + @remarks This value is here for consistency. It's also used to make the implementation of + wrapping internal errors simpler. + */ + FIRAuthInternalErrorCodeInternalError = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInternalError, + + /** @var FIRAuthInternalErrorCodeTooManyRequests + @brief Indicates that too many requests were made to a server method. + */ + FIRAuthInternalErrorCodeTooManyRequests = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeTooManyRequests, + + /** @var FIRAuthInternalErrorCodeInvalidCustomToken + @brief Indicates a validation error with the custom token. + */ + FIRAuthInternalErrorCodeInvalidCustomToken = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidCustomToken, + + /** @var FIRAuthInternalErrorCodeCredentialMismatch + @brief Indicates the service account and the API key belong to different projects. + */ + FIRAuthInternalErrorCodeCustomTokenMismatch = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeCustomTokenMismatch, + + /** @var FIRAuthInternalErrorCodeInvalidCredential + @brief Indicates the IDP token or requestUri is invalid. + */ + FIRAuthInternalErrorCodeInvalidCredential = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidCredential, + + /** @var FIRAuthInternalErrorCodeRequiresRecentLogin + @brief Indicates the user has attemped to change email or password more than 5 minutes after + signing in. + */ + FIRAuthInternalErrorCodeRequiresRecentLogin = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeRequiresRecentLogin, + + /** @var FIRAuthInternalErrorCodeInvalidUserToken + @brief Indicates user's saved auth credential is invalid, the user needs to sign in again. + */ + FIRAuthInternalErrorCodeInvalidUserToken = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidUserToken, + + /** @var FIRAuthInternalErrorCodeInvalidEmail + @brief Indicates the email identifier is invalid. + */ + FIRAuthInternalErrorCodeInvalidEmail = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidEmail, + + /** @var FIRAuthInternalErrorCodeAccountExistsWithDifferentCredential + @brief Indicates account linking is needed. + */ + FIRAuthInternalErrorCodeAccountExistsWithDifferentCredential = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeAccountExistsWithDifferentCredential, + + /** @var FIRAuthInternalErrorCodeProviderAlreadyLinked + @brief Indicates an attempt to link a provider to which we are already linked. + */ + FIRAuthInternalErrorCodeProviderAlreadyLinked = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeProviderAlreadyLinked, + + /** @var FIRAuthInternalErrorCodeNoSuchProvider + @brief Indicates an attempt to unlink a provider that is not is not linked. + */ + FIRAuthInternalErrorCodeNoSuchProvider = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeNoSuchProvider, + + /** @var FIRAuthInternalErrorCodeUserTokenExpired + @brief Indicates the token issue time is older than account's valid_since time. + */ + FIRAuthInternalErrorCodeUserTokenExpired = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeUserTokenExpired, + + /** @var FIRAuthInternalErrorCodeUserNotFound + @brief Indicates the user account was been found. + */ + FIRAuthInternalErrorCodeUserNotFound = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeUserNotFound, + + /** @var FIRAuthInternalErrorCodeInvalidAPIKey + @brief Indicates an invalid API Key was supplied in the request. + */ + FIRAuthInternalErrorCodeInvalidAPIKey = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidAPIKey, + + /** @var FIRAuthInternalErrorCodeOperationNotAllowed + @brief Indicates that admin disabled sign-in with the specified IDP. + */ + FIRAuthInternalErrorCodeOperationNotAllowed = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeOperationNotAllowed, + + /** @var FIRAuthInternalErrorCodeUserMismatch + @brief Indicates that user attempted to reauthenticate with a user other than the current + user. + */ + FIRAuthInternalErrorCodeUserMismatch = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeUserMismatch, + + /** @var FIRAuthInternalErrorCodeCredentialAlreadyInUse + @brief Indicates an attempt to link with a credential that has already been linked with a + different Firebase account. + */ + FIRAuthInternalErrorCodeCredentialAlreadyInUse = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeCredentialAlreadyInUse, + + /** @var FIRAuthInternalErrorCodeWeakPassword + @brief Indicates an attempt to set a password that is considered too weak. + */ + FIRAuthInternalErrorCodeWeakPassword = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeWeakPassword, + + /** @var FIRAuthInternalErrorCodeAppNotAuthorized + @brief Indicates the App is not authorized to use Firebase Authentication with the + provided API Key. + */ + FIRAuthInternalErrorCodeAppNotAuthorized = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeAppNotAuthorized, + + /** @var FIRAuthInternalErrorCodeExpiredActionCode + @brief Indicates the OOB code is expired. + */ + FIRAuthInternalErrorCodeExpiredActionCode = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeExpiredActionCode, + + /** @var FIRAuthInternalErrorCodeInvalidActionCode + @brief Indicates the OOB code is invalid. + */ + FIRAuthInternalErrorCodeInvalidActionCode = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidActionCode, + + /** Indicates that there are invalid parameters in the payload during a "send password reset email + * " attempt. + */ + FIRAuthInternalErrorCodeInvalidMessagePayload = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidMessagePayload, + + /** Indicates that the sender email is invalid during a "send password reset email" attempt. + */ + FIRAuthInternalErrorCodeInvalidSender = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidSender, + + /** Indicates that the recipient email is invalid. + */ + FIRAuthInternalErrorCodeInvalidRecipientEmail = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidRecipientEmail, + + /** Indicates that the iOS bundle ID is missing when a iOS App Store ID is provided. + */ + FIRAuthinternalErrorCodeMissingIosBundleID = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingIosBundleID, + + /** Indicates that the android package name is missing when the @c androidInstallApp flag is set + to true. + */ + FIRAuthInternalErrorCodeMissingAndroidPackageName = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingAndroidPackageName, + + /** Indicates that the domain specified in the continue URL is not allowlisted in the Firebase + console. + */ + FIRAuthInternalErrorCodeUnauthorizedDomain = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeUnauthorizedDomain, + + /** Indicates that the domain specified in the continue URI is not valid. + */ + FIRAuthInternalErrorCodeInvalidContinueURI = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidContinueURI, + + /** Indicates that a continue URI was not provided in a request to the backend which requires + one. + */ + FIRAuthInternalErrorCodeMissingContinueURI = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingContinueURI, + + /** Indicates that an email address was expected but one was not provided. + */ + FIRAuthInternalErrorCodeMissingEmail = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMissingEmail, + + /** Indicates that a phone number was not provided in a call to @c verifyPhoneNumber:completion:. + */ + FIRAuthInternalErrorCodeMissingPhoneNumber = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingPhoneNumber, + + /** Indicates that an invalid phone number was provided in a call to @c + verifyPhoneNumber:completion:. + */ + FIRAuthInternalErrorCodeInvalidPhoneNumber = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidPhoneNumber, + + /** Indicates that the phone auth credential was created with an empty verification code. + */ + FIRAuthInternalErrorCodeMissingVerificationCode = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingVerificationCode, + + /** Indicates that an invalid verification code was used in the verifyPhoneNumber request. + */ + FIRAuthInternalErrorCodeInvalidVerificationCode = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidVerificationCode, + + /** Indicates that the phone auth credential was created with an empty verification ID. + */ + FIRAuthInternalErrorCodeMissingVerificationID = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingVerificationID, + + /** Indicates that the APNS device token is missing in the verifyClient request. + */ + FIRAuthInternalErrorCodeMissingAppCredential = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingAppCredential, + + /** Indicates that an invalid APNS device token was used in the verifyClient request. + */ + FIRAuthInternalErrorCodeInvalidAppCredential = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidAppCredential, + + /** Indicates that the reCAPTCHA token is not valid. + */ + FIRAuthInternalErrorCodeCaptchaCheckFailed = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeCaptchaCheckFailed, + + /** Indicates that an invalid verification ID was used in the verifyPhoneNumber request. + */ + FIRAuthInternalErrorCodeInvalidVerificationID = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidVerificationID, + + /** Indicates that the quota of SMS messages for a given project has been exceeded. + */ + FIRAuthInternalErrorCodeQuotaExceeded = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeQuotaExceeded, + + /** Indicates that an attempt was made to present a new web context while one was already being + presented. + */ + FIRAuthInternalErrorCodeWebContextAlreadyPresented = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeWebContextAlreadyPresented, + + /** Indicates that the URL presentation was cancelled prematurely by the user. + */ + FIRAuthInternalErrorCodeWebContextCancelled = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeWebContextCancelled, + + /** Indicates a general failure during the app verification flow. + */ + FIRAuthInternalErrorCodeAppVerificationUserInteractionFailure = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeAppVerificationUserInteractionFailure, + + /** Indicates that the clientID used to invoke a web flow is invalid. + */ + FIRAuthInternalErrorCodeInvalidClientID = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidClientID, + + /** Indicates that a network request within a SFSafariViewController or WKWebView failed. + */ + FIRAuthInternalErrorCodeWebNetworkRequestFailed = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeWebNetworkRequestFailed, + + /** Indicates that an internal error occurred within a SFSafariViewController or WKWebView. + */ + FIRAuthInternalErrorCodeWebInternalError = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeWebInternalError, + + /** Indicates that an internal error occurred within a SFSafariViewController or WKWebView. + */ + FIRAuthInternalErrorCodeWebSignInUserInteractionFailure = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeWebSignInUserInteractionFailure, + + // The enum values between 17046 and 17051 are reserved and should NOT be used for new error + // codes. + + /** Indicates that the SMS code has expired + */ + FIRAuthInternalErrorCodeSessionExpired = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeSessionExpired, + + FIRAuthInternalErrorCodeMissingAppToken = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingAppToken, + + FIRAuthInternalErrorCodeNotificationNotForwarded = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeNotificationNotForwarded, + + FIRAuthInternalErrorCodeAppNotVerified = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeAppNotVerified, + + /** Indicates that the Game Center local player was not authenticated. + */ + FIRAuthInternalErrorCodeLocalPlayerNotAuthenticated = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeLocalPlayerNotAuthenticated, + + /** Indicates that the Game Center local player was not authenticated. + */ + FIRAuthInternalErrorCodeGameKitNotLinked = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeGameKitNotLinked, + + /** Indicates that the second factor is required for sign in. + */ + FIRAuthInternalErrorCodeSecondFactorRequired = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeSecondFactorRequired, + + /** Indicates that the multi factor session is missing. + */ + FIRAuthInternalErrorCodeMissingMultiFactorSession = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingMultiFactorSession, + + /** Indicates that the multi factor info is missing. + */ + FIRAuthInternalErrorCodeMissingMultiFactorInfo = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingMultiFactorInfo, + + /** Indicates that the multi factor session is invalid. + */ + FIRAuthInternalErrorCodeInvalidMultiFactorSession = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidMultiFactorSession, + + /** Indicates that the multi factor info is not found. + */ + FIRAuthInternalErrorCodeMultiFactorInfoNotFound = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMultiFactorInfoNotFound, + + /** Indicates that the operation is admin only. + */ + FIRAuthInternalErrorCodeAdminRestrictedOperation = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeAdminRestrictedOperation, + + /** Indicates that the email is unverified. + */ + FIRAuthInternalErrorCodeUnverifiedEmail = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeUnverifiedEmail, + + /** Indicates that the second factor is already enrolled. + */ + FIRAuthInternalErrorCodeSecondFactorAlreadyEnrolled = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeSecondFactorAlreadyEnrolled, + + /** Indicates that the number of multi factors reached the limit. + */ + FIRAuthInternalErrorCodeMaximumSecondFactorCountExceeded = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMaximumSecondFactorCountExceeded, + + /** Indicates that the first factor is not supportted. + */ + FIRAuthInternalErrorCodeUnsupportedFirstFactor = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeUnsupportedFirstFactor, + + /** Indicates that the email needs to be verified before changed. + */ + FIRAuthInternalErrorCodeEmailChangeNeedsVerification = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeEmailChangeNeedsVerification, + + /** Indicates that the nonce is missing or invalid. + */ + FIRAuthInternalErrorCodeMissingOrInvalidNonce = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingOrInvalidNonce, + + /** Indicates that a non-null user was expected as an argmument to the operation but a null + user was provided. + */ + FIRAuthInternalErrorCodeNullUser = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeNullUser, + + /** Indicates that the provider id given for the web operation is invalid. + */ + FIRAuthInternalErrorCodeInvalidProviderID = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidProviderID, + + /** @var FIRAuthInternalErrorCodeTenantIDMismatch + @brief Indicates an error occurred when an attempt is made to update the current user with a + tenantId that differs from the current FirebaseAuth instance's tenantId. + */ + FIRAuthInternalErrorCodeTenantIDMismatch = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeTenantIDMismatch, + + /** @var FIRAuthInternalErrorCodeUnsupportedTenantOperation + @brief Indicates an error occurred when operation is not supported in a multi-tenant context. + */ + FIRAuthInternalErrorCodeUnsupportedTenantOperation = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeUnsupportedTenantOperation, + + /** Indicates that the Firebase Dynamic Link domain used is either not configured or is + unauthorized for the current project. + */ + FIRAuthInternalErrorCodeInvalidDynamicLinkDomain = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidDynamicLinkDomain, + + FIRAuthInternalErrorCodeMalformedJWT = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMalformedJWT, + + /** @var FIRAuthInternalErrorCodeRPCRequestEncodingError + @brief Indicates an error encoding the RPC request. + @remarks This is typically due to some sort of unexpected input value. + + See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details. + */ + FIRAuthInternalErrorCodeRPCRequestEncodingError = 1, + + /** @var FIRAuthInternalErrorCodeJSONSerializationError + @brief Indicates an error serializing an RPC request. + @remarks This is typically due to some sort of unexpected input value. + + If an @c NSJSONSerialization.isValidJSONObject: check fails, the error will contain no + @c NSUnderlyingError key in the @c NSError.userInfo dictionary. If an error was + encountered calling @c NSJSONSerialization.dataWithJSONObject:options:error:, the + resulting error will be associated with the @c NSUnderlyingError key in the + @c NSError.userInfo dictionary. + */ + FIRAuthInternalErrorCodeJSONSerializationError = 2, + + /** @var FIRAuthInternalErrorCodeUnexpectedErrorResponse + @brief Indicates an HTTP error occurred and the data returned either couldn't be deserialized + or couldn't be decoded. + @remarks See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details + about the HTTP error which occurred. + + If the response could be deserialized as JSON then the @c NSError.userInfo dictionary will + contain a value for the key @c FIRAuthErrorUserInfoDeserializedResponseKey which is the + deserialized response value. + + If the response could not be deserialized as JSON then the @c NSError.userInfo dictionary + will contain values for the @c NSUnderlyingErrorKey and @c FIRAuthErrorUserInfoDataKey + keys. + */ + FIRAuthInternalErrorCodeUnexpectedErrorResponse = 3, + + /** @var FIRAuthInternalErrorCodeUnexpectedResponse + @brief Indicates the HTTP response indicated the request was a successes, but the response + contains something other than a JSON-encoded dictionary, or the data type of the response + indicated it is different from the type of response we expected. + @remarks See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary. + If this key is present in the dictionary, it may contain an error from + @c NSJSONSerialization error (indicating the response received was of the wrong data + type). + + See the @c FIRAuthErrorUserInfoDeserializedResponseKey value in the @c NSError.userInfo + dictionary. If the response could be deserialized, it's deserialized representation will + be associated with this key. If the @c NSUnderlyingError value in the @c NSError.userInfo + dictionary is @c nil, this indicates the JSON didn't represent a dictionary. + */ + FIRAuthInternalErrorCodeUnexpectedResponse = 4, + + /** @var FIRAuthInternalErrorCodeRPCResponseDecodingError + @brief Indicates an error decoding the RPC response. + This is typically due to some sort of unexpected response value from the server. + @remarks See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details. + + See the @c FIRErrorUserInfoDecodedResponseKey value in the @c NSError.userInfo dictionary. + The deserialized representation of the response will be associated with this key. + */ + FIRAuthInternalErrorCodeRPCResponseDecodingError = 5, +}; + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h new file mode 100644 index 0000000..9201305 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h @@ -0,0 +1,69 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol FIRAuthUIDelegate; + +/** @typedef FIRAuthURLPresentationCompletion + @brief The type of block invoked when the URLPresentation completes. + @param callbackURL The callback URL if the presentation ends with a matching callback. + @param error The error if the presentation fails to start or ends with an error. + */ +typedef void (^FIRAuthURLPresentationCompletion)(NSURL *_Nullable callbackURL, + NSError *_Nullable error); + +/** @typedef FIRAuthCallbackMatcher + @brief The type of block invoked for checking whether a callback URL matches. + @param callbackURL The callback URL to check for match. + @return Whether or not the specific callback URL matches or not. + */ +typedef BOOL (^FIRAuthURLCallbackMatcher)(NSURL *_Nullable callbackURL); + +/** @class FIRAuthURLPresenter + @brief A Class responsible for presenting URL via SFSafariViewController or WKWebView. + */ +@interface FIRAuthURLPresenter : NSObject + +/** @fn presentURL:UIDelegate:callbackMatcher:completion: + @brief Presents an URL to interact with user. + @param URL The URL to present. + @param UIDelegate The UI delegate to present view controller. + @param completion A block to be called either synchronously if the presentation fails to start, + or asynchronously in future on an unspecified thread once the presentation finishes. + */ +- (void)presentURL:(NSURL *)URL + UIDelegate:(nullable id)UIDelegate + callbackMatcher:(FIRAuthURLCallbackMatcher)callbackMatcher + completion:(FIRAuthURLPresentationCompletion)completion; + +/** @fn canHandleURL: + @brief Determines if a URL was produced by the currently presented URL. + @param URL The URL to handle. + @return Whether the URL could be handled or not. + */ +- (BOOL)canHandleURL:(NSURL *)URL; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.m new file mode 100644 index 0000000..2defaf0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.m @@ -0,0 +1,208 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthURLPresenter () +@end + +// Disable unguarded availability warnings because SFSafariViewController is been used throughout +// the code, including as an iVar, which cannot be simply excluded by @available check. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + +@implementation FIRAuthURLPresenter { + /** @var _isPresenting + @brief Whether or not some web-based content is being presented. + Accesses to this property are serialized on the global Auth work queue + and thus this variable should not be read or written outside of the work queue. + */ + BOOL _isPresenting; + + /** @var _callbackMatcher + @brief The callback URL matcher for the current presentation, if one is active. + */ + FIRAuthURLCallbackMatcher _Nullable _callbackMatcher; + + /** @var _safariViewController + @brief The SFSafariViewController used for the current presentation, if any. + */ + SFSafariViewController *_Nullable _safariViewController; + + /** @var _webViewController + @brief The FIRAuthWebViewController used for the current presentation, if any. + */ + FIRAuthWebViewController *_Nullable _webViewController; + + /** @var _UIDelegate + @brief The UIDelegate used to present the SFSafariViewController. + */ + id _UIDelegate; + + /** @var _completion + @brief The completion handler for the current presentation, if one is active. + Accesses to this variable are serialized on the global Auth work queue + and thus this variable should not be read or written outside of the work queue. + @remarks This variable is also used as a flag to indicate a presentation is active. + */ + FIRAuthURLPresentationCompletion _Nullable _completion; +} + +- (void)presentURL:(NSURL *)URL + UIDelegate:(nullable id)UIDelegate + callbackMatcher:(FIRAuthURLCallbackMatcher)callbackMatcher + completion:(FIRAuthURLPresentationCompletion)completion { + if (_isPresenting) { + // Unable to start a new presentation on top of another. + // Invoke the new completion closure and leave the old one as-is + // to be invoked when the presentation finishes. + dispatch_async(dispatch_get_main_queue(), ^() { + completion(nil, [FIRAuthErrorUtils webContextAlreadyPresentedErrorWithMessage:nil]); + }); + return; + } + _isPresenting = YES; + _callbackMatcher = callbackMatcher; + _completion = [completion copy]; + dispatch_async(dispatch_get_main_queue(), ^() { + self->_UIDelegate = UIDelegate ?: [FIRAuthDefaultUIDelegate defaultUIDelegate]; +#if TARGET_OS_MACCATALYST + self->_webViewController = [[FIRAuthWebViewController alloc] initWithURL:URL delegate:self]; + UINavigationController *navController = + [[UINavigationController alloc] initWithRootViewController:self->_webViewController]; + [self->_UIDelegate presentViewController:navController animated:YES completion:nil]; +#else + if ([SFSafariViewController class]) { + self->_safariViewController = [[SFSafariViewController alloc] initWithURL:URL]; + self->_safariViewController.delegate = self; + [self->_UIDelegate presentViewController:self->_safariViewController + animated:YES + completion:nil]; + return; + } else { + self->_webViewController = [[FIRAuthWebViewController alloc] initWithURL:URL delegate:self]; + UINavigationController *navController = + [[UINavigationController alloc] initWithRootViewController:self->_webViewController]; + [self->_UIDelegate presentViewController:navController animated:YES completion:nil]; + } +#endif + }); +} + +- (BOOL)canHandleURL:(NSURL *)URL { + if (_isPresenting && _callbackMatcher && _callbackMatcher(URL)) { + [self finishPresentationWithURL:URL error:nil]; + return YES; + } + return NO; +} + +#pragma mark - SFSafariViewControllerDelegate + +- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller { + dispatch_async(FIRAuthGlobalWorkQueue(), ^() { + if (controller == self->_safariViewController) { + self->_safariViewController = nil; + // TODO:Ensure that the SFSafariViewController is actually removed from the screen before + // invoking finishPresentationWithURL:error: + [self finishPresentationWithURL:nil + error:[FIRAuthErrorUtils webContextCancelledErrorWithMessage:nil]]; + } + }); +} + +#pragma mark - FIRAuthwebViewControllerDelegate + +- (BOOL)webViewController:(FIRAuthWebViewController *)webViewController canHandleURL:(NSURL *)URL { + __block BOOL result = NO; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^() { + if (webViewController == self->_webViewController) { + result = [self canHandleURL:URL]; + } + }); + return result; +} + +- (void)webViewControllerDidCancel:(FIRAuthWebViewController *)webViewController { + dispatch_async(FIRAuthGlobalWorkQueue(), ^() { + if (webViewController == self->_webViewController) { + [self finishPresentationWithURL:nil + error:[FIRAuthErrorUtils webContextCancelledErrorWithMessage:nil]]; + } + }); +} + +- (void)webViewController:(FIRAuthWebViewController *)webViewController + didFailWithError:(NSError *)error { + dispatch_async(FIRAuthGlobalWorkQueue(), ^() { + if (webViewController == self->_webViewController) { + [self finishPresentationWithURL:nil error:error]; + } + }); +} + +#pragma mark - Private methods + +/** @fn finishPresentationWithURL:error: + @brief Finishes the presentation for a given URL, if any. + @param URL The URL to finish presenting. + @param error The error with which to finish presenting, if any. + */ +- (void)finishPresentationWithURL:(nullable NSURL *)URL error:(nullable NSError *)error { + _callbackMatcher = nil; + id UIDelegate = _UIDelegate; + _UIDelegate = nil; + FIRAuthURLPresentationCompletion completion = [_completion copy]; + _completion = NULL; + void (^finishBlock)(void) = ^() { + self->_isPresenting = NO; + completion(URL, error); + }; + SFSafariViewController *safariViewController = _safariViewController; + _safariViewController = nil; + FIRAuthWebViewController *webViewController = _webViewController; + _webViewController = nil; + if (safariViewController || webViewController) { + dispatch_async(dispatch_get_main_queue(), ^() { + [UIDelegate dismissViewControllerAnimated:YES + completion:^() { + dispatch_async(FIRAuthGlobalWorkQueue(), finishBlock); + }]; + }); + } else { + finishBlock(); + } +} + +#pragma clang diagnostic pop // ignored "-Wunguarded-availability" + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h new file mode 100644 index 0000000..7a3d080 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h @@ -0,0 +1,102 @@ +/* + * 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 + +@class FIRAuthRequestConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRFetchAuthDomainCallback + @brief The callback invoked at the end of the flow to fetch the Auth domain. + @param authDomain The Auth domain. + @param error The error that occurred while fetching the auth domain, if any. + */ +typedef void (^FIRFetchAuthDomainCallback)(NSString *_Nullable authDomain, + NSError *_Nullable error); + +/** @class FIRAuthURLUtils + @brief A utility class used to facilitate the creation of auth related URLs. + */ +@interface FIRAuthWebUtils : NSObject + +/** @fn randomStringWithLength: + @brief Generates a random string of a specified length. + */ ++ (NSString *)randomStringWithLength:(NSUInteger)length; + +/** @fn isCallbackSchemeRegisteredForCustomURLScheme: + @brief Checks whether or not the provided custom URL scheme has been registered by the app. + @param URLScheme The custom URL scheme to be checked against all custom URL schemes registered + by the app. + @return whether or not the provided custom URL scheme has been registered by the app. + */ ++ (BOOL)isCallbackSchemeRegisteredForCustomURLScheme:(NSString *)URLScheme; + +/** @fn isExpectedCallbackURL:eventID:authType + @brief Parses a URL into all available query items. + @param URL The actual callback URL. + @param eventID The expected event ID. + @param authType The expected auth type. + @param callbackScheme The expected callback custom scheme. + @return Whether or not the actual callback URL matches the expected callback URL. + */ ++ (BOOL)isExpectedCallbackURL:(nullable NSURL *)URL + eventID:(NSString *)eventID + authType:(NSString *)authType + callbackScheme:(NSString *)callbackScheme; + +/** @fn fetchAuthDomainWithCompletion:completion: + @brief Fetches the auth domain associated with the Firebase Project. + @param completion The callback invoked after the auth domain has been constructed or an error + has been encountered. + */ ++ (void)fetchAuthDomainWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + completion:(FIRFetchAuthDomainCallback)completion; + +/** @fn queryItemValue:from: + @brief Utility function to get a value from a NSURLQueryItem array. + @param name The key. + @param queryList The NSURLQueryItem array. + @return The value for the key. + */ + ++ (nullable NSString *)queryItemValue:(NSString *)name from:(NSArray *)queryList; + +/** @fn dictionaryWithHttpArgumentsString: + @brief Utility function to get a dictionary from a http argument string. + @param argString The http argument string. + @return The resulting dictionary of query arguments. + */ ++ (NSDictionary *)dictionaryWithHttpArgumentsString:(NSString *)argString; + +/** @fn stringByUnescapingFromURLArgument:from: + @brief Utility function to get a string by unescapting URL arguments. + @param argument The argument string. + @return The resulting string after unescaping URL argument. + */ ++ (NSString *)stringByUnescapingFromURLArgument:(NSString *)argument; + +/** @fn parseURL: + @brief Parses an incoming URL into all available query items. + @param urlString The url to be parsed. + @return A dictionary of available query items in the target URL. + */ ++ (NSDictionary *)parseURL:(NSString *)urlString; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.m new file mode 100644 index 0000000..d3029c0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.m @@ -0,0 +1,211 @@ +/* + * 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 "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" + +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthWebUtils + ++ (NSArray *)supportedAuthDomains { + return @[ @"firebaseapp.com", @"web.app" ]; +} + ++ (NSString *)randomStringWithLength:(NSUInteger)length { + NSMutableString *randomString = [[NSMutableString alloc] init]; + for (int i = 0; i < length; i++) { + [randomString + appendString:[NSString stringWithFormat:@"%c", 'a' + arc4random_uniform('z' - 'a' + 1)]]; + } + return randomString; +} + ++ (BOOL)isCallbackSchemeRegisteredForCustomURLScheme:(NSString *)URLScheme { + NSString *expectedCustomScheme = [URLScheme lowercaseString]; + NSArray *urlTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"]; + for (NSDictionary *urlType in urlTypes) { + NSArray *urlTypeSchemes = urlType[@"CFBundleURLSchemes"]; + for (NSString *urlTypeScheme in urlTypeSchemes) { + if ([urlTypeScheme.lowercaseString isEqualToString:expectedCustomScheme]) { + return YES; + } + } + } + return NO; +} + ++ (BOOL)isExpectedCallbackURL:(nullable NSURL *)URL + eventID:(NSString *)eventID + authType:(NSString *)authType + callbackScheme:(NSString *)callbackScheme { + if (!URL) { + return NO; + } + NSURLComponents *actualURLComponents = [NSURLComponents componentsWithURL:URL + resolvingAgainstBaseURL:NO]; + actualURLComponents.query = nil; + actualURLComponents.fragment = nil; + + NSURLComponents *expectedURLComponents = [[NSURLComponents alloc] init]; + expectedURLComponents.scheme = callbackScheme; + expectedURLComponents.host = @"firebaseauth"; + expectedURLComponents.path = @"/link"; + + if (![expectedURLComponents.URL isEqual:actualURLComponents.URL]) { + return NO; + } + NSDictionary *URLQueryItems = + [self dictionaryWithHttpArgumentsString:URL.query]; + NSURL *deeplinkURL = [NSURL URLWithString:URLQueryItems[@"deep_link_id"]]; + NSDictionary *deeplinkQueryItems = + [self dictionaryWithHttpArgumentsString:deeplinkURL.query]; + if ([deeplinkQueryItems[@"authType"] isEqualToString:authType] && + [deeplinkQueryItems[@"eventId"] isEqualToString:eventID]) { + return YES; + } + return NO; +} + ++ (void)fetchAuthDomainWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + completion:(FIRFetchAuthDomainCallback)completion { + if (requestConfiguration.emulatorHostAndPort) { + // If we are using the auth emulator, we do not want to call the GetProjectConfig endpoint. The + // widget is hosted on the emulator host and port, so we can return that directly. + completion(requestConfiguration.emulatorHostAndPort, nil); + return; + } + FIRGetProjectConfigRequest *request = + [[FIRGetProjectConfigRequest alloc] initWithRequestConfiguration:requestConfiguration]; + + [FIRAuthBackend + getProjectConfig:request + callback:^(FIRGetProjectConfigResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + completion(nil, error); + return; + } + // Look up an authorized domain ends with one of the supportedAuthDomains. + // The sequence of supportedAuthDomains matters. ("firebaseapp.com", "web.app") + // The searching ends once the first valid suportedAuthDomain is found. + NSString *authDomain; + for (NSString *domain in response.authorizedDomains) { + for (NSString *suportedAuthDomain in [self supportedAuthDomains]) { + NSInteger index = domain.length - suportedAuthDomain.length; + if (index >= 2) { + if ([domain hasSuffix:suportedAuthDomain] && + domain.length >= suportedAuthDomain.length + 2) { + authDomain = domain; + break; + } + } + } + if (authDomain != nil) { + break; + } + } + if (!authDomain.length) { + completion(nil, [FIRAuthErrorUtils + unexpectedErrorResponseWithDeserializedResponse:response]); + return; + } + completion(authDomain, nil); + }]; +} + +/** @fn queryItemValue:from: + @brief Utility function to get a value from a NSURLQueryItem array. + @param name The key. + @param queryList The NSURLQueryItem array. + @return The value for the key. + */ ++ (nullable NSString *)queryItemValue:(NSString *)name from:(NSArray *)queryList { + for (NSURLQueryItem *item in queryList) { + if ([item.name isEqualToString:name]) { + return item.value; + } + } + return nil; +} + ++ (NSDictionary *)dictionaryWithHttpArgumentsString:(NSString *)argString { + NSMutableDictionary *ret = [NSMutableDictionary dictionary]; + NSArray *components = [argString componentsSeparatedByString:@"&"]; + NSString *component; + // Use reverse order so that the first occurrence of a key replaces + // those subsequent. + for (component in [components reverseObjectEnumerator]) { + if (component.length == 0) continue; + NSRange pos = [component rangeOfString:@"="]; + NSString *key; + NSString *val; + if (pos.location == NSNotFound) { + key = [self stringByUnescapingFromURLArgument:component]; + val = @""; + } else { + key = [self stringByUnescapingFromURLArgument:[component substringToIndex:pos.location]]; + val = [self stringByUnescapingFromURLArgument:[component substringFromIndex:pos.location + + pos.length]]; + } + // returns nil on invalid UTF8 and NSMutableDictionary raises an exception when passed nil + // values. + if (!key) key = @""; + if (!val) val = @""; + [ret setObject:val forKey:key]; + } + return ret; +} + ++ (NSString *)stringByUnescapingFromURLArgument:(NSString *)argument { + NSMutableString *resultString = [NSMutableString stringWithString:argument]; + [resultString replaceOccurrencesOfString:@"+" + withString:@" " + options:NSLiteralSearch + range:NSMakeRange(0, [resultString length])]; + return [resultString stringByRemovingPercentEncoding]; +} + ++ (NSDictionary *)parseURL:(NSString *)urlString { + NSString *linkURL = [NSURLComponents componentsWithString:urlString].query; + if (!linkURL) { + return @{}; + } + NSArray *URLComponents = [linkURL componentsSeparatedByString:@"&"]; + NSMutableDictionary *queryItems = + [[NSMutableDictionary alloc] initWithCapacity:URLComponents.count]; + for (NSString *component in URLComponents) { + NSRange equalRange = [component rangeOfString:@"="]; + if (equalRange.location != NSNotFound) { + NSString *queryItemKey = + [[component substringToIndex:equalRange.location] stringByRemovingPercentEncoding]; + NSString *queryItemValue = + [[component substringFromIndex:equalRange.location + 1] stringByRemovingPercentEncoding]; + if (queryItemKey && queryItemValue) { + queryItems[queryItemKey] = queryItemValue; + } + } + } + return queryItems; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.h new file mode 100644 index 0000000..1a837c2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.h @@ -0,0 +1,44 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthWebView + @brief A class reponsible for creating a WKWebView for use within Firebase Auth. + */ +@interface FIRAuthWebView : UIView + +/** @property webView + * @brief The web view. + */ +@property(nonatomic, weak) WKWebView *webView; + +/** @property spinner + * @brief The spinner that indicates web view loading. + */ +@property(nonatomic, weak) UIActivityIndicatorView *spinner; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.m new file mode 100644 index 0000000..2ea8df8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.m @@ -0,0 +1,104 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebView.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthWebView + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor whiteColor]; + [self initializeSubviews]; + } + return self; +} + +/** @fn initializeSubviews + @brief Initializes the subviews of this view. + */ +- (void)initializeSubviews { + WKWebView *webView = [self createWebView]; + UIActivityIndicatorView *spinner = [self createSpinner]; + + // The order of the following controls z-order. + [self addSubview:webView]; + [self addSubview:spinner]; + + [self layoutSubviews]; + _webView = webView; + _spinner = spinner; +} + +- (void)layoutSubviews { + CGFloat height = self.bounds.size.height; + CGFloat width = self.bounds.size.width; + _webView.frame = CGRectMake(0, 0, width, height); + _spinner.center = _webView.center; +} + +/** @fn createWebView + @brief Creates a web view to be used by this view. + @return The newly created web view. + */ +- (WKWebView *)createWebView { + WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero]; + // Trickery to make the web view not do weird things (like showing a black background when + // the prompt in the navigation bar animates changes.) + webView.opaque = NO; + webView.backgroundColor = [UIColor clearColor]; + webView.scrollView.opaque = NO; + webView.scrollView.backgroundColor = [UIColor clearColor]; + webView.scrollView.bounces = NO; + webView.scrollView.alwaysBounceVertical = NO; + webView.scrollView.alwaysBounceHorizontal = NO; + return webView; +} + +/** @fn createSpinner + @brief Creates a spinner to be used by this view. + @return The newly created spinner. + */ +- (UIActivityIndicatorView *)createSpinner { + UIActivityIndicatorViewStyle spinnerStyle; +#if defined(TARGET_OS_MACCATALYST) + if (@available(iOS 13.0, *)) { + spinnerStyle = UIActivityIndicatorViewStyleMedium; + } else { +// iOS 13 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + spinnerStyle = UIActivityIndicatorViewStyleGray; +#pragma clang diagnostic pop + } +#else + spinnerStyle = UIActivityIndicatorViewStyleGray; +#endif + UIActivityIndicatorView *spinner = + [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:spinnerStyle]; + return spinner; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h new file mode 100644 index 0000000..2f01ed2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h @@ -0,0 +1,78 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import + +@class FIRAuthWebViewController; + +NS_ASSUME_NONNULL_BEGIN + +/** @protocol FIRAuthWebViewControllerDelegate + @brief Defines a delegate for FIRAuthWebViewController + */ +@protocol FIRAuthWebViewControllerDelegate + +/** @fn webViewController:canHandleURL: + @brief Determines if a URL should be handled by the delegate. + @param URL The URL to handle. + @return Whether the URL could be handled or not. + */ +- (BOOL)webViewController:(FIRAuthWebViewController *)webViewController canHandleURL:(NSURL *)URL; + +/** @fn webViewControllerDidCancel: + @brief Notifies the delegate that the web view controller is being cancelled by the user. + @param webViewController The web view controller in question. + */ +- (void)webViewControllerDidCancel:(FIRAuthWebViewController *)webViewController; + +/** @fn webViewController:didFailWithError: + @brief Notifies the delegate that the web view controller failed to load a page. + @param webViewController The web view controller in question. + @param error The error that has occurred. + */ +- (void)webViewController:(FIRAuthWebViewController *)webViewController + didFailWithError:(NSError *)error; + +@end + +/** @class FIRAuthWebViewController + @brief Reponsible for creating a UIViewController for presenting a FIRAutWebView. + */ +@interface FIRAuthWebViewController : UIViewController + +/** @fn initWithNibName:bundle: + * @brief Please call initWithURL:delegate: + */ +- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil + bundle:(nullable NSBundle *)nibBundleOrNil NS_UNAVAILABLE; + +/** @fn initWithCoder: + * @brief Please call initWithURL:delegate: + */ +- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE; + +- (instancetype)initWithURL:(NSURL *)URL + delegate:(__weak id)delegate + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.m new file mode 100644 index 0000000..acedd12 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.m @@ -0,0 +1,118 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebView.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthWebViewController () +@end + +@implementation FIRAuthWebViewController { + /** @var _URL + @brief The initial URL to display. + */ + NSURL *_URL; + + /** @var _delegate + @brief The delegate to call. + */ + __weak id _delegate; + + /** @var _webView; + @brief The web view instance for easier access. + */ + __weak FIRAuthWebView *_webView; +} + +- (instancetype)initWithURL:(NSURL *)URL + delegate:(__weak id)delegate { + self = [super initWithNibName:nil bundle:nil]; + if (self) { + _URL = URL; + _delegate = delegate; + } + return self; +} + +#pragma mark - Lifecycle + +- (void)loadView { + FIRAuthWebView *webView = [[FIRAuthWebView alloc] initWithFrame:[UIScreen mainScreen].bounds]; + webView.webView.navigationDelegate = self; + self.view = webView; + _webView = webView; + self.navigationItem.leftBarButtonItem = + [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(cancel)]; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + // Loads the requested URL in the web view. + [_webView.webView loadRequest:[NSURLRequest requestWithURL:_URL]]; +} + +#pragma mark - UI Targets + +- (void)cancel { + [_delegate webViewControllerDidCancel:self]; +} + +#pragma mark - WKNavigationDelegate + +- (void)webView:(WKWebView *)webView + decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction + decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { + [_delegate webViewController:self canHandleURL:navigationAction.request.URL]; + decisionHandler(WKNavigationActionPolicyAllow); +} + +- (void)webView:(WKWebView *)webView + didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation { + _webView.spinner.hidden = NO; + [_webView.spinner startAnimating]; +} + +- (void)webView:(WKWebView *)webView + didFinishNavigation:(null_unspecified WKNavigation *)navigation { + _webView.spinner.hidden = YES; + [_webView.spinner stopAnimating]; +} + +- (void)webView:(WKWebView *)webView + didFailNavigation:(null_unspecified WKNavigation *)navigation + withError:(NSError *)error { + if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) { + // It's okay for the page to be redirected before it is completely loaded. See b/32028062 . + return; + } + // Forward notification to our delegate. + [self webView:webView didFinishNavigation:navigation]; + [_delegate webViewController:self didFailWithError:error]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h new file mode 100644 index 0000000..114cbfd --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h @@ -0,0 +1,31 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface NSData (FIRBase64) + +/** @fn fir_base64URLEncodedStringWithOptions: + @brief Get a web safe base64 encoded string + @param options The base64 encoding options + */ +- (NSString *)fir_base64URLEncodedStringWithOptions:(NSDataBase64EncodingOptions)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.m b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.m new file mode 100644 index 0000000..0afc53b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation NSData (FIRBase64) + +- (NSString *)fir_base64URLEncodedStringWithOptions:(NSDataBase64EncodingOptions)options { + NSString *string = [self base64EncodedStringWithOptions:options]; + string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"_"]; + string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"-"]; + string = [string stringByReplacingOccurrencesOfString:@"=" withString:@""]; + return string; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRAppInternal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRAppInternal.h new file mode 100644 index 0000000..6c7d723 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRAppInternal.h @@ -0,0 +1,153 @@ +/* + * 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 + +@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; +extern NSString *const kFirebaseCoreErrorDomain; + +/** The NSUserDefaults suite name for FirebaseCore, for those storage locations that use it. */ +extern NSString *const kFirebaseCoreDefaultsSuiteName; + +/** + * 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; + +/** @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; + +/** + * 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 to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * 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/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRComponent.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRComponent.h new file mode 100644 index 0000000..cb51ee7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/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 + +@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 *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 *)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/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRComponentContainer.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRComponentContainer.h new file mode 100644 index 0000000..af18a93 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRComponentContainer.h @@ -0,0 +1,41 @@ +/* + * 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 + +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> 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/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRComponentType.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRComponentType.h new file mode 100644 index 0000000..6f2aca7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/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 + +@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/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h new file mode 100644 index 0000000..76c0c05 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/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 + +@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/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRDependency.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRDependency.h new file mode 100644 index 0000000..46e9b7e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/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 + +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/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h new file mode 100644 index 0000000..9f94256 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/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 + +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 required 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/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRLibrary.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRLibrary.h new file mode 100644 index 0000000..9575e94 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * 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 + +@class FIRApp; +@class FIRComponent; + +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 *)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/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRLogger.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRLogger.h new file mode 100644 index 0000000..b6242ff --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIRLogger.h @@ -0,0 +1,146 @@ +/* + * 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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern FIRLoggerService kFIRLoggerAnalytics; +extern FIRLoggerService kFIRLoggerCrash; +extern FIRLoggerService kFIRLoggerCore; +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/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIROptionsInternal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIROptionsInternal.h new file mode 100644 index 0000000..8efc5fc --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FIROptionsInternal.h @@ -0,0 +1,115 @@ +/* + * 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 + +/** + * 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 + NS_DESIGNATED_INITIALIZER; + +/** + * 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/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FirebaseCoreInternal.h b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FirebaseCoreInternal.h new file mode 100644 index 0000000..88d012b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/FirebaseCore/Sources/Private/FirebaseCoreInternal.h @@ -0,0 +1,28 @@ +// 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. + +#import + +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRComponent.h" +#import "FirebaseCore/Sources/Private/FIRComponentContainer.h" +#import "FirebaseCore/Sources/Private/FIRComponentType.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/saraWhatsUp/Pods/FirebaseAuth/Interop/Auth/Public/FIRAuthInterop.h b/saraWhatsUp/Pods/FirebaseAuth/Interop/Auth/Public/FIRAuthInterop.h new file mode 100644 index 0000000..a33da7c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/Interop/Auth/Public/FIRAuthInterop.h @@ -0,0 +1,44 @@ +/* + * 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 FIRAuthInterop_h +#define FIRAuthInterop_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRTokenCallback + @brief The type of block which gets called when a token is ready. + */ +typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable error) + NS_SWIFT_NAME(TokenCallback); + +/// Common methods for Auth interoperability. +NS_SWIFT_NAME(AuthInterop) +@protocol FIRAuthInterop + +/// Retrieves the Firebase authentication token, possibly refreshing it if it has expired. +- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(FIRTokenCallback)callback; + +/// Get the current Auth user's UID. Returns nil if there is no user signed in. +- (nullable NSString *)getUserID; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRAuthInterop_h */ diff --git a/saraWhatsUp/Pods/FirebaseAuth/LICENSE b/saraWhatsUp/Pods/FirebaseAuth/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/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/saraWhatsUp/Pods/FirebaseAuth/README.md b/saraWhatsUp/Pods/FirebaseAuth/README.md new file mode 100644 index 0000000..7be298d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseAuth/README.md @@ -0,0 +1,319 @@ +[![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-appcheck-badge]][gh-actions] +[![Actions Status][gh-appdistribution-badge]][gh-actions] +[![Actions Status][gh-auth-badge]][gh-actions] +[![Actions Status][gh-cocoapods-integration-badge]][gh-actions] +[![Actions Status][gh-core-badge]][gh-actions] +[![Actions Status][gh-core-diagnostics-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-google-utilities-badge]][gh-actions] +[![Actions Status][gh-google-utilities-components-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-mlmodeldownloader-badge]][gh-actions] +[![Actions Status][gh-performance-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] + +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics +and FirebaseML. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. +1. [Standard pod install](README.md#standard-pod-install) +1. [Swift Package Manager](SwiftPackageManager.md) +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). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager.md](SwiftPackageManager.md). + +### Installing from GitHub + +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: +```ruby +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: + +```ruby +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). + +### 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 12.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +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 + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### 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/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@13 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. 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. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md). + +## 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 Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### 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. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduces official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on 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 watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are 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-appcheck-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/app_check/badge.svg +[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg +[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg +[gh-cocoapods-integration-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/cocoapods-integration/badge.svg +[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg +[gh-core-diagnostics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core-diagnostics/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-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg +[gh-google-utilities-components-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities-components/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-mlmodeldownloader-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/mlmodeldownloader/badge.svg +[gh-performance-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/performance/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 diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h new file mode 100644 index 0000000..6429ac7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h @@ -0,0 +1,56 @@ +/* + * 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 + +/// Values stored in analyticsEnabledState. Never alter these constants since they must match with +/// values persisted to disk. +typedef NS_ENUM(int64_t, FIRAnalyticsEnabledState) { + // 0 is the default value for keys not found stored in persisted config, so it cannot represent + // kFIRAnalyticsEnabledStateSetNo. It must represent kFIRAnalyticsEnabledStateNotSet. + kFIRAnalyticsEnabledStateNotSet = 0, + kFIRAnalyticsEnabledStateSetYes = 1, + kFIRAnalyticsEnabledStateSetNo = 2, +}; + +/// The user defaults key for the persisted measurementEnabledState value. FIRAPersistedConfig reads +/// measurementEnabledState using this same key. +static NSString *const kFIRAPersistedConfigMeasurementEnabledStateKey = + @"/google/measurement/measurement_enabled_state"; + +static NSString *const kFIRAnalyticsConfigurationSetEnabledNotification = + @"FIRAnalyticsConfigurationSetEnabledNotification"; +static NSString *const kFIRAnalyticsConfigurationSetMinimumSessionIntervalNotification = + @"FIRAnalyticsConfigurationSetMinimumSessionIntervalNotification"; +static NSString *const kFIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification = + @"FIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification"; + +@interface FIRAnalyticsConfiguration : NSObject + +/// Returns the shared instance of FIRAnalyticsConfiguration. ++ (FIRAnalyticsConfiguration *)sharedInstance; + +// Sets whether analytics collection is enabled for this app on this device. This setting is +// persisted across app sessions. By default it is enabled. +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets whether analytics collection is enabled for this app on this device, and a flag to persist +/// the value or not. The setting should not be persisted if being set by the global data collection +/// flag. +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled + persistSetting:(BOOL)shouldPersist; + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m new file mode 100644 index 0000000..07c786c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m @@ -0,0 +1,62 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +@implementation FIRAnalyticsConfiguration +#pragma clang diagnostic pop + ++ (FIRAnalyticsConfiguration *)sharedInstance { + static FIRAnalyticsConfiguration *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRAnalyticsConfiguration alloc] init]; + }); + return sharedInstance; +} + +- (void)postNotificationName:(NSString *)name value:(id)value { + if (!name.length || !value) { + return; + } + [[NSNotificationCenter defaultCenter] postNotificationName:name + object:self + userInfo:@{name : value}]; +} + +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled { + [self setAnalyticsCollectionEnabled:analyticsCollectionEnabled persistSetting:YES]; +} + +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled + persistSetting:(BOOL)shouldPersist { + // Persist the measurementEnabledState. Use FIRAnalyticsEnabledState values instead of YES/NO. + FIRAnalyticsEnabledState analyticsEnabledState = + analyticsCollectionEnabled ? kFIRAnalyticsEnabledStateSetYes : kFIRAnalyticsEnabledStateSetNo; + if (shouldPersist) { + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + [userDefaults setObject:@(analyticsEnabledState) + forKey:kFIRAPersistedConfigMeasurementEnabledStateKey]; + [userDefaults synchronize]; + } + + [self postNotificationName:kFIRAnalyticsConfigurationSetEnabledNotification + value:@(analyticsCollectionEnabled)]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m new file mode 100644 index 0000000..05660ac --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m @@ -0,0 +1,856 @@ +// 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. + +#include + +#if __has_include() +#import +#endif + +#if __has_include() +#import +#endif + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h" + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" +#import "FirebaseCore/Sources/FIRBundleUtil.h" +#import "FirebaseCore/Sources/FIRComponentContainerInternal.h" +#import "FirebaseCore/Sources/FIRConfigurationInternal.h" +#import "FirebaseCore/Sources/FIRFirebaseUserAgent.h" + +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h" +#import "FirebaseCore/Sources/Private/FIRLibrary.h" +#import "FirebaseCore/Sources/Private/FIRLogger.h" +#import "FirebaseCore/Sources/Private/FIROptionsInternal.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +#import + +#import + +// The kFIRService strings are only here while transitioning CoreDiagnostics from the Analytics +// pod to a Core dependency. These symbols are not used and should be deleted after the transition. +NSString *const kFIRServiceAdMob; +NSString *const kFIRServiceAuth; +NSString *const kFIRServiceAuthUI; +NSString *const kFIRServiceCrash; +NSString *const kFIRServiceDatabase; +NSString *const kFIRServiceDynamicLinks; +NSString *const kFIRServiceFirestore; +NSString *const kFIRServiceFunctions; +NSString *const kFIRServiceInstanceID; +NSString *const kFIRServiceInvites; +NSString *const kFIRServiceMessaging; +NSString *const kFIRServiceMeasurement; +NSString *const kFIRServicePerformance; +NSString *const kFIRServiceRemoteConfig; +NSString *const kFIRServiceStorage; +NSString *const kGGLServiceAnalytics; +NSString *const kGGLServiceSignIn; + +NSString *const kFIRDefaultAppName = @"__FIRAPP_DEFAULT"; +NSString *const kFIRAppReadyToConfigureSDKNotification = @"FIRAppReadyToConfigureSDKNotification"; +NSString *const kFIRAppDeleteNotification = @"FIRAppDeleteNotification"; +NSString *const kFIRAppIsDefaultAppKey = @"FIRAppIsDefaultAppKey"; +NSString *const kFIRAppNameKey = @"FIRAppNameKey"; +NSString *const kFIRGoogleAppIDKey = @"FIRGoogleAppIDKey"; + +NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat = + @"/google/firebase/global_data_collection_enabled:%@"; +NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey = + @"FirebaseDataCollectionDefaultEnabled"; + +NSString *const kFIRAppDiagnosticsConfigurationTypeKey = @"ConfigType"; +NSString *const kFIRAppDiagnosticsErrorKey = @"Error"; +NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRApp"; +NSString *const kFIRAppDiagnosticsSDKNameKey = @"SDKName"; +NSString *const kFIRAppDiagnosticsSDKVersionKey = @"SDKVersion"; +NSString *const kFIRAppDiagnosticsApplePlatformPrefix = @"apple-platform"; + +// Auth internal notification notification and key. +NSString *const FIRAuthStateDidChangeInternalNotification = + @"FIRAuthStateDidChangeInternalNotification"; +NSString *const FIRAuthStateDidChangeInternalNotificationAppKey = + @"FIRAuthStateDidChangeInternalNotificationAppKey"; +NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey = + @"FIRAuthStateDidChangeInternalNotificationTokenKey"; +NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey = + @"FIRAuthStateDidChangeInternalNotificationUIDKey"; + +/** + * Error domain for exceptions and NSError construction. + */ +NSString *const kFirebaseCoreErrorDomain = @"com.firebase.core"; + +/** The NSUserDefaults suite name for FirebaseCore, for those storage locations that use it. */ +NSString *const kFirebaseCoreDefaultsSuiteName = @"com.firebase.core"; + +/** + * The URL to download plist files. + */ +static NSString *const kPlistURL = @"https://console.firebase.google.com/"; + +/** + * An array of all classes that registered as `FIRCoreConfigurable` in order to receive lifecycle + * events from Core. + */ +static NSMutableArray> *sRegisteredAsConfigurable; + +@interface FIRApp () + +#ifdef DEBUG +@property(nonatomic) BOOL alreadyOutputDataCollectionFlag; +#endif // DEBUG + +@end + +@implementation FIRApp + +// This is necessary since our custom getter prevents `_options` from being created. +@synthesize options = _options; + +static NSMutableDictionary *sAllApps; +static FIRApp *sDefaultApp; + ++ (void)configure { + FIROptions *options = [FIROptions defaultOptions]; + if (!options) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"`FirebaseApp.configure()` could not find " + @"a valid GoogleService-Info.plist in your project. Please download one " + @"from %@.", + kPlistURL]; + } + [FIRApp configureWithOptions:options]; +} + ++ (void)configureWithOptions:(FIROptions *)options { + if (!options) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Options is nil. Please pass a valid options."]; + } + [FIRApp configureWithName:kFIRDefaultAppName options:options]; +} + ++ (NSCharacterSet *)applicationNameAllowedCharacters { + static NSCharacterSet *applicationNameAllowedCharacters; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSMutableCharacterSet *allowedNameCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedNameCharacters addCharactersInString:@"-_"]; + applicationNameAllowedCharacters = [allowedNameCharacters copy]; + }); + return applicationNameAllowedCharacters; +} + ++ (void)configureWithName:(NSString *)name options:(FIROptions *)options { + if (!name || !options) { + [NSException raise:kFirebaseCoreErrorDomain format:@"Neither name nor options can be nil."]; + } + if (name.length == 0) { + [NSException raise:kFirebaseCoreErrorDomain format:@"Name cannot be empty."]; + } + + if ([name isEqualToString:kFIRDefaultAppName]) { + if (sDefaultApp) { + // The default app already exists. Handle duplicate `configure` calls and return. + [self appWasConfiguredTwice:sDefaultApp usingOptions:options]; + return; + } + + FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configuring the default app."); + } else { + // Validate the app name and ensure it hasn't been configured already. + NSCharacterSet *nameCharacters = [NSCharacterSet characterSetWithCharactersInString:name]; + + if (![[self applicationNameAllowedCharacters] isSupersetOfSet:nameCharacters]) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App name can only contain alphanumeric, " + @"hyphen (-), and underscore (_) characters"]; + } + + @synchronized(self) { + if (sAllApps && sAllApps[name]) { + // The app already exists. Handle a duplicate `configure` call and return. + [self appWasConfiguredTwice:sAllApps[name] usingOptions:options]; + return; + } + } + + FIRLogDebug(kFIRLoggerCore, @"I-COR000002", @"Configuring app named %@", name); + } + + @synchronized(self) { + FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; + if (app.isDefaultApp) { + sDefaultApp = app; + } + + [FIRApp addAppToAppDictionary:app]; + + // The FIRApp instance is ready to go, `sDefaultApp` is assigned, other SDKs are now ready to be + // instantiated. + [app.container instantiateEagerComponents]; + [FIRApp sendNotificationsToSDKs:app]; + } +} + +/// Called when `configure` has been called multiple times for the same app. This can either throw +/// an exception (most cases) or ignore the duplicate configuration in situations where it's allowed +/// like an extension. ++ (void)appWasConfiguredTwice:(FIRApp *)app usingOptions:(FIROptions *)options { + // Only extensions should potentially be able to call `configure` more than once. + if (![GULAppEnvironmentUtil isAppExtension]) { + // Throw an exception since this is now an invalid state. + if (app.isDefaultApp) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Default app has already been configured."]; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App named %@ has already been configured.", app.name]; + } + } + + // In an extension, the entry point could be called multiple times. As long as the options are + // identical we should allow multiple `configure` calls. + if ([options isEqual:app.options]) { + // Everything is identical but the extension's lifecycle triggered `configure` twice. + // Ignore duplicate calls and return since everything should still be in a valid state. + FIRLogDebug(kFIRLoggerCore, @"I-COR000035", + @"Ignoring second `configure` call in an extension."); + return; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App named %@ has already been configured.", app.name]; + } +} + ++ (FIRApp *)defaultApp { + if (sDefaultApp) { + return sDefaultApp; + } + FIRLogError(kFIRLoggerCore, @"I-COR000003", + @"The default Firebase app has not yet been " + @"configured. Add `FirebaseApp.configure()` to your " + @"application initialization. This can be done in " + @"in the App Delegate's application(_:didFinishLaunchingWithOptions:)` " + @"(or the `@main` struct's initializer in SwiftUI). " + @"Read more: https://goo.gl/ctyzm8."); + return nil; +} + ++ (FIRApp *)appNamed:(NSString *)name { + @synchronized(self) { + if (sAllApps) { + FIRApp *app = sAllApps[name]; + if (app) { + return app; + } + } + FIRLogError(kFIRLoggerCore, @"I-COR000004", @"App with name %@ does not exist.", name); + return nil; + } +} + ++ (NSDictionary *)allApps { + @synchronized(self) { + if (!sAllApps) { + FIRLogError(kFIRLoggerCore, @"I-COR000005", @"No app has been configured yet."); + } + return [sAllApps copy]; + } +} + +// Public only for tests ++ (void)resetApps { + @synchronized(self) { + sDefaultApp = nil; + [sAllApps removeAllObjects]; + sAllApps = nil; + [[self userAgent] reset]; + } +} + +- (void)deleteApp:(FIRAppVoidBoolCallback)completion { + @synchronized([self class]) { + if (sAllApps && sAllApps[self.name]) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000006", @"Deleting app named %@", self.name); + + // Remove all registered libraries from the container to avoid creating new instances. + [self.container removeAllComponents]; + // Remove all cached instances from the container before deleting the app. + [self.container removeAllCachedInstances]; + + [sAllApps removeObjectForKey:self.name]; + [self clearDataCollectionSwitchFromUserDefaults]; + if ([self.name isEqualToString:kFIRDefaultAppName]) { + sDefaultApp = nil; + } + NSDictionary *appInfoDict = @{kFIRAppNameKey : self.name}; + [[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppDeleteNotification + object:[self class] + userInfo:appInfoDict]; + completion(YES); + } else { + FIRLogError(kFIRLoggerCore, @"I-COR000007", @"App does not exist."); + completion(NO); + } + } +} + ++ (void)addAppToAppDictionary:(FIRApp *)app { + if (!sAllApps) { + sAllApps = [NSMutableDictionary dictionary]; + } + if ([app configureCore]) { + sAllApps[app.name] = app; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Configuration fails. It may be caused by an invalid GOOGLE_APP_ID in " + @"GoogleService-Info.plist or set in the customized options."]; + } +} + +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options { + self = [super init]; + if (self) { + _name = [name copy]; + _options = [options copy]; + _options.editingLocked = YES; + _isDefaultApp = [name isEqualToString:kFIRDefaultAppName]; + _container = [[FIRComponentContainer alloc] initWithApp:self]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (BOOL)configureCore { + [self checkExpectedBundleID]; + if (![self isAppIDValid]) { + return NO; + } + + // Initialize the Analytics once there is a valid options under default app. Analytics should + // always initialize first by itself before the other SDKs. + if ([self.name isEqualToString:kFIRDefaultAppName]) { + Class firAnalyticsClass = NSClassFromString(@"FIRAnalytics"); + if (firAnalyticsClass) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" + SEL startWithConfigurationSelector = @selector(startWithConfiguration:options:); +#pragma clang diagnostic pop + if ([firAnalyticsClass respondsToSelector:startWithConfigurationSelector]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [firAnalyticsClass performSelector:startWithConfigurationSelector + withObject:[FIRConfiguration sharedInstance].analyticsConfiguration + withObject:_options]; +#pragma clang diagnostic pop + } + } + } + + [self subscribeForAppDidBecomeActiveNotifications]; + + return YES; +} + +- (FIROptions *)options { + return [_options copy]; +} + +- (void)setDataCollectionDefaultEnabled:(BOOL)dataCollectionDefaultEnabled { +#ifdef DEBUG + FIRLogDebug(kFIRLoggerCore, @"I-COR000034", @"Explicitly %@ data collection flag.", + dataCollectionDefaultEnabled ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; +#endif // DEBUG + + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, self.name]; + [[NSUserDefaults standardUserDefaults] setBool:dataCollectionDefaultEnabled forKey:key]; + + // Core also controls the FirebaseAnalytics flag, so check if the Analytics flags are set + // within FIROptions and change the Analytics value if necessary. Analytics only works with the + // default app, so return if this isn't the default app. + if (!self.isDefaultApp) { + return; + } + + // Check if the Analytics flag is explicitly set. If so, no further actions are necessary. + if ([self.options isAnalyticsCollectionExplicitlySet]) { + return; + } + + // The Analytics flag has not been explicitly set, so update with the value being set. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[FIRAnalyticsConfiguration sharedInstance] + setAnalyticsCollectionEnabled:dataCollectionDefaultEnabled + persistSetting:NO]; +#pragma clang diagnostic pop +} + +- (BOOL)isDataCollectionDefaultEnabled { + // Check if it's been manually set before in code, and use that as the higher priority value. + NSNumber *defaultsObject = [[self class] readDataCollectionSwitchFromUserDefaultsForApp:self]; + if (defaultsObject != nil) { +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000031", @"Data Collection flag is %@ in user defaults.", + [defaultsObject boolValue] ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return [defaultsObject boolValue]; + } + + // Read the Info.plist to see if the flag is set. If it's not set, it should default to `YES`. + // As per the implementation of `readDataCollectionSwitchFromPlist`, it's a cached value and has + // no performance impact calling multiple times. + NSNumber *collectionEnabledPlistValue = [[self class] readDataCollectionSwitchFromPlist]; + if (collectionEnabledPlistValue != nil) { +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000032", @"Data Collection flag is %@ in plist.", + [collectionEnabledPlistValue boolValue] ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return [collectionEnabledPlistValue boolValue]; + } + +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000033", @"Data Collection flag is not set."); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return YES; +} + +#pragma mark - private + ++ (void)sendNotificationsToSDKs:(FIRApp *)app { + // TODO: Remove this notification once all SDKs are registered with `FIRCoreConfigurable`. + NSNumber *isDefaultApp = [NSNumber numberWithBool:app.isDefaultApp]; + NSDictionary *appInfoDict = @{ + kFIRAppNameKey : app.name, + kFIRAppIsDefaultAppKey : isDefaultApp, + kFIRGoogleAppIDKey : app.options.googleAppID + }; + [[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppReadyToConfigureSDKNotification + object:self + userInfo:appInfoDict]; + + // This is the new way of sending information to SDKs. + // TODO: Do we want this on a background thread, maybe? + @synchronized(self) { + for (Class library in sRegisteredAsConfigurable) { + [library configureWithApp:app]; + } + } +} + ++ (NSError *)errorForMissingOptions { + NSDictionary *errorDict = @{ + NSLocalizedDescriptionKey : + @"Unable to parse GoogleService-Info.plist in order to configure services.", + NSLocalizedRecoverySuggestionErrorKey : + @"Check formatting and location of GoogleService-Info.plist." + }; + return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-100 userInfo:errorDict]; +} + ++ (NSError *)errorForInvalidAppID { + NSDictionary *errorDict = @{ + NSLocalizedDescriptionKey : @"Unable to validate Google App ID", + NSLocalizedRecoverySuggestionErrorKey : + @"Check formatting and location of GoogleService-Info.plist or GoogleAppID set in the " + @"customized options." + }; + return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-101 userInfo:errorDict]; +} + ++ (BOOL)isDefaultAppConfigured { + return (sDefaultApp != nil); +} + ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version { + // Create the set of characters which aren't allowed, only if this feature is used. + NSMutableCharacterSet *allowedSet = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedSet addCharactersInString:@"-_."]; + NSCharacterSet *disallowedSet = [allowedSet invertedSet]; + // Make sure the library name and version strings do not contain unexpected characters, and + // add the name/version pair to the dictionary. + if ([name rangeOfCharacterFromSet:disallowedSet].location == NSNotFound && + [version rangeOfCharacterFromSet:disallowedSet].location == NSNotFound) { + [[self userAgent] setValue:version forComponent:name]; + } else { + FIRLogError(kFIRLoggerCore, @"I-COR000027", + @"The library name (%@) or version number (%@) contain invalid characters. " + @"Only alphanumeric, dash, underscore and period characters are allowed.", + name, version); + } +} + ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name { + [self registerInternalLibrary:library withName:name withVersion:FIRFirebaseVersion()]; +} + ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version { + // This is called at +load time, keep the work to a minimum. + + // Ensure the class given conforms to the proper protocol. + if (![(Class)library conformsToProtocol:@protocol(FIRLibrary)] || + ![(Class)library respondsToSelector:@selector(componentsToRegister)]) { + [NSException raise:NSInvalidArgumentException + format:@"Class %@ attempted to register components, but it does not conform to " + @"`FIRLibrary or provide a `componentsToRegister:` method.", + library]; + } + + [FIRComponentContainer registerAsComponentRegistrant:library]; + if ([(Class)library respondsToSelector:@selector(configureWithApp:)]) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sRegisteredAsConfigurable = [[NSMutableArray alloc] init]; + }); + @synchronized(self) { + [sRegisteredAsConfigurable addObject:library]; + } + } + [self registerLibrary:name withVersion:version]; +} + ++ (FIRFirebaseUserAgent *)userAgent { + static dispatch_once_t onceToken; + static FIRFirebaseUserAgent *_userAgent; + dispatch_once(&onceToken, ^{ + _userAgent = [[FIRFirebaseUserAgent alloc] init]; + [_userAgent setValue:FIRFirebaseVersion() forComponent:@"fire-ios"]; + }); + return _userAgent; +} + ++ (NSString *)firebaseUserAgent { + return [[self userAgent] firebaseUserAgent]; +} + +- (void)checkExpectedBundleID { + NSArray *bundles = [FIRBundleUtil relevantBundles]; + NSString *expectedBundleID = [self expectedBundleID]; + // The checking is only done when the bundle ID is provided in the serviceInfo dictionary for + // backward compatibility. + if (expectedBundleID != nil && ![FIRBundleUtil hasBundleIdentifierPrefix:expectedBundleID + inBundles:bundles]) { + FIRLogError(kFIRLoggerCore, @"I-COR000008", + @"The project's Bundle ID is inconsistent with " + @"either the Bundle ID in '%@.%@', or the Bundle ID in the options if you are " + @"using a customized options. To ensure that everything can be configured " + @"correctly, you may need to make the Bundle IDs consistent. To continue with this " + @"plist file, you may change your app's bundle identifier to '%@'. Or you can " + @"download a new configuration file that matches your bundle identifier from %@ " + @"and replace the current one.", + kServiceInfoFileName, kServiceInfoFileType, expectedBundleID, kPlistURL); + } +} + +#pragma mark - private - App ID Validation + +/** + * Validates the format and fingerprint of the app ID contained in GOOGLE_APP_ID in the plist file. + * This is the main method for validating app ID. + * + * @return YES if the app ID fulfills the expected format and fingerprint, NO otherwise. + */ +- (BOOL)isAppIDValid { + NSString *appID = _options.googleAppID; + BOOL isValid = [FIRApp validateAppID:appID]; + if (!isValid) { + NSString *expectedBundleID = [self expectedBundleID]; + FIRLogError(kFIRLoggerCore, @"I-COR000009", + @"The GOOGLE_APP_ID either in the plist file " + @"'%@.%@' or the one set in the customized options is invalid. If you are using " + @"the plist file, use the iOS version of bundle identifier to download the file, " + @"and do not manually edit the GOOGLE_APP_ID. You may change your app's bundle " + @"identifier to '%@'. Or you can download a new configuration file that matches " + @"your bundle identifier from %@ and replace the current one.", + kServiceInfoFileName, kServiceInfoFileType, expectedBundleID, kPlistURL); + }; + return isValid; +} + ++ (BOOL)validateAppID:(NSString *)appID { + // Failing validation only occurs when we are sure we are looking at a V2 app ID and it does not + // have a valid fingerprint, otherwise we just warn about the potential issue. + if (!appID.length) { + return NO; + } + + NSScanner *stringScanner = [NSScanner scannerWithString:appID]; + stringScanner.charactersToBeSkipped = nil; + + NSString *appIDVersion; + if (![stringScanner scanCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] + intoString:&appIDVersion]) { + return NO; + } + + if (![stringScanner scanString:@":" intoString:NULL]) { + // appIDVersion must be separated by ":" + return NO; + } + + NSArray *knownVersions = @[ @"1" ]; + if (![knownVersions containsObject:appIDVersion]) { + // Permit unknown yet properly formatted app ID versions. + FIRLogInfo(kFIRLoggerCore, @"I-COR000010", @"Unknown GOOGLE_APP_ID version: %@", appIDVersion); + return YES; + } + + if (![self validateAppIDFormat:appID withVersion:appIDVersion]) { + return NO; + } + + if (![self validateAppIDFingerprint:appID withVersion:appIDVersion]) { + return NO; + } + + return YES; +} + ++ (NSString *)actualBundleID { + return [[NSBundle mainBundle] bundleIdentifier]; +} + +/** + * Validates that the format of the app ID string is what is expected based on the supplied version. + * The version must end in ":". + * + * For v1 app ids the format is expected to be + * '::ios:'. + * + * This method does not verify that the contents of the app id are correct, just that they fulfill + * the expected format. + * + * @param appID Contents of GOOGLE_APP_ID from the plist file. + * @param version Indicates what version of the app id format this string should be. + * @return YES if provided string fufills the expected format, NO otherwise. + */ ++ (BOOL)validateAppIDFormat:(NSString *)appID withVersion:(NSString *)version { + if (!appID.length || !version.length) { + return NO; + } + + NSScanner *stringScanner = [NSScanner scannerWithString:appID]; + stringScanner.charactersToBeSkipped = nil; + + // Skip version part + // '**::ios:' + if (![stringScanner scanString:version intoString:NULL]) { + // The version part is missing or mismatched + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '*:*:ios:' + if (![stringScanner scanString:@":" intoString:NULL]) { + // appIDVersion must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // ':**:ios:'. + NSInteger projectNumber = NSNotFound; + if (![stringScanner scanInteger:&projectNumber]) { + // NO project number found. + return NO; + } + + // Validate version part (see part between '*' symbols below) + // ':*:*ios:'. + if (![stringScanner scanString:@":" intoString:NULL]) { + // The project number must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::*ios*:'. + NSString *platform; + if (![stringScanner scanUpToString:@":" intoString:&platform]) { + return NO; + } + + if (![platform isEqualToString:@"ios"]) { + // The platform must be @"ios" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::ios*:*'. + if (![stringScanner scanString:@":" intoString:NULL]) { + // The platform must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::ios:**'. + unsigned long long fingerprint = NSNotFound; + if (![stringScanner scanHexLongLong:&fingerprint]) { + // Fingerprint part is missing + return NO; + } + + if (!stringScanner.isAtEnd) { + // There are not allowed characters in the fingerprint part + return NO; + } + + return YES; +} + +/** + * Validates that the fingerprint of the app ID string is what is expected based on the supplied + * version. + * + * Note that the v1 hash algorithm is not permitted on the client and cannot be fully validated. + * + * @param appID Contents of GOOGLE_APP_ID from the plist file. + * @param version Indicates what version of the app id format this string should be. + * @return YES if provided string fufills the expected fingerprint and the version is known, NO + * otherwise. + */ ++ (BOOL)validateAppIDFingerprint:(NSString *)appID withVersion:(NSString *)version { + // Extract the supplied fingerprint from the supplied app ID. + // This assumes the app ID format is the same for all known versions below. If the app ID format + // changes in future versions, the tokenizing of the app ID format will need to take into account + // the version of the app ID. + NSArray *components = [appID componentsSeparatedByString:@":"]; + if (components.count != 4) { + return NO; + } + + NSString *suppliedFingerprintString = components[3]; + if (!suppliedFingerprintString.length) { + return NO; + } + + uint64_t suppliedFingerprint; + NSScanner *scanner = [NSScanner scannerWithString:suppliedFingerprintString]; + if (![scanner scanHexLongLong:&suppliedFingerprint]) { + return NO; + } + + if ([version isEqual:@"1"]) { + // The v1 hash algorithm is not permitted on the client so the actual hash cannot be validated. + return YES; + } + + // Unknown version. + return NO; +} + +- (NSString *)expectedBundleID { + return _options.bundleID; +} + +// end App ID validation + +#pragma mark - Reading From Plist & User Defaults + +/** + * Clears the data collection switch from the standard NSUserDefaults for easier testing and + * readability. + */ +- (void)clearDataCollectionSwitchFromUserDefaults { + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, self.name]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:key]; +} + +/** + * Reads the data collection switch from the standard NSUserDefaults for easier testing and + * readability. + */ ++ (nullable NSNumber *)readDataCollectionSwitchFromUserDefaultsForApp:(FIRApp *)app { + // Read the object in user defaults, and only return if it's an NSNumber. + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, app.name]; + id collectionEnabledDefaultsObject = [[NSUserDefaults standardUserDefaults] objectForKey:key]; + if ([collectionEnabledDefaultsObject isKindOfClass:[NSNumber class]]) { + return collectionEnabledDefaultsObject; + } + + return nil; +} + +/** + * Reads the data collection switch from the Info.plist for easier testing and readability. Will + * only read once from the plist and return the cached value. + */ ++ (nullable NSNumber *)readDataCollectionSwitchFromPlist { + static NSNumber *collectionEnabledPlistObject; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Read the data from the `Info.plist`, only assign it if it's there and an NSNumber. + id plistValue = [[NSBundle mainBundle] + objectForInfoDictionaryKey:kFIRGlobalAppDataCollectionEnabledPlistKey]; + if (plistValue && [plistValue isKindOfClass:[NSNumber class]]) { + collectionEnabledPlistObject = (NSNumber *)plistValue; + } + }); + + return collectionEnabledPlistObject; +} + +#pragma mark - App Life Cycle + +- (void)subscribeForAppDidBecomeActiveNotifications { +#if TARGET_OS_IOS || TARGET_OS_TV + NSNotificationName notificationName = UIApplicationDidBecomeActiveNotification; +#elif TARGET_OS_OSX + NSNotificationName notificationName = NSApplicationDidBecomeActiveNotification; +#endif + +#if !TARGET_OS_WATCH + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appDidBecomeActive:) + name:notificationName + object:nil]; +#endif +} + +- (void)appDidBecomeActive:(NSNotification *)notification { + [self logCoreTelemetryIfEnabled]; +} + +- (void)logCoreTelemetryIfEnabled { + if ([self isDataCollectionDefaultEnabled]) { + dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{ + [FIRCoreDiagnosticsConnector logCoreTelemetryWithOptions:[self options]]; + }); + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.h new file mode 100644 index 0000000..3fc69c6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.h @@ -0,0 +1,49 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +// TODO: Remove this once Auth moves over to Core's instance registration system. +/** @class FIRAppAssociationRegistration + @brief Manages object associations as a singleton-dependent: At most one object is + registered for any given host/key pair, and the object shall be created on-the-fly when + asked for. + */ +@interface FIRAppAssociationRegistration : NSObject + +/** @fn registeredObjectWithHost:key:creationBlock: + @brief Retrieves the registered object with a particular host and key. + @param host The host object. + @param key The key to specify the registered object on the host. + @param creationBlock The block to return the object to be registered if not already. + The block is executed immediately before this method returns if it is executed at all. + It can also be executed multiple times across different method invocations if previous + execution of the block returns @c nil. + @return The registered object for the host/key pair, or @c nil if no object is registered + and @c creationBlock returns @c nil. + @remarks The method is thread-safe but non-reentrant in the sense that attempting to call this + method again within the @c creationBlock with the same host/key pair raises an exception. + The registered object is retained by the host. + */ ++ (nullable ObjectType)registeredObjectWithHost:(id)host + key:(NSString *)key + creationBlock:(ObjectType _Nullable (^)(void))creationBlock; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.m new file mode 100644 index 0000000..f3f812c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.m @@ -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 "FirebaseCore/Sources/FIRAppAssociationRegistration.h" + +#import + +@implementation FIRAppAssociationRegistration + ++ (nullable id)registeredObjectWithHost:(id)host + key:(NSString *)key + creationBlock:(id _Nullable (^)(void))creationBlock { + @synchronized(self) { + SEL dictKey = @selector(registeredObjectWithHost:key:creationBlock:); + NSMutableDictionary *objectsByKey = objc_getAssociatedObject(host, dictKey); + if (!objectsByKey) { + objectsByKey = [[NSMutableDictionary alloc] init]; + objc_setAssociatedObject(host, dictKey, objectsByKey, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + id obj = objectsByKey[key]; + NSValue *creationBlockBeingCalled = [NSValue valueWithPointer:dictKey]; + if (obj) { + if ([creationBlockBeingCalled isEqual:obj]) { + [NSException raise:@"Reentering registeredObjectWithHost:key:creationBlock: not allowed" + format:@"host: %@ key: %@", host, key]; + } + return obj; + } + objectsByKey[key] = creationBlockBeingCalled; + obj = creationBlock(); + objectsByKey[key] = obj; + return obj; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h new file mode 100644 index 0000000..d9475dd --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h @@ -0,0 +1,53 @@ +/* + * 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 + +/** + * This class provides utilities for accessing resources in bundles. + */ +@interface FIRBundleUtil : NSObject + +/** + * Finds all relevant bundles, starting with [NSBundle mainBundle]. + */ ++ (NSArray *)relevantBundles; + +/** + * Reads the options dictionary from one of the provided bundles. + * + * @param resourceName The resource name, e.g. @"GoogleService-Info". + * @param fileType The file type (extension), e.g. @"plist". + * @param bundles The bundles to expect, in priority order. See also + * +[FIRBundleUtil relevantBundles]. + */ ++ (NSString *)optionsDictionaryPathWithResourceName:(NSString *)resourceName + andFileType:(NSString *)fileType + inBundles:(NSArray *)bundles; + +/** + * Finds URL schemes defined in all relevant bundles, starting with those from + * [NSBundle mainBundle]. + */ ++ (NSArray *)relevantURLSchemes; + +/** + * Checks if any of the given bundles have a matching bundle identifier prefix (removing extension + * suffixes). + */ ++ (BOOL)hasBundleIdentifierPrefix:(NSString *)bundleIdentifier inBundles:(NSArray *)bundles; + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m new file mode 100644 index 0000000..de2c295 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m @@ -0,0 +1,79 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Sources/FIRBundleUtil.h" + +#import + +@implementation FIRBundleUtil + ++ (NSArray *)relevantBundles { + return @[ [NSBundle mainBundle], [NSBundle bundleForClass:[self class]] ]; +} + ++ (NSString *)optionsDictionaryPathWithResourceName:(NSString *)resourceName + andFileType:(NSString *)fileType + inBundles:(NSArray *)bundles { + // Loop through all bundles to find the config dict. + for (NSBundle *bundle in bundles) { + NSString *path = [bundle pathForResource:resourceName ofType:fileType]; + // Use the first one we find. + if (path) { + return path; + } + } + return nil; +} + ++ (NSArray *)relevantURLSchemes { + NSMutableArray *result = [[NSMutableArray alloc] init]; + for (NSBundle *bundle in [[self class] relevantBundles]) { + NSArray *urlTypes = [bundle objectForInfoDictionaryKey:@"CFBundleURLTypes"]; + for (NSDictionary *urlType in urlTypes) { + [result addObjectsFromArray:urlType[@"CFBundleURLSchemes"]]; + } + } + return result; +} + ++ (BOOL)hasBundleIdentifierPrefix:(NSString *)bundleIdentifier inBundles:(NSArray *)bundles { + for (NSBundle *bundle in bundles) { + if ([bundle.bundleIdentifier isEqualToString:bundleIdentifier]) { + return YES; + } + + if ([GULAppEnvironmentUtil isAppExtension]) { + // A developer could be using the same `FIROptions` for both their app and extension. Since + // extensions have a suffix added to the bundleID, we consider a matching prefix as valid. + NSString *appBundleIDFromExtension = + [self bundleIdentifierByRemovingLastPartFrom:bundle.bundleIdentifier]; + if ([appBundleIDFromExtension isEqualToString:bundleIdentifier]) { + return YES; + } + } + } + return NO; +} + ++ (NSString *)bundleIdentifierByRemovingLastPartFrom:(NSString *)bundleIdentifier { + NSString *bundleIDComponentsSeparator = @"."; + + NSMutableArray *bundleIDComponents = + [[bundleIdentifier componentsSeparatedByString:bundleIDComponentsSeparator] mutableCopy]; + [bundleIDComponents removeLastObject]; + + return [bundleIDComponents componentsJoinedByString:bundleIDComponentsSeparator]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m new file mode 100644 index 0000000..9c1fbed --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m @@ -0,0 +1,65 @@ +/* + * 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 "FirebaseCore/Sources/Private/FIRComponent.h" + +#import "FirebaseCore/Sources/Private/FIRComponentContainer.h" +#import "FirebaseCore/Sources/Private/FIRDependency.h" + +@interface FIRComponent () + +- (instancetype)initWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + dependencies:(NSArray *)dependencies + creationBlock:(FIRComponentCreationBlock)creationBlock; + +@end + +@implementation FIRComponent + ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock { + return [[FIRComponent alloc] initWithProtocol:protocol + instantiationTiming:FIRInstantiationTimingLazy + dependencies:@[] + creationBlock:creationBlock]; +} + ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + dependencies:(NSArray *)dependencies + creationBlock:(FIRComponentCreationBlock)creationBlock { + return [[FIRComponent alloc] initWithProtocol:protocol + instantiationTiming:instantiationTiming + dependencies:dependencies + creationBlock:creationBlock]; +} + +- (instancetype)initWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + dependencies:(NSArray *)dependencies + creationBlock:(FIRComponentCreationBlock)creationBlock { + self = [super init]; + if (self) { + _protocol = protocol; + _instantiationTiming = instantiationTiming; + _dependencies = [dependencies copy]; + _creationBlock = creationBlock; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m new file mode 100644 index 0000000..bbe8878 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m @@ -0,0 +1,214 @@ +/* + * 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 "FirebaseCore/Sources/Private/FIRComponentContainer.h" + +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRComponent.h" +#import "FirebaseCore/Sources/Private/FIRLibrary.h" +#import "FirebaseCore/Sources/Private/FIRLogger.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRComponentContainer () + +/// The dictionary of components that are registered for a particular app. The key is an `NSString` +/// of the protocol. +@property(nonatomic, strong) NSMutableDictionary *components; + +/// Cached instances of components that requested to be cached. +@property(nonatomic, strong) NSMutableDictionary *cachedInstances; + +/// Protocols of components that have requested to be eagerly instantiated. +@property(nonatomic, strong, nullable) NSMutableArray *eagerProtocolsToInstantiate; + +@end + +@implementation FIRComponentContainer + +// Collection of all classes that register to provide components. +static NSMutableSet *sFIRComponentRegistrants; + +#pragma mark - Public Registration + ++ (void)registerAsComponentRegistrant:(Class)klass { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sFIRComponentRegistrants = [[NSMutableSet alloc] init]; + }); + + [self registerAsComponentRegistrant:klass inSet:sFIRComponentRegistrants]; +} + ++ (void)registerAsComponentRegistrant:(Class)klass + inSet:(NSMutableSet *)allRegistrants { + [allRegistrants addObject:klass]; +} + +#pragma mark - Internal Initialization + +- (instancetype)initWithApp:(FIRApp *)app { + return [self initWithApp:app registrants:sFIRComponentRegistrants]; +} + +- (instancetype)initWithApp:(FIRApp *)app registrants:(NSMutableSet *)allRegistrants { + self = [super init]; + if (self) { + _app = app; + _cachedInstances = [NSMutableDictionary dictionary]; + _components = [NSMutableDictionary dictionary]; + + [self populateComponentsFromRegisteredClasses:allRegistrants forApp:app]; + } + return self; +} + +- (void)populateComponentsFromRegisteredClasses:(NSSet *)classes forApp:(FIRApp *)app { + // Keep track of any components that need to eagerly instantiate after all components are added. + self.eagerProtocolsToInstantiate = [[NSMutableArray alloc] init]; + + // Loop through the verified component registrants and populate the components array. + for (Class klass in classes) { + // Loop through all the components being registered and store them as appropriate. + // Classes which do not provide functionality should use a dummy FIRComponentRegistrant + // protocol. + for (FIRComponent *component in [klass componentsToRegister]) { + // Check if the component has been registered before, and error out if so. + NSString *protocolName = NSStringFromProtocol(component.protocol); + if (self.components[protocolName]) { + FIRLogError(kFIRLoggerCore, @"I-COR000029", + @"Attempted to register protocol %@, but it already has an implementation.", + protocolName); + continue; + } + + // Store the creation block for later usage. + self.components[protocolName] = component.creationBlock; + + // Queue any protocols that should be eagerly instantiated. Don't instantiate them yet + // because they could depend on other components that haven't been added to the components + // array yet. + BOOL shouldInstantiateEager = + (component.instantiationTiming == FIRInstantiationTimingAlwaysEager); + BOOL shouldInstantiateDefaultEager = + (component.instantiationTiming == FIRInstantiationTimingEagerInDefaultApp && + [app isDefaultApp]); + if (shouldInstantiateEager || shouldInstantiateDefaultEager) { + [self.eagerProtocolsToInstantiate addObject:component.protocol]; + } + } + } +} + +#pragma mark - Instance Creation + +- (void)instantiateEagerComponents { + // After all components are registered, instantiate the ones that are requesting eager + // instantiation. + @synchronized(self) { + for (Protocol *protocol in self.eagerProtocolsToInstantiate) { + // Get an instance for the protocol, which will instantiate it since it couldn't have been + // cached yet. Ignore the instance coming back since we don't need it. + __unused id unusedInstance = [self instanceForProtocol:protocol]; + } + + // All eager instantiation is complete, clear the stored property now. + self.eagerProtocolsToInstantiate = nil; + } +} + +/// Instantiate an instance of a class that conforms to the specified protocol. +/// This will: +/// - Call the block to create an instance if possible, +/// - Validate that the instance returned conforms to the protocol it claims to, +/// - Cache the instance if the block requests it +/// +/// Note that this method assumes the caller already has @sychronized on self. +- (nullable id)instantiateInstanceForProtocol:(Protocol *)protocol + withBlock:(FIRComponentCreationBlock)creationBlock { + if (!creationBlock) { + return nil; + } + + // Create an instance using the creation block. + BOOL shouldCache = NO; + id instance = creationBlock(self, &shouldCache); + if (!instance) { + return nil; + } + + // An instance was created, validate that it conforms to the protocol it claims to. + NSString *protocolName = NSStringFromProtocol(protocol); + if (![instance conformsToProtocol:protocol]) { + FIRLogError(kFIRLoggerCore, @"I-COR000030", + @"An instance conforming to %@ was requested, but the instance provided does not " + @"conform to the protocol", + protocolName); + } + + // The instance is ready to be returned, but check if it should be cached first before returning. + if (shouldCache) { + self.cachedInstances[protocolName] = instance; + } + + return instance; +} + +#pragma mark - Internal Retrieval + +- (nullable id)instanceForProtocol:(Protocol *)protocol { + // Check if there is a cached instance, and return it if so. + NSString *protocolName = NSStringFromProtocol(protocol); + + id cachedInstance; + @synchronized(self) { + cachedInstance = self.cachedInstances[protocolName]; + if (!cachedInstance) { + // Use the creation block to instantiate an instance and return it. + FIRComponentCreationBlock creationBlock = self.components[protocolName]; + cachedInstance = [self instantiateInstanceForProtocol:protocol withBlock:creationBlock]; + } + } + return cachedInstance; +} + +#pragma mark - Lifecycle + +- (void)removeAllCachedInstances { + @synchronized(self) { + // Loop through the cache and notify each instance that is a maintainer to clean up after + // itself. + for (id instance in self.cachedInstances.allValues) { + if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] && + [instance respondsToSelector:@selector(appWillBeDeleted:)]) { + [instance appWillBeDeleted:self.app]; + } + } + + // Empty the cache. + [self.cachedInstances removeAllObjects]; + } +} + +- (void)removeAllComponents { + @synchronized(self) { + [self.components removeAllObjects]; + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h new file mode 100644 index 0000000..7e76413 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h @@ -0,0 +1,49 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +#import "FirebaseCore/Sources/Private/FIRComponentContainer.h" +#import "FirebaseCore/Sources/Private/FIRLibrary.h" + +@class FIRApp; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRComponentContainer (Private) + +/// Initializes a container for a given app. This should only be called by the app itself. +- (instancetype)initWithApp:(FIRApp *)app; + +/// Retrieves an instance that conforms to the specified protocol. This will return `nil` if the +/// protocol wasn't registered, or if the instance couldn't be instantiated for the provided app. +- (nullable id)instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Instantiates all the components that have registered as "eager" after initialization. +- (void)instantiateEagerComponents; + +/// Remove all of the cached instances stored and allow them to clean up after themselves. +- (void)removeAllCachedInstances; + +/// Removes all the components. After calling this method no new instances will be created. +- (void)removeAllComponents; + +/// Register a class to provide components for the interoperability system. The class should conform +/// to `FIRComponentRegistrant` and provide an array of `FIRComponent` objects. ++ (void)registerAsComponentRegistrant:(Class)klass; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m new file mode 100644 index 0000000..9051336 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m @@ -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. + */ + +#import "FirebaseCore/Sources/Private/FIRComponentType.h" + +#import "FirebaseCore/Sources/FIRComponentContainerInternal.h" + +@implementation FIRComponentType + ++ (id)instanceForProtocol:(Protocol *)protocol inContainer:(FIRComponentContainer *)container { + // Forward the call to the container. + return [container instanceForProtocol:protocol]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m new file mode 100644 index 0000000..83b3248 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m @@ -0,0 +1,46 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Sources/FIRConfigurationInternal.h" + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" + +extern void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +@implementation FIRConfiguration + ++ (instancetype)sharedInstance { + static FIRConfiguration *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRConfiguration alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _analyticsConfiguration = [FIRAnalyticsConfiguration sharedInstance]; + } + return self; +} + +- (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel { + NSAssert(loggerLevel <= FIRLoggerLevelMax && loggerLevel >= FIRLoggerLevelMin, + @"Invalid logger level, %ld", (long)loggerLevel); + FIRSetLoggerLevel(loggerLevel); +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h new file mode 100644 index 0000000..9361e73 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h @@ -0,0 +1,29 @@ +/* + * 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 "FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h" + +@class FIRAnalyticsConfiguration; + +@interface FIRConfiguration () + +/** + * The configuration class for Firebase Analytics. This should be removed once the logic for + * enabling and disabling Analytics is moved to Analytics. + */ +@property(nonatomic, readwrite) FIRAnalyticsConfiguration *analyticsConfiguration; + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRCoreDiagnosticsConnector.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRCoreDiagnosticsConnector.m new file mode 100644 index 0000000..db54936 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRCoreDiagnosticsConnector.m @@ -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 "FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h" + +#import "Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h" + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h" + +#import "FirebaseCore/Sources/FIRDiagnosticsData.h" +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIROptionsInternal.h" + +// Define the interop class symbol declared as an extern in FIRCoreDiagnosticsInterop. +Class FIRCoreDiagnosticsImplementation; + +@implementation FIRCoreDiagnosticsConnector + ++ (void)initialize { + if (!FIRCoreDiagnosticsImplementation) { + FIRCoreDiagnosticsImplementation = NSClassFromString(@"FIRCoreDiagnostics"); + if (FIRCoreDiagnosticsImplementation) { + NSAssert([FIRCoreDiagnosticsImplementation + conformsToProtocol:@protocol(FIRCoreDiagnosticsInterop)], + @"If FIRCoreDiagnostics is implemented, it must conform to the interop protocol."); + NSAssert( + [FIRCoreDiagnosticsImplementation respondsToSelector:@selector(sendDiagnosticsData:)], + @"If FIRCoreDiagnostics is implemented, it must implement +sendDiagnosticsData."); + } + } +} + ++ (void)logCoreTelemetryWithOptions:(FIROptions *)options { + if (FIRCoreDiagnosticsImplementation) { + FIRDiagnosticsData *diagnosticsData = [[FIRDiagnosticsData alloc] init]; + [diagnosticsData insertValue:@(YES) forKey:kFIRCDIsDataCollectionDefaultEnabledKey]; + [diagnosticsData insertValue:[FIRApp firebaseUserAgent] forKey:kFIRCDFirebaseUserAgentKey]; + [diagnosticsData insertValue:@(FIRConfigTypeCore) forKey:kFIRCDConfigurationTypeKey]; + [diagnosticsData insertValue:options.googleAppID forKey:kFIRCDGoogleAppIDKey]; + [diagnosticsData insertValue:options.bundleID forKey:kFIRCDBundleIDKey]; + [diagnosticsData insertValue:@(options.usingOptionsFromDefaultPlist) + forKey:kFIRCDUsingOptionsFromDefaultPlistKey]; + [diagnosticsData insertValue:options.libraryVersionID forKey:kFIRCDLibraryVersionIDKey]; + [FIRCoreDiagnosticsImplementation sendDiagnosticsData:diagnosticsData]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDependency.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDependency.m new file mode 100644 index 0000000..e1e2578 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDependency.m @@ -0,0 +1,44 @@ +/* + * 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 "FirebaseCore/Sources/Private/FIRDependency.h" + +@interface FIRDependency () + +- (instancetype)initWithProtocol:(Protocol *)protocol isRequired:(BOOL)required; + +@end + +@implementation FIRDependency + ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol { + return [[self alloc] initWithProtocol:protocol isRequired:YES]; +} + ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol isRequired:(BOOL)required { + return [[self alloc] initWithProtocol:protocol isRequired:required]; +} + +- (instancetype)initWithProtocol:(Protocol *)protocol isRequired:(BOOL)required { + self = [super init]; + if (self) { + _protocol = protocol; + _isRequired = required; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.h new file mode 100644 index 0000000..5b5ff8a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.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 + +#import "Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Implements the FIRCoreDiagnosticsData protocol to log diagnostics data. */ +@interface FIRDiagnosticsData : NSObject + +/** Inserts values into the diagnosticObjects dictionary if the value isn't nil. + * + * @param value The value to insert if it's not nil. + * @param key The key to associate it with. + */ +- (void)insertValue:(nullable id)value forKey:(NSString *)key; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.m new file mode 100644 index 0000000..0beed25 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.m @@ -0,0 +1,66 @@ +/* + * 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 "FirebaseCore/Sources/FIRDiagnosticsData.h" + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h" + +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIROptionsInternal.h" + +@implementation FIRDiagnosticsData { + /** Backing ivar for the diagnosticObjects property. */ + NSMutableDictionary *_diagnosticObjects; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _diagnosticObjects = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)insertValue:(nullable id)value forKey:(NSString *)key { + if (key) { + _diagnosticObjects[key] = value; + } +} + +#pragma mark - FIRCoreDiagnosticsData + +- (NSDictionary *)diagnosticObjects { + if (!_diagnosticObjects[kFIRCDllAppsCountKey]) { + _diagnosticObjects[kFIRCDllAppsCountKey] = @([FIRApp allApps].count); + } + if (!_diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey]) { + _diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey] = + @([[FIRApp defaultApp] isDataCollectionDefaultEnabled]); + } + if (!_diagnosticObjects[kFIRCDFirebaseUserAgentKey]) { + _diagnosticObjects[kFIRCDFirebaseUserAgentKey] = [FIRApp firebaseUserAgent]; + } + return _diagnosticObjects; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +- (void)setDiagnosticObjects:(NSDictionary *)diagnosticObjects { + NSAssert(NO, @"Please use -insertValue:forKey:"); +} +#pragma clang diagnostic pop + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h new file mode 100644 index 0000000..ffb11fb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFirebaseUserAgent : NSObject + +/** Returns the firebase user agent which consists of environment part and the components added via + * `setValue:forComponent` method. */ +- (NSString *)firebaseUserAgent; + +/** Sets value associated with the specified component. If value is `nil` then the component is + * removed. */ +- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName; + +/** Resets manually added components. */ +- (void)reset; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m new file mode 100644 index 0000000..04e7566 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#import "FirebaseCore/Sources/FIRFirebaseUserAgent.h" + +#import + +@interface FIRFirebaseUserAgent () + +@property(nonatomic, readonly) NSMutableDictionary *valuesByComponent; +@property(nonatomic, readonly) NSDictionary *environmentComponents; +@property(nonatomic, readonly) NSString *firebaseUserAgent; + +@end + +@implementation FIRFirebaseUserAgent + +@synthesize firebaseUserAgent = _firebaseUserAgent; +@synthesize environmentComponents = _environmentComponents; + +- (instancetype)init { + self = [super init]; + if (self) { + _valuesByComponent = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSString *)firebaseUserAgent { + @synchronized(self) { + if (_firebaseUserAgent == nil) { + NSMutableDictionary *allComponents = + [self.valuesByComponent mutableCopy]; + [allComponents setValuesForKeysWithDictionary:self.environmentComponents]; + + __block NSMutableArray *components = + [[NSMutableArray alloc] initWithCapacity:self.valuesByComponent.count]; + [allComponents enumerateKeysAndObjectsUsingBlock:^( + NSString *_Nonnull name, NSString *_Nonnull value, BOOL *_Nonnull stop) { + [components addObject:[NSString stringWithFormat:@"%@/%@", name, value]]; + }]; + [components sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + _firebaseUserAgent = [components componentsJoinedByString:@" "]; + } + return _firebaseUserAgent; + } +} + +- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName { + @synchronized(self) { + self.valuesByComponent[componentName] = value; + // Reset cached user agent string. + _firebaseUserAgent = nil; + } +} + +- (void)reset { + @synchronized(self) { + // Reset components. + _valuesByComponent = [[[self class] environmentComponents] mutableCopy]; + // Reset cached user agent string. + _firebaseUserAgent = nil; + } +} + +#pragma mark - Environment components + +- (NSDictionary *)environmentComponents { + if (_environmentComponents == nil) { + _environmentComponents = [[self class] environmentComponents]; + } + return _environmentComponents; +} + ++ (NSDictionary *)environmentComponents { + NSMutableDictionary *components = [NSMutableDictionary dictionary]; + + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + NSString *xcodeVersion = info[@"DTXcodeBuild"]; + NSString *appleSdkVersion = info[@"DTSDKBuild"]; + NSString *isFromAppstoreFlagValue = [GULAppEnvironmentUtil isFromAppStore] ? @"true" : @"false"; + + components[@"apple-platform"] = [GULAppEnvironmentUtil applePlatform]; + components[@"apple-sdk"] = appleSdkVersion; + components[@"appstore"] = isFromAppstoreFlagValue; + components[@"deploy"] = [GULAppEnvironmentUtil deploymentType]; + components[@"device"] = [GULAppEnvironmentUtil deviceModel]; + components[@"os-version"] = [GULAppEnvironmentUtil systemVersion]; + components[@"xcode"] = xcodeVersion; + + return [components copy]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatInfo.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatInfo.m new file mode 100644 index 0000000..ef6b363 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatInfo.m @@ -0,0 +1,72 @@ +// 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 "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h" +#import +#import +#import +#import +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" + +const static long secondsInDay = 86400; +@implementation FIRHeartbeatInfo : NSObject + +/** Updates the storage with the heartbeat information corresponding to this tag. + * @param heartbeatTag Tag which could either be sdk specific tag or the global tag. + * @return Boolean representing whether the heartbeat needs to be sent for this tag or not. + */ ++ (BOOL)updateIfNeededHeartbeatDateForTag:(NSString *)heartbeatTag { + @synchronized(self) { + NSString *const kHeartbeatStorageName = @"HEARTBEAT_INFO_STORAGE"; + id dataStorage; +#if TARGET_OS_TV + NSUserDefaults *defaults = + [[NSUserDefaults alloc] initWithSuiteName:kFirebaseCoreDefaultsSuiteName]; + dataStorage = + [[GULHeartbeatDateStorageUserDefaults alloc] initWithDefaults:defaults + key:kHeartbeatStorageName]; +#else + dataStorage = [[GULHeartbeatDateStorage alloc] initWithFileName:kHeartbeatStorageName]; +#endif + NSDate *heartbeatTime = [dataStorage heartbeatDateForTag:heartbeatTag]; + NSDate *currentDate = [NSDate date]; + if (heartbeatTime != nil) { + NSTimeInterval secondsBetween = [currentDate timeIntervalSinceDate:heartbeatTime]; + if (secondsBetween < secondsInDay) { + return false; + } + } + return [dataStorage setHearbeatDate:currentDate forTag:heartbeatTag]; + } +} + ++ (FIRHeartbeatInfoCode)heartbeatCodeForTag:(NSString *)heartbeatTag { + NSString *globalTag = @"GLOBAL"; + BOOL isSdkHeartbeatNeeded = [FIRHeartbeatInfo updateIfNeededHeartbeatDateForTag:heartbeatTag]; + BOOL isGlobalHeartbeatNeeded = [FIRHeartbeatInfo updateIfNeededHeartbeatDateForTag:globalTag]; + if (!isSdkHeartbeatNeeded && !isGlobalHeartbeatNeeded) { + // Both sdk and global heartbeat not needed. + return FIRHeartbeatInfoCodeNone; + } else if (isSdkHeartbeatNeeded && !isGlobalHeartbeatNeeded) { + // Only SDK heartbeat needed. + return FIRHeartbeatInfoCodeSDK; + } else if (!isSdkHeartbeatNeeded && isGlobalHeartbeatNeeded) { + // Only global heartbeat needed. + return FIRHeartbeatInfoCodeGlobal; + } else { + // Both sdk and global heartbeat are needed. + return FIRHeartbeatInfoCodeCombined; + } +} +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m new file mode 100644 index 0000000..6707a96 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m @@ -0,0 +1,174 @@ +// 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 "FirebaseCore/Sources/Private/FIRLogger.h" + +#import +#import +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h" + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +FIRLoggerService kFIRLoggerCore = @"[Firebase/Core]"; + +// All the FIRLoggerService definitions should be migrated to clients. Do not add new ones! +FIRLoggerService kFIRLoggerAnalytics = @"[Firebase/Analytics]"; +FIRLoggerService kFIRLoggerCrash = @"[Firebase/Crash]"; +FIRLoggerService kFIRLoggerRemoteConfig = @"[Firebase/RemoteConfig]"; + +/// Arguments passed on launch. +NSString *const kFIRDisableDebugModeApplicationArgument = @"-FIRDebugDisabled"; +NSString *const kFIREnableDebugModeApplicationArgument = @"-FIRDebugEnabled"; +NSString *const kFIRLoggerForceSDTERRApplicationArgument = @"-FIRLoggerForceSTDERR"; + +/// Key for the debug mode bit in NSUserDefaults. +NSString *const kFIRPersistedDebugModeKey = @"/google/firebase/debug_mode"; + +/// NSUserDefaults that should be used to store and read variables. If nil, `standardUserDefaults` +/// will be used. +static NSUserDefaults *sFIRLoggerUserDefaults; + +static dispatch_once_t sFIRLoggerOnceToken; + +// The sFIRAnalyticsDebugMode flag is here to support the -FIRDebugEnabled/-FIRDebugDisabled +// flags used by Analytics. Users who use those flags expect Analytics to log verbosely, +// while the rest of Firebase logs at the default level. This flag is introduced to support +// that behavior. +static BOOL sFIRAnalyticsDebugMode; + +#ifdef DEBUG +/// The regex pattern for the message code. +static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$"; +static NSRegularExpression *sMessageCodeRegex; +#endif + +void FIRLoggerInitializeASL(void) { + dispatch_once(&sFIRLoggerOnceToken, ^{ + // Register Firebase Version with GULLogger. + GULLoggerRegisterVersion(FIRFirebaseVersion()); + + // Override the aslOptions to ASL_OPT_STDERR if the override argument is passed in. + NSArray *arguments = [NSProcessInfo processInfo].arguments; + BOOL overrideSTDERR = [arguments containsObject:kFIRLoggerForceSDTERRApplicationArgument]; + + // Use the standard NSUserDefaults if it hasn't been explicitly set. + if (sFIRLoggerUserDefaults == nil) { + sFIRLoggerUserDefaults = [NSUserDefaults standardUserDefaults]; + } + + BOOL forceDebugMode = NO; + BOOL debugMode = [sFIRLoggerUserDefaults boolForKey:kFIRPersistedDebugModeKey]; + if ([arguments containsObject:kFIRDisableDebugModeApplicationArgument]) { // Default mode + [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; + } else if ([arguments containsObject:kFIREnableDebugModeApplicationArgument] || + debugMode) { // Debug mode + [sFIRLoggerUserDefaults setBool:YES forKey:kFIRPersistedDebugModeKey]; + forceDebugMode = YES; + } + GULLoggerInitializeASL(); + if (overrideSTDERR) { + GULLoggerEnableSTDERR(); + } + if (forceDebugMode) { + GULLoggerForceDebug(); + } + }); +} + +__attribute__((no_sanitize("thread"))) void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode) { + sFIRAnalyticsDebugMode = analyticsDebugMode; +} + +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel) { + FIRLoggerInitializeASL(); + GULSetLoggerLevel((GULLoggerLevel)loggerLevel); +} + +#ifdef DEBUG +void FIRResetLogger(void) { + extern void GULResetLogger(void); + sFIRLoggerOnceToken = 0; + [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; + sFIRLoggerUserDefaults = nil; + GULResetLogger(); +} + +void FIRSetLoggerUserDefaults(NSUserDefaults *defaults) { + sFIRLoggerUserDefaults = defaults; +} +#endif + +/** + * Check if the level is high enough to be loggable. + * + * Analytics can override the log level with an intentional race condition. + * Add the attribute to get a clean thread sanitizer run. + */ +__attribute__((no_sanitize("thread"))) BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, + BOOL analyticsComponent) { + FIRLoggerInitializeASL(); + if (sFIRAnalyticsDebugMode && analyticsComponent) { + return YES; + } + return GULIsLoggableLevel((GULLoggerLevel)loggerLevel); +} + +void FIRLogBasic(FIRLoggerLevel level, + FIRLoggerService service, + NSString *messageCode, + NSString *message, + va_list args_ptr) { + FIRLoggerInitializeASL(); + GULLogBasic((GULLoggerLevel)level, service, + sFIRAnalyticsDebugMode && [kFIRLoggerAnalytics isEqualToString:service], messageCode, + message, args_ptr); +} + +/** + * Generates the logging functions using macros. + * + * Calling FIRLogError(kFIRLoggerCore, @"I-COR000001", @"Configure %@ failed.", @"blah") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [Firebase/Core][I-COR000001] Configure blah failed. + * Calling FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configure succeed.") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [Firebase/Core][I-COR000001] Configure succeed. + */ +#define FIR_LOGGING_FUNCTION(level) \ + void FIRLog##level(FIRLoggerService service, NSString *messageCode, NSString *message, ...) { \ + va_list args_ptr; \ + va_start(args_ptr, message); \ + FIRLogBasic(FIRLoggerLevel##level, service, messageCode, message, args_ptr); \ + va_end(args_ptr); \ + } + +FIR_LOGGING_FUNCTION(Error) +FIR_LOGGING_FUNCTION(Warning) +FIR_LOGGING_FUNCTION(Notice) +FIR_LOGGING_FUNCTION(Info) +FIR_LOGGING_FUNCTION(Debug) + +#undef FIR_MAKE_LOGGER + +#pragma mark - FIRLoggerWrapper + +@implementation FIRLoggerWrapper + ++ (void)logWithLevel:(FIRLoggerLevel)level + withService:(FIRLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args { + FIRLogBasic(level, service, messageCode, message, args); +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m new file mode 100644 index 0000000..e66b4e6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m @@ -0,0 +1,498 @@ +// 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 "FirebaseCore/Sources/FIRBundleUtil.h" +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRLogger.h" +#import "FirebaseCore/Sources/Private/FIROptionsInternal.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +// Keys for the strings in the plist file. +NSString *const kFIRAPIKey = @"API_KEY"; +NSString *const kFIRTrackingID = @"TRACKING_ID"; +NSString *const kFIRGoogleAppID = @"GOOGLE_APP_ID"; +NSString *const kFIRClientID = @"CLIENT_ID"; +NSString *const kFIRGCMSenderID = @"GCM_SENDER_ID"; +NSString *const kFIRAndroidClientID = @"ANDROID_CLIENT_ID"; +NSString *const kFIRDatabaseURL = @"DATABASE_URL"; +NSString *const kFIRStorageBucket = @"STORAGE_BUCKET"; +// The key to locate the expected bundle identifier in the plist file. +NSString *const kFIRBundleID = @"BUNDLE_ID"; +// The key to locate the project identifier in the plist file. +NSString *const kFIRProjectID = @"PROJECT_ID"; + +NSString *const kFIRIsMeasurementEnabled = @"IS_MEASUREMENT_ENABLED"; +NSString *const kFIRIsAnalyticsCollectionEnabled = @"FIREBASE_ANALYTICS_COLLECTION_ENABLED"; +NSString *const kFIRIsAnalyticsCollectionDeactivated = @"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED"; + +NSString *const kFIRIsAnalyticsEnabled = @"IS_ANALYTICS_ENABLED"; +NSString *const kFIRIsSignInEnabled = @"IS_SIGNIN_ENABLED"; + +// Library version ID formatted like: +// @"5" // Major version (one or more digits) +// @"04" // Minor version (exactly 2 digits) +// @"01" // Build number (exactly 2 digits) +// @"000"; // Fixed "000" +NSString *kFIRLibraryVersionID; + +// Plist file name. +NSString *const kServiceInfoFileName = @"GoogleService-Info"; +// Plist file type. +NSString *const kServiceInfoFileType = @"plist"; + +// Exception raised from attempting to modify a FIROptions after it's been copied to a FIRApp. +NSString *const kFIRExceptionBadModification = + @"Attempted to modify options after it's set on FIRApp. Please modify all properties before " + @"initializing FIRApp."; + +@interface FIROptions () + +/** + * This property maintains the actual configuration key-value pairs. + */ +@property(nonatomic, readwrite) NSMutableDictionary *optionsDictionary; + +/** + * Calls `analyticsOptionsDictionaryWithInfoDictionary:` using [NSBundle mainBundle].infoDictionary. + * It combines analytics options from both the infoDictionary and the GoogleService-Info.plist. + * Values which are present in the main plist override values from the GoogleService-Info.plist. + */ +@property(nonatomic, readonly) NSDictionary *analyticsOptionsDictionary; + +/** + * Combination of analytics options from both the infoDictionary and the GoogleService-Info.plist. + * Values which are present in the infoDictionary override values from the GoogleService-Info.plist. + */ +- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary; + +/** + * Throw exception if editing is locked when attempting to modify an option. + */ +- (void)checkEditingLocked; + +@end + +@implementation FIROptions { + /// Backing variable for self.analyticsOptionsDictionary. + NSDictionary *_analyticsOptionsDictionary; +} + +static FIROptions *sDefaultOptions = nil; +static NSDictionary *sDefaultOptionsDictionary = nil; +static dispatch_once_t sDefaultOptionsOnceToken; +static dispatch_once_t sDefaultOptionsDictionaryOnceToken; + +#pragma mark - Public only for internal class methods + ++ (FIROptions *)defaultOptions { + dispatch_once(&sDefaultOptionsOnceToken, ^{ + NSDictionary *defaultOptionsDictionary = [self defaultOptionsDictionary]; + if (defaultOptionsDictionary != nil) { + sDefaultOptions = + [[FIROptions alloc] initInternalWithOptionsDictionary:defaultOptionsDictionary]; + } + }); + + return sDefaultOptions; +} + +#pragma mark - Private class methods + ++ (NSDictionary *)defaultOptionsDictionary { + dispatch_once(&sDefaultOptionsDictionaryOnceToken, ^{ + NSString *plistFilePath = [FIROptions plistFilePathWithName:kServiceInfoFileName]; + if (plistFilePath == nil) { + return; + } + sDefaultOptionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath]; + if (sDefaultOptionsDictionary == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000011", + @"The configuration file is not a dictionary: " + @"'%@.%@'.", + kServiceInfoFileName, kServiceInfoFileType); + } + }); + + return sDefaultOptionsDictionary; +} + +// Returns the path of the plist file with a given file name. ++ (NSString *)plistFilePathWithName:(NSString *)fileName { + NSArray *bundles = [FIRBundleUtil relevantBundles]; + NSString *plistFilePath = + [FIRBundleUtil optionsDictionaryPathWithResourceName:fileName + andFileType:kServiceInfoFileType + inBundles:bundles]; + if (plistFilePath == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000012", @"Could not locate configuration file: '%@.%@'.", + fileName, kServiceInfoFileType); + } + return plistFilePath; +} + ++ (void)resetDefaultOptions { + sDefaultOptions = nil; + sDefaultOptionsDictionary = nil; + sDefaultOptionsOnceToken = 0; + sDefaultOptionsDictionaryOnceToken = 0; +} + +#pragma mark - Private instance methods + +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)optionsDictionary { + self = [super init]; + if (self) { + _optionsDictionary = [optionsDictionary mutableCopy]; + _usingOptionsFromDefaultPlist = YES; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + FIROptions *newOptions = [(FIROptions *)[[self class] allocWithZone:zone] + initInternalWithOptionsDictionary:self.optionsDictionary]; + if (newOptions) { + newOptions.deepLinkURLScheme = self.deepLinkURLScheme; + newOptions.appGroupID = self.appGroupID; + newOptions.editingLocked = self.isEditingLocked; + newOptions.usingOptionsFromDefaultPlist = self.usingOptionsFromDefaultPlist; + } + return newOptions; +} + +#pragma mark - Public instance methods + +- (instancetype)init { + // Unavailable. + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (instancetype)initWithContentsOfFile:(NSString *)plistPath { + self = [super init]; + if (self) { + if (plistPath == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000013", @"The plist file path is nil."); + return nil; + } + _optionsDictionary = [[NSDictionary dictionaryWithContentsOfFile:plistPath] mutableCopy]; + if (_optionsDictionary == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000014", + @"The configuration file at %@ does not exist or " + @"is not a well-formed plist file.", + plistPath); + return nil; + } + // TODO: Do we want to validate the dictionary here? It says we do that already in + // the public header. + } + return self; +} + +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID GCMSenderID:(NSString *)GCMSenderID { + self = [super init]; + if (self) { + NSMutableDictionary *mutableOptionsDict = [NSMutableDictionary dictionary]; + [mutableOptionsDict setValue:googleAppID forKey:kFIRGoogleAppID]; + [mutableOptionsDict setValue:GCMSenderID forKey:kFIRGCMSenderID]; + [mutableOptionsDict setValue:[[NSBundle mainBundle] bundleIdentifier] forKey:kFIRBundleID]; + self.optionsDictionary = mutableOptionsDict; + } + return self; +} + +- (NSString *)APIKey { + return self.optionsDictionary[kFIRAPIKey]; +} + +- (void)checkEditingLocked { + if (self.isEditingLocked) { + [NSException raise:kFirebaseCoreErrorDomain format:kFIRExceptionBadModification]; + } +} + +- (void)setAPIKey:(NSString *)APIKey { + [self checkEditingLocked]; + _optionsDictionary[kFIRAPIKey] = [APIKey copy]; +} + +- (NSString *)clientID { + return self.optionsDictionary[kFIRClientID]; +} + +- (void)setClientID:(NSString *)clientID { + [self checkEditingLocked]; + _optionsDictionary[kFIRClientID] = [clientID copy]; +} + +- (NSString *)trackingID { + return self.optionsDictionary[kFIRTrackingID]; +} + +- (void)setTrackingID:(NSString *)trackingID { + [self checkEditingLocked]; + _optionsDictionary[kFIRTrackingID] = [trackingID copy]; +} + +- (NSString *)GCMSenderID { + return self.optionsDictionary[kFIRGCMSenderID]; +} + +- (void)setGCMSenderID:(NSString *)GCMSenderID { + [self checkEditingLocked]; + _optionsDictionary[kFIRGCMSenderID] = [GCMSenderID copy]; +} + +- (NSString *)projectID { + return self.optionsDictionary[kFIRProjectID]; +} + +- (void)setProjectID:(NSString *)projectID { + [self checkEditingLocked]; + _optionsDictionary[kFIRProjectID] = [projectID copy]; +} + +- (NSString *)androidClientID { + return self.optionsDictionary[kFIRAndroidClientID]; +} + +- (void)setAndroidClientID:(NSString *)androidClientID { + [self checkEditingLocked]; + _optionsDictionary[kFIRAndroidClientID] = [androidClientID copy]; +} + +- (NSString *)googleAppID { + return self.optionsDictionary[kFIRGoogleAppID]; +} + +- (void)setGoogleAppID:(NSString *)googleAppID { + [self checkEditingLocked]; + _optionsDictionary[kFIRGoogleAppID] = [googleAppID copy]; +} + +- (NSString *)libraryVersionID { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // The unit tests are set up to catch anything that does not properly convert. + NSString *version = FIRFirebaseVersion(); + NSArray *components = [version componentsSeparatedByString:@"."]; + NSString *major = [components objectAtIndex:0]; + NSString *minor = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:1] intValue]]; + NSString *patch = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:2] intValue]]; + kFIRLibraryVersionID = [NSString stringWithFormat:@"%@%@%@000", major, minor, patch]; + }); + return kFIRLibraryVersionID; +} + +- (void)setLibraryVersionID:(NSString *)libraryVersionID { + _optionsDictionary[kFIRLibraryVersionID] = [libraryVersionID copy]; +} + +- (NSString *)databaseURL { + return self.optionsDictionary[kFIRDatabaseURL]; +} + +- (void)setDatabaseURL:(NSString *)databaseURL { + [self checkEditingLocked]; + + _optionsDictionary[kFIRDatabaseURL] = [databaseURL copy]; +} + +- (NSString *)storageBucket { + return self.optionsDictionary[kFIRStorageBucket]; +} + +- (void)setStorageBucket:(NSString *)storageBucket { + [self checkEditingLocked]; + _optionsDictionary[kFIRStorageBucket] = [storageBucket copy]; +} + +- (void)setDeepLinkURLScheme:(NSString *)deepLinkURLScheme { + [self checkEditingLocked]; + _deepLinkURLScheme = [deepLinkURLScheme copy]; +} + +- (NSString *)bundleID { + return self.optionsDictionary[kFIRBundleID]; +} + +- (void)setBundleID:(NSString *)bundleID { + [self checkEditingLocked]; + _optionsDictionary[kFIRBundleID] = [bundleID copy]; +} + +- (void)setAppGroupID:(NSString *)appGroupID { + [self checkEditingLocked]; + _appGroupID = [appGroupID copy]; +} + +#pragma mark - Equality + +- (BOOL)isEqual:(id)object { + if (!object || ![object isKindOfClass:[FIROptions class]]) { + return NO; + } + + return [self isEqualToOptions:(FIROptions *)object]; +} + +- (BOOL)isEqualToOptions:(FIROptions *)options { + // Skip any non-FIROptions classes. + if (![options isKindOfClass:[FIROptions class]]) { + return NO; + } + + // Check the internal dictionary and custom properties for differences. + if (![options.optionsDictionary isEqualToDictionary:self.optionsDictionary]) { + return NO; + } + + // Validate extra properties not contained in the dictionary. Only validate it if one of the + // objects has the property set. + if ((options.deepLinkURLScheme != nil || self.deepLinkURLScheme != nil) && + ![options.deepLinkURLScheme isEqualToString:self.deepLinkURLScheme]) { + return NO; + } + + if ((options.appGroupID != nil || self.appGroupID != nil) && + ![options.appGroupID isEqualToString:self.appGroupID]) { + return NO; + } + + // Validate the Analytics options haven't changed with the Info.plist. + if (![options.analyticsOptionsDictionary isEqualToDictionary:self.analyticsOptionsDictionary]) { + return NO; + } + + // We don't care about the `editingLocked` or `usingOptionsFromDefaultPlist` properties since + // those relate to lifecycle and construction, we only care if the contents of the options + // themselves are equal. + return YES; +} + +- (NSUInteger)hash { + // This is strongly recommended for any object that implements a custom `isEqual:` method to + // ensure that dictionary and set behavior matches other `isEqual:` checks. + // Note: `self.analyticsOptionsDictionary` was left out here since it solely relies on the + // contents of the main bundle's `Info.plist`. We should avoid reading that file and the contents + // should be identical. + return self.optionsDictionary.hash ^ self.deepLinkURLScheme.hash ^ self.appGroupID.hash; +} + +#pragma mark - Internal instance methods + +- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary { + if (_analyticsOptionsDictionary == nil) { + NSMutableDictionary *tempAnalyticsOptions = [[NSMutableDictionary alloc] init]; + NSArray *measurementKeys = @[ + kFIRIsMeasurementEnabled, kFIRIsAnalyticsCollectionEnabled, + kFIRIsAnalyticsCollectionDeactivated + ]; + for (NSString *key in measurementKeys) { + id value = infoDictionary[key] ?: self.optionsDictionary[key] ?: nil; + if (!value) { + continue; + } + tempAnalyticsOptions[key] = value; + } + _analyticsOptionsDictionary = tempAnalyticsOptions; + } + return _analyticsOptionsDictionary; +} + +- (NSDictionary *)analyticsOptionsDictionary { + return [self analyticsOptionsDictionaryWithInfoDictionary:[NSBundle mainBundle].infoDictionary]; +} + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. This uses the old plist flag IS_MEASUREMENT_ENABLED, which should still + * be supported. + */ +- (BOOL)isMeasurementEnabled { + if (self.isAnalyticsCollectionDeactivated) { + return NO; + } + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsMeasurementEnabled]; + if (value == nil) { + // TODO: This could probably be cleaned up since FIROptions shouldn't know about FIRApp or have + // to check if it's the default app. The FIROptions instance can't be modified after + // `+configure` is called, so it's not a good place to copy it either in case the flag is + // changed at runtime. + + // If no values are set for Analytics, fall back to the global collection switch in FIRApp. + // Analytics only supports the default FIRApp, so check that first. + if (![FIRApp isDefaultAppConfigured]) { + return NO; + } + + // Fall back to the default app's collection switch when the key is not in the dictionary. + return [FIRApp defaultApp].isDataCollectionDefaultEnabled; + } + return [value boolValue]; +} + +- (BOOL)isAnalyticsCollectionExplicitlySet { + // If it's de-activated, it classifies as explicity set. If not, it's not a good enough indication + // that the developer wants FirebaseAnalytics enabled so continue checking. + if (self.isAnalyticsCollectionDeactivated) { + return YES; + } + + // Check if the current Analytics flag is set. + id collectionEnabledObject = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionEnabled]; + if (collectionEnabledObject && [collectionEnabledObject isKindOfClass:[NSNumber class]]) { + // It doesn't matter what the value is, it's explicitly set. + return YES; + } + + // Check if the old measurement flag is set. + id measurementEnabledObject = self.analyticsOptionsDictionary[kFIRIsMeasurementEnabled]; + if (measurementEnabledObject && [measurementEnabledObject isKindOfClass:[NSNumber class]]) { + // It doesn't matter what the value is, it's explicitly set. + return YES; + } + + // No flags are set to explicitly enable or disable FirebaseAnalytics. + return NO; +} + +- (BOOL)isAnalyticsCollectionEnabled { + if (self.isAnalyticsCollectionDeactivated) { + return NO; + } + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionEnabled]; + if (value == nil) { + return self.isMeasurementEnabled; // Fall back to older plist flag. + } + return [value boolValue]; +} + +- (BOOL)isAnalyticsCollectionDeactivated { + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionDeactivated]; + if (value == nil) { + return NO; // Analytics Collection is not deactivated when the key is not in the dictionary. + } + return [value boolValue]; +} + +- (BOOL)isAnalyticsEnabled { + return [self.optionsDictionary[kFIRIsAnalyticsEnabled] boolValue]; +} + +- (BOOL)isSignInEnabled { + return [self.optionsDictionary[kFIRIsSignInEnabled] boolValue]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m new file mode 100644 index 0000000..f458a3a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +#ifndef Firebase_VERSION +#error "Firebase_VERSION is not defined: add -DFirebase_VERSION=... to the build invocation" +#endif + +// The following two macros supply the incantation so that the C +// preprocessor does not try to parse the version as a floating +// point number. See +// https://www.guyrutenberg.com/2008/12/20/expanding-macros-into-string-constants-in-c/ +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x + +NSString* FIRFirebaseVersion(void) { + return @STR(Firebase_VERSION); +} diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAppInternal.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAppInternal.h new file mode 100644 index 0000000..6c7d723 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAppInternal.h @@ -0,0 +1,153 @@ +/* + * 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 + +@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; +extern NSString *const kFirebaseCoreErrorDomain; + +/** The NSUserDefaults suite name for FirebaseCore, for those storage locations that use it. */ +extern NSString *const kFirebaseCoreDefaultsSuiteName; + +/** + * 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; + +/** @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; + +/** + * 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 to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * 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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponent.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponent.h new file mode 100644 index 0000000..cb51ee7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/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 + +@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 *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 *)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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentContainer.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentContainer.h new file mode 100644 index 0000000..af18a93 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentContainer.h @@ -0,0 +1,41 @@ +/* + * 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 + +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> 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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentType.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentType.h new file mode 100644 index 0000000..6f2aca7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/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 + +@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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h new file mode 100644 index 0000000..76c0c05 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/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 + +@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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRDependency.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRDependency.h new file mode 100644 index 0000000..46e9b7e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/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 + +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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h new file mode 100644 index 0000000..9f94256 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/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 + +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 required 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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLibrary.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLibrary.h new file mode 100644 index 0000000..9575e94 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * 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 + +@class FIRApp; +@class FIRComponent; + +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 *)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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLogger.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLogger.h new file mode 100644 index 0000000..b6242ff --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLogger.h @@ -0,0 +1,146 @@ +/* + * 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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern FIRLoggerService kFIRLoggerAnalytics; +extern FIRLoggerService kFIRLoggerCrash; +extern FIRLoggerService kFIRLoggerCore; +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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIROptionsInternal.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIROptionsInternal.h new file mode 100644 index 0000000..8efc5fc --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIROptionsInternal.h @@ -0,0 +1,115 @@ +/* + * 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 + +/** + * 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 + NS_DESIGNATED_INITIALIZER; + +/** + * 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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FirebaseCoreInternal.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FirebaseCoreInternal.h new file mode 100644 index 0000000..88d012b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Private/FirebaseCoreInternal.h @@ -0,0 +1,28 @@ +// 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. + +#import + +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRComponent.h" +#import "FirebaseCore/Sources/Private/FIRComponentContainer.h" +#import "FirebaseCore/Sources/Private/FIRComponentType.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/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h new file mode 100644 index 0000000..f5578c6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h @@ -0,0 +1,127 @@ +/* + * 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 + +@class FIROptions; + +NS_ASSUME_NONNULL_BEGIN + +/** A block that takes a BOOL and has no return value. */ +typedef void (^FIRAppVoidBoolCallback)(BOOL success) NS_SWIFT_NAME(FirebaseAppVoidBoolCallback); + +/** + * The entry point of Firebase SDKs. + * + * Initialize and configure FIRApp using +[FIRApp configure] + * or other customized ways as shown below. + * + * The logging system has two modes: default mode and debug mode. In default mode, only logs with + * log level Notice, Warning and Error will be sent to device. In debug mode, all logs will be sent + * to device. The log levels that Firebase uses are consistent with the ASL log levels. + * + * Enable debug mode by passing the -FIRDebugEnabled argument to the application. You can add this + * argument in the application's Xcode scheme. When debug mode is enabled via -FIRDebugEnabled, + * further executions of the application will also be in debug mode. In order to return to default + * mode, you must explicitly disable the debug mode with the application argument -FIRDebugDisabled. + * + * It is also possible to change the default logging level in code by calling setLoggerLevel: on + * the FIRConfiguration interface. + */ +NS_SWIFT_NAME(FirebaseApp) +@interface FIRApp : NSObject + +/** + * Configures a default Firebase app. Raises an exception if any configuration step fails. The + * default app is named "__FIRAPP_DEFAULT". This method should be called after the app is launched + * and before using Firebase services. This method should be called from the main thread and + * contains synchronous file I/O (reading GoogleService-Info.plist from disk). + */ ++ (void)configure; + +/** + * Configures the default Firebase app with the provided options. The default app is named + * "__FIRAPP_DEFAULT". Raises an exception if any configuration step fails. This method should be + * called from the main thread. + * + * @param options The Firebase application options used to configure the service. + */ ++ (void)configureWithOptions:(FIROptions *)options NS_SWIFT_NAME(configure(options:)); + +/** + * Configures a Firebase app with the given name and options. Raises an exception if any + * configuration step fails. This method should be called from the main thread. + * + * @param name The application's name given by the developer. The name should should only contain + Letters, Numbers and Underscore. + * @param options The Firebase application options used to configure the services. + */ +// clang-format off ++ (void)configureWithName:(NSString *)name + options:(FIROptions *)options NS_SWIFT_NAME(configure(name:options:)); +// clang-format on + +/** + * Returns the default app, or nil if the default app does not exist. + */ ++ (nullable FIRApp *)defaultApp NS_SWIFT_NAME(app()); + +/** + * Returns a previously created FIRApp instance with the given name, or nil if no such app exists. + * This method is thread safe. + */ ++ (nullable FIRApp *)appNamed:(NSString *)name NS_SWIFT_NAME(app(name:)); + +/** + * Returns the set of all extant FIRApp instances, or nil if there are no FIRApp instances. This + * method is thread safe. + */ +@property(class, readonly, nullable) NSDictionary *allApps; + +/** + * Cleans up the current FIRApp, freeing associated data and returning its name to the pool for + * future use. This method is thread safe. + */ +- (void)deleteApp:(FIRAppVoidBoolCallback)completion; + +/** + * FIRApp instances should not be initialized directly. Call +[FIRApp configure], + * +[FIRApp configureWithOptions:], or +[FIRApp configureWithNames:options:] directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Gets the name of this app. + */ +@property(nonatomic, copy, readonly) NSString *name; + +/** + * Gets a copy of the options for this app. These are non-modifiable. + */ +@property(nonatomic, copy, readonly) FIROptions *options; + +/** + * Gets or sets whether automatic data collection is enabled for all products. Defaults to `YES` + * unless `FirebaseDataCollectionDefaultEnabled` is set to `NO` in your app's Info.plist. This value + * is persisted across runs of the app so that it can be set once when users have consented to + * collection. + */ +@property(nonatomic, readwrite, getter=isDataCollectionDefaultEnabled) + BOOL dataCollectionDefaultEnabled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h new file mode 100644 index 0000000..2b8e678 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h @@ -0,0 +1,45 @@ +/* + * 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 + +#import "FIRLoggerLevel.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * This interface provides global level properties that the developer can tweak. + */ +NS_SWIFT_NAME(FirebaseConfiguration) +@interface FIRConfiguration : NSObject + +/** Returns the shared configuration object. */ +@property(class, nonatomic, readonly) FIRConfiguration *sharedInstance NS_SWIFT_NAME(shared); + +/** + * Sets the logging level for internal Firebase logging. Firebase will only log messages + * that are logged at or below loggerLevel. The messages are logged both to the Xcode + * console and to the device's log. Note that if an app is running from AppStore, it will + * never log above FIRLoggerLevelNotice even if loggerLevel is set to a higher (more verbose) + * setting. + * + * @param loggerLevel The maximum logging level. The default level is set to FIRLoggerLevelNotice. + */ +- (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h new file mode 100644 index 0000000..dca3aa0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +// Note that importing GULLoggerLevel.h will lead to a non-modular header +// import error. + +/** + * The log levels used by internal logging. + */ +typedef NS_ENUM(NSInteger, FIRLoggerLevel) { + /** Error level, matches ASL_LEVEL_ERR. */ + FIRLoggerLevelError = 3, + /** Warning level, matches ASL_LEVEL_WARNING. */ + FIRLoggerLevelWarning = 4, + /** Notice level, matches ASL_LEVEL_NOTICE. */ + FIRLoggerLevelNotice = 5, + /** Info level, matches ASL_LEVEL_INFO. */ + FIRLoggerLevelInfo = 6, + /** Debug level, matches ASL_LEVEL_DEBUG. */ + FIRLoggerLevelDebug = 7, + /** Minimum log level. */ + FIRLoggerLevelMin = FIRLoggerLevelError, + /** Maximum log level. */ + FIRLoggerLevelMax = FIRLoggerLevelDebug +} NS_SWIFT_NAME(FirebaseLoggerLevel); diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h new file mode 100644 index 0000000..afabbf1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h @@ -0,0 +1,126 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class provides constant fields of Google APIs. + */ +NS_SWIFT_NAME(FirebaseOptions) +@interface FIROptions : NSObject + +/** + * Returns the default options. The first time this is called it synchronously reads + * GoogleService-Info.plist from disk. + */ ++ (nullable FIROptions *)defaultOptions NS_SWIFT_NAME(defaultOptions()); + +/** + * An iOS API key used for authenticating requests from your app, e.g. + * @"AIzaSyDdVgKwhZl0sTTTLZ7iTmt1r3N2cJLnaDk", used to identify your app to Google servers. + */ +@property(nonatomic, copy, nullable) NSString *APIKey NS_SWIFT_NAME(apiKey); + +/** + * The bundle ID for the application. Defaults to `[[NSBundle mainBundle] bundleID]` when not set + * manually or in a plist. + */ +@property(nonatomic, copy) NSString *bundleID; + +/** + * The OAuth2 client ID for iOS application used to authenticate Google users, for example + * @"12345.apps.googleusercontent.com", used for signing in with Google. + */ +@property(nonatomic, copy, nullable) NSString *clientID; + +/** + * The tracking ID for Google Analytics, e.g. @"UA-12345678-1", used to configure Google Analytics. + */ +@property(nonatomic, copy, nullable) NSString *trackingID; + +/** + * The Project Number from the Google Developer's console, for example @"012345678901", used to + * configure Google Cloud Messaging. + */ +@property(nonatomic, copy) NSString *GCMSenderID NS_SWIFT_NAME(gcmSenderID); + +/** + * The Project ID from the Firebase console, for example @"abc-xyz-123". + */ +@property(nonatomic, copy, nullable) NSString *projectID; + +/** + * The Android client ID used in Google AppInvite when an iOS app has its Android version, for + * example @"12345.apps.googleusercontent.com". + */ +@property(nonatomic, copy, nullable) NSString *androidClientID; + +/** + * The Google App ID that is used to uniquely identify an instance of an app. + */ +@property(nonatomic, copy) NSString *googleAppID; + +/** + * The database root URL, e.g. @"http://abc-xyz-123.firebaseio.com". + */ +@property(nonatomic, copy, nullable) NSString *databaseURL; + +/** + * The URL scheme used to set up Durable Deep Link service. + */ +@property(nonatomic, copy, nullable) NSString *deepLinkURLScheme; + +/** + * The Google Cloud Storage bucket name, e.g. @"abc-xyz-123.storage.firebase.com". + */ +@property(nonatomic, copy, nullable) NSString *storageBucket; + +/** + * The App Group identifier to share data between the application and the application extensions. + * The App Group must be configured in the application and on the Apple Developer Portal. Default + * value `nil`. + */ +@property(nonatomic, copy, nullable) NSString *appGroupID; + +/** + * Initializes a customized instance of FIROptions from the file at the given plist file path. This + * will read the file synchronously from disk. + * For example, + * NSString *filePath = + * [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"]; + * FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath]; + * Returns nil if the plist file does not exist or is invalid. + */ +- (nullable instancetype)initWithContentsOfFile:(NSString *)plistPath NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a customized instance of FIROptions with required fields. Use the mutable properties + * to modify fields for configuring specific services. + */ +// clang-format off +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + GCMSenderID:(NSString *)GCMSenderID + NS_SWIFT_NAME(init(googleAppID:gcmSenderID:)) NS_DESIGNATED_INITIALIZER; +// clang-format on + +/** Unavailable. Please use `init(contentsOfFile:)` or `init(googleAppID:gcmSenderID:)` instead. */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h new file mode 100644 index 0000000..651edaf --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Returns the current version of Firebase. */ +NS_SWIFT_NAME(FirebaseVersion()) +NSString* FIRFirebaseVersion(void); + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h new file mode 100644 index 0000000..680d604 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h @@ -0,0 +1,21 @@ +/* + * 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 "FIRApp.h" +#import "FIRConfiguration.h" +#import "FIRLoggerLevel.h" +#import "FIROptions.h" +#import "FIRVersion.h" diff --git a/saraWhatsUp/Pods/FirebaseCore/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h b/saraWhatsUp/Pods/FirebaseCore/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h new file mode 100644 index 0000000..69c4072 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.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 + +NS_ASSUME_NONNULL_BEGIN + +/** If present, is a BOOL wrapped in an NSNumber. */ +#define kFIRCDIsDataCollectionDefaultEnabledKey @"FIRCDIsDataCollectionDefaultEnabledKey" + +/** If present, is an int32_t wrapped in an NSNumber. */ +#define kFIRCDConfigurationTypeKey @"FIRCDConfigurationTypeKey" + +/** If present, is an NSString. */ +#define kFIRCDSdkNameKey @"FIRCDSdkNameKey" + +/** If present, is an NSString. */ +#define kFIRCDSdkVersionKey @"FIRCDSdkVersionKey" + +/** If present, is an int32_t wrapped in an NSNumber. */ +#define kFIRCDllAppsCountKey @"FIRCDllAppsCountKey" + +/** If present, is an NSString. */ +#define kFIRCDGoogleAppIDKey @"FIRCDGoogleAppIDKey" + +/** If present, is an NSString. */ +#define kFIRCDBundleIDKey @"FIRCDBundleID" + +/** If present, is a BOOL wrapped in an NSNumber. */ +#define kFIRCDUsingOptionsFromDefaultPlistKey @"FIRCDUsingOptionsFromDefaultPlistKey" + +/** If present, is an NSString. */ +#define kFIRCDLibraryVersionIDKey @"FIRCDLibraryVersionIDKey" + +/** If present, is an NSString. */ +#define kFIRCDFirebaseUserAgentKey @"FIRCDFirebaseUserAgentKey" + +/** Defines the interface of a data object needed to log diagnostics data. */ +@protocol FIRCoreDiagnosticsData + +@required + +/** A dictionary containing data (non-exhaustive) to be logged in diagnostics. */ +@property(nonatomic) NSDictionary *diagnosticObjects; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h b/saraWhatsUp/Pods/FirebaseCore/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h new file mode 100644 index 0000000..2b0eb71 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.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. + */ + +#import + +#import "FIRCoreDiagnosticsData.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Allows the interoperation of FirebaseCore and FirebaseCoreDiagnostics. */ +@protocol FIRCoreDiagnosticsInterop + +/** Sends the given diagnostics data. + * + * @param diagnosticsData The diagnostics data object to send. + */ ++ (void)sendDiagnosticsData:(id)diagnosticsData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCore/LICENSE b/saraWhatsUp/Pods/FirebaseCore/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/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/saraWhatsUp/Pods/FirebaseCore/README.md b/saraWhatsUp/Pods/FirebaseCore/README.md new file mode 100644 index 0000000..7be298d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCore/README.md @@ -0,0 +1,319 @@ +[![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-appcheck-badge]][gh-actions] +[![Actions Status][gh-appdistribution-badge]][gh-actions] +[![Actions Status][gh-auth-badge]][gh-actions] +[![Actions Status][gh-cocoapods-integration-badge]][gh-actions] +[![Actions Status][gh-core-badge]][gh-actions] +[![Actions Status][gh-core-diagnostics-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-google-utilities-badge]][gh-actions] +[![Actions Status][gh-google-utilities-components-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-mlmodeldownloader-badge]][gh-actions] +[![Actions Status][gh-performance-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] + +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics +and FirebaseML. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. +1. [Standard pod install](README.md#standard-pod-install) +1. [Swift Package Manager](SwiftPackageManager.md) +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). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager.md](SwiftPackageManager.md). + +### Installing from GitHub + +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: +```ruby +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: + +```ruby +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). + +### 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 12.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +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 + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### 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/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@13 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. 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. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md). + +## 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 Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### 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. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduces official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on 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 watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are 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-appcheck-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/app_check/badge.svg +[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg +[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg +[gh-cocoapods-integration-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/cocoapods-integration/badge.svg +[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg +[gh-core-diagnostics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core-diagnostics/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-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg +[gh-google-utilities-components-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities-components/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-mlmodeldownloader-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/mlmodeldownloader/badge.svg +[gh-performance-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/performance/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 diff --git a/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m new file mode 100644 index 0000000..c06da7f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m @@ -0,0 +1,551 @@ +/* + * 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 +#include + +#import + +#import +#import +#import + +#import "Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h" +#import "Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h" + +#import +#import +#import + +#import "Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h" + +/** The logger service string to use when printing to the console. */ +static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]"; + +#ifdef FIREBASE_BUILD_ZIP_FILE +static BOOL kUsingZipFile = YES; +#else // FIREBASE_BUILD_ZIP_FILE +static BOOL kUsingZipFile = NO; +#endif // FIREBASE_BUILD_ZIP_FILE + +#if SWIFT_PACKAGE +#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM +#elif FIREBASE_BUILD_CARTHAGE +#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE +#elif FIREBASE_BUILD_ZIP_FILE +#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE +#else +#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS +#endif + +static NSString *const kFIRServiceMLModelInterpreter = @"MLModelInterpreter"; + +static NSString *const kFIRServiceAdMob = @"AdMob"; +static NSString *const kFIRServiceAuth = @"Auth"; +static NSString *const kFIRServiceAuthUI = @"AuthUI"; +static NSString *const kFIRServiceCrash = @"Crash"; +static NSString *const kFIRServiceDatabase = @"Database"; +static NSString *const kFIRServiceDynamicLinks = @"DynamicLinks"; +static NSString *const kFIRServiceFirestore = @"Firestore"; +static NSString *const kFIRServiceFunctions = @"Functions"; +static NSString *const kFIRServiceIAM = @"InAppMessaging"; +static NSString *const kFIRServiceInstanceID = @"InstanceID"; +static NSString *const kFIRServiceInvites = @"Invites"; +static NSString *const kFIRServiceMessaging = @"Messaging"; +static NSString *const kFIRServiceMeasurement = @"Measurement"; +static NSString *const kFIRServicePerformance = @"Performance"; +static NSString *const kFIRServiceRemoteConfig = @"RemoteConfig"; +static NSString *const kFIRServiceStorage = @"Storage"; +static NSString *const kGGLServiceAnalytics = @"Analytics"; +static NSString *const kGGLServiceSignIn = @"SignIn"; +static NSString *const kFIRAppDiagnosticsConfigurationTypeKey = + @"FIRAppDiagnosticsConfigurationTypeKey"; +static NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRAppDiagnosticsFIRAppKey"; +static NSString *const kFIRAppDiagnosticsSDKNameKey = @"FIRAppDiagnosticsSDKNameKey"; +static NSString *const kFIRAppDiagnosticsSDKVersionKey = @"FIRAppDiagnosticsSDKVersionKey"; +static NSString *const kFIRCoreDiagnosticsHeartbeatTag = @"FIRCoreDiagnostics"; + +/** + * The file name to the recent heartbeat date. + */ +NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTICS_HEARTBEAT_DATE"; + +/** + * @note This should implement the GDTCOREventDataObject protocol, but can't because of + * weak-linking. + */ +@interface FIRCoreDiagnosticsLog : NSObject + +/** The config that will be converted to proto bytes. */ +@property(nonatomic) logs_proto_mobilesdk_ios_ICoreConfiguration config; + +@end + +@implementation FIRCoreDiagnosticsLog + +- (instancetype)initWithConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration)config { + self = [super init]; + if (self) { + _config = config; + } + return self; +} + +// Provided and required by the GDTCOREventDataObject protocol. +- (NSData *)transportBytes { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + + // Encode 1 time to determine the size. + if (!pb_encode(&sizestream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) { + GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for size: %s", + PB_GET_ERROR(&sizestream)); + } + + // Encode a 2nd time to actually get the bytes from it. + size_t bufferSize = sizestream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + CFDataSetLength(dataRef, bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) { + GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for bytes: %s", + PB_GET_ERROR(&ostream)); + } + CFDataSetLength(dataRef, ostream.bytes_written); + + return CFBridgingRelease(dataRef); +} + +- (void)dealloc { + pb_release(logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config); +} + +@end + +NS_ASSUME_NONNULL_BEGIN + +/** This class produces a protobuf containing diagnostics and usage data to be logged. */ +@interface FIRCoreDiagnostics : NSObject + +/** The queue on which all diagnostics collection will occur. */ +@property(nonatomic, readonly) dispatch_queue_t diagnosticsQueue; + +/** The transport object used to send data. */ +@property(nonatomic, readonly) GDTCORTransport *transport; + +/** The storage to store the date of the last sent heartbeat. */ +@property(nonatomic, readonly) GULHeartbeatDateStorage *heartbeatDateStorage; + +@end + +NS_ASSUME_NONNULL_END + +@implementation FIRCoreDiagnostics + ++ (instancetype)sharedInstance { + static FIRCoreDiagnostics *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRCoreDiagnostics alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + GDTCORTransport *transport = [[GDTCORTransport alloc] initWithMappingID:@"137" + transformers:nil + target:kGDTCORTargetFLL]; + + GULHeartbeatDateStorage *dateStorage = + [[GULHeartbeatDateStorage alloc] initWithFileName:kFIRCoreDiagnosticsHeartbeatDateFileName]; + + return [self initWithTransport:transport heartbeatDateStorage:dateStorage]; +} + +/** Initializer for unit tests. + * + * @param transport A `GDTCORTransport` instance which that be used to send event. + * @param heartbeatDateStorage An instanse of date storage to track heartbeat sending. + * @return Returns the initialized `FIRCoreDiagnostics` instance. + */ +- (instancetype)initWithTransport:(GDTCORTransport *)transport + heartbeatDateStorage:(GULHeartbeatDateStorage *)heartbeatDateStorage { + self = [super init]; + if (self) { + _diagnosticsQueue = + dispatch_queue_create("com.google.FIRCoreDiagnostics", DISPATCH_QUEUE_SERIAL); + _transport = transport; + _heartbeatDateStorage = heartbeatDateStorage; + } + return self; +} + +#pragma mark - nanopb helper functions + +/** Callocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. + * + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param string The string to encode as pb_bytes. + */ +pb_bytes_array_t *FIREncodeString(NSString *string) { + NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding]; + return FIREncodeData(stringBytes); +} + +/** Callocs a pb_bytes_array and copies the given NSData bytes into the bytes array. + * + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param data The data to copy into the new bytes array. + */ +pb_bytes_array_t *FIREncodeData(NSData *data) { + pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + if (pbBytesArray != NULL) { + [data getBytes:pbBytesArray->bytes length:data.length]; + pbBytesArray->size = (pb_size_t)data.length; + } + return pbBytesArray; +} + +/** Maps a service string to the representative nanopb enum. + * + * @param serviceString The SDK service string to convert. + * @return The representative nanopb enum. + */ +logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType FIRMapFromServiceStringToTypeEnum( + NSString *serviceString) { + static NSDictionary *serviceStringToTypeEnum; + if (serviceStringToTypeEnum == nil) { + serviceStringToTypeEnum = @{ + kFIRServiceAdMob : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ADMOB), + kFIRServiceMessaging : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MESSAGING), + kFIRServiceMeasurement : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MEASUREMENT), + kFIRServiceRemoteConfig : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_REMOTE_CONFIG), + kFIRServiceDatabase : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DATABASE), + kFIRServiceDynamicLinks : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DYNAMIC_LINKS), + kFIRServiceAuth : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH), + kFIRServiceAuthUI : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH_UI), + kFIRServiceFirestore : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FIRESTORE), + kFIRServiceFunctions : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FUNCTIONS), + kFIRServicePerformance : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE), + kFIRServiceStorage : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE), + kFIRServiceMLModelInterpreter : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER), + kGGLServiceAnalytics : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS), + kGGLServiceSignIn : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SIGN_IN), + kFIRServiceIAM : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_IN_APP_MESSAGING), + }; + } + if (serviceStringToTypeEnum[serviceString] != nil) { + return (int32_t)serviceStringToTypeEnum[serviceString].longLongValue; + } + return logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE; +} + +#pragma mark - Proto population functions + +/** Populates the given proto with data related to an SDK logDiagnostics call from the + * diagnosticObjects dictionary. + * + * @param config The proto to populate + * @param diagnosticObjects The dictionary of diagnostics objects. + */ +void FIRPopulateProtoWithInfoFromUserInfoParams(logs_proto_mobilesdk_ios_ICoreConfiguration *config, + NSDictionary *diagnosticObjects) { + NSNumber *configurationType = diagnosticObjects[kFIRCDConfigurationTypeKey]; + if (configurationType != nil) { + switch (configurationType.integerValue) { + case logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE: + config->configuration_type = + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE; + config->has_configuration_type = 1; + break; + case logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK: + config->configuration_type = + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK; + config->has_configuration_type = 1; + break; + default: + break; + } + } + + NSString *sdkName = diagnosticObjects[kFIRCDSdkNameKey]; + if (sdkName) { + config->sdk_name = FIRMapFromServiceStringToTypeEnum(sdkName); + config->has_sdk_name = 1; + } + + NSString *version = diagnosticObjects[kFIRCDSdkVersionKey]; + if (version) { + config->sdk_version = FIREncodeString(version); + } +} + +/** Populates the given proto with data from the calling FIRApp using the given + * diagnosticObjects dictionary. + * + * @param config The proto to populate + * @param diagnosticObjects The dictionary of diagnostics objects. + */ +void FIRPopulateProtoWithCommonInfoFromApp(logs_proto_mobilesdk_ios_ICoreConfiguration *config, + NSDictionary *diagnosticObjects) { + config->pod_name = logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE; + config->has_pod_name = 1; + + if (!diagnosticObjects[kFIRCDllAppsCountKey]) { + GDTCORLogError(GDTCORMCEGeneralError, @"%@", + @"App count is a required value in the data dict."); + } + config->app_count = (int32_t)[diagnosticObjects[kFIRCDllAppsCountKey] integerValue]; + config->has_app_count = 1; + + NSString *googleAppID = diagnosticObjects[kFIRCDGoogleAppIDKey]; + if (googleAppID.length) { + config->app_id = FIREncodeString(googleAppID); + } + + NSString *bundleID = diagnosticObjects[kFIRCDBundleIDKey]; + if (bundleID.length) { + config->bundle_id = FIREncodeString(bundleID); + } + + NSString *firebaseUserAgent = diagnosticObjects[kFIRCDFirebaseUserAgentKey]; + if (firebaseUserAgent.length) { + config->platform_info = FIREncodeString(firebaseUserAgent); + } + + NSNumber *usingOptionsFromDefaultPlist = diagnosticObjects[kFIRCDUsingOptionsFromDefaultPlistKey]; + if (usingOptionsFromDefaultPlist != nil) { + config->use_default_app = [usingOptionsFromDefaultPlist boolValue]; + config->has_use_default_app = 1; + } + + NSString *libraryVersionID = diagnosticObjects[kFIRCDLibraryVersionIDKey]; + if (libraryVersionID) { + config->icore_version = FIREncodeString(libraryVersionID); + } + + NSString *deviceModel = [GULAppEnvironmentUtil deviceModel]; + if (deviceModel.length) { + config->device_model = FIREncodeString(deviceModel); + } + + NSString *osVersion = [GULAppEnvironmentUtil systemVersion]; + if (osVersion.length) { + config->os_version = FIREncodeString(osVersion); + } + + config->using_zip_file = kUsingZipFile; + config->has_using_zip_file = 1; + config->deployment_type = kDeploymentType; + config->has_deployment_type = 1; + config->deployed_in_app_store = [GULAppEnvironmentUtil isFromAppStore]; + config->has_deployed_in_app_store = 1; +} + +/** Populates the given proto with installed services data. + * + * @param config The proto to populate + */ +void FIRPopulateProtoWithInstalledServices(logs_proto_mobilesdk_ios_ICoreConfiguration *config) { + NSMutableArray *sdkServiceInstalledArray = [NSMutableArray array]; + + // AdMob + if (NSClassFromString(@"GADBannerView") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAdMob))]; + } + // CloudMessaging + if (NSClassFromString(@"FIRMessaging") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMessaging))]; + } + // RemoteConfig + if (NSClassFromString(@"FIRRemoteConfig") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceRemoteConfig))]; + } + // Measurement/Analtyics + if (NSClassFromString(@"FIRAnalytics") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMeasurement))]; + } + // ML Model Interpreter + if (NSClassFromString(@"FIRCustomModelInterpreter") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLModelInterpreter))]; + } + // Database + if (NSClassFromString(@"FIRDatabase") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceDatabase))]; + } + // DynamicDeepLink + if (NSClassFromString(@"FIRDynamicLinks") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceDynamicLinks))]; + } + // Auth + if (NSClassFromString(@"FIRAuth") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAuth))]; + } + // AuthUI + if (NSClassFromString(@"FUIAuth") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAuthUI))]; + } + // Firestore + if (NSClassFromString(@"FIRFirestore") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceFirestore))]; + } + // Functions + if (NSClassFromString(@"FIRFunctions") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceFunctions))]; + } + // Performance + if (NSClassFromString(@"FIRPerformance") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServicePerformance))]; + } + // Storage + if (NSClassFromString(@"FIRStorage") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceStorage))]; + } + // SignIn via Google pod + if (NSClassFromString(@"GIDSignIn") != nil && NSClassFromString(@"GGLContext") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kGGLServiceSignIn))]; + } + // Analytics via Google pod + if (NSClassFromString(@"GAI") != nil && NSClassFromString(@"GGLContext") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kGGLServiceAnalytics))]; + } + + // In-App Messaging + if (NSClassFromString(@"FIRInAppMessaging") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceIAM))]; + } + + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *servicesInstalled = + calloc(sdkServiceInstalledArray.count, + sizeof(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType)); + if (servicesInstalled == NULL) { + return; + } + for (NSUInteger i = 0; i < sdkServiceInstalledArray.count; i++) { + NSNumber *typeEnum = sdkServiceInstalledArray[i]; + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType serviceType = + (int32_t)typeEnum.integerValue; + servicesInstalled[i] = serviceType; + } + + config->sdk_service_installed = servicesInstalled; + config->sdk_service_installed_count = (int32_t)sdkServiceInstalledArray.count; +} + +/** Populates the proto with Info.plist values. + * + * @param config The proto to populate. + */ +void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfiguration *config) { + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + + NSString *xcodeVersion = info[@"DTXcodeBuild"] ?: @""; + NSString *sdkVersion = info[@"DTSDKBuild"] ?: @""; + NSString *combinedVersions = [NSString stringWithFormat:@"%@-%@", xcodeVersion, sdkVersion]; + config->apple_framework_version = FIREncodeString(combinedVersions); + + NSString *minVersion = info[@"MinimumOSVersion"]; + if (minVersion) { + config->min_supported_ios_version = FIREncodeString(minVersion); + } + + // Apps can turn off swizzling in the Info.plist, check if they've explicitly set the value and + // report it. It's enabled by default. + NSNumber *appDelegateSwizzledNum = info[@"FirebaseAppDelegateProxyEnabled"]; + BOOL appDelegateSwizzled = YES; + if ([appDelegateSwizzledNum isKindOfClass:[NSNumber class]]) { + appDelegateSwizzled = [appDelegateSwizzledNum boolValue]; + } + config->swizzling_enabled = appDelegateSwizzled; + config->has_swizzling_enabled = 1; +} + +#pragma mark - FIRCoreDiagnosticsInterop + ++ (void)sendDiagnosticsData:(nonnull id)diagnosticsData { + FIRCoreDiagnostics *diagnostics = [FIRCoreDiagnostics sharedInstance]; + [diagnostics sendDiagnosticsData:diagnosticsData]; +} + +- (void)sendDiagnosticsData:(nonnull id)diagnosticsData { + dispatch_async(self.diagnosticsQueue, ^{ + NSDictionary *diagnosticObjects = diagnosticsData.diagnosticObjects; + NSNumber *isDataCollectionDefaultEnabled = + diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey]; + if (isDataCollectionDefaultEnabled && ![isDataCollectionDefaultEnabled boolValue]) { + return; + } + + // Create the proto. + logs_proto_mobilesdk_ios_ICoreConfiguration icore_config = + logs_proto_mobilesdk_ios_ICoreConfiguration_init_default; + + icore_config.using_gdt = 1; + icore_config.has_using_gdt = 1; + + // Populate the proto with information. + FIRPopulateProtoWithInfoFromUserInfoParams(&icore_config, diagnosticObjects); + FIRPopulateProtoWithCommonInfoFromApp(&icore_config, diagnosticObjects); + FIRPopulateProtoWithInstalledServices(&icore_config); + FIRPopulateProtoWithInfoPlistValues(&icore_config); + [self setHeartbeatFlagIfNeededToConfig:&icore_config]; + + // This log object is capable of converting the proto to bytes. + FIRCoreDiagnosticsLog *log = [[FIRCoreDiagnosticsLog alloc] initWithConfig:icore_config]; + + // Send the log as a telemetry event. + GDTCOREvent *event = [self.transport eventForTransport]; + event.dataObject = (id)log; + [self.transport sendTelemetryEvent:event]; + }); +} + +#pragma mark - Heartbeat + +- (void)setHeartbeatFlagIfNeededToConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration *)config { + // Check if need to send a heartbeat. + NSDate *currentDate = [NSDate date]; + NSDate *lastCheckin = + [self.heartbeatDateStorage heartbeatDateForTag:kFIRCoreDiagnosticsHeartbeatTag]; + if (lastCheckin) { + // Ensure the previous checkin was on a different date in the past. + if ([self isDate:currentDate inSameDayOrBeforeThan:lastCheckin]) { + return; + } + } + + // Update heartbeat sent date. + [self.heartbeatDateStorage setHearbeatDate:currentDate forTag:kFIRCoreDiagnosticsHeartbeatTag]; + // Set the flag. + config->sdk_name = logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE; + config->has_sdk_name = 1; +} + +- (BOOL)isDate:(NSDate *)date1 inSameDayOrBeforeThan:(NSDate *)date2 { + return [[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2] || + [date1 compare:date2] == NSOrderedAscending; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c new file mode 100644 index 0000000..2a9a622 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c @@ -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. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.7 */ + +#include "firebasecore.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[22] = { + PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, logs_proto_mobilesdk_ios_ICoreConfiguration, configuration_type, configuration_type, 0), + PB_FIELD( 7, UENUM , REPEATED, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_service_installed, configuration_type, 0), + PB_FIELD( 9, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, device_model, sdk_service_installed, 0), + PB_FIELD( 10, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_id, device_model, 0), + PB_FIELD( 12, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, bundle_id, app_id, 0), + PB_FIELD( 16, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, pod_name, bundle_id, 0), + PB_FIELD( 18, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, icore_version, pod_name, 0), + PB_FIELD( 19, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_version, icore_version, 0), + PB_FIELD( 20, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_name, sdk_version, 0), + PB_FIELD( 21, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_count, sdk_name, 0), + PB_FIELD( 22, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, os_version, app_count, 0), + PB_FIELD( 24, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, min_supported_ios_version, os_version, 0), + PB_FIELD( 25, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, use_default_app, min_supported_ios_version, 0), + PB_FIELD( 26, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, deployed_in_app_store, use_default_app, 0), + PB_FIELD( 27, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, dynamic_framework_count, deployed_in_app_store, 0), + PB_FIELD( 28, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, apple_framework_version, dynamic_framework_count, 0), + PB_FIELD( 29, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_zip_file, apple_framework_version, 0), + PB_FIELD( 30, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, deployment_type, using_zip_file, 0), + PB_FIELD( 31, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, platform_info, deployment_type, 0), + PB_FIELD( 33, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, swizzling_enabled, platform_info, 0), + PB_FIELD( 36, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_gdt, swizzling_enabled, 0), + PB_LAST_FIELD +}; + + + + + + + +/* @@protoc_insertion_point(eof) */ diff --git a/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h new file mode 100644 index 0000000..ac92211 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h @@ -0,0 +1,193 @@ +/* + * 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. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.7 */ + +#ifndef PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED +#define PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType { + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_UNKNOWN_CONFIGURATION_TYPE = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK = 2 +} logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_UNKNOWN_CONFIGURATION_TYPE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType)(logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType { + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_UNKNOWN_BUILD_TYPE = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_INTERNAL = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_EAP = 2, + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD = 3 +} logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_UNKNOWN_BUILD_TYPE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType)(logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType { + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ADMOB = 2, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_APP_INVITE = 3, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SIGN_IN = 5, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_GCM = 6, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MAPS = 7, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SCION = 8, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS = 9, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_APP_INDEXING = 10, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_CONFIG = 11, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DURABLE_DEEP_LINKS = 12, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_CRASH = 13, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH = 14, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DATABASE = 15, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE = 16, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MESSAGING = 17, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MEASUREMENT = 18, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_REMOTE_CONFIG = 19, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DYNAMIC_LINKS = 20, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_INVITES = 21, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH_UI = 22, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FIRESTORE = 23, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE = 24, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_FACE = 26, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_BARCODE = 27, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_TEXT = 28, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_LABEL = 29, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER = 30, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_IN_APP_MESSAGING = 31, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FUNCTIONS = 32, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_NATURAL_LANGUAGE = 33, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_AUTOML = 34, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION = 35 +} logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType)(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName { + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_UNKNOWN_POD_NAME = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_GOOGLE = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE = 2 +} logs_proto_mobilesdk_ios_ICoreConfiguration_PodName; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_UNKNOWN_POD_NAME +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_PodName)(logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType { + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_UNKNOWN = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE = 2, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE = 3, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM = 4 +} logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_UNKNOWN +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType)(logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM+1)) + +/* Struct definitions */ +typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration { + bool has_configuration_type; + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType configuration_type; + pb_size_t sdk_service_installed_count; + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *sdk_service_installed; + pb_bytes_array_t *device_model; + pb_bytes_array_t *app_id; + pb_bytes_array_t *bundle_id; + bool has_pod_name; + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName pod_name; + pb_bytes_array_t *icore_version; + pb_bytes_array_t *sdk_version; + bool has_sdk_name; + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType sdk_name; + bool has_app_count; + int32_t app_count; + pb_bytes_array_t *os_version; + pb_bytes_array_t *min_supported_ios_version; + bool has_use_default_app; + bool use_default_app; + bool has_deployed_in_app_store; + bool deployed_in_app_store; + bool has_dynamic_framework_count; + int32_t dynamic_framework_count; + pb_bytes_array_t *apple_framework_version; + bool has_using_zip_file; + bool using_zip_file; + bool has_deployment_type; + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType deployment_type; + pb_bytes_array_t *platform_info; + bool has_swizzling_enabled; + bool swizzling_enabled; + bool has_using_gdt; + bool using_gdt; +/* @@protoc_insertion_point(struct:logs_proto_mobilesdk_ios_ICoreConfiguration) */ +} logs_proto_mobilesdk_ios_ICoreConfiguration; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_default {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, 0, NULL, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0} +#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_zero {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, 0, NULL, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define logs_proto_mobilesdk_ios_ICoreConfiguration_pod_name_tag 16 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_configuration_type_tag 1 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_icore_version_tag 18 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_version_tag 19 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_service_installed_tag 7 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_name_tag 20 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_device_model_tag 9 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_os_version_tag 22 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_id_tag 10 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_bundle_id_tag 12 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_min_supported_ios_version_tag 24 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_use_default_app_tag 25 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_count_tag 21 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployed_in_app_store_tag 26 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_dynamic_framework_count_tag 27 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_apple_framework_version_tag 28 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_zip_file_tag 29 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployment_type_tag 30 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_platform_info_tag 31 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_swizzling_enabled_tag 33 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_gdt_tag 36 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[22]; + +/* Maximum encoded size of messages (where known) */ +/* logs_proto_mobilesdk_ios_ICoreConfiguration_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define FIREBASECORE_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Public/FIRCoreDiagnostics.h b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Public/FIRCoreDiagnostics.h new file mode 100644 index 0000000..5076d6b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Public/FIRCoreDiagnostics.h @@ -0,0 +1,18 @@ +/* + * 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. + */ + +// There are no actual public headers in the lib. This is a dummy public header to prevent Cocoapods +// from adding all internal headers as public. diff --git a/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h new file mode 100644 index 0000000..69c4072 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.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 + +NS_ASSUME_NONNULL_BEGIN + +/** If present, is a BOOL wrapped in an NSNumber. */ +#define kFIRCDIsDataCollectionDefaultEnabledKey @"FIRCDIsDataCollectionDefaultEnabledKey" + +/** If present, is an int32_t wrapped in an NSNumber. */ +#define kFIRCDConfigurationTypeKey @"FIRCDConfigurationTypeKey" + +/** If present, is an NSString. */ +#define kFIRCDSdkNameKey @"FIRCDSdkNameKey" + +/** If present, is an NSString. */ +#define kFIRCDSdkVersionKey @"FIRCDSdkVersionKey" + +/** If present, is an int32_t wrapped in an NSNumber. */ +#define kFIRCDllAppsCountKey @"FIRCDllAppsCountKey" + +/** If present, is an NSString. */ +#define kFIRCDGoogleAppIDKey @"FIRCDGoogleAppIDKey" + +/** If present, is an NSString. */ +#define kFIRCDBundleIDKey @"FIRCDBundleID" + +/** If present, is a BOOL wrapped in an NSNumber. */ +#define kFIRCDUsingOptionsFromDefaultPlistKey @"FIRCDUsingOptionsFromDefaultPlistKey" + +/** If present, is an NSString. */ +#define kFIRCDLibraryVersionIDKey @"FIRCDLibraryVersionIDKey" + +/** If present, is an NSString. */ +#define kFIRCDFirebaseUserAgentKey @"FIRCDFirebaseUserAgentKey" + +/** Defines the interface of a data object needed to log diagnostics data. */ +@protocol FIRCoreDiagnosticsData + +@required + +/** A dictionary containing data (non-exhaustive) to be logged in diagnostics. */ +@property(nonatomic) NSDictionary *diagnosticObjects; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h new file mode 100644 index 0000000..2b0eb71 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.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. + */ + +#import + +#import "FIRCoreDiagnosticsData.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Allows the interoperation of FirebaseCore and FirebaseCoreDiagnostics. */ +@protocol FIRCoreDiagnosticsInterop + +/** Sends the given diagnostics data. + * + * @param diagnosticsData The diagnostics data object to send. + */ ++ (void)sendDiagnosticsData:(id)diagnosticsData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseCoreDiagnostics/LICENSE b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/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/saraWhatsUp/Pods/FirebaseCoreDiagnostics/README.md b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/README.md new file mode 100644 index 0000000..7be298d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseCoreDiagnostics/README.md @@ -0,0 +1,319 @@ +[![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-appcheck-badge]][gh-actions] +[![Actions Status][gh-appdistribution-badge]][gh-actions] +[![Actions Status][gh-auth-badge]][gh-actions] +[![Actions Status][gh-cocoapods-integration-badge]][gh-actions] +[![Actions Status][gh-core-badge]][gh-actions] +[![Actions Status][gh-core-diagnostics-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-google-utilities-badge]][gh-actions] +[![Actions Status][gh-google-utilities-components-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-mlmodeldownloader-badge]][gh-actions] +[![Actions Status][gh-performance-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] + +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics +and FirebaseML. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. +1. [Standard pod install](README.md#standard-pod-install) +1. [Swift Package Manager](SwiftPackageManager.md) +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). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager.md](SwiftPackageManager.md). + +### Installing from GitHub + +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: +```ruby +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: + +```ruby +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). + +### 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 12.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +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 + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### 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/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@13 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. 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. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md). + +## 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 Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### 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. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduces official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on 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 watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are 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-appcheck-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/app_check/badge.svg +[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg +[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg +[gh-cocoapods-integration-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/cocoapods-integration/badge.svg +[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg +[gh-core-diagnostics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core-diagnostics/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-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg +[gh-google-utilities-components-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities-components/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-mlmodeldownloader-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/mlmodeldownloader/badge.svg +[gh-performance-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/performance/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 diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h new file mode 100644 index 0000000..834b740 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#import + +@protocol FIRAppCheckTokenResultInterop; + +NS_ASSUME_NONNULL_BEGIN + +NS_SWIFT_NAME(AppCheckTokenHandlerInterop) +typedef void (^FIRAppCheckTokenHandlerInterop)(id tokenResult); + +@protocol FIRAppCheckInterop + +/// Retrieve a cached or generate a new FAA Token. If forcingRefresh == YES always generates a new +/// token and updates the cache. +- (void)getTokenForcingRefresh:(BOOL)forcingRefresh + completion:(FIRAppCheckTokenHandlerInterop)handler + NS_SWIFT_NAME(getToken(forcingRefresh:completion:)); + +/// A notification with the specified name is sent to the default notification center +/// (`NotificationCenter.default`) each time a Firebase app check token is refreshed. +/// The user info dictionary contains `-[self notificationTokenKey]` and +/// `-[self notificationAppNameKey]` keys. +- (NSString *)tokenDidChangeNotificationName; + +/// `userInfo` key for the FAC token in a notification for `tokenDidChangeNotificationName`. +- (NSString *)notificationTokenKey; +/// `userInfo` key for the `FirebaseApp.name` in a notification for +/// `tokenDidChangeNotificationName`. +- (NSString *)notificationAppNameKey; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h new file mode 100644 index 0000000..cb86a1b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol FIRAppCheckTokenResultInterop + +/// App Check token in the case of success or a dummy token in the case of a failure. +/// In general, the value of the token should always be set to the request header. +@property(nonatomic, readonly) NSString *token; + +/// A token fetch error in the case of a failure or `nil` in the case of success. +@property(nonatomic, readonly, nullable) NSError *error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRAppInternal.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRAppInternal.h new file mode 100644 index 0000000..6c7d723 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRAppInternal.h @@ -0,0 +1,153 @@ +/* + * 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 + +@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; +extern NSString *const kFirebaseCoreErrorDomain; + +/** The NSUserDefaults suite name for FirebaseCore, for those storage locations that use it. */ +extern NSString *const kFirebaseCoreDefaultsSuiteName; + +/** + * 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; + +/** @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; + +/** + * 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 to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * 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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRComponent.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRComponent.h new file mode 100644 index 0000000..cb51ee7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/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 + +@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 *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 *)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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRComponentContainer.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRComponentContainer.h new file mode 100644 index 0000000..af18a93 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRComponentContainer.h @@ -0,0 +1,41 @@ +/* + * 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 + +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> 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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRComponentType.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRComponentType.h new file mode 100644 index 0000000..6f2aca7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/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 + +@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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h new file mode 100644 index 0000000..76c0c05 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/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 + +@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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRDependency.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRDependency.h new file mode 100644 index 0000000..46e9b7e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/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 + +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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h new file mode 100644 index 0000000..9f94256 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/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 + +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 required 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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRLibrary.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRLibrary.h new file mode 100644 index 0000000..9575e94 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * 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 + +@class FIRApp; +@class FIRComponent; + +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 *)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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRLogger.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRLogger.h new file mode 100644 index 0000000..b6242ff --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIRLogger.h @@ -0,0 +1,146 @@ +/* + * 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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern FIRLoggerService kFIRLoggerAnalytics; +extern FIRLoggerService kFIRLoggerCrash; +extern FIRLoggerService kFIRLoggerCore; +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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIROptionsInternal.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIROptionsInternal.h new file mode 100644 index 0000000..8efc5fc --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FIROptionsInternal.h @@ -0,0 +1,115 @@ +/* + * 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 + +/** + * 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 + NS_DESIGNATED_INITIALIZER; + +/** + * 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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FirebaseCoreInternal.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FirebaseCoreInternal.h new file mode 100644 index 0000000..88d012b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseCore/Sources/Private/FirebaseCoreInternal.h @@ -0,0 +1,28 @@ +// 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. + +#import + +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRComponent.h" +#import "FirebaseCore/Sources/Private/FIRComponentContainer.h" +#import "FirebaseCore/Sources/Private/FIRComponentType.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/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDataSnapshot.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDataSnapshot.m new file mode 100644 index 0000000..8801534 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDataSnapshot.m @@ -0,0 +1,105 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h" +#import "FirebaseDatabase/Sources/FTransformedEnumerator.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +@interface FIRDataSnapshot () +@property(nonatomic, strong) FIRDatabaseReference *ref; +@end + +@implementation FIRDataSnapshot + +- (id)initWithRef:(FIRDatabaseReference *)ref indexedNode:(FIndexedNode *)node { + self = [super init]; + if (self != nil) { + self->_ref = ref; + self->_node = node; + } + return self; +} + +- (id)value { + return [self.node.node val]; +} + +- (id)valueInExportFormat { + return [self.node.node valForExport:YES]; +} + +- (FIRDataSnapshot *)childSnapshotForPath:(NSString *)childPathString { + [FValidation validateFrom:@"child:" validPathString:childPathString]; + FPath *childPath = [[FPath alloc] initWith:childPathString]; + FIRDatabaseReference *childRef = [self.ref child:childPathString]; + + id childNode = [self.node.node getChild:childPath]; + return [[FIRDataSnapshot alloc] + initWithRef:childRef + indexedNode:[FIndexedNode indexedNodeWithNode:childNode]]; +} + +- (BOOL)hasChild:(NSString *)childPathString { + [FValidation validateFrom:@"hasChild:" validPathString:childPathString]; + FPath *childPath = [[FPath alloc] initWith:childPathString]; + return ![[self.node.node getChild:childPath] isEmpty]; +} + +- (id)priority { + id priority = [self.node.node getPriority]; + return priority.val; +} + +- (BOOL)hasChildren { + if ([self.node.node isLeafNode]) { + return false; + } else { + return ![self.node.node isEmpty]; + } +} + +- (BOOL)exists { + return ![self.node.node isEmpty]; +} + +- (NSString *)key { + return [self.ref key]; +} + +- (NSUInteger)childrenCount { + return [self.node.node numChildren]; +} + +- (NSEnumerator *)children { + return [[FTransformedEnumerator alloc] + initWithEnumerator:self.node.childEnumerator + andTransform:^id(FNamedNode *node) { + FIRDatabaseReference *childRef = [self.ref child:node.name]; + return [[FIRDataSnapshot alloc] + initWithRef:childRef + indexedNode:[FIndexedNode indexedNodeWithNode:node.node]]; + }]; +} + +- (NSString *)description { + return + [NSString stringWithFormat:@"Snap (%@) %@", self.key, self.node.node]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabase.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabase.m new file mode 100644 index 0000000..7ba88b1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabase.m @@ -0,0 +1,260 @@ +/* + * 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 + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "Interop/Auth/Public/FIRAuthInterop.h" + +#import "FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +@implementation FIRDatabase + ++ (FIRDatabase *)database { + if (![FIRApp isDefaultAppConfigured]) { + [NSException + raise:@"FIRAppNotConfigured" + format:@"The default FirebaseApp instance must be " + @"configured before the default Database instance " + @"can be initialized. One way to ensure this is to " + @"call `FirebaseApp.configure()` in the App Delegate's " + @"`application(_:didFinishLaunchingWithOptions:)` " + @"(or the `@main` struct's initializer in SwiftUI)."]; + } + return [FIRDatabase databaseForApp:[FIRApp defaultApp]]; +} + ++ (FIRDatabase *)databaseWithURL:(NSString *)url { + FIRApp *app = [FIRApp defaultApp]; + if (app == nil) { + [NSException + raise:@"FIRAppNotConfigured" + format: + @"Failed to get default Firebase Database instance. " + @"Must call `[FIRApp configure]` (`FirebaseApp.configure()` in " + @"Swift) before using Firebase Database."]; + } + return [FIRDatabase databaseForApp:app URL:url]; +} + ++ (FIRDatabase *)databaseForApp:(FIRApp *)app { + if (app == nil) { + [NSException raise:@"InvalidFIRApp" + format:@"nil FIRApp instance passed to databaseForApp."]; + } + NSString *url = app.options.databaseURL; + if (!url) { + if (!app.options.projectID) { + [NSException + raise:@"MissingProjectId" + format:@"Can't determine Firebase Database URL. Be sure to " + @"include a Project ID when calling " + @"`FirebaseApp.configure()`."]; + } + FFLog(@"I-RDB024002", @"Using default host for project %@", + app.options.projectID); + url = [NSString + stringWithFormat:@"https://%@-default-rtdb.firebaseio.com", + app.options.projectID]; + } + return [FIRDatabase databaseForApp:app URL:url]; +} + ++ (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url { + if (app == nil) { + [NSException raise:@"InvalidFIRApp" + format:@"nil FIRApp instance passed to databaseForApp."]; + } + if (url == nil) { + [NSException raise:@"MissingDatabaseURL" + format:@"Failed to get FirebaseDatabase instance: " + @"Specify DatabaseURL within FIRApp or from your " + @"databaseForApp:URL: call."]; + } + id provider = + FIR_COMPONENT(FIRDatabaseProvider, app.container); + return [provider databaseForApp:app URL:url]; +} + ++ (NSString *)buildVersion { + // TODO: Restore git hash when build moves back to git + return [NSString stringWithFormat:@"%@_%s", FIRFirebaseVersion(), __DATE__]; +} + ++ (FIRDatabase *)createDatabaseForTests:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config { + FIRDatabase *db = [[FIRDatabase alloc] initWithApp:nil + repoInfo:repoInfo + config:config]; + [db ensureRepo]; + return db; +} + ++ (NSString *)sdkVersion { + return FIRFirebaseVersion(); +} + ++ (void)setLoggingEnabled:(BOOL)enabled { + [FUtilities setLoggingEnabled:enabled]; + FFLog(@"I-RDB024001", @"BUILD Version: %@", [FIRDatabase buildVersion]); +} + +- (id)initWithApp:(FIRApp *)app + repoInfo:(FRepoInfo *)info + config:(FIRDatabaseConfig *)config { + self = [super init]; + if (self != nil) { + self->_repoInfo = info; + self->_config = config; + self->_app = app; + } + return self; +} + +- (FIRDatabaseReference *)reference { + [self ensureRepo]; + + return [[FIRDatabaseReference alloc] initWithRepo:self.repo + path:[FPath empty]]; +} + +- (FIRDatabaseReference *)referenceWithPath:(NSString *)path { + [self ensureRepo]; + + [FValidation validateFrom:@"referenceWithPath" validRootPathString:path]; + FPath *childPath = [[FPath alloc] initWith:path]; + return [[FIRDatabaseReference alloc] initWithRepo:self.repo path:childPath]; +} + +- (FIRDatabaseReference *)referenceFromURL:(NSString *)databaseUrl { + [self ensureRepo]; + + if (databaseUrl == nil) { + [NSException raise:@"InvalidDatabaseURL" + format:@"Invalid nil url passed to referenceFromURL:"]; + } + FParsedUrl *parsedUrl = [FUtilities parseUrl:databaseUrl]; + [FValidation validateFrom:@"referenceFromURL:" validURL:parsedUrl]; + + BOOL isInvalidHost = + !parsedUrl.repoInfo.isCustomHost && + ![_repoInfo.host isEqualToString:parsedUrl.repoInfo.host]; + if (isInvalidHost) { + [NSException raise:@"InvalidDatabaseURL" + format:@"Invalid URL (%@) passed to getReference(). URL " + @"was expected to match configured Database URL: %@", + databaseUrl, _repoInfo.host]; + } + return [[FIRDatabaseReference alloc] initWithRepo:self.repo + path:parsedUrl.path]; +} + +- (void)purgeOutstandingWrites { + [self ensureRepo]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo purgeOutstandingWrites]; + }); +} + +- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port { + if (host.length == 0) { + [NSException raise:NSInvalidArgumentException + format:@"Cannot connect to nil or empty host."]; + } + if (self.repo != nil) { + [NSException + raise:NSInternalInconsistencyException + format:@"Cannot connect to emulator after database initialization. " + @"Call useEmulator(host:port:) before creating a database " + @"reference or trying to load data."]; + } + NSString *fullHost = + [NSString stringWithFormat:@"%@:%li", host, (long)port]; + FRepoInfo *emulatorInfo = [[FRepoInfo alloc] initWithInfo:self.repoInfo + emulatedHost:fullHost]; + self->_repoInfo = emulatorInfo; +} + +- (void)goOnline { + [self ensureRepo]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo resume]; + }); +} + +- (void)goOffline { + [self ensureRepo]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo interrupt]; + }); +} + +- (void)setPersistenceEnabled:(BOOL)persistenceEnabled { + [self assertUnfrozen:@"setPersistenceEnabled"]; + self->_config.persistenceEnabled = persistenceEnabled; +} + +- (BOOL)persistenceEnabled { + return self->_config.persistenceEnabled; +} + +- (void)setPersistenceCacheSizeBytes:(NSUInteger)persistenceCacheSizeBytes { + [self assertUnfrozen:@"setPersistenceCacheSizeBytes"]; + self->_config.persistenceCacheSizeBytes = persistenceCacheSizeBytes; +} + +- (NSUInteger)persistenceCacheSizeBytes { + return self->_config.persistenceCacheSizeBytes; +} + +- (void)setCallbackQueue:(dispatch_queue_t)callbackQueue { + [self assertUnfrozen:@"setCallbackQueue"]; + self->_config.callbackQueue = callbackQueue; +} + +- (dispatch_queue_t)callbackQueue { + return self->_config.callbackQueue; +} + +- (void)assertUnfrozen:(NSString *)methodName { + if (self.repo != nil) { + [NSException + raise:@"FIRDatabaseAlreadyInUse" + format:@"Calls to %@ must be made before any other usage of " + "FIRDatabase instance.", + methodName]; + } +} + +- (void)ensureRepo { + if (self.repo == nil) { + self.repo = [FRepoManager createRepo:self.repoInfo + config:self.config + database:self]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h new file mode 100644 index 0000000..9d8bdb2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h @@ -0,0 +1,46 @@ +/* + * 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 + +@class FIRApp; +@class FIRDatabase; + +NS_ASSUME_NONNULL_BEGIN + +/// This protocol is used in the interop registration process to register an +/// instance provider for individual FIRApps. +@protocol FIRDatabaseProvider + +/// Gets a FirebaseDatabase instance for the specified URL, using the specified +/// FirebaseApp. +- (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url; + +@end + +/// A concrete implementation for FIRDatabaseProvider to create Database +/// instances. +@interface FIRDatabaseComponent : NSObject + +/// The FIRApp that instances will be set up with. +@property(nonatomic, weak, readonly) FIRApp *app; + +/// Unavailable, use `databaseForApp:URL:` instead. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.m new file mode 100644 index 0000000..33bb032 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.m @@ -0,0 +1,172 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h" + +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" + +#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "Interop/Auth/Public/FIRAuthInterop.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A NSMutableDictionary of FirebaseApp name and FRepoInfo to FirebaseDatabase + * instance. */ +typedef NSMutableDictionary FIRDatabaseDictionary; + +@interface FIRDatabaseComponent () +@property(nonatomic) FIRDatabaseDictionary *instances; +/// Internal intializer. +- (instancetype)initWithApp:(FIRApp *)app; +@end + +@implementation FIRDatabaseComponent + +#pragma mark - Initialization + +- (instancetype)initWithApp:(FIRApp *)app { + self = [super init]; + if (self) { + _app = app; + _instances = [NSMutableDictionary dictionary]; + } + return self; +} + +#pragma mark - Lifecycle + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self + withName:@"fire-db"]; +} + +#pragma mark - FIRComponentRegistrant + ++ (NSArray *)componentsToRegister { + FIRDependency *authDep = + [FIRDependency dependencyWithProtocol:@protocol(FIRAuthInterop) + isRequired:NO]; + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + *isCacheable = YES; + return [[FIRDatabaseComponent alloc] initWithApp:container.app]; + }; + FIRComponent *databaseProvider = + [FIRComponent componentWithProtocol:@protocol(FIRDatabaseProvider) + instantiationTiming:FIRInstantiationTimingLazy + dependencies:@[ authDep ] + creationBlock:creationBlock]; + return @[ databaseProvider ]; +} + +#pragma mark - Instance management. + +- (void)appWillBeDeleted:(FIRApp *)app { + NSString *appName = app.name; + if (appName == nil) { + return; + } + FIRDatabaseDictionary *instances = [self instances]; + @synchronized(instances) { + // Clean up the deleted instance in an effort to remove any resources + // still in use. Note: Any leftover instances of this exact database + // will be invalid. + for (FIRDatabase *database in [instances allValues]) { + [FRepoManager disposeRepos:database.config]; + } + [instances removeAllObjects]; + } +} + +#pragma mark - FIRDatabaseProvider Conformance + +- (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url { + if (app == nil) { + [NSException raise:@"InvalidFIRApp" + format:@"nil FIRApp instance passed to databaseForApp."]; + } + + if (url == nil) { + [NSException raise:@"MissingDatabaseURL" + format:@"Failed to get FirebaseDatabase instance: " + "Specify DatabaseURL within FIRApp or from your " + "databaseForApp:URL: call."]; + } + + NSURL *databaseUrl = [NSURL URLWithString:url]; + + if (databaseUrl == nil) { + [NSException raise:@"InvalidDatabaseURL" + format:@"The Database URL '%@' cannot be parsed. " + "Specify a valid DatabaseURL within FIRApp or from " + "your databaseForApp:URL: call.", + url]; + } else if (![databaseUrl.path isEqualToString:@""] && + ![databaseUrl.path isEqualToString:@"/"]) { + [NSException + raise:@"InvalidDatabaseURL" + format:@"Configured Database URL '%@' is invalid. It should point " + "to the root of a Firebase Database but it includes a " + "path: %@", + databaseUrl, databaseUrl.path]; + } + + FIRDatabaseDictionary *instances = [self instances]; + @synchronized(instances) { + FParsedUrl *parsedUrl = + [FUtilities parseUrl:databaseUrl.absoluteString]; + NSString *urlIndex = + [NSString stringWithFormat:@"%@:%@", parsedUrl.repoInfo.host, + [parsedUrl.path toString]]; + FIRDatabase *database = instances[urlIndex]; + if (!database) { + id contextProvider = + [FIRDatabaseConnectionContextProvider + contextProviderWithAuth:FIR_COMPONENT(FIRAuthInterop, + app.container) + appCheck:FIR_COMPONENT(FIRAppCheckInterop, + app.container)]; + + // If this is the default app, don't set the session persistence key + // so that we use our default ("default") instead of the FIRApp + // default ("[DEFAULT]") so that we preserve the default location + // used by the legacy Firebase SDK. + NSString *sessionIdentifier = @"default"; + if (![FIRApp isDefaultAppConfigured] || + app != [FIRApp defaultApp]) { + sessionIdentifier = app.name; + } + + FIRDatabaseConfig *config = [[FIRDatabaseConfig alloc] + initWithSessionIdentifier:sessionIdentifier + googleAppID:app.options.googleAppID + contextProvider:contextProvider]; + database = [[FIRDatabase alloc] initWithApp:app + repoInfo:parsedUrl.repoInfo + config:config]; + instances[urlIndex] = database; + } + + return database; + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h new file mode 100644 index 0000000..6e3ad25 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h @@ -0,0 +1,72 @@ +/* + * 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 + +@protocol FIRDatabaseConnectionContextProvider; + +NS_ASSUME_NONNULL_BEGIN + +/** + * TODO: Merge FIRDatabaseConfig into FIRDatabase. + */ +@interface FIRDatabaseConfig : NSObject + +- (id)initWithSessionIdentifier:(NSString *)identifier + googleAppID:(NSString *)googleAppID + contextProvider: + (id)contextProvider; + +/** + * By default the Firebase Database client will keep data in memory while your + * application is running, but not when it is restarted. By setting this value + * to YES, the data will be persisted to on-device (disk) storage and will thus + * be available again when the app is restarted (even when there is no network + * connectivity at that time). Note that this property must be set before + * creating your first FIRDatabaseReference and only needs to be called once per + * application. + * + * If your app uses Firebase Authentication, the client will automatically + * persist the user's authentication token across restarts, even without + * persistence enabled. But if the auth token expired while offline and you've + * enabled persistence, the client will pause write operations until you + * successfully re-authenticate (or explicitly unauthenticate) to prevent your + * writes from being sent unauthenticated and failing due to security rules. + */ +@property(nonatomic) BOOL persistenceEnabled; + +/** + * By default the Firebase Database client will use up to 10MB of disk space to + * cache data. If the cache grows beyond this size, the client will start + * removing data that hasn't been recently used. If you find that your + * application caches too little or too much data, call this method to change + * the cache size. This property must be set before creating your first + * FIRDatabaseReference and only needs to be called once per application. + * + * Note that the specified cache size is only an approximation and the size on + * disk may temporarily exceed it at times. + */ +@property(nonatomic) NSUInteger persistenceCacheSizeBytes; + +/** + * Sets the dispatch queue on which all events are raised. The default queue is + * the main queue. + */ +@property(nonatomic, strong) dispatch_queue_t callbackQueue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.m new file mode 100644 index 0000000..ad6202d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.m @@ -0,0 +1,96 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" + +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h" + +@interface FIRDatabaseConfig (Private) + +@property(nonatomic, strong, readwrite) NSString *sessionIdentifier; +@property(nonatomic, strong, readwrite) NSString *googleAppID; + +@end + +@implementation FIRDatabaseConfig + +- (id)init { + [NSException raise:NSInvalidArgumentException + format:@"Can't create config objects!"]; + return nil; +} + +- (id)initWithSessionIdentifier:(NSString *)identifier + googleAppID:(NSString *)googleAppID + contextProvider: + (id)contextProvider { + self = [super init]; + if (self != nil) { + self->_sessionIdentifier = identifier; + self->_callbackQueue = dispatch_get_main_queue(); + self->_googleAppID = googleAppID; + self->_persistenceCacheSizeBytes = + 10 * 1024 * 1024; // Default cache size is 10MB + self->_contextProvider = contextProvider; + } + return self; +} + +- (void)assertUnfrozen { + if (self.isFrozen) { + [NSException raise:NSGenericException + format:@"Can't modify config objects after they are in use " + @"for FIRDatabaseReferences."]; + } +} + +- (void)setContextProvider: + (id)contextProvider { + [self assertUnfrozen]; + self->_contextProvider = contextProvider; +} + +- (void)setPersistenceEnabled:(BOOL)persistenceEnabled { + [self assertUnfrozen]; + self->_persistenceEnabled = persistenceEnabled; +} + +- (void)setPersistenceCacheSizeBytes:(NSUInteger)persistenceCacheSizeBytes { + [self assertUnfrozen]; + // Can't be less than 1MB + if (persistenceCacheSizeBytes < 1024 * 1024) { + [NSException raise:NSInvalidArgumentException + format:@"The minimum cache size must be at least 1MB"]; + } + if (persistenceCacheSizeBytes > 100 * 1024 * 1024) { + [NSException raise:NSInvalidArgumentException + format:@"Firebase Database currently doesn't support a " + @"cache size larger than 100MB"]; + } + self->_persistenceCacheSizeBytes = persistenceCacheSizeBytes; +} + +- (void)setCallbackQueue:(dispatch_queue_t)callbackQueue { + [self assertUnfrozen]; + self->_callbackQueue = callbackQueue; +} + +- (void)freeze { + self->_isFrozen = YES; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m new file mode 100644 index 0000000..e83d498 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m @@ -0,0 +1,765 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h" +#import "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/FPathIndex.h" +#import "FirebaseDatabase/Sources/FPriorityIndex.h" +#import "FirebaseDatabase/Sources/FValueIndex.h" +#import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FNextPushId.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +@implementation FIRDatabaseQuery + +@synthesize repo; +@synthesize path; +@synthesize queryParams; + +#define INVALID_QUERY_PARAM_ERROR @"InvalidQueryParameter" + ++ (dispatch_queue_t)sharedQueue { + // We use this shared queue across all of the FQueries so things happen FIFO + // (as opposed to dispatch_get_global_queue(0, 0) which is concurrent) + static dispatch_once_t pred; + static dispatch_queue_t sharedDispatchQueue; + + dispatch_once(&pred, ^{ + sharedDispatchQueue = dispatch_queue_create("FirebaseWorker", NULL); + }); + + return sharedDispatchQueue; +} + +- (id)initWithRepo:(FRepo *)theRepo path:(FPath *)thePath { + return [self initWithRepo:theRepo + path:thePath + params:nil + orderByCalled:NO + priorityMethodCalled:NO]; +} + +- (id)initWithRepo:(FRepo *)theRepo + path:(FPath *)thePath + params:(FQueryParams *)theParams + orderByCalled:(BOOL)orderByCalled + priorityMethodCalled:(BOOL)priorityMethodCalled { + self = [super init]; + if (self) { + self.repo = theRepo; + self.path = thePath; + if (!theParams) { + theParams = [FQueryParams defaultInstance]; + } + if (![theParams isValid]) { + @throw [[NSException alloc] + initWithName:@"InvalidArgumentError" + reason:@"Queries are limited to two constraints" + userInfo:nil]; + } + self.queryParams = theParams; + self.orderByCalled = orderByCalled; + self.priorityMethodCalled = priorityMethodCalled; + } + return self; +} + +- (FQuerySpec *)querySpec { + return [[FQuerySpec alloc] initWithPath:self.path params:self.queryParams]; +} + +- (void)validateQueryEndpointsForParams:(FQueryParams *)params { + if ([params.index isEqual:[FKeyIndex keyIndex]]) { + if ([params hasStart]) { + if (params.indexStartKey != [FUtilities minName] && + params.indexStartKey != [FUtilities maxName]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't use queryStartingAtValue:childKey:, " + @"queryStartingAfterValue:childKey:, " + @"or queryEqualTo:andChildKey: in " + @"combination with queryOrderedByKey"]; + } + if (![params.indexStartValue.val isKindOfClass:[NSString class]]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't use queryStartingAtValue: or " + @"queryStartingAfterValue: " + @"with non-string types when used with " + @"queryOrderedByKey"]; + } + } + if ([params hasEnd]) { + if (params.indexEndKey != [FUtilities maxName] && + params.indexEndKey != [FUtilities minName]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't use queryEndingAtValue:childKey: or " + @"queryEndingBeforeValue:childKey: " + @"queryEqualToValue:childKey: in " + @"combination with queryOrderedByKey"]; + } + if (![params.indexEndValue.val isKindOfClass:[NSString class]]) { + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't use queryEndingAtValue: or " + @"queryEndingBeforeValue: " + @"with other types than string in combination with " + @"queryOrderedByKey"]; + } + } + } else if ([params.index isEqual:[FPriorityIndex priorityIndex]]) { + if (([params hasStart] && + ![FValidation validatePriorityValue:params.indexStartValue.val]) || + ([params hasEnd] && + ![FValidation validatePriorityValue:params.indexEndValue.val])) { + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format:@"When using queryOrderedByPriority, values provided to " + @"queryStartingAtValue:, queryStartingAfterValue:, " + @"queryEndingAtValue:, queryEndingBeforeValue:, or " + @"queryEqualToValue: must be valid priorities."]; + } + } +} + +- (void)validateEqualToCall { + if ([self.queryParams hasStart]) { + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format: + @"Cannot combine queryEqualToValue: and queryStartingAtValue: " + @"or queryStartingAfterValue:"]; + } + if ([self.queryParams hasEnd]) { + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format:@"Cannot combine queryEqualToValue: and queryEndingAtValue: " + @"or queryEndingBeforeValue:"]; + } +} + +- (void)validateNoPreviousOrderByCalled { + if (self.orderByCalled) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Cannot use multiple queryOrderedBy calls!"]; + } +} + +- (void)validateIndexValueType:(id)type fromMethod:(NSString *)method { + if (type != nil && ![type isKindOfClass:[NSNumber class]] && + ![type isKindOfClass:[NSString class]] && + ![type isKindOfClass:[NSNull class]]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"You can only pass nil, NSString or NSNumber to %@", + method]; + } +} + +- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue { + return [self queryStartingAtInternal:startValue + childKey:nil + from:@"queryStartingAtValue:" + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue + childKey:(NSString *)childKey { + if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryStartingAtValue: instead of " + @"queryStartingAtValue:childKey: when using " + @"queryOrderedByKey:" + userInfo:nil]; + } + NSString *methodName = @"queryStartingAtValue:childKey:"; + if (childKey != nil) { + [FValidation validateFrom:methodName validKey:childKey]; + } + return [self queryStartingAtInternal:startValue + childKey:childKey + from:methodName + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryStartingAfterValue:(id)startAfterValue { + return [self queryStartingAfterValue:startAfterValue childKey:nil]; +} + +- (FIRDatabaseQuery *)queryStartingAfterValue:(id)startAfterValue + childKey:(NSString *)childKey { + if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { + if (childKey != nil) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason: + @"You must use queryStartingAfterValue: instead of " + @"queryStartingAfterValue:childKey: when using " + @"queryOrderedByKey:" + userInfo:nil]; + } + if ([startAfterValue isKindOfClass:[NSString class]]) { + startAfterValue = [FNextPushId successor:startAfterValue]; + } + } else { + if (childKey == nil) { + childKey = [FUtilities maxName]; + } else { + childKey = [FNextPushId successor:childKey]; + } + } + NSString *methodName = @"queryStartingAfterValue:childKey:"; + if (childKey != nil && ![childKey isEqual:[FUtilities maxName]]) { + [FValidation validateFrom:methodName validKey:childKey]; + } + return [self queryStartingAtInternal:startAfterValue + childKey:childKey + from:methodName + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryStartingAtInternal:(id)startValue + childKey:(NSString *)childKey + from:(NSString *)methodName + priorityMethod:(BOOL)priorityMethod { + [self validateIndexValueType:startValue fromMethod:methodName]; + if ([self.queryParams hasStart]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call %@ after queryStartingAtValue, " + @"queryStartingAfterValue, or " + @"queryEqualToValue was previously called", + methodName]; + } + id startNode = [FSnapshotUtilities nodeFrom:startValue]; + FQueryParams *params = [self.queryParams startAt:startNode + childKey:childKey]; + [self validateQueryEndpointsForParams:params]; + return [[FIRDatabaseQuery alloc] + initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue { + return [self queryEndingAtInternal:endValue + childKey:nil + from:@"queryEndingAtValue:" + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue + childKey:(NSString *)childKey { + if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryEndingAtValue: instead of " + @"queryEndingAtValue:childKey: when using " + @"queryOrderedByKey:" + userInfo:nil]; + } + NSString *methodName = @"queryEndingAtValue:childKey:"; + if (childKey != nil) { + [FValidation validateFrom:methodName validKey:childKey]; + } + return [self queryEndingAtInternal:endValue + childKey:childKey + from:methodName + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryEndingBeforeValue:(id)endValue { + return [self queryEndingBeforeValue:endValue childKey:nil]; +} + +- (FIRDatabaseQuery *)queryEndingBeforeValue:(id)endValue + childKey:(NSString *)childKey { + if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { + if (childKey != nil) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryEndingBeforeValue: instead of " + @"queryEndingBeforeValue:childKey: when using " + @"queryOrderedByKey:" + userInfo:nil]; + } + if ([endValue isKindOfClass:[NSString class]]) { + endValue = [FNextPushId predecessor:endValue]; + } + } else { + if (childKey == nil) { + childKey = [FUtilities minName]; + } else { + childKey = [FNextPushId predecessor:childKey]; + } + } + NSString *methodName = @"queryEndingBeforeValue:childKey:"; + if (childKey != nil && ![childKey isEqual:[FUtilities minName]]) { + [FValidation validateFrom:methodName validKey:childKey]; + } + return [self queryEndingAtInternal:endValue + childKey:childKey + from:methodName + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryEndingAtInternal:(id)endValue + childKey:(NSString *)childKey + from:(NSString *)methodName + priorityMethod:(BOOL)priorityMethod { + [self validateIndexValueType:endValue fromMethod:methodName]; + if ([self.queryParams hasEnd]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call %@ after queryEndingAtValue or " + @"queryEqualToValue was previously called", + methodName]; + } + id endNode = [FSnapshotUtilities nodeFrom:endValue]; + FQueryParams *params = [self.queryParams endAt:endNode childKey:childKey]; + [self validateQueryEndpointsForParams:params]; + return [[FIRDatabaseQuery alloc] + initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryEqualToValue:(id)value { + return [self queryEqualToInternal:value + childKey:nil + from:@"queryEqualToValue:" + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryEqualToValue:(id)value + childKey:(NSString *)childKey { + if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryEqualToValue: instead of " + @"queryEqualTo:childKey: when using queryOrderedByKey:" + userInfo:nil]; + } + return [self queryEqualToInternal:value + childKey:childKey + from:@"queryEqualToValue:childKey:" + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryEqualToInternal:(id)value + childKey:(NSString *)childKey + from:(NSString *)methodName + priorityMethod:(BOOL)priorityMethod { + [self validateIndexValueType:value fromMethod:methodName]; + if (childKey != nil) { + [FValidation validateFrom:methodName validKey:childKey]; + } + if ([self.queryParams hasEnd] || [self.queryParams hasStart]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call %@ after queryStartingAtValue, " + @"queryStartingAfterValue, queryEndingAtValue, " + @"queryEndingBeforeValue or queryEqualToValue " + @"was previously called", + methodName]; + } + id node = [FSnapshotUtilities nodeFrom:value]; + FQueryParams *params = [[self.queryParams startAt:node + childKey:childKey] endAt:node + childKey:childKey]; + [self validateQueryEndpointsForParams:params]; + return [[FIRDatabaseQuery alloc] + initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; +} + +- (void)validateLimitRange:(NSUInteger)limit { + // No need to check for negative ranges, since limit is unsigned + if (limit == 0) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Limit can't be zero"]; + } + if (limit >= 1ul << 31) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Limit must be less than 2,147,483,648"]; + } +} + +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit { + if (self.queryParams.limitSet) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call queryLimitedToFirst: if a limit was " + @"previously set"]; + } + [self validateLimitRange:limit]; + FQueryParams *params = [self.queryParams limitToFirst:limit]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit { + if (self.queryParams.limitSet) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call queryLimitedToLast: if a limit was " + @"previously set"]; + } + [self validateLimitRange:limit]; + FQueryParams *params = [self.queryParams limitToLast:limit]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)indexPathString { + if ([indexPathString isEqualToString:@"$key"] || + [indexPathString isEqualToString:@".key"]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString stringWithFormat: + @"(queryOrderedByChild:) %@ is invalid. " + @" Use queryOrderedByKey: instead.", + indexPathString] + userInfo:nil]; + } else if ([indexPathString isEqualToString:@"$priority"] || + [indexPathString isEqualToString:@".priority"]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString stringWithFormat: + @"(queryOrderedByChild:) %@ is invalid. " + @" Use queryOrderedByPriority: instead.", + indexPathString] + userInfo:nil]; + } else if ([indexPathString isEqualToString:@"$value"] || + [indexPathString isEqualToString:@".value"]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString stringWithFormat: + @"(queryOrderedByChild:) %@ is invalid. " + @" Use queryOrderedByValue: instead.", + indexPathString] + userInfo:nil]; + } + [self validateNoPreviousOrderByCalled]; + + [FValidation validateFrom:@"queryOrderedByChild:" + validPathString:indexPathString]; + FPath *indexPath = [FPath pathWithString:indexPathString]; + if (indexPath.isEmpty) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString + stringWithFormat:@"(queryOrderedByChild:) with an " + @"empty path is invalid. Use " + @"queryOrderedByValue: instead."] + userInfo:nil]; + } + id index = [[FPathIndex alloc] initWithPath:indexPath]; + + FQueryParams *params = [self.queryParams orderBy:index]; + [self validateQueryEndpointsForParams:params]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:YES + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryOrderedByKey { + [self validateNoPreviousOrderByCalled]; + FQueryParams *params = [self.queryParams orderBy:[FKeyIndex keyIndex]]; + [self validateQueryEndpointsForParams:params]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:YES + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryOrderedByValue { + [self validateNoPreviousOrderByCalled]; + FQueryParams *params = [self.queryParams orderBy:[FValueIndex valueIndex]]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:YES + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryOrderedByPriority { + [self validateNoPreviousOrderByCalled]; + FQueryParams *params = + [self.queryParams orderBy:[FPriorityIndex priorityIndex]]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:YES + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *))block { + [FValidation validateFrom:@"observeEventType:withBlock:" + knownEventType:eventType]; + return [self observeEventType:eventType + withBlock:block + withCancelBlock:nil]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + [FValidation + validateFrom:@"observeEventType:andPreviousSiblingKeyWithBlock:" + knownEventType:eventType]; + return [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [FValidation validateFrom:@"observeEventType:withBlock:withCancelBlock:" + knownEventType:eventType]; + + if (eventType == FIRDataEventTypeValue) { + // Handle FIRDataEventTypeValue specially because they shouldn't have + // prevName callbacks + NSUInteger handle = [[FUtilities LUIDGenerator] integerValue]; + [self observeValueEventWithHandle:handle + withBlock:block + cancelCallback:cancelBlock]; + return handle; + } else { + // Wrap up the userCallback so we can treat everything as a callback + // that has a prevName + fbt_void_datasnapshot userCallback = [block copy]; + return [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, + NSString *prevName) { + if (userCallback != nil) { + userCallback(snapshot); + } + } + withCancelBlock:cancelBlock]; + } +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [FValidation validateFrom:@"observeEventType:" + @"andPreviousSiblingKeyWithBlock:withCancelBlock:" + knownEventType:eventType]; + + if (eventType == FIRDataEventTypeValue) { + // TODO: This gets hit by observeSingleEventOfType. Need to fix. + /* + @throw [[NSException alloc] initWithName:@"InvalidEventTypeForObserver" + reason:@"(observeEventType:andPreviousSiblingKeyWithBlock:withCancelBlock:) + Cannot use + observeEventType:andPreviousSiblingKeyWithBlock:withCancelBlock: with + FIRDataEventTypeValue. Use observeEventType:withBlock:withCancelBlock: + instead." userInfo:nil]; + */ + } + + NSUInteger handle = [[FUtilities LUIDGenerator] integerValue]; + NSDictionary *callbacks = + @{[NSNumber numberWithInteger:eventType] : [block copy]}; + [self observeChildEventWithHandle:handle + withCallbacks:callbacks + cancelCallback:cancelBlock]; + + return handle; +} + +// If we want to distinguish between value event listeners and child event +// listeners, like in the Java client, we can consider exporting this. If we do, +// add argument validation. Otherwise, arguments are validated in the +// public-facing portions of the API. Also, move the FIRDatabaseHandle logic. +- (void)observeValueEventWithHandle:(FIRDatabaseHandle)handle + withBlock:(fbt_void_datasnapshot)block + cancelCallback:(fbt_void_nserror)cancelBlock { + // Note that we don't need to copy the callbacks here, FEventRegistration + // callback properties set to copy + FValueEventRegistration *registration = + [[FValueEventRegistration alloc] initWithRepo:self.repo + handle:handle + callback:block + cancelCallback:cancelBlock]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo addEventRegistration:registration forQuery:self.querySpec]; + }); +} + +// Note: as with the above method, we may wish to expose this at some point. +- (void)observeChildEventWithHandle:(FIRDatabaseHandle)handle + withCallbacks:(NSDictionary *)callbacks + cancelCallback:(fbt_void_nserror)cancelBlock { + // Note that we don't need to copy the callbacks here, FEventRegistration + // callback properties set to copy + FChildEventRegistration *registration = + [[FChildEventRegistration alloc] initWithRepo:self.repo + handle:handle + callbacks:callbacks + cancelCallback:cancelBlock]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo addEventRegistration:registration forQuery:self.querySpec]; + }); +} + +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle { + FValueEventRegistration *event = + [[FValueEventRegistration alloc] initWithRepo:self.repo + handle:handle + callback:nil + cancelCallback:nil]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo removeEventRegistration:event forQuery:self.querySpec]; + }); +} + +- (void)removeAllObservers { + [self removeObserverWithHandle:NSNotFound]; +} + +- (void)keepSynced:(BOOL)keepSynced { + if ([self.path.getFront isEqualToString:kDotInfoPrefix]) { + [NSException raise:NSInvalidArgumentException + format:@"Can't keep query on .info tree synced (this " + @"already is the case)."]; + } + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo keepQuery:self.querySpec synced:keepSynced]; + }); +} + +- (void)getDataWithCompletionBlock:(void (^)(NSError *__nullable error, + FIRDataSnapshot *snapshot))block { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo getData:self withCompletionBlock:block]; + }); +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block { + + [self observeSingleEventOfType:eventType + withBlock:block + withCancelBlock:nil]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + + [self observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + + // XXX: user reported memory leak in method + + // "When you copy a block, any references to other blocks from within that + // block are copied if necessary—an entire tree may be copied (from the + // top). If you have block variables and you reference a block from within + // the block, that block will be copied." + // http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW1 + // So... we don't need to do this since inside the on: we copy this block + // off the stack to the heap. + // __block fbt_void_datasnapshot userCallback = [callback copy]; + + [self observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, + NSString *prevName) { + if (block != nil) { + block(snapshot); + } + } + withCancelBlock:cancelBlock]; +} + +/** + * Attaches a listener, waits for the first event, and then removes the listener + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + + // XXX: user reported memory leak in method + + // "When you copy a block, any references to other blocks from within that + // block are copied if necessary—an entire tree may be copied (from the + // top). If you have block variables and you reference a block from within + // the block, that block will be copied." + // http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW1 + // So... we don't need to do this since inside the on: we copy this block + // off the stack to the heap. + // __block fbt_void_datasnapshot userCallback = [callback copy]; + + __block FIRDatabaseHandle handle; + __block BOOL firstCall = YES; + + fbt_void_datasnapshot_nsstring callback = [block copy]; + fbt_void_datasnapshot_nsstring wrappedCallback = + ^(FIRDataSnapshot *snap, NSString *prevName) { + if (firstCall) { + firstCall = NO; + [self removeObserverWithHandle:handle]; + callback(snap, prevName); + } + }; + + fbt_void_nserror cancelCallback = [cancelBlock copy]; + handle = [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:wrappedCallback + withCancelBlock:^(NSError *error) { + [self removeObserverWithHandle:handle]; + + if (cancelCallback) { + cancelCallback(error); + } + }]; +} + +- (NSString *)description { + return [NSString + stringWithFormat:@"(%@ %@)", self.path, self.queryParams.description]; +} + +- (FIRDatabaseReference *)ref { + return [[FIRDatabaseReference alloc] initWithRepo:self.repo path:self.path]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRMutableData.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRMutableData.m new file mode 100644 index 0000000..c05e319 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRMutableData.m @@ -0,0 +1,149 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h" +#import "FirebaseDatabase/Sources/Core/FSnapshotHolder.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/FTransformedEnumerator.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" + +@interface FIRMutableData () + +- (id)initWithPrefixPath:(FPath *)path + andSnapshotHolder:(FSnapshotHolder *)snapshotHolder; + +@property(strong, nonatomic) FSnapshotHolder *data; +@property(strong, nonatomic) FPath *prefixPath; + +@end + +@implementation FIRMutableData + +@synthesize data; +@synthesize prefixPath; + +- (id)initWithNode:(id)node { + FSnapshotHolder *holder = [[FSnapshotHolder alloc] init]; + FPath *path = [FPath empty]; + [holder updateSnapshot:path withNewSnapshot:node]; + return [self initWithPrefixPath:path andSnapshotHolder:holder]; +} + +- (id)initWithPrefixPath:(FPath *)path + andSnapshotHolder:(FSnapshotHolder *)snapshotHolder { + self = [super init]; + if (self) { + self.prefixPath = path; + self.data = snapshotHolder; + } + return self; +} + +- (FIRMutableData *)childDataByAppendingPath:(NSString *)path { + FPath *wholePath = [self.prefixPath childFromString:path]; + return [[FIRMutableData alloc] initWithPrefixPath:wholePath + andSnapshotHolder:self.data]; +} + +- (FIRMutableData *)parent { + if ([self.prefixPath isEmpty]) { + return nil; + } else { + FPath *path = [self.prefixPath parent]; + return [[FIRMutableData alloc] initWithPrefixPath:path + andSnapshotHolder:self.data]; + } +} + +- (void)setValue:(id)aValue { + id node = [FSnapshotUtilities nodeFrom:aValue + withValidationFrom:@"setValue:"]; + [self.data updateSnapshot:self.prefixPath withNewSnapshot:node]; +} + +- (void)setPriority:(id)aPriority { + id node = [self.data getNode:self.prefixPath]; + id pri = [FSnapshotUtilities nodeFrom:aPriority]; + node = [node updatePriority:pri]; + [self.data updateSnapshot:self.prefixPath withNewSnapshot:node]; +} + +- (id)value { + return [[self.data getNode:self.prefixPath] val]; +} + +- (id)priority { + return [[[self.data getNode:self.prefixPath] getPriority] val]; +} + +- (BOOL)hasChildren { + id node = [self.data getNode:self.prefixPath]; + return ![node isLeafNode] && ![(FChildrenNode *)node isEmpty]; +} + +- (BOOL)hasChildAtPath:(NSString *)path { + id node = [self.data getNode:self.prefixPath]; + FPath *childPath = [[FPath alloc] initWith:path]; + return ![[node getChild:childPath] isEmpty]; +} + +- (NSUInteger)childrenCount { + return [[self.data getNode:self.prefixPath] numChildren]; +} + +- (NSString *)key { + return [self.prefixPath getBack]; +} + +- (id)nodeValue { + return [self.data getNode:self.prefixPath]; +} + +- (NSEnumerator *)children { + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:self.nodeValue]; + return [[FTransformedEnumerator alloc] + initWithEnumerator:[indexedNode childEnumerator] + andTransform:^id(FNamedNode *node) { + FPath *childPath = [self.prefixPath childFromString:node.name]; + FIRMutableData *childData = + [[FIRMutableData alloc] initWithPrefixPath:childPath + andSnapshotHolder:self.data]; + return childData; + }]; +} + +- (BOOL)isEqualToData:(FIRMutableData *)other { + return self.data == other.data && + [[self.prefixPath description] + isEqualToString:[other.prefixPath description]]; +} + +- (NSString *)description { + if (self.key == nil) { + return [NSString + stringWithFormat:@"FIRMutableData (top-most transaction) %@ %@", + self.key, self.value]; + } else { + return [NSString + stringWithFormat:@"FIRMutableData (%@) %@", self.key, self.value]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRServerValue.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRServerValue.m new file mode 100644 index 0000000..9cbeedd --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRServerValue.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h" + +@implementation FIRServerValue + ++ (NSDictionary *)timestamp { + static NSDictionary *timestamp = nil; + if (timestamp == nil) { + timestamp = @{@".sv" : @"timestamp"}; + } + return timestamp; +} + ++ (NSDictionary *)increment:(NSNumber *)delta { + return @{@".sv" : @{@"increment" : delta}}; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRTransactionResult.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRTransactionResult.m new file mode 100644 index 0000000..dcc4e9a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRTransactionResult.m @@ -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. + */ + +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h" + +@implementation FIRTransactionResult + +@synthesize update; +@synthesize isSuccess; + ++ (FIRTransactionResult *)successWithValue:(FIRMutableData *)value { + FIRTransactionResult *result = [[FIRTransactionResult alloc] init]; + result.isSuccess = YES; + result.update = value; + return result; +} + ++ (FIRTransactionResult *)abort { + FIRTransactionResult *result = [[FIRTransactionResult alloc] init]; + result.isSuccess = NO; + result.update = nil; + return result; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h new file mode 100644 index 0000000..bb006ff --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h @@ -0,0 +1,28 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" + +@interface FIRDataSnapshot () + +// in _Private for testing purposes +@property(nonatomic, strong) FIndexedNode *node; + +- (id)initWithRef:(FIRDatabaseReference *)ref indexedNode:(FIndexedNode *)node; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h new file mode 100644 index 0000000..0717e05 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h @@ -0,0 +1,43 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" + +@interface FIRDatabaseQuery () + ++ (dispatch_queue_t)sharedQueue; + +- (id)initWithRepo:(FRepo *)repo path:(FPath *)path; +- (id)initWithRepo:(FRepo *)repo + path:(FPath *)path + params:(FQueryParams *)params + orderByCalled:(BOOL)orderByCalled + priorityMethodCalled:(BOOL)priorityMethodCalled; + +@property(nonatomic, strong) FRepo *repo; +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) FQueryParams *queryParams; +@property(nonatomic) BOOL orderByCalled; +@property(nonatomic) BOOL priorityMethodCalled; + +- (FQuerySpec *)querySpec; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h new file mode 100644 index 0000000..fe1f6ee --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" + +@interface FIRDatabaseReference () + +- (id)initWithConfig:(FIRDatabaseConfig *)config; +- (id)initWithRepo:(FRepo *)repo path:(FPath *)path; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h new file mode 100644 index 0000000..fb202ec --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h @@ -0,0 +1,37 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h" + +@class FRepo; +@class FRepoInfo; +@class FIRDatabaseConfig; + +@interface FIRDatabase () + +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FIRDatabaseConfig *config; +@property(nonatomic, strong) FRepo *repo; + +- (id)initWithApp:(FIRApp *)app + repoInfo:(FRepoInfo *)info + config:(FIRDatabaseConfig *)config; + ++ (NSString *)buildVersion; ++ (FIRDatabase *)createDatabaseForTests:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h new file mode 100644 index 0000000..f3bb2c6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h @@ -0,0 +1,26 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FIRMutableData () + +- (id)initWithNode:(id)node; +- (id)nodeValue; +- (BOOL)isEqualToData:(FIRMutableData *)other; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h new file mode 100644 index 0000000..ef8cd54 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h" + +@interface FIRTransactionResult () + +@property(nonatomic) BOOL isSuccess; +@property(nonatomic, strong) FIRMutableData *update; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h new file mode 100644 index 0000000..3fe2bf6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __FTYPEDEFS_PRIVATE__ +#define __FTYPEDEFS_PRIVATE__ + +#import + +typedef NS_ENUM(NSInteger, FTransactionStatus) { + FTransactionInitializing, // 0 + FTransactionRun, // 1 + FTransactionSent, // 2 + FTransactionCompleted, // 3 + FTransactionSentNeedsAbort, // 4 + FTransactionNeedsAbort // 5 +}; + +@protocol FNode; +@class FPath; +@class FIRTransactionResult; +@class FIRMutableData; +@class FIRDataSnapshot; +@class FCompoundHash; + +typedef void (^fbt_void_nserror_bool_datasnapshot)(NSError *error, + BOOL committed, + FIRDataSnapshot *snapshot); +typedef FIRTransactionResult * (^fbt_transactionresult_mutabledata)( + FIRMutableData *currentData); +typedef void (^fbt_void_path_node)(FPath *, id); +typedef void (^fbt_void_nsstring)(NSString *); +typedef BOOL (^fbt_bool_nsstring_node)(NSString *, id); +typedef void (^fbt_void_path_node_marray)(FPath *, id, NSMutableArray *); +typedef BOOL (^fbt_bool_void)(void); +typedef void (^fbt_void_nsstring_nsstring)(NSString *str1, NSString *str2); +typedef void (^fbt_void_nsstring_id_nsstring)(NSString *str1, id dict1, + NSString *str2); +typedef void (^fbt_void_nsstring_nserror)(NSString *str, NSError *error); +typedef BOOL (^fbt_bool_path)(FPath *str); +typedef void (^fbt_void_id)(id data); +typedef NSString * (^fbt_nsstring_void)(void); +typedef FCompoundHash * (^fbt_compoundhash_void)(void); +typedef NSArray * (^fbt_nsarray_nsstring_id)(NSString *status, id Data); +typedef NSArray * (^fbt_nsarray_nsstring)(NSString *status); + +// WWDC 2012 session 712 starting in page 83 for saving blocks in properties +// (use @property (strong) type name). + +#endif diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.h new file mode 100644 index 0000000..51ad626 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.h @@ -0,0 +1,201 @@ +/* + * 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. + */ + +#ifndef Firebase_FConstants_h +#define Firebase_FConstants_h + +#import + +#pragma mark - +#pragma mark Wire Protocol Envelope Constants + +FOUNDATION_EXPORT NSString *const kFWPRequestType; +FOUNDATION_EXPORT NSString *const kFWPRequestTypeData; +FOUNDATION_EXPORT NSString *const kFWPRequestDataPayload; +FOUNDATION_EXPORT NSString *const kFWPRequestNumber; +FOUNDATION_EXPORT NSString *const kFWPRequestPayloadBody; +FOUNDATION_EXPORT NSString *const kFWPRequestError; +FOUNDATION_EXPORT NSString *const kFWPRequestAction; +FOUNDATION_EXPORT NSString *const kFWPResponseForRNData; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatus; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusOk; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusFailed; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusDataStale; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionData; +FOUNDATION_EXPORT NSString *const kFWPResponseDataWarnings; + +FOUNDATION_EXPORT NSString *const kFWPAsyncServerAction; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerPayloadBody; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdate; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataMerge; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataRangeMerge; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerAuthRevoked; +FOUNDATION_EXPORT NSString *const kFWPASyncServerListenCancelled; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerSecurityDebug; +FOUNDATION_EXPORT NSString + *const kFWPAsyncServerDataUpdateBodyPath; // {"a": "d", "b": {"p": "/", "d": + // """}} +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateBodyData; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateStartPath; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateEndPath; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateRangeMerge; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateBodyTag; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataQueries; + +FOUNDATION_EXPORT NSString *const kFWPAsyncServerEnvelopeType; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerEnvelopeData; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessage; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessageType; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessageData; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataMessage; + +FOUNDATION_EXPORT NSString *const kFWPAsyncServerHello; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerHelloTimestamp; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerHelloVersion; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerHelloConnectedHost; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerHelloSession; + +FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessageShutdown; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessageReset; + +#pragma mark - +#pragma mark Wire Protocol Payload Constants + +FOUNDATION_EXPORT NSString *const kFWPRequestActionPut; +FOUNDATION_EXPORT NSString *const kFWPRequestActionMerge; +FOUNDATION_EXPORT NSString *const kFWPRequestActionGet; +FOUNDATION_EXPORT NSString *const kFWPRequestActionTaggedListen; +FOUNDATION_EXPORT NSString *const kFWPRequestActionTaggedUnlisten; +FOUNDATION_EXPORT NSString + *const kFWPRequestActionListen; // {"t": "d", "d": {"r": 1, "a": "l", "b": { + // "p": "/" } } } +FOUNDATION_EXPORT NSString *const kFWPRequestActionUnlisten; +FOUNDATION_EXPORT NSString *const kFWPRequestActionStats; +FOUNDATION_EXPORT NSString *const kFWPRequestActionDisconnectPut; +FOUNDATION_EXPORT NSString *const kFWPRequestActionDisconnectMerge; +FOUNDATION_EXPORT NSString *const kFWPRequestActionDisconnectCancel; +FOUNDATION_EXPORT NSString *const kFWPRequestActionAppCheck; +FOUNDATION_EXPORT NSString *const kFWPRequestActionAuth; +FOUNDATION_EXPORT NSString *const kFWPRequestActionUnauth; +FOUNDATION_EXPORT NSString *const kFWPRequestAppCheckToken; +FOUNDATION_EXPORT NSString *const kFWPRequestCredential; +FOUNDATION_EXPORT NSString *const kFWPRequestPath; +FOUNDATION_EXPORT NSString *const kFWPRequestCounters; +FOUNDATION_EXPORT NSString *const kFWPRequestQueries; +FOUNDATION_EXPORT NSString *const kFWPRequestTag; +FOUNDATION_EXPORT NSString *const kFWPRequestData; +FOUNDATION_EXPORT NSString *const kFWPRequestHash; +FOUNDATION_EXPORT NSString *const kFWPRequestCompoundHash; +FOUNDATION_EXPORT NSString *const kFWPRequestCompoundHashPaths; +FOUNDATION_EXPORT NSString *const kFWPRequestCompoundHashHashes; +FOUNDATION_EXPORT NSString *const kFWPRequestStatus; + +#pragma mark - +#pragma mark Websock Transport Constants + +FOUNDATION_EXPORT NSString *const kWireProtocolVersionParam; +FOUNDATION_EXPORT NSString *const kWebsocketProtocolVersion; +FOUNDATION_EXPORT NSString *const kWebsocketServerKillPacket; +FOUNDATION_EXPORT NSString *const kPersistentConnectionOffline; +FOUNDATION_EXPORT const int kWebsocketMaxFrameSize; +FOUNDATION_EXPORT NSUInteger const kWebsocketKeepaliveInterval; +FOUNDATION_EXPORT NSUInteger const kWebsocketConnectTimeout; +FOUNDATION_EXPORT UInt64 const kPersistentConnectionGetConnectTimeout; + +FOUNDATION_EXPORT float const kPersistentConnReconnectMinDelay; +FOUNDATION_EXPORT float const kPersistentConnReconnectMaxDelay; +FOUNDATION_EXPORT float const kPersistentConnReconnectMultiplier; +FOUNDATION_EXPORT float const + kPersistentConnSuccessfulConnectionEstablishedDelay; + +#pragma mark - +#pragma mark Query / QueryParams constants + +FOUNDATION_EXPORT NSString *const kQueryDefault; +FOUNDATION_EXPORT NSString *const kQueryDefaultObject; +FOUNDATION_EXPORT NSString *const kViewManagerDictConstView; +FOUNDATION_EXPORT NSString *const kFQPIndexStartValue; +FOUNDATION_EXPORT NSString *const kFQPIndexStartName; +FOUNDATION_EXPORT NSString *const kFQPIndexEndValue; +FOUNDATION_EXPORT NSString *const kFQPIndexEndName; +FOUNDATION_EXPORT NSString *const kFQPLimit; +FOUNDATION_EXPORT NSString *const kFQPViewFrom; +FOUNDATION_EXPORT NSString *const kFQPViewFromLeft; +FOUNDATION_EXPORT NSString *const kFQPViewFromRight; +FOUNDATION_EXPORT NSString *const kFQPIndex; + +#pragma mark - +#pragma mark Interrupt Reasons + +FOUNDATION_EXPORT NSString *const kFInterruptReasonServerKill; +FOUNDATION_EXPORT NSString *const kFInterruptReasonWaitingForOpen; +FOUNDATION_EXPORT NSString *const kFInterruptReasonRepoInterrupt; +FOUNDATION_EXPORT NSString *const kFInterruptReasonAuthExpired; + +#pragma mark - +#pragma mark Payload constants + +FOUNDATION_EXPORT NSString *const kPayloadPriority; +FOUNDATION_EXPORT NSString *const kPayloadValue; +FOUNDATION_EXPORT NSString *const kPayloadMetadataPrefix; + +#pragma mark - +#pragma mark ServerValue constants + +FOUNDATION_EXPORT NSString *const kServerValueSubKey; +FOUNDATION_EXPORT NSString *const kServerValuePriority; + +#pragma mark - +#pragma mark.info/ constants + +FOUNDATION_EXPORT NSString *const kDotInfoPrefix; +FOUNDATION_EXPORT NSString *const kDotInfoConnected; +FOUNDATION_EXPORT NSString *const kDotInfoServerTimeOffset; + +#pragma mark - +#pragma mark ObjectiveC to JavaScript type constants + +FOUNDATION_EXPORT NSString *const kJavaScriptObject; +FOUNDATION_EXPORT NSString *const kJavaScriptString; +FOUNDATION_EXPORT NSString *const kJavaScriptBoolean; +FOUNDATION_EXPORT NSString *const kJavaScriptNumber; +FOUNDATION_EXPORT NSString *const kJavaScriptNull; +FOUNDATION_EXPORT NSString *const kJavaScriptTrue; +FOUNDATION_EXPORT NSString *const kJavaScriptFalse; + +#pragma mark - +#pragma mark Error handling constants + +FOUNDATION_EXPORT NSString *const kFErrorDomain; +FOUNDATION_EXPORT NSUInteger const kFAuthError; +FOUNDATION_EXPORT NSString *const kFErrorWriteCanceled; + +#pragma mark - +#pragma mark Validation Constants + +FOUNDATION_EXPORT NSUInteger const kFirebaseMaxObjectDepth; +FOUNDATION_EXPORT const unsigned int kFirebaseMaxLeafSize; + +#pragma mark - +#pragma mark Transaction Constants + +FOUNDATION_EXPORT NSUInteger const kFTransactionMaxRetries; +FOUNDATION_EXPORT NSString *const kFTransactionTooManyRetries; +FOUNDATION_EXPORT NSString *const kFTransactionNoData; +FOUNDATION_EXPORT NSString *const kFTransactionSet; +FOUNDATION_EXPORT NSString *const kFTransactionDisconnect; + +#endif diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.m new file mode 100644 index 0000000..08b769c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.m @@ -0,0 +1,191 @@ +/* + * 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 "FirebaseDatabase/Sources/Constants/FConstants.h" + +#pragma mark - +#pragma mark Wire Protocol Envelope Constants + +NSString *const kFWPRequestType = @"t"; +NSString *const kFWPRequestTypeData = @"d"; +NSString *const kFWPRequestDataPayload = @"d"; +NSString *const kFWPRequestNumber = @"r"; +NSString *const kFWPRequestPayloadBody = @"b"; +NSString *const kFWPRequestError = @"error"; +NSString *const kFWPRequestAction = @"a"; +NSString *const kFWPResponseForRNData = @"b"; +NSString *const kFWPResponseForActionStatus = @"s"; +NSString *const kFWPResponseForActionStatusOk = @"ok"; +NSString *const kFWPResponseForActionStatusFailed = @"failed"; +NSString *const kFWPResponseForActionStatusDataStale = @"datastale"; +NSString *const kFWPResponseForActionData = @"d"; +NSString *const kFWPResponseDataWarnings = @"w"; +NSString *const kFWPAsyncServerAction = @"a"; +NSString *const kFWPAsyncServerPayloadBody = @"b"; +NSString *const kFWPAsyncServerDataUpdate = @"d"; +NSString *const kFWPAsyncServerDataMerge = @"m"; +NSString *const kFWPAsyncServerDataRangeMerge = @"rm"; +NSString *const kFWPAsyncServerAuthRevoked = @"ac"; +NSString *const kFWPASyncServerListenCancelled = @"c"; +NSString *const kFWPAsyncServerSecurityDebug = @"sd"; +NSString *const kFWPAsyncServerDataUpdateBodyPath = + @"p"; // {"a": "d", "b": {"p": "/", "d": ""}} +NSString *const kFWPAsyncServerDataUpdateBodyData = @"d"; +NSString *const kFWPAsyncServerDataUpdateStartPath = @"s"; +NSString *const kFWPAsyncServerDataUpdateEndPath = @"e"; +NSString *const kFWPAsyncServerDataUpdateRangeMerge = @"m"; +NSString *const kFWPAsyncServerDataUpdateBodyTag = @"t"; +NSString *const kFWPAsyncServerDataQueries = @"q"; + +NSString *const kFWPAsyncServerEnvelopeType = @"t"; +NSString *const kFWPAsyncServerEnvelopeData = @"d"; +NSString *const kFWPAsyncServerControlMessage = @"c"; +NSString *const kFWPAsyncServerControlMessageType = @"t"; +NSString *const kFWPAsyncServerControlMessageData = @"d"; +NSString *const kFWPAsyncServerDataMessage = @"d"; + +NSString *const kFWPAsyncServerHello = @"h"; +NSString *const kFWPAsyncServerHelloTimestamp = @"ts"; +NSString *const kFWPAsyncServerHelloVersion = @"v"; +NSString *const kFWPAsyncServerHelloConnectedHost = @"h"; +NSString *const kFWPAsyncServerHelloSession = @"s"; + +NSString *const kFWPAsyncServerControlMessageShutdown = @"s"; +NSString *const kFWPAsyncServerControlMessageReset = @"r"; + +#pragma mark - +#pragma mark Wire Protocol Payload Constants + +NSString *const kFWPRequestActionPut = @"p"; +NSString *const kFWPRequestActionMerge = @"m"; +NSString *const kFWPRequestActionGet = @"g"; +NSString *const kFWPRequestActionListen = + @"l"; // {"t": "d", "d": {"r": 1, "a": "l", "b": { "p": "/" } } } +NSString *const kFWPRequestActionUnlisten = @"u"; +NSString *const kFWPRequestActionStats = @"s"; +NSString *const kFWPRequestActionTaggedListen = @"q"; +NSString *const kFWPRequestActionTaggedUnlisten = @"n"; +NSString *const kFWPRequestActionDisconnectPut = @"o"; +NSString *const kFWPRequestActionDisconnectMerge = @"om"; +NSString *const kFWPRequestActionDisconnectCancel = @"oc"; +NSString *const kFWPRequestActionAuth = @"auth"; +NSString *const kFWPRequestActionAppCheck = @"appcheck"; +NSString *const kFWPRequestActionUnauth = @"unauth"; +NSString *const kFWPRequestAppCheckToken = @"token"; +NSString *const kFWPRequestCredential = @"cred"; +NSString *const kFWPRequestPath = @"p"; +NSString *const kFWPRequestCounters = @"c"; +NSString *const kFWPRequestQueries = @"q"; +NSString *const kFWPRequestTag = @"t"; +NSString *const kFWPRequestData = @"d"; +NSString *const kFWPRequestHash = @"h"; +NSString *const kFWPRequestCompoundHash = @"ch"; +NSString *const kFWPRequestCompoundHashPaths = @"ps"; +NSString *const kFWPRequestCompoundHashHashes = @"hs"; +NSString *const kFWPRequestStatus = @"s"; + +#pragma mark - +#pragma mark Websock Transport Constants + +NSString *const kWireProtocolVersionParam = @"v"; +NSString *const kWebsocketProtocolVersion = @"5"; +NSString *const kWebsocketServerKillPacket = @"kill"; +NSString *const kPersistentConnectionOffline = @"Client is offline."; +const int kWebsocketMaxFrameSize = 16384; +NSUInteger const kWebsocketKeepaliveInterval = 45; +NSUInteger const kWebsocketConnectTimeout = 30; +UInt64 const kPersistentConnectionGetConnectTimeout = 3 * NSEC_PER_SEC; + +float const kPersistentConnReconnectMinDelay = 1.0; +float const kPersistentConnReconnectMaxDelay = 30.0; +float const kPersistentConnReconnectMultiplier = 1.3f; +float const kPersistentConnSuccessfulConnectionEstablishedDelay = 30.0; + +#pragma mark - +#pragma mark Query constants + +NSString *const kQueryDefault = @"default"; +NSString *const kQueryDefaultObject = @"{}"; +NSString *const kViewManagerDictConstView = @"view"; +NSString *const kFQPIndexStartValue = @"sp"; +NSString *const kFQPIndexStartName = @"sn"; +NSString *const kFQPIndexEndValue = @"ep"; +NSString *const kFQPIndexEndName = @"en"; +NSString *const kFQPLimit = @"l"; +NSString *const kFQPViewFrom = @"vf"; +NSString *const kFQPViewFromLeft = @"l"; +NSString *const kFQPViewFromRight = @"r"; +NSString *const kFQPIndex = @"i"; + +#pragma mark - +#pragma mark Interrupt Reasons + +NSString *const kFInterruptReasonServerKill = @"server_kill"; +NSString *const kFInterruptReasonWaitingForOpen = @"waiting_for_open"; +NSString *const kFInterruptReasonRepoInterrupt = @"repo_interrupt"; + +#pragma mark - +#pragma mark Payload constants + +NSString *const kPayloadPriority = @".priority"; +NSString *const kPayloadValue = @".value"; +NSString *const kPayloadMetadataPrefix = @"."; + +#pragma mark - +#pragma mark ServerValue constants + +NSString *const kServerValueSubKey = @".sv"; +NSString *const kServerValuePriority = @"timestamp"; + +#pragma mark - +#pragma mark.info/ constants + +NSString *const kDotInfoPrefix = @".info"; +NSString *const kDotInfoConnected = @"connected"; +NSString *const kDotInfoServerTimeOffset = @"serverTimeOffset"; + +#pragma mark - +#pragma mark ObjectiveC to JavaScript type constants + +NSString *const kJavaScriptObject = @"object"; +NSString *const kJavaScriptString = @"string"; +NSString *const kJavaScriptBoolean = @"boolean"; +NSString *const kJavaScriptNumber = @"number"; +NSString *const kJavaScriptNull = @"null"; +NSString *const kJavaScriptTrue = @"true"; +NSString *const kJavaScriptFalse = @"false"; + +#pragma mark - +#pragma mark Error handling constants + +NSString *const kFErrorDomain = @"com.firebase"; +NSUInteger const kFAuthError = 1; +NSString *const kFErrorWriteCanceled = @"write_canceled"; + +#pragma mark - +#pragma mark Validation Constants + +NSUInteger const kFirebaseMaxObjectDepth = 1000; +const unsigned int kFirebaseMaxLeafSize = 1024 * 1024 * 10; // 10 MB + +#pragma mark - +#pragma mark Transaction Constants + +NSUInteger const kFTransactionMaxRetries = 25; +NSString *const kFTransactionTooManyRetries = @"maxretry"; +NSString *const kFTransactionNoData = @"nodata"; +NSString *const kFTransactionSet = @"set"; +NSString *const kFTransactionDisconnect = @"disconnect"; diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.h new file mode 100644 index 0000000..a144c3e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.h @@ -0,0 +1,38 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FCompoundHashBuilder : NSObject + +- (FPath *)currentPath; + +@end + +typedef BOOL (^FCompoundHashSplitStrategy)(FCompoundHashBuilder *builder); + +@interface FCompoundHash : NSObject + +@property(nonatomic, strong, readonly) NSArray *posts; +@property(nonatomic, strong, readonly) NSArray *hashes; + ++ (FCompoundHash *)fromNode:(id)node; ++ (FCompoundHash *)fromNode:(id)node + splitStrategy:(FCompoundHashSplitStrategy)strategy; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.m new file mode 100644 index 0000000..dbe6cb9 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.m @@ -0,0 +1,259 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FCompoundHash.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" + +@interface FCompoundHashBuilder () + +@property(nonatomic, strong) FCompoundHashSplitStrategy splitStrategy; + +@property(nonatomic, strong) NSMutableArray *currentPaths; +@property(nonatomic, strong) NSMutableArray *currentHashes; + +@end + +@implementation FCompoundHashBuilder { + + // NOTE: We use the existence of this to know if we've started building a + // range (i.e. encountered a leaf node). + NSMutableString *optHashValueBuilder; + + // The current path as a stack. This is used in combination with + // currentPathDepth to simultaneously store the last leaf node path. The + // depth is changed when descending and ascending, at the same time the + // current key is set for the current depth. Because the keys are left + // unchanged for ascending the path will also contain the path of the last + // visited leaf node (using lastLeafDepth elements) + NSMutableArray *currentPath; + NSInteger lastLeafDepth; + NSInteger currentPathDepth; + + BOOL needsComma; +} + +- (instancetype)initWithSplitStrategy:(FCompoundHashSplitStrategy)strategy { + self = [super init]; + if (self != nil) { + self->_splitStrategy = strategy; + self->optHashValueBuilder = nil; + self->currentPath = [NSMutableArray array]; + self->lastLeafDepth = -1; + self->currentPathDepth = 0; + self->needsComma = YES; + self->_currentPaths = [NSMutableArray array]; + self->_currentHashes = [NSMutableArray array]; + } + return self; +} + +- (BOOL)isBuildingRange { + return self->optHashValueBuilder != nil; +} + +- (NSUInteger)currentHashLength { + return self->optHashValueBuilder.length; +} + +- (FPath *)currentPath { + return [self currentPathWithDepth:self->currentPathDepth]; +} + +- (FPath *)currentPathWithDepth:(NSInteger)depth { + NSArray *pieces = + [self->currentPath subarrayWithRange:NSMakeRange(0, depth)]; + return [[FPath alloc] initWithPieces:pieces andPieceNum:0]; +} + +- (void)enumerateCurrentPathToDepth:(NSInteger)depth + withBlock:(void (^)(NSString *key))block { + for (NSInteger i = 0; i < depth; i++) { + block(self->currentPath[i]); + } +} + +- (void)appendKey:(NSString *)key toString:(NSMutableString *)string { + [FSnapshotUtilities appendHashV2RepresentationForString:key + toString:string]; +} + +- (void)ensureRange { + if (![self isBuildingRange]) { + optHashValueBuilder = [NSMutableString string]; + [optHashValueBuilder appendString:@"("]; + [self + enumerateCurrentPathToDepth:self->currentPathDepth + withBlock:^(NSString *key) { + [self appendKey:key + toString:self->optHashValueBuilder]; + [self->optHashValueBuilder appendString:@":("]; + }]; + self->needsComma = NO; + } +} + +- (void)processLeaf:(FLeafNode *)leafNode { + [self ensureRange]; + + self->lastLeafDepth = self->currentPathDepth; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:leafNode + toString:self->optHashValueBuilder + hashVersion:FDataHashVersionV2]; + self->needsComma = YES; + if (self.splitStrategy(self)) { + [self endRange]; + } +} + +- (void)startChild:(NSString *)key { + [self ensureRange]; + + if (self->needsComma) { + [self->optHashValueBuilder appendString:@","]; + } + [self appendKey:key toString:self->optHashValueBuilder]; + [self->optHashValueBuilder appendString:@":("]; + if (self->currentPathDepth == currentPath.count) { + [self->currentPath addObject:key]; + } else { + self->currentPath[self->currentPathDepth] = key; + } + self->currentPathDepth++; + self->needsComma = NO; +} + +- (void)endChild { + self->currentPathDepth--; + if ([self isBuildingRange]) { + [self->optHashValueBuilder appendString:@")"]; + } + self->needsComma = YES; +} + +- (void)finishHashing { + NSAssert(self->currentPathDepth == 0, + @"Can't finish hashing in the middle of processing a child"); + if ([self isBuildingRange]) { + [self endRange]; + } + + // Always close with the empty hash for the remaining range to allow simple + // appending + [self.currentHashes addObject:@""]; +} + +- (void)endRange { + NSAssert([self isBuildingRange], + @"Can't end range without starting a range!"); + // Add closing parenthesis for current depth + for (NSUInteger i = 0; i < currentPathDepth; i++) { + [self->optHashValueBuilder appendString:@")"]; + } + [self->optHashValueBuilder appendString:@")"]; + + FPath *lastLeafPath = [self currentPathWithDepth:self->lastLeafDepth]; + NSString *hash = + [FStringUtilities base64EncodedSha1:self->optHashValueBuilder]; + [self.currentHashes addObject:hash]; + [self.currentPaths addObject:lastLeafPath]; + + self->optHashValueBuilder = nil; +} + +@end + +@interface FCompoundHash () + +@property(nonatomic, strong, readwrite) NSArray *posts; +@property(nonatomic, strong, readwrite) NSArray *hashes; + +@end + +@implementation FCompoundHash + +- (id)initWithPosts:(NSArray *)posts hashes:(NSArray *)hashes { + self = [super init]; + if (self != nil) { + if (posts.count != hashes.count - 1) { + [NSException raise:NSInvalidArgumentException + format:@"Number of posts need to be n-1 for n hashes " + @"in FCompoundHash"]; + } + self.posts = posts; + self.hashes = hashes; + } + return self; +} + ++ (FCompoundHashSplitStrategy)simpleSizeSplitStrategyForNode:(id)node { + NSUInteger estimatedSize = + [FSnapshotUtilities estimateSerializedNodeSize:node]; + + // Splits for + // 1k -> 512 (2 parts) + // 5k -> 715 (7 parts) + // 100k -> 3.2k (32 parts) + // 500k -> 7k (71 parts) + // 5M -> 23k (228 parts) + NSUInteger splitThreshold = MAX(512, (NSUInteger)sqrt(estimatedSize * 100)); + + return ^BOOL(FCompoundHashBuilder *builder) { + // Never split on priorities + return [builder currentHashLength] > splitThreshold && + ![[[builder currentPath] getBack] isEqualToString:@".priority"]; + }; +} + ++ (FCompoundHash *)fromNode:(id)node { + return [FCompoundHash + fromNode:node + splitStrategy:[FCompoundHash simpleSizeSplitStrategyForNode:node]]; +} + ++ (FCompoundHash *)fromNode:(id)node + splitStrategy:(FCompoundHashSplitStrategy)strategy { + if ([node isEmpty]) { + return [[FCompoundHash alloc] initWithPosts:@[] hashes:@[ @"" ]]; + } else { + FCompoundHashBuilder *builder = + [[FCompoundHashBuilder alloc] initWithSplitStrategy:strategy]; + [FCompoundHash processNode:node builder:builder]; + [builder finishHashing]; + return [[FCompoundHash alloc] initWithPosts:builder.currentPaths + hashes:builder.currentHashes]; + } +} + ++ (void)processNode:(id)node builder:(FCompoundHashBuilder *)builder { + if ([node isLeafNode]) { + [builder processLeaf:node]; + } else { + NSAssert(![node isEmpty], @"Can't calculate hash on empty node!"); + FChildrenNode *childrenNode = (FChildrenNode *)node; + [childrenNode enumerateChildrenAndPriorityUsingBlock:^( + NSString *key, id node, BOOL *stop) { + [builder startChild:key]; + [self processNode:node builder:builder]; + [builder endChild]; + }]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.h new file mode 100644 index 0000000..093b6af --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.h @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" + +@class FQuerySpec; +@protocol FSyncTreeHash; + +typedef NSArray * (^fbt_startListeningBlock)(FQuerySpec *query, NSNumber *tagId, + id hash, + fbt_nsarray_nsstring onComplete); +typedef void (^fbt_stopListeningBlock)(FQuerySpec *query, NSNumber *tagId); + +@interface FListenProvider : NSObject + +@property(nonatomic, copy) fbt_startListeningBlock startListening; +@property(nonatomic, copy) fbt_stopListeningBlock stopListening; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.m new file mode 100644 index 0000000..d0dee79 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.m @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FListenProvider.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" + +@implementation FListenProvider + +@synthesize startListening; +@synthesize stopListening; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.h new file mode 100644 index 0000000..592b5d0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.h @@ -0,0 +1,103 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/Realtime/FConnection.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@protocol FPersistentConnectionDelegate; +@protocol FSyncTreeHash; +@class FQuerySpec; +@class FIRDatabaseConfig; + +@interface FPersistentConnection : NSObject + +@property(nonatomic, weak) id delegate; +@property(nonatomic) BOOL pauseWrites; + +- (id)initWithRepoInfo:(FRepoInfo *)repoInfo + dispatchQueue:(dispatch_queue_t)queue + config:(FIRDatabaseConfig *)config; + +- (void)open; + +- (void)putData:(id)data + forPath:(NSString *)pathString + withHash:(NSString *)hash + withCallback:(fbt_void_nsstring_nsstring)onComplete; +- (void)mergeData:(id)data + forPath:(NSString *)pathString + withCallback:(fbt_void_nsstring_nsstring)onComplete; + +- (void)listen:(FQuerySpec *)query + tagId:(NSNumber *)tagId + hash:(id)hash + onComplete:(fbt_void_nsstring)onComplete; + +- (void)unlisten:(FQuerySpec *)query tagId:(NSNumber *)tagId; +- (void)refreshAuthToken:(NSString *)token; +- (void)refreshAppCheckToken:(NSString *)token; +- (void)onDisconnectPutData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback; +- (void)onDisconnectMergeData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback; +- (void)onDisconnectCancelPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback; +- (void)ackPuts; +- (void)getDataAtPath:(NSString *)pathString + withParams:(NSDictionary *)queryWireProtocolParams + withCallback:(fbt_void_nsstring_id_nsstring)onComplete; +- (void)purgeOutstandingWrites; + +- (void)interruptForReason:(NSString *)reason; +- (void)resumeForReason:(NSString *)reason; +- (BOOL)isInterruptedForReason:(NSString *)reason; + +// FConnection delegate methods +- (void)onReady:(FConnection *)fconnection + atTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID; +- (void)onDataMessage:(FConnection *)fconnection + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FConnection *)fconnection + withReason:(FDisconnectReason)reason; +- (void)onKill:(FConnection *)fconnection withReason:(NSString *)reason; + +// Testing methods +- (NSDictionary *)dumpListens; + +@end + +@protocol FPersistentConnectionDelegate + +- (void)onDataUpdate:(FPersistentConnection *)fpconnection + forPath:(NSString *)pathString + message:(id)message + isMerge:(BOOL)isMerge + tagId:(NSNumber *)tagId; +- (void)onRangeMerge:(NSArray *)ranges + forPath:(NSString *)path + tagId:(NSNumber *)tag; +- (void)onConnect:(FPersistentConnection *)fpconnection; +- (void)onDisconnect:(FPersistentConnection *)fpconnection; +- (void)onServerInfoUpdate:(FPersistentConnection *)fpconnection + updates:(NSDictionary *)updates; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.m new file mode 100644 index 0000000..60f1d19 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.m @@ -0,0 +1,1334 @@ +/* + * 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 + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Core/FCompoundHash.h" +#import "FirebaseDatabase/Sources/Core/FPersistentConnection.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FRangeMerge.h" +#import "FirebaseDatabase/Sources/Core/FSyncTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h" +#if TARGET_OS_WATCH +#import +#else +#import +#endif // TARGET_OS_WATCH +#import +#import + +@interface FOutstandingQuery : NSObject + +@property(nonatomic, strong) FQuerySpec *query; +@property(nonatomic, strong) NSNumber *tagId; +@property(nonatomic, strong) id syncTreeHash; +@property(nonatomic, copy) fbt_void_nsstring onComplete; + +@end + +@implementation FOutstandingQuery + +@end + +@interface FOutstandingPut : NSObject + +@property(nonatomic, strong) NSString *action; +@property(nonatomic, strong) NSDictionary *request; +@property(nonatomic, copy) fbt_void_nsstring_nsstring onCompleteBlock; +@property(nonatomic) BOOL sent; + +@end + +@implementation FOutstandingPut + +@end + +@interface FOutstandingGet : NSObject + +@property(nonatomic, strong) NSDictionary *request; +@property(nonatomic, copy) fbt_void_nsstring_id_nsstring onCompleteBlock; +@property(nonatomic) BOOL sent; + +@end + +@implementation FOutstandingGet + +@end + +typedef enum { + ConnectionStateDisconnected, + ConnectionStateGettingToken, + ConnectionStateConnecting, + ConnectionStateAuthenticating, + ConnectionStateConnected +} ConnectionState; + +@interface FPersistentConnection () { + ConnectionState connectionState; + BOOL firstConnection; + NSTimeInterval reconnectDelay; + NSTimeInterval lastConnectionAttemptTime; + NSTimeInterval lastConnectionEstablishedTime; +#if !TARGET_OS_WATCH + SCNetworkReachabilityRef reachability; +#endif // !TARGET_OS_WATCH +} + +- (int)getNextRequestNumber; +- (void)onDataPushWithAction:(NSString *)action andBody:(NSDictionary *)body; +- (void)handleTimestamp:(NSNumber *)timestamp; +- (void)sendOnDisconnectAction:(NSString *)action + forPath:(NSString *)pathString + withData:(id)data + andCallback:(fbt_void_nsstring_nsstring)callback; + +@property(nonatomic, strong) FConnection *realtime; +@property(nonatomic, strong) NSMutableDictionary *listens; +@property(nonatomic, strong) NSMutableDictionary *outstandingPuts; +@property(nonatomic, strong) NSMutableDictionary *outstandingGets; +@property(nonatomic, strong) NSMutableArray *onDisconnectQueue; +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FAtomicNumber *putCounter; +@property(nonatomic, strong) FAtomicNumber *getCounter; +@property(nonatomic, strong) FAtomicNumber *requestNumber; +@property(nonatomic, strong) NSMutableDictionary *requestCBHash; +@property(nonatomic, strong) FIRDatabaseConfig *config; +@property(nonatomic) NSUInteger unackedListensCount; +@property(nonatomic, strong) NSMutableArray *putsToAck; +@property(nonatomic, strong) dispatch_queue_t dispatchQueue; +@property(nonatomic, strong) NSString *lastSessionID; +@property(nonatomic, strong) NSMutableSet *interruptReasons; +@property(nonatomic, strong) FIRRetryHelper *retryHelper; +@property(nonatomic, strong) id + contextProvider; +@property(nonatomic, strong) NSString *authToken; +@property(nonatomic) BOOL forceTokenRefreshes; +@property(nonatomic) NSUInteger currentFetchTokenAttempt; + +@end + +@implementation FPersistentConnection + +- (id)initWithRepoInfo:(FRepoInfo *)repoInfo + dispatchQueue:(dispatch_queue_t)dispatchQueue + config:(FIRDatabaseConfig *)config { + self = [super init]; + if (self) { + self->_config = config; + self->_repoInfo = repoInfo; + self->_dispatchQueue = dispatchQueue; + self->_contextProvider = config.contextProvider; + NSAssert(self->_contextProvider != nil, + @"Expected auth token provider"); + self.interruptReasons = [NSMutableSet set]; + + self.listens = [[NSMutableDictionary alloc] init]; + self.outstandingPuts = [[NSMutableDictionary alloc] init]; + self.outstandingGets = [[NSMutableDictionary alloc] init]; + self.onDisconnectQueue = [[NSMutableArray alloc] init]; + self.putCounter = [[FAtomicNumber alloc] init]; + self.getCounter = [[FAtomicNumber alloc] init]; + self.requestNumber = [[FAtomicNumber alloc] init]; + self.requestCBHash = [[NSMutableDictionary alloc] init]; + self.unackedListensCount = 0; + self.putsToAck = [NSMutableArray array]; + connectionState = ConnectionStateDisconnected; + firstConnection = YES; + reconnectDelay = kPersistentConnReconnectMinDelay; + + self->_retryHelper = [[FIRRetryHelper alloc] + initWithDispatchQueue:dispatchQueue + minRetryDelayAfterFailure:kPersistentConnReconnectMinDelay + maxRetryDelay:kPersistentConnReconnectMaxDelay + retryExponent:kPersistentConnReconnectMultiplier + jitterFactor:0.7]; + + [self setupNotifications]; + // Make sure we don't actually connect until open is called + [self interruptForReason:kFInterruptReasonWaitingForOpen]; + } + // nb: The reason establishConnection isn't called here like the JS version + // is because callers need to set the delegate first. The ctor can be + // modified to accept the delegate but that deviates from normal ios + // conventions. After the delegate has been set, the caller is responsible + // for calling establishConnection: + return self; +} + +- (void)dealloc { +#if !TARGET_OS_WATCH + if (reachability) { + // Unschedule the notifications + SCNetworkReachabilitySetDispatchQueue(reachability, NULL); + CFRelease(reachability); + } +#endif // !TARGET_OS_WATCH +} + +#pragma mark - +#pragma mark Public methods + +- (void)open { + [self resumeForReason:kFInterruptReasonWaitingForOpen]; +} + +/** + * Note that the listens dictionary has a type of Map[String (pathString), + * Map[FQueryParams, FOutstandingQuery]] + * + * This means, for each path we care about, there are sets of queryParams that + * correspond to an FOutstandingQuery object. There can be multiple sets at a + * path since we overlap listens for a short time while adding or removing a + * query from a location in the tree. + */ +- (void)listen:(FQuerySpec *)query + tagId:(NSNumber *)tagId + hash:(id)hash + onComplete:(fbt_void_nsstring)onComplete { + FFLog(@"I-RDB034001", @"Listen called for %@", query); + + NSAssert(self.listens[query] == nil, + @"listen() called twice for the same query"); + NSAssert(query.isDefault || !query.loadsAllData, + @"listen called for non-default but complete query"); + FOutstandingQuery *outstanding = [[FOutstandingQuery alloc] init]; + outstanding.query = query; + outstanding.tagId = tagId; + outstanding.syncTreeHash = hash; + outstanding.onComplete = onComplete; + [self.listens setObject:outstanding forKey:query]; + if ([self connected]) { + [self sendListen:outstanding]; + } +} + +- (void)putData:(id)data + forPath:(NSString *)pathString + withHash:(NSString *)hash + withCallback:(fbt_void_nsstring_nsstring)onComplete { + [self putInternal:data + forAction:kFWPRequestActionPut + forPath:pathString + withHash:hash + withCallback:onComplete]; +} + +- (void)mergeData:(id)data + forPath:(NSString *)pathString + withCallback:(fbt_void_nsstring_nsstring)onComplete { + [self putInternal:data + forAction:kFWPRequestActionMerge + forPath:pathString + withHash:nil + withCallback:onComplete]; +} + +- (void)onDisconnectPutData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback { + if ([self canSendWrites]) { + [self sendOnDisconnectAction:kFWPRequestActionDisconnectPut + forPath:[path description] + withData:data + andCallback:callback]; + } else { + FTupleOnDisconnect *tuple = [[FTupleOnDisconnect alloc] init]; + tuple.pathString = [path description]; + tuple.action = kFWPRequestActionDisconnectPut; + tuple.data = data; + tuple.onComplete = callback; + [self.onDisconnectQueue addObject:tuple]; + } +} + +- (void)onDisconnectMergeData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback { + if ([self canSendWrites]) { + [self sendOnDisconnectAction:kFWPRequestActionDisconnectMerge + forPath:[path description] + withData:data + andCallback:callback]; + } else { + FTupleOnDisconnect *tuple = [[FTupleOnDisconnect alloc] init]; + tuple.pathString = [path description]; + tuple.action = kFWPRequestActionDisconnectMerge; + tuple.data = data; + tuple.onComplete = callback; + [self.onDisconnectQueue addObject:tuple]; + } +} + +- (void)onDisconnectCancelPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback { + if ([self canSendWrites]) { + [self sendOnDisconnectAction:kFWPRequestActionDisconnectCancel + forPath:[path description] + withData:[NSNull null] + andCallback:callback]; + } else { + FTupleOnDisconnect *tuple = [[FTupleOnDisconnect alloc] init]; + tuple.pathString = [path description]; + tuple.action = kFWPRequestActionDisconnectCancel; + tuple.data = [NSNull null]; + tuple.onComplete = callback; + [self.onDisconnectQueue addObject:tuple]; + } +} + +- (void)unlisten:(FQuerySpec *)query tagId:(NSNumber *)tagId { + FPath *path = query.path; + FFLog(@"I-RDB034002", @"Unlistening for %@", query); + + NSArray *outstanding = [self removeListen:query]; + if (outstanding.count > 0 && [self connected]) { + [self sendUnlisten:path queryParams:query.params tagId:tagId]; + } +} + +- (void)refreshAuthToken:(NSString *)token { + self.authToken = token; + if ([self connected]) { + if (token != nil) { + [self sendAuthAndRestoreStateAfterComplete:NO]; + } else { + [self sendUnauth]; + } + } +} + +#pragma mark - +#pragma mark Connection status + +- (BOOL)connected { + return self->connectionState == ConnectionStateAuthenticating || + self->connectionState == ConnectionStateConnected; +} + +- (BOOL)canSendWrites { + return self->connectionState == ConnectionStateConnected; +} + +- (BOOL)canSendReads { + return self->connectionState == ConnectionStateConnected; +} + +#pragma mark - +#pragma mark FConnection delegate methods + +- (void)onReady:(FConnection *)fconnection + atTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID { + FFLog(@"I-RDB034003", @"On ready"); + lastConnectionEstablishedTime = [[NSDate date] timeIntervalSince1970]; + [self handleTimestamp:timestamp]; + + if (firstConnection) { + [self sendConnectStats]; + } + + [self restoreAuth]; + firstConnection = NO; + self.lastSessionID = sessionID; + dispatch_async(self.dispatchQueue, ^{ + [self.delegate onConnect:self]; + }); +} + +- (void)onDataMessage:(FConnection *)fconnection + withMessage:(NSDictionary *)message { + if (message[kFWPRequestNumber] != nil) { + // this is a response to a request we sent + NSNumber *rn = [NSNumber + numberWithInt:[[message objectForKey:kFWPRequestNumber] intValue]]; + if ([self.requestCBHash objectForKey:rn]) { + void (^callback)(NSDictionary *) = + [self.requestCBHash objectForKey:rn]; + [self.requestCBHash removeObjectForKey:rn]; + + if (callback) { + // dispatch_async(self.dispatchQueue, ^{ + callback([message objectForKey:kFWPResponseForRNData]); + //}); + } + } + } else if (message[kFWPRequestError] != nil) { + NSString *error = [message objectForKey:kFWPRequestError]; + @throw [[NSException alloc] initWithName:@"FirebaseDatabaseServerError" + reason:error + userInfo:nil]; + } else if (message[kFWPAsyncServerAction] != nil) { + // this is a server push of some sort + NSString *action = [message objectForKey:kFWPAsyncServerAction]; + NSDictionary *body = [message objectForKey:kFWPAsyncServerPayloadBody]; + [self onDataPushWithAction:action andBody:body]; + } +} + +- (void)onDisconnect:(FConnection *)fconnection + withReason:(FDisconnectReason)reason { + FFLog(@"I-RDB034004", @"Got on disconnect due to %s", + (reason == DISCONNECT_REASON_SERVER_RESET) ? "server_reset" + : "other"); + connectionState = ConnectionStateDisconnected; + // Drop the realtime connection + self.realtime = nil; + [self cancelSentTransactions]; + [self.requestCBHash removeAllObjects]; + self.unackedListensCount = 0; + if ([self shouldReconnect]) { + NSTimeInterval timeSinceLastConnectSucceeded = + [[NSDate date] timeIntervalSince1970] - + lastConnectionEstablishedTime; + BOOL lastConnectionWasSuccessful; + if (lastConnectionEstablishedTime > 0) { + lastConnectionWasSuccessful = + timeSinceLastConnectSucceeded > + kPersistentConnSuccessfulConnectionEstablishedDelay; + } else { + lastConnectionWasSuccessful = NO; + } + + if (reason == DISCONNECT_REASON_SERVER_RESET || + lastConnectionWasSuccessful) { + [self.retryHelper signalSuccess]; + } + [self tryScheduleReconnect]; + } + lastConnectionEstablishedTime = 0; + [self.delegate onDisconnect:self]; +} + +- (void)onKill:(FConnection *)fconnection withReason:(NSString *)reason { + FFWarn(@"I-RDB034005", + @"Firebase Database connection was forcefully killed by the server. " + @" Will not attempt reconnect. Reason: %@", + reason); + [self interruptForReason:kFInterruptReasonServerKill]; +} + +#pragma mark - +#pragma mark Connection handling methods + +- (void)interruptForReason:(NSString *)reason { + FFLog(@"I-RDB034006", @"Connection interrupted for: %@", reason); + + [self.interruptReasons addObject:reason]; + if (self.realtime) { + // Will call onDisconnect and set the connection state to Disconnected + [self.realtime close]; + self.realtime = nil; + } else { + [self.retryHelper cancel]; + self->connectionState = ConnectionStateDisconnected; + } + // Reset timeouts + [self.retryHelper signalSuccess]; +} + +- (void)resumeForReason:(NSString *)reason { + FFLog(@"I-RDB034007", @"Connection no longer interrupted for: %@", reason); + [self.interruptReasons removeObject:reason]; + + if ([self shouldReconnect] && + connectionState == ConnectionStateDisconnected) { + [self tryScheduleReconnect]; + } +} + +- (BOOL)shouldReconnect { + return self.interruptReasons.count == 0; +} + +- (BOOL)isInterruptedForReason:(NSString *)reason { + return [self.interruptReasons containsObject:reason]; +} + +#pragma mark - +#pragma mark Private methods + +- (void)tryScheduleReconnect { + if ([self shouldReconnect]) { + NSAssert(self->connectionState == ConnectionStateDisconnected, + @"Not in disconnected state: %d", self->connectionState); + BOOL forceRefresh = self.forceTokenRefreshes; + self.forceTokenRefreshes = NO; + FFLog(@"I-RDB034008", @"Scheduling connection attempt"); + [self.retryHelper retry:^{ + FFLog(@"I-RDB034009", @"Trying to fetch auth token"); + NSAssert(self->connectionState == ConnectionStateDisconnected, + @"Not in disconnected state: %d", self->connectionState); + self->connectionState = ConnectionStateGettingToken; + self.currentFetchTokenAttempt++; + NSUInteger thisFetchTokenAttempt = self.currentFetchTokenAttempt; + [self.contextProvider + fetchContextForcingRefresh:forceRefresh + withCallback:^( + FIRDatabaseConnectionContext *context, + NSError *error) { + if (thisFetchTokenAttempt == + self.currentFetchTokenAttempt) { + if (error != nil) { + self->connectionState = + ConnectionStateDisconnected; + FFLog(@"I-RDB034010", + @"Error fetching token: %@", error); + [self tryScheduleReconnect]; + } else { + // Someone could have interrupted us while + // fetching the token, marking the + // connection as Disconnected + if (self->connectionState == + ConnectionStateGettingToken) { + FFLog(@"I-RDB034011", + @"Successfully fetched token, " + @"opening connection"); + [self + openNetworkConnectionWithContext: + context]; + } else { + NSAssert( + self->connectionState == + ConnectionStateDisconnected, + @"Expected connection state " + @"disconnected, but got %d", + self->connectionState); + FFLog(@"I-RDB034012", + @"Not opening connection after " + @"token refresh, because " + @"connection was set to " + @"disconnected."); + } + } + } else { + FFLog(@"I-RDB034013", + @"Ignoring fetch token result, because " + @"this was not the latest attempt."); + } + }]; + }]; + } +} + +- (void)openNetworkConnectionWithContext: + (FIRDatabaseConnectionContext *)context { + NSAssert(self->connectionState == ConnectionStateGettingToken, + @"Trying to open network connection while in wrong state: %d", + self->connectionState); + // TODO: Save entire context? + self.authToken = context.authToken; + + self->connectionState = ConnectionStateConnecting; + self.realtime = [[FConnection alloc] initWith:self.repoInfo + andDispatchQueue:self.dispatchQueue + googleAppID:self.config.googleAppID + lastSessionID:self.lastSessionID + appCheckToken:context.appCheckToken]; + self.realtime.delegate = self; + [self.realtime open]; +} + +#if !TARGET_OS_WATCH +static void reachabilityCallback(SCNetworkReachabilityRef ref, + SCNetworkReachabilityFlags flags, void *info) { + if (flags & kSCNetworkReachabilityFlagsReachable) { + FFLog(@"I-RDB034014", + @"Network became reachable. Trigger a connection attempt"); + FPersistentConnection *self = (__bridge FPersistentConnection *)info; + // Reset reconnect delay + [self.retryHelper signalSuccess]; + if (self->connectionState == ConnectionStateDisconnected) { + [self tryScheduleReconnect]; + } + } else { + FFLog(@"I-RDB034015", @"Network is not reachable"); + } +} +#endif // !TARGET_OS_WATCH + +- (void)enteringForeground { + dispatch_async(self.dispatchQueue, ^{ + // Reset reconnect delay + [self.retryHelper signalSuccess]; + if (self->connectionState == ConnectionStateDisconnected) { + [self tryScheduleReconnect]; + } + }); +} + +- (void)setupNotifications { +#if TARGET_OS_WATCH + if (@available(watchOS 7.0, *)) { + __weak FPersistentConnection *weakSelf = self; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserverForName:WKApplicationWillEnterForegroundNotification + object:nil + queue:nil + usingBlock:^(NSNotification *_Nonnull note) { + [weakSelf enteringForeground]; + }]; + } +#else + NSString *const *foregroundConstant = (NSString *const *)dlsym( + RTLD_DEFAULT, "UIApplicationWillEnterForegroundNotification"); + if (foregroundConstant) { + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(enteringForeground) + name:*foregroundConstant + object:nil]; + } + // An empty address is interpreted a generic internet access + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + reachability = SCNetworkReachabilityCreateWithAddress( + kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress); + SCNetworkReachabilityContext ctx = {0, (__bridge void *)(self), NULL, NULL, + NULL}; + if (SCNetworkReachabilitySetCallback(reachability, reachabilityCallback, + &ctx)) { + SCNetworkReachabilitySetDispatchQueue(reachability, self.dispatchQueue); + } else { + FFLog(@"I-RDB034016", + @"Failed to set up network reachability monitoring"); + CFRelease(reachability); + reachability = NULL; + } +#endif // !TARGET_OS_WATCH +} + +- (void)sendAuthAndRestoreStateAfterComplete:(BOOL)restoreStateAfterComplete { + NSAssert([self connected], @"Must be connected to send auth"); + NSAssert(self.authToken != nil, + @"Can't send auth if there is no credential"); + + NSDictionary *requestData = @{kFWPRequestCredential : self.authToken}; + [self sendAction:kFWPRequestActionAuth + body:requestData + sensitive:YES + callback:^(NSDictionary *data) { + self->connectionState = ConnectionStateConnected; + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + id responseData = [data objectForKey:kFWPResponseForActionData]; + if (responseData == nil) { + responseData = @"error"; + } + + BOOL statusOk = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (statusOk) { + if (restoreStateAfterComplete) { + [self restoreState]; + } + } else { + self.authToken = nil; + self.forceTokenRefreshes = YES; + if ([status isEqualToString:@"expired_token"]) { + FFLog(@"I-RDB034017", @"Authentication failed: %@ (%@)", + status, responseData); + } else { + FFWarn(@"I-RDB034018", @"Authentication failed: %@ (%@)", + status, responseData); + } + [self.realtime close]; + } + }]; +} + +- (void)sendUnauth { + [self sendAction:kFWPRequestActionUnauth + body:@{} + sensitive:NO + callback:nil]; +} + +- (void)onAuthRevokedWithStatus:(NSString *)status + andReason:(NSString *)reason { + // This might be for an earlier token than we just recently sent. But since + // we need to close the connection anyways, we can set it to null here and + // we will refresh the token later on reconnect + if ([status isEqualToString:@"expired_token"]) { + FFLog(@"I-RDB034019", @"Auth token revoked: %@ (%@)", status, reason); + } else { + FFWarn(@"I-RDB034020", @"Auth token revoked: %@ (%@)", status, reason); + } + self.authToken = nil; + self.forceTokenRefreshes = YES; + // Try reconnecting on auth revocation + [self.realtime close]; +} + +- (void)onListenRevoked:(FPath *)path { + NSArray *queries = [self removeAllListensAtPath:path]; + for (FOutstandingQuery *query in queries) { + query.onComplete(@"permission_denied"); + } +} + +- (void)sendOnDisconnectAction:(NSString *)action + forPath:(NSString *)pathString + withData:(id)data + andCallback:(fbt_void_nsstring_nsstring)callback { + + NSDictionary *request = + @{kFWPRequestPath : pathString, kFWPRequestData : data}; + FFLog(@"I-RDB034021", @"onDisconnect %@: %@", action, request); + + [self sendAction:action + body:request + sensitive:NO + callback:^(NSDictionary *data) { + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + NSString *errorReason = + [data objectForKey:kFWPResponseForActionData]; + callback(status, errorReason); + }]; +} + +- (void)sendPut:(NSNumber *)index { + NSAssert([self canSendWrites], + @"sendPut called when not able to send writes"); + FOutstandingPut *put = self.outstandingPuts[index]; + assert(put != nil); + fbt_void_nsstring_nsstring onComplete = put.onCompleteBlock; + + // Do not async this block; copying the block insinde sendAction: doesn't + // happen in time (or something) so coredumps + put.sent = YES; + [self sendAction:put.action + body:put.request + sensitive:NO + callback:^(NSDictionary *data) { + FOutstandingPut *currentPut = self.outstandingPuts[index]; + if (currentPut == put) { + [self.outstandingPuts removeObjectForKey:index]; + + if (onComplete != nil) { + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + NSString *errorReason = + [data objectForKey:kFWPResponseForActionData]; + if (self.unackedListensCount == 0) { + onComplete(status, errorReason); + } else { + FTupleCallbackStatus *putToAck = + [[FTupleCallbackStatus alloc] init]; + putToAck.block = onComplete; + putToAck.status = status; + putToAck.errorReason = errorReason; + [self.putsToAck addObject:putToAck]; + } + } + } else { + FFLog(@"I-RDB034022", + @"Ignoring on complete for put %@ because it was " + @"already removed", + index); + } + }]; +} + +- (void)sendGet:(NSNumber *)index { + NSAssert([self canSendReads], + @"sendGet called when not able to send reads"); + FOutstandingGet *get = self.outstandingGets[index]; + NSAssert(get != nil, @"sendGet found no outstanding get at index %@", + index); + if ([get sent]) { + return; + } + get.sent = YES; + [self sendAction:kFWPRequestActionGet + body:get.request + sensitive:NO + callback:^(NSDictionary *data) { + FOutstandingGet *currentGet = self.outstandingGets[index]; + if (currentGet == get) { + [self.outstandingGets removeObjectForKey:index]; + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + id resultData = [data objectForKey:kFWPResponseForActionData]; + if (resultData == (id)[NSNull null]) { + resultData = nil; + } + if ([status isEqualToString:kFWPResponseForActionStatusOk]) { + get.onCompleteBlock(status, resultData, nil); + return; + } + get.onCompleteBlock(status, nil, resultData); + } else { + FFLog(@"I-RDB034045", + @"Ignoring on complete for get %@ because it was " + @"already removed", + index); + } + }]; +} + +- (void)sendUnlisten:(FPath *)path + queryParams:(FQueryParams *)queryParams + tagId:(NSNumber *)tagId { + FFLog(@"I-RDB034023", @"Unlisten on %@ for %@", path, queryParams); + + NSMutableDictionary *request = [NSMutableDictionary + dictionaryWithObjectsAndKeys:[path toString], kFWPRequestPath, nil]; + if (tagId != nil) { + [request setObject:queryParams.wireProtocolParams + forKey:kFWPRequestQueries]; + [request setObject:tagId forKey:kFWPRequestTag]; + } + + [self sendAction:kFWPRequestActionTaggedUnlisten + body:request + sensitive:NO + callback:nil]; +} + +- (void)putInternal:(id)data + forAction:(NSString *)action + forPath:(NSString *)pathString + withHash:(NSString *)hash + withCallback:(fbt_void_nsstring_nsstring)onComplete { + + NSMutableDictionary *request = [NSMutableDictionary + dictionaryWithObjectsAndKeys:pathString, kFWPRequestPath, data, + kFWPRequestData, nil]; + if (hash) { + [request setObject:hash forKey:kFWPRequestHash]; + } + + FOutstandingPut *put = [[FOutstandingPut alloc] init]; + put.action = action; + put.request = request; + put.onCompleteBlock = onComplete; + put.sent = NO; + + NSNumber *index = [self.putCounter getAndIncrement]; + self.outstandingPuts[index] = put; + + if ([self canSendWrites]) { + FFLog(@"I-RDB034024", @"Was connected, and added as index: %@", index); + [self sendPut:index]; + } else { + FFLog(@"I-RDB034025", + @"Wasn't connected or writes paused, so added to outstanding " + @"puts only. Path: %@", + pathString); + } +} + +- (void)getDataAtPath:(NSString *)pathString + withParams:(NSDictionary *)queryWireProtocolParams + withCallback:(fbt_void_nsstring_id_nsstring)onComplete { + NSMutableDictionary *request = [NSMutableDictionary + dictionaryWithObjectsAndKeys:pathString, kFWPRequestPath, + queryWireProtocolParams, + kFWPRequestQueries, nil]; + FOutstandingGet *get = [[FOutstandingGet alloc] init]; + get.request = request; + get.onCompleteBlock = onComplete; + get.sent = NO; + + NSNumber *index = [self.getCounter getAndIncrement]; + self.outstandingGets[index] = get; + + if (![self connected]) { + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, + kPersistentConnectionGetConnectTimeout), + self.dispatchQueue, ^{ + FOutstandingGet *currGet = self.outstandingGets[index]; + if ([currGet sent] || currGet == nil) { + return; + } + FFLog(@"I-RDB034045", + @"get %@ timed out waiting for a connection", index); + currGet.sent = YES; + currGet.onCompleteBlock(kFWPResponseForActionStatusFailed, nil, + kPersistentConnectionOffline); + [self.outstandingGets removeObjectForKey:index]; + }); + return; + } + + if ([self canSendReads]) { + FFLog(@"I-RDB034024", @"Sending get: %@", index); + [self sendGet:index]; + } +} + +- (void)sendListen:(FOutstandingQuery *)listenSpec { + FQuerySpec *query = listenSpec.query; + FFLog(@"I-RDB034026", @"Listen for %@", query); + NSMutableDictionary *request = + [NSMutableDictionary dictionaryWithObject:[query.path toString] + forKey:kFWPRequestPath]; + + // Only bother to send query if it's non-default + if (listenSpec.tagId != nil) { + [request setObject:[query.params wireProtocolParams] + forKey:kFWPRequestQueries]; + [request setObject:listenSpec.tagId forKey:kFWPRequestTag]; + } + + [request setObject:[listenSpec.syncTreeHash simpleHash] + forKey:kFWPRequestHash]; + if ([listenSpec.syncTreeHash includeCompoundHash]) { + FCompoundHash *compoundHash = [listenSpec.syncTreeHash compoundHash]; + NSMutableArray *posts = [NSMutableArray array]; + for (FPath *path in compoundHash.posts) { + [posts addObject:path.wireFormat]; + } + request[kFWPRequestCompoundHash] = @{ + kFWPRequestCompoundHashHashes : compoundHash.hashes, + kFWPRequestCompoundHashPaths : posts + }; + } + + fbt_void_nsdictionary onResponse = ^(NSDictionary *response) { + FFLog(@"I-RDB034027", @"Listen response %@", response); + // warn in any case, even if the listener was removed + [self warnOnListenWarningsForQuery:query + payload:response[kFWPResponseForActionData]]; + + FOutstandingQuery *currentListenSpec = self.listens[query]; + + // only trigger actions if the listen hasn't been removed (and maybe + // readded) + if (currentListenSpec == listenSpec) { + NSString *status = [response objectForKey:kFWPRequestStatus]; + if (![status isEqualToString:@"ok"]) { + [self removeListen:query]; + } + + if (listenSpec.onComplete) { + listenSpec.onComplete(status); + } + } + + self.unackedListensCount--; + NSAssert(self.unackedListensCount >= 0, + @"unackedListensCount decremented to be negative."); + if (self.unackedListensCount == 0) { + [self ackPuts]; + } + }; + + [self sendAction:kFWPRequestActionTaggedListen + body:request + sensitive:NO + callback:onResponse]; + + self.unackedListensCount++; +} + +- (void)warnOnListenWarningsForQuery:(FQuerySpec *)query payload:(id)payload { + if (payload != nil && [payload isKindOfClass:[NSDictionary class]]) { + NSDictionary *payloadDict = payload; + id warnings = payloadDict[kFWPResponseDataWarnings]; + if (warnings != nil && [warnings isKindOfClass:[NSArray class]]) { + NSArray *warningsArr = warnings; + if ([warningsArr containsObject:@"no_index"]) { + NSString *indexSpec = [NSString + stringWithFormat:@"\".indexOn\": \"%@\"", + [query.params.index queryDefinition]]; + NSString *indexPath = [query.path description]; + FFWarn(@"I-RDB034028", + @"Using an unspecified index. Your data will be " + @"downloaded and filtered on the client. " + "Consider adding %@ at %@ to your security rules for " + "better performance", + indexSpec, indexPath); + } + } + } +} + +- (int)getNextRequestNumber { + return [[self.requestNumber getAndIncrement] intValue]; +} + +- (void)sendAction:(NSString *)action + body:(NSDictionary *)message + sensitive:(BOOL)sensitive + callback:(void (^)(NSDictionary *data))onMessage { + // Hold onto the onMessage callback for this request before firing it off + NSNumber *rn = [NSNumber numberWithInt:[self getNextRequestNumber]]; + NSDictionary *msg = [NSDictionary + dictionaryWithObjectsAndKeys:rn, kFWPRequestNumber, action, + kFWPRequestAction, message, + kFWPRequestPayloadBody, nil]; + + [self.realtime sendRequest:msg sensitive:sensitive]; + + if (onMessage) { + // Debug message without a callback; bump the rn, but don't hold onto + // the cb + [self.requestCBHash setObject:[onMessage copy] forKey:rn]; + } +} + +- (void)cancelSentTransactions { + NSMutableDictionary + *cancelledOutstandingPuts = [[NSMutableDictionary alloc] init]; + + for (NSNumber *index in self.outstandingPuts) { + FOutstandingPut *put = self.outstandingPuts[index]; + if (put.request[kFWPRequestHash] && put.sent) { + // This is a sent transaction put. + cancelledOutstandingPuts[index] = put; + } + } + + [cancelledOutstandingPuts + enumerateKeysAndObjectsUsingBlock:^( + NSNumber *index, FOutstandingPut *outstandingPut, BOOL *stop) { + // `onCompleteBlock:` may invoke `rerunTransactionsForPath:` and + // enqueue new writes. We defer calling it until we have finished + // enumerating all existing writes. + outstandingPut.onCompleteBlock( + kFTransactionDisconnect, + @"Client was disconnected while running a transaction"); + [self.outstandingPuts removeObjectForKey:index]; + }]; +} + +- (void)onDataPushWithAction:(NSString *)action andBody:(NSDictionary *)body { + FFLog(@"I-RDB034029", @"handleServerMessage: %@, %@", action, body); + id delegate = self.delegate; + if ([action isEqualToString:kFWPAsyncServerDataUpdate] || + [action isEqualToString:kFWPAsyncServerDataMerge]) { + BOOL isMerge = [action isEqualToString:kFWPAsyncServerDataMerge]; + + if ([body objectForKey:kFWPAsyncServerDataUpdateBodyPath] && + [body objectForKey:kFWPAsyncServerDataUpdateBodyData]) { + NSString *path = + [body objectForKey:kFWPAsyncServerDataUpdateBodyPath]; + id payloadData = + [body objectForKey:kFWPAsyncServerDataUpdateBodyData]; + if (isMerge && [payloadData isKindOfClass:[NSDictionary class]] && + [payloadData count] == 0) { + // ignore empty merge + } else { + [delegate + onDataUpdate:self + forPath:path + message:payloadData + isMerge:isMerge + tagId:[body objectForKey: + kFWPAsyncServerDataUpdateBodyTag]]; + } + } else { + FFLog( + @"I-RDB034030", + @"Malformed data response from server missing path or data: %@", + body); + } + } else if ([action isEqualToString:kFWPAsyncServerDataRangeMerge]) { + NSString *path = body[kFWPAsyncServerDataUpdateBodyPath]; + NSArray *ranges = body[kFWPAsyncServerDataUpdateBodyData]; + NSNumber *tag = body[kFWPAsyncServerDataUpdateBodyTag]; + NSMutableArray *rangeMerges = [NSMutableArray array]; + for (NSDictionary *range in ranges) { + NSString *startString = range[kFWPAsyncServerDataUpdateStartPath]; + NSString *endString = range[kFWPAsyncServerDataUpdateEndPath]; + id updateData = range[kFWPAsyncServerDataUpdateRangeMerge]; + id updates = [FSnapshotUtilities nodeFrom:updateData]; + FPath *start = (startString != nil) + ? [[FPath alloc] initWith:startString] + : nil; + FPath *end = + (endString != nil) ? [[FPath alloc] initWith:endString] : nil; + FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:start + end:end + updates:updates]; + [rangeMerges addObject:merge]; + } + [delegate onRangeMerge:rangeMerges forPath:path tagId:tag]; + } else if ([action isEqualToString:kFWPAsyncServerAuthRevoked]) { + NSString *status = [body objectForKey:kFWPResponseForActionStatus]; + NSString *reason = [body objectForKey:kFWPResponseForActionData]; + [self onAuthRevokedWithStatus:status andReason:reason]; + } else if ([action isEqualToString:kFWPASyncServerListenCancelled]) { + NSString *pathString = + [body objectForKey:kFWPAsyncServerDataUpdateBodyPath]; + [self onListenRevoked:[[FPath alloc] initWith:pathString]]; + } else if ([action isEqualToString:kFWPAsyncServerSecurityDebug]) { + NSString *msg = [body objectForKey:@"msg"]; + if (msg != nil) { + NSArray *msgs = [msg componentsSeparatedByString:@"\n"]; + for (NSString *m in msgs) { + FFWarn(@"I-RDB034031", @"%@", m); + } + } + } else { + // TODO: revoke listens, auth, security debug + FFLog(@"I-RDB034032", @"Unsupported action from server: %@", action); + } +} + +- (void)restoreAuth { + FFLog(@"I-RDB034033", @"Calling restore state"); + + NSAssert(self->connectionState == ConnectionStateConnecting, + @"Wanted to restore auth, but was in wrong state: %d", + self->connectionState); + if (self.authToken == nil) { + FFLog(@"I-RDB034034", @"Not restoring auth because token is nil"); + self->connectionState = ConnectionStateConnected; + [self restoreState]; + } else { + FFLog(@"I-RDB034035", @"Restoring auth"); + self->connectionState = ConnectionStateAuthenticating; + [self sendAuthAndRestoreStateAfterComplete:YES]; + } +} + +- (void)restoreState { + NSAssert(self->connectionState == ConnectionStateConnected, + @"Should be connected if we're restoring state, but we are: %d", + self->connectionState); + + [self.listens enumerateKeysAndObjectsUsingBlock:^( + FQuerySpec *query, FOutstandingQuery *outstandingListen, + BOOL *stop) { + FFLog(@"I-RDB034036", @"Restoring listen for %@", query); + [self sendListen:outstandingListen]; + }]; + + NSArray *putKeys = [[self.outstandingPuts allKeys] + sortedArrayUsingSelector:@selector(compare:)]; + for (int i = 0; i < [putKeys count]; i++) { + if ([self.outstandingPuts objectForKey:[putKeys objectAtIndex:i]] != + nil) { + FFLog(@"I-RDB034037", @"Restoring put: %d", i); + [self sendPut:[putKeys objectAtIndex:i]]; + } else { + FFLog(@"I-RDB034038", @"Restoring put: skipped nil: %d", i); + } + } + + NSArray *getKeys = [[self.outstandingGets allKeys] + sortedArrayUsingSelector:@selector(compare:)]; + for (int i = 0; i < [getKeys count]; i++) { + if ([self.outstandingGets objectForKey:[getKeys objectAtIndex:i]] != + nil) { + FFLog(@"I-RDB034037", @"Restoring get: %d", i); + [self sendGet:[getKeys objectAtIndex:i]]; + } else { + FFLog(@"I-RDB034038", @"Restoring get: skipped nil: %d", i); + } + } + + for (FTupleOnDisconnect *tuple in self.onDisconnectQueue) { + [self sendOnDisconnectAction:tuple.action + forPath:tuple.pathString + withData:tuple.data + andCallback:tuple.onComplete]; + } + [self.onDisconnectQueue removeAllObjects]; +} + +- (NSArray *)removeListen:(FQuerySpec *)query { + NSAssert(query.isDefault || !query.loadsAllData, + @"removeListen called for non-default but complete query"); + + FOutstandingQuery *outstanding = self.listens[query]; + if (!outstanding) { + FFLog(@"I-RDB034039", + @"Trying to remove listener for query %@ but no listener exists", + query); + return @[]; + } else { + [self.listens removeObjectForKey:query]; + return @[ outstanding ]; + } +} + +- (NSArray *)removeAllListensAtPath:(FPath *)path { + FFLog(@"I-RDB034040", @"Removing all listens at path %@", path); + NSMutableArray *removed = [NSMutableArray array]; + NSMutableArray *toRemove = [NSMutableArray array]; + [self.listens + enumerateKeysAndObjectsUsingBlock:^( + FQuerySpec *spec, FOutstandingQuery *outstanding, BOOL *stop) { + if ([spec.path isEqual:path]) { + [removed addObject:outstanding]; + [toRemove addObject:spec]; + } + }]; + [self.listens removeObjectsForKeys:toRemove]; + return removed; +} + +- (void)purgeOutstandingWrites { + // We might have unacked puts in our queue that we need to ack now before we + // send out any cancels... + [self ackPuts]; + // Cancel in order + NSArray *keys = [[self.outstandingPuts allKeys] + sortedArrayUsingSelector:@selector(compare:)]; + for (NSNumber *key in keys) { + FOutstandingPut *put = self.outstandingPuts[key]; + if (put.onCompleteBlock != nil) { + put.onCompleteBlock(kFErrorWriteCanceled, nil); + } + } + for (FTupleOnDisconnect *onDisconnect in self.onDisconnectQueue) { + if (onDisconnect.onComplete != nil) { + onDisconnect.onComplete(kFErrorWriteCanceled, nil); + } + } + [self.outstandingPuts removeAllObjects]; + [self.onDisconnectQueue removeAllObjects]; +} + +- (void)ackPuts { + for (FTupleCallbackStatus *put in self.putsToAck) { + put.block(put.status, put.errorReason); + } + [self.putsToAck removeAllObjects]; +} + +- (void)handleTimestamp:(NSNumber *)timestamp { + FFLog(@"I-RDB034041", @"Handling timestamp: %@", timestamp); + double timestampDeltaMs = [timestamp doubleValue] - + ([[NSDate date] timeIntervalSince1970] * 1000); + [self.delegate onServerInfoUpdate:self + updates:@{ + kDotInfoServerTimeOffset : [NSNumber + numberWithDouble:timestampDeltaMs] + }]; +} + +- (void)sendStats:(NSDictionary *)stats { + if ([stats count] > 0) { + NSDictionary *request = @{kFWPRequestCounters : stats}; + [self sendAction:kFWPRequestActionStats + body:request + sensitive:NO + callback:^(NSDictionary *data) { + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + NSString *errorReason = + [data objectForKey:kFWPResponseForActionData]; + BOOL statusOk = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (!statusOk) { + FFLog(@"I-RDB034042", @"Failed to send stats: %@", + errorReason); + } + }]; + } else { + FFLog(@"I-RDB034043", @"Not sending stats because stats are empty"); + } +} + +- (void)sendConnectStats { + NSMutableDictionary *stats = [NSMutableDictionary dictionary]; + +#if TARGET_OS_IOS || TARGET_OS_TV + if (self.config.persistenceEnabled) { + stats[@"persistence.ios.enabled"] = @1; + } +#elif TARGET_OS_OSX + if (self.config.persistenceEnabled) { + stats[@"persistence.osx.enabled"] = @1; + } +#elif TARGET_OS_WATCH + if (self.config.persistenceEnabled) { + stats[@"persistence.watchos.enabled"] = @1; + } +#endif + NSString *sdkVersion = + [[FIRDatabase sdkVersion] stringByReplacingOccurrencesOfString:@"." + withString:@"-"]; + NSString *sdkStatName = + [NSString stringWithFormat:@"sdk.objc.%@", sdkVersion]; + stats[sdkStatName] = @1; + FFLog(@"I-RDB034044", @"Sending first connection stats"); + [self sendStats:stats]; +} + +- (NSDictionary *)dumpListens { + return self.listens; +} + +#pragma mark - App Check Token update + +// TODO: Add tests! +- (void)refreshAppCheckToken:(NSString *)token { + if (![self connected]) { + // A fresh FAC token will be sent as a part of initial handshake. + return; + } + + if (token.length == 0) { + // No token to send. + return; + } + + // Send updated FAC token to the open connection. + [self sendAppCheckToken:token]; +} + +- (void)sendAppCheckToken:(NSString *)token { + NSDictionary *requestData = @{kFWPRequestAppCheckToken : token}; + [self sendAction:kFWPRequestActionAppCheck + body:requestData + sensitive:YES + callback:^(NSDictionary *data) { + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + id responseData = [data objectForKey:kFWPResponseForActionData]; + if (responseData == nil) { + responseData = @"Response data was empty."; + } + + BOOL statusOk = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (!statusOk) { + self.authToken = nil; + self.forceTokenRefreshes = YES; + if ([status isEqualToString:@"invalid_token"]) { + FFLog(@"I-RDB034045", @"App check failed: %@ (%@)", + status, responseData); + } else { + FFWarn(@"I-RDB034046", @"App check failed: %@ (%@)", + status, responseData); + } + [self.realtime close]; + } + }]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.h new file mode 100644 index 0000000..5d957c5 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.h @@ -0,0 +1,60 @@ +/* + * 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 + +@protocol FIndex +, FNodeFilter, FNode; + +@interface FQueryParams : NSObject + +@property(nonatomic, readonly) BOOL limitSet; +@property(nonatomic, readonly) NSInteger limit; + +@property(nonatomic, strong, readonly) NSString *viewFrom; +@property(nonatomic, strong, readonly) id indexStartValue; +@property(nonatomic, strong, readonly) NSString *indexStartKey; +@property(nonatomic, strong, readonly) id indexEndValue; +@property(nonatomic, strong, readonly) NSString *indexEndKey; + +@property(nonatomic, strong, readonly) id index; + +- (BOOL)loadsAllData; +- (BOOL)isDefault; +- (BOOL)isValid; +- (BOOL)hasAnchoredLimit; + +- (FQueryParams *)limitTo:(NSInteger)limit; +- (FQueryParams *)limitToFirst:(NSInteger)newLimit; +- (FQueryParams *)limitToLast:(NSInteger)newLimit; + +- (FQueryParams *)startAt:(id)indexValue childKey:(NSString *)key; +- (FQueryParams *)startAt:(id)indexValue; +- (FQueryParams *)endAt:(id)indexValue childKey:(NSString *)key; +- (FQueryParams *)endAt:(id)indexValue; + +- (FQueryParams *)orderBy:(id)index; + ++ (FQueryParams *)defaultInstance; ++ (FQueryParams *)fromQueryObject:(NSDictionary *)dict; + +- (BOOL)hasStart; +- (BOOL)hasEnd; + +- (NSDictionary *)wireProtocolParams; +- (BOOL)isViewFromLeft; +- (id)nodeFilter; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.m new file mode 100644 index 0000000..fcef36c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.m @@ -0,0 +1,393 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FPriorityIndex.h" +#import "FirebaseDatabase/Sources/FRangedFilter.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +@interface FQueryParams () + +@property(nonatomic, readwrite) BOOL limitSet; +@property(nonatomic, readwrite) NSInteger limit; + +@property(nonatomic, strong, readwrite) NSString *viewFrom; +/** + * indexStartValue is anything you can store as a priority / value. + */ +@property(nonatomic, strong, readwrite) id indexStartValue; +@property(nonatomic, strong, readwrite) NSString *indexStartKey; +/** + * indexStartValue is anything you can store as a priority / value. + */ +@property(nonatomic, strong, readwrite) id indexEndValue; +@property(nonatomic, strong, readwrite) NSString *indexEndKey; + +@property(nonatomic, strong, readwrite) id index; + +@end + +@implementation FQueryParams + ++ (FQueryParams *)defaultInstance { + static FQueryParams *defaultParams = nil; + static dispatch_once_t defaultParamsToken; + dispatch_once(&defaultParamsToken, ^{ + defaultParams = [[FQueryParams alloc] init]; + }); + return defaultParams; +} + +- (id)init { + self = [super init]; + if (self) { + self->_limitSet = NO; + self->_limit = 0; + + self->_viewFrom = nil; + self->_indexStartValue = nil; + self->_indexStartKey = nil; + self->_indexEndValue = nil; + self->_indexEndKey = nil; + + self->_index = [FPriorityIndex priorityIndex]; + } + return self; +} + +/** + * Only valid if hasStart is true + */ +- (id)indexStartValue { + NSAssert([self hasStart], @"Only valid if start has been set"); + return _indexStartValue; +} + +/** + * Only valid if hasStart is true. + * @return The starting key name for the range defined by these query parameters + */ +- (NSString *)indexStartKey { + NSAssert([self hasStart], @"Only valid if start has been set"); + if (_indexStartKey == nil) { + return [FUtilities minName]; + } else { + return _indexStartKey; + } +} + +/** + * Only valid if hasEnd is true. + */ +- (id)indexEndValue { + NSAssert([self hasEnd], @"Only valid if end has been set"); + return _indexEndValue; +} + +/** + * Only valid if hasEnd is true. + * @return The end key name for the range defined by these query parameters + */ +- (NSString *)indexEndKey { + NSAssert([self hasEnd], @"Only valid if end has been set"); + if (_indexEndKey == nil) { + return [FUtilities maxName]; + } else { + return _indexEndKey; + } +} + +/** + * @return true if a limit has been set and has been explicitly anchored + */ +- (BOOL)hasAnchoredLimit { + return self.limitSet && self.viewFrom != nil; +} + +/** + * Only valid to call if limitSet returns true + */ +- (NSInteger)limit { + NSAssert(self.limitSet, @"Only valid if limit has been set"); + return _limit; +} + +- (BOOL)hasStart { + return self->_indexStartValue != nil; +} + +- (BOOL)hasEnd { + return self->_indexEndValue != nil; +} + +- (id)copyWithZone:(NSZone *)zone { + // Immutable + return self; +} + +- (id)mutableCopy { + FQueryParams *other = [[[self class] alloc] init]; + // Maybe need to do extra copying here + other->_limitSet = _limitSet; + other->_limit = _limit; + other->_indexStartValue = _indexStartValue; + other->_indexStartKey = _indexStartKey; + other->_indexEndValue = _indexEndValue; + other->_indexEndKey = _indexEndKey; + other->_viewFrom = _viewFrom; + other->_index = _index; + return other; +} + +- (FQueryParams *)limitTo:(NSInteger)newLimit { + FQueryParams *newParams = [self mutableCopy]; + newParams->_limitSet = YES; + newParams->_limit = newLimit; + newParams->_viewFrom = nil; + return newParams; +} + +- (FQueryParams *)limitToFirst:(NSInteger)newLimit { + FQueryParams *newParams = [self mutableCopy]; + newParams->_limitSet = YES; + newParams->_limit = newLimit; + newParams->_viewFrom = kFQPViewFromLeft; + return newParams; +} + +- (FQueryParams *)limitToLast:(NSInteger)newLimit { + FQueryParams *newParams = [self mutableCopy]; + newParams->_limitSet = YES; + newParams->_limit = newLimit; + newParams->_viewFrom = kFQPViewFromRight; + return newParams; +} + +- (FQueryParams *)startAt:(id)indexValue childKey:(NSString *)key { + NSAssert([indexValue isLeafNode] || [indexValue isEmpty], nil); + FQueryParams *newParams = [self mutableCopy]; + newParams->_indexStartValue = indexValue; + newParams->_indexStartKey = key; + return newParams; +} + +- (FQueryParams *)startAt:(id)indexValue { + return [self startAt:indexValue childKey:nil]; +} + +- (FQueryParams *)endAt:(id)indexValue childKey:(NSString *)key { + NSAssert([indexValue isLeafNode] || [indexValue isEmpty], nil); + FQueryParams *newParams = [self mutableCopy]; + newParams->_indexEndValue = indexValue; + newParams->_indexEndKey = key; + return newParams; +} + +- (FQueryParams *)endAt:(id)indexValue { + return [self endAt:indexValue childKey:nil]; +} + +- (FQueryParams *)orderBy:(id)newIndex { + FQueryParams *newParams = [self mutableCopy]; + newParams->_index = newIndex; + return newParams; +} + +- (NSDictionary *)wireProtocolParams { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + if ([self hasStart]) { + [dict setObject:[self.indexStartValue valForExport:YES] + forKey:kFQPIndexStartValue]; + + // Don't use property as it will be [MIN-NAME] + if (self->_indexStartKey != nil) { + [dict setObject:self->_indexStartKey forKey:kFQPIndexStartName]; + } + } + + if ([self hasEnd]) { + [dict setObject:[self.indexEndValue valForExport:YES] + forKey:kFQPIndexEndValue]; + + // Don't use property as it will be [MAX-NAME] + if (self->_indexEndKey != nil) { + [dict setObject:self->_indexEndKey forKey:kFQPIndexEndName]; + } + } + + if (self.limitSet) { + [dict setObject:[NSNumber numberWithInteger:self.limit] + forKey:kFQPLimit]; + NSString *vf = self.viewFrom; + if (vf == nil) { + // limit() rather than limitToFirst or limitToLast was called. + // This means that only one of startSet or endSet is true. Use them + // to calculate which side of the view to anchor to. If neither is + // set, Anchor to end + if ([self hasStart]) { + vf = kFQPViewFromLeft; + } else { + vf = kFQPViewFromRight; + } + } + [dict setObject:vf forKey:kFQPViewFrom]; + } + + // For now, priority index is the default, so we only specify if it's some + // other index. + if (![self.index isEqual:[FPriorityIndex priorityIndex]]) { + [dict setObject:[self.index queryDefinition] forKey:kFQPIndex]; + } + + return dict; +} + ++ (FQueryParams *)fromQueryObject:(NSDictionary *)dict { + if (dict.count == 0) { + return [FQueryParams defaultInstance]; + } + + FQueryParams *params = [[FQueryParams alloc] init]; + if (dict[kFQPLimit] != nil) { + params->_limitSet = YES; + params->_limit = [dict[kFQPLimit] integerValue]; + } + + if (dict[kFQPIndexStartValue] != nil) { + params->_indexStartValue = + [FSnapshotUtilities nodeFrom:dict[kFQPIndexStartValue]]; + if (dict[kFQPIndexStartName] != nil) { + params->_indexStartKey = dict[kFQPIndexStartName]; + } + } + + if (dict[kFQPIndexEndValue] != nil) { + params->_indexEndValue = + [FSnapshotUtilities nodeFrom:dict[kFQPIndexEndValue]]; + if (dict[kFQPIndexEndName] != nil) { + params->_indexEndKey = dict[kFQPIndexEndName]; + } + } + + if (dict[kFQPViewFrom] != nil) { + NSString *viewFrom = dict[kFQPViewFrom]; + if (![viewFrom isEqualToString:kFQPViewFromLeft] && + ![viewFrom isEqualToString:kFQPViewFromRight]) { + [NSException raise:NSInvalidArgumentException + format:@"Unknown view from paramter: %@", viewFrom]; + } + params->_viewFrom = viewFrom; + } + + NSString *index = dict[kFQPIndex]; + if (index != nil) { + params->_index = [FIndex indexFromQueryDefinition:index]; + } + + return params; +} + +- (BOOL)isViewFromLeft { + if (self.viewFrom != nil) { + // Not null, we can just check + return [self.viewFrom isEqualToString:kFQPViewFromLeft]; + } else { + // If start is set, it's view from left. Otherwise not. + return self.hasStart; + } +} + +- (id)nodeFilter { + if (self.loadsAllData) { + return [[FIndexedFilter alloc] initWithIndex:self.index]; + } else if (self.limitSet) { + return [[FLimitedFilter alloc] initWithQueryParams:self]; + } else { + return [[FRangedFilter alloc] initWithQueryParams:self]; + } +} + +- (BOOL)isValid { + return !(self.hasStart && self.hasEnd && self.limitSet && + !self.hasAnchoredLimit); +} + +- (BOOL)loadsAllData { + return !(self.hasStart || self.hasEnd || self.limitSet); +} + +- (BOOL)isDefault { + return [self loadsAllData] && + [self.index isEqual:[FPriorityIndex priorityIndex]]; +} + +- (NSString *)description { + return [[self wireProtocolParams] description]; +} + +- (BOOL)isEqual:(id)obj { + if (self == obj) { + return YES; + } + if (![obj isKindOfClass:[self class]]) { + return NO; + } + FQueryParams *other = (FQueryParams *)obj; + if (self->_limitSet != other->_limitSet) + return NO; + if (self->_limit != other->_limit) + return NO; + if ((self->_index != other->_index) && + ![self->_index isEqual:other->_index]) + return NO; + if ((self->_indexStartKey != other->_indexStartKey) && + ![self->_indexStartKey isEqualToString:other->_indexStartKey]) + return NO; + if ((self->_indexStartValue != other->_indexStartValue) && + ![self->_indexStartValue isEqual:other->_indexStartValue]) + return NO; + if ((self->_indexEndKey != other->_indexEndKey) && + ![self->_indexEndKey isEqualToString:other->_indexEndKey]) + return NO; + if ((self->_indexEndValue != other->_indexEndValue) && + ![self->_indexEndValue isEqual:other->_indexEndValue]) + return NO; + if ([self isViewFromLeft] != [other isViewFromLeft]) + return NO; + + return YES; +} + +- (NSUInteger)hash { + NSUInteger result = _limitSet ? _limit : 0; + result = 31 * result + ([self isViewFromLeft] ? 1231 : 1237); + result = 31 * result + [_indexStartKey hash]; + result = 31 * result + [_indexStartValue hash]; + result = 31 * result + [_indexEndKey hash]; + result = 31 * result + [_indexEndValue hash]; + result = 31 * result + [_index hash]; + return result; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.h new file mode 100644 index 0000000..f3e1882 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.h @@ -0,0 +1,36 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/FIndex.h" + +@interface FQuerySpec : NSObject + +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) FQueryParams *params; + +- (id)initWithPath:(FPath *)path params:(FQueryParams *)params; + ++ (FQuerySpec *)defaultQueryAtPath:(FPath *)path; + +- (id)index; +- (BOOL)isDefault; +- (BOOL)loadsAllData; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.m new file mode 100644 index 0000000..ea76984 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.m @@ -0,0 +1,86 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FQuerySpec.h" + +@interface FQuerySpec () + +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong, readwrite) FQueryParams *params; + +@end + +@implementation FQuerySpec + +- (id)initWithPath:(FPath *)path params:(FQueryParams *)params { + self = [super init]; + if (self != nil) { + self->_path = path; + self->_params = params; + } + return self; +} + ++ (FQuerySpec *)defaultQueryAtPath:(FPath *)path { + return [[FQuerySpec alloc] initWithPath:path + params:[FQueryParams defaultInstance]]; +} + +- (id)copyWithZone:(NSZone *)zone { + // Immutable + return self; +} + +- (id)index { + return self.params.index; +} + +- (BOOL)isDefault { + return self.params.isDefault; +} + +- (BOOL)loadsAllData { + return self.params.loadsAllData; +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[FQuerySpec class]]) { + return NO; + } + + FQuerySpec *other = (FQuerySpec *)object; + + if (![self.path isEqual:other.path]) { + return NO; + } + + return [self.params isEqual:other.params]; +} + +- (NSUInteger)hash { + return self.path.hash * 31 + self.params.hash; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FQuerySpec (path: %@, params: %@)", + self.path, self.params]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.h new file mode 100644 index 0000000..674f936 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.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. + */ + +#import + +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +/** + * Applies a merge of a snap for a given interval of paths. + * Each leaf in the current node which the relative path lies *after* (the + * optional) start and lies *before or at* (the optional) end will be deleted. + * Each leaf in snap that lies in the interval will be added to the resulting + * node. Nodes outside of the range are ignored. nil for start and end are + * sentinel values that represent -infinity and +infinity respectively (aka + * includes any path). Priorities of children nodes are treated as leaf children + * of that node. + */ +@interface FRangeMerge : NSObject + +- (instancetype)initWithStart:(FPath *)start + end:(FPath *)end + updates:(id)updates; + +- (id)applyToNode:(id)node; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.m new file mode 100644 index 0000000..7ec74b2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.m @@ -0,0 +1,134 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FRangeMerge.h" + +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" + +@interface FRangeMerge () + +@property(nonatomic, strong) FPath *optExclusiveStart; +@property(nonatomic, strong) FPath *optInclusiveEnd; +@property(nonatomic, strong) id updates; + +@end + +@implementation FRangeMerge + +- (instancetype)initWithStart:(FPath *)start + end:(FPath *)end + updates:(id)updates { + self = [super init]; + if (self != nil) { + self->_optExclusiveStart = start; + self->_optInclusiveEnd = end; + self->_updates = updates; + } + return self; +} + +- (id)applyToNode:(id)node { + return [self updateRangeInNode:[FPath empty] + node:node + updates:self.updates]; +} + +- (id)updateRangeInNode:(FPath *)currentPath + node:(id)node + updates:(id)updates { + NSComparisonResult startComparison = + (self.optExclusiveStart == nil) + ? NSOrderedDescending + : [currentPath compare:self.optExclusiveStart]; + NSComparisonResult endComparison = + (self.optInclusiveEnd == nil) + ? NSOrderedAscending + : [currentPath compare:self.optInclusiveEnd]; + BOOL startInNode = self.optExclusiveStart != nil && + [currentPath contains:self.optExclusiveStart]; + BOOL endInNode = self.optInclusiveEnd != nil && + [currentPath contains:self.optInclusiveEnd]; + if (startComparison == NSOrderedDescending && + endComparison == NSOrderedAscending && !endInNode) { + // child is completly contained + return updates; + } else if (startComparison == NSOrderedDescending && endInNode && + [updates isLeafNode]) { + return updates; + } else if (startComparison == NSOrderedDescending && + endComparison == NSOrderedSame) { + NSAssert(endInNode, @"End not in node"); + NSAssert(![updates isLeafNode], @"Found leaf node update, this case " + @"should have been handled above."); + if ([node isLeafNode]) { + // Update node was not a leaf node, so we can delete it + return [FEmptyNode emptyNode]; + } else { + // Unaffected by range, ignore + return node; + } + } else if (startInNode || endInNode) { + // There is a partial update we need to do, so collect all relevant + // children + NSMutableSet *allChildren = [NSMutableSet set]; + [node enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + [allChildren addObject:key]; + }]; + [updates enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + [allChildren addObject:key]; + }]; + + __block id newNode = node; + void (^action)(id, BOOL *) = ^void(NSString *key, BOOL *stop) { + id currentChild = [node getImmediateChild:key]; + id updatedChild = + [self updateRangeInNode:[currentPath childFromString:key] + node:currentChild + updates:[updates getImmediateChild:key]]; + // Only need to update if the node changed + if (updatedChild != currentChild) { + newNode = [newNode updateImmediateChild:key + withNewChild:updatedChild]; + } + }; + + [allChildren enumerateObjectsUsingBlock:action]; + + // Add priority last, so the node is not empty when applying + if (!updates.getPriority.isEmpty || !node.getPriority.isEmpty) { + BOOL stop = NO; + action(@".priority", &stop); + } + return newNode; + } else { + // Unaffected by this range + NSAssert(endComparison == NSOrderedDescending || + startComparison <= NSOrderedSame, + @"Invalid range for update"); + return node; + } +} + +- (NSString *)description { + return [NSString stringWithFormat:@"RangeMerge (optExclusiveStart = %@, " + @"optExclusiveEng = %@, updates = %@)", + self.optExclusiveStart, + self.optInclusiveEnd, self.updates]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.h new file mode 100644 index 0000000..94adbc2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.h @@ -0,0 +1,102 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FPersistentConnection.h" +#import "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h" +#import + +@class FQuerySpec; +@class FPersistence; +@class FAuthenticationManager; +@class FIRDatabaseConfig; +@protocol FEventRegistration; +@class FCompoundWrite; +@protocol FClock; +@class FIRDatabase; + +@interface FRepo : NSObject + +@property(nonatomic, strong) FIRDatabaseConfig *_Nullable config; + +- (id _Nonnull)initWithRepoInfo:(FRepoInfo *_Nullable)info + config:(FIRDatabaseConfig *_Nullable)config + database:(FIRDatabase *_Nullable)database; + +- (void)set:(FPath *_Nullable)path + withNode:(id _Nullable)node + withCallback:(fbt_void_nserror_ref _Nullable)onComplete; +- (void)update:(FPath *_Nullable)path + withNodes:(FCompoundWrite *_Nullable)compoundWrite + withCallback:(fbt_void_nserror_ref _Nullable)callback; +- (void)purgeOutstandingWrites; + +- (void)getData:(FIRDatabaseQuery *_Nullable)query + withCompletionBlock: + (void (^_Nonnull)(NSError *_Nullable error, + FIRDataSnapshot *_Nullable snapshot))block; + +- (void)addEventRegistration:(id _Nullable)eventRegistration + forQuery:(FQuerySpec *_Nullable)query; +- (void)removeEventRegistration: + (id _Nullable)eventRegistration + forQuery:(FQuerySpec *_Nullable)query; +- (void)keepQuery:(FQuerySpec *_Nullable)query synced:(BOOL)synced; + +- (NSString *_Nullable)name; +- (NSTimeInterval)serverTime; + +- (void)onDataUpdate:(FPersistentConnection *_Nullable)fpconnection + forPath:(NSString *_Nullable)pathString + message:(id _Nullable)message + isMerge:(BOOL)isMerge + tagId:(NSNumber *_Nullable)tagId; +- (void)onConnect:(FPersistentConnection *_Nullable)fpconnection; +- (void)onDisconnect:(FPersistentConnection *_Nullable)fpconnection; + +// Disconnect methods +- (void)onDisconnectCancel:(FPath *_Nullable)path + withCallback:(fbt_void_nserror_ref _Nullable)callback; +- (void)onDisconnectSet:(FPath *_Nullable)path + withNode:(id _Nullable)node + withCallback:(fbt_void_nserror_ref _Nullable)callback; +- (void)onDisconnectUpdate:(FPath *_Nullable)path + withNodes:(FCompoundWrite *_Nullable)compoundWrite + withCallback:(fbt_void_nserror_ref _Nullable)callback; + +// Connection Management. +- (void)interrupt; +- (void)resume; + +// Transactions +- (void)startTransactionOnPath:(FPath *_Nullable)path + update: + (fbt_transactionresult_mutabledata _Nullable)update + onComplete: + (fbt_void_nserror_bool_datasnapshot _Nullable)onComplete + withLocalEvents:(BOOL)applyLocally; + +// Testing methods +- (NSDictionary *_Nullable)dumpListens; +- (void)dispose; +- (void)setHijackHash:(BOOL)hijack; + +@property(nonatomic, strong, readonly) FAuthenticationManager *_Nullable auth; +@property(nonatomic, strong, readonly) FIRDatabase *_Nullable database; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.m new file mode 100644 index 0000000..f041b57 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.m @@ -0,0 +1,1542 @@ +/* + * 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 + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Core/FListenProvider.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseDatabase/Sources/Core/FRepo_Private.h" +#import "FirebaseDatabase/Sources/Core/FServerValues.h" +#import "FirebaseDatabase/Sources/Core/FSnapshotHolder.h" +#import "FirebaseDatabase/Sources/Core/FSyncTree.h" +#import "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FTree.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRaiser.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h" +#import "FirebaseDatabase/Sources/FClock.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/Persistence/FCachePolicy.h" +#import "FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h" +#import "FirebaseDatabase/Sources/Persistence/FPersistenceManager.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h" +#import + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#endif + +@interface FRepo () + +@property(nonatomic, strong) FOffsetClock *serverClock; +@property(nonatomic, strong) FPersistenceManager *persistenceManager; +@property(nonatomic, strong) FIRDatabase *database; +@property(nonatomic, strong, readwrite) FAuthenticationManager *auth; +@property(nonatomic, strong) FSyncTree *infoSyncTree; +@property(nonatomic) NSInteger writeIdCounter; +@property(nonatomic) BOOL hijackHash; +@property(nonatomic, strong) FTree *transactionQueueTree; +@property(nonatomic) BOOL loggedTransactionPersistenceWarning; + +/** + * Test only. For load testing the server. + */ +@property(nonatomic, strong) id (^interceptServerDataCallback) + (NSString *pathString, id data); +@end + +@implementation FRepo + +- (id)initWithRepoInfo:(FRepoInfo *)info + config:(FIRDatabaseConfig *)config + database:(FIRDatabase *)database { + self = [super init]; + if (self) { + self.repoInfo = info; + self.config = config; + self.database = database; + + // Access can occur outside of shared queue, so the clock needs to be + // initialized here + self.serverClock = + [[FOffsetClock alloc] initWithClock:[FSystemClock clock] offset:0]; + + self.connection = [[FPersistentConnection alloc] + initWithRepoInfo:self.repoInfo + dispatchQueue:[FIRDatabaseQuery sharedQueue] + config:self.config]; + + // Needs to be called before authentication manager is instantiated + self.eventRaiser = + [[FEventRaiser alloc] initWithQueue:self.config.callbackQueue]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self deferredInit]; + }); + } + return self; +} + +- (void)deferredInit { + // TODO: cleanup on dealloc + __weak FRepo *weakSelf = self; + [self.config.contextProvider listenForAuthTokenChanges:^(NSString *token) { + [weakSelf.connection refreshAuthToken:token]; + }]; + + [self.config.contextProvider + listenForAppCheckTokenChanges:^(NSString *token) { + [weakSelf.connection refreshAppCheckToken:token]; + }]; + + // Open connection now so that by the time we are connected the deferred + // init has run This relies on the fact that all callbacks run on repos + // queue + self.connection.delegate = self; + [self.connection open]; + + self.dataUpdateCount = 0; + self.rangeMergeUpdateCount = 0; + self.interceptServerDataCallback = nil; + + if (self.config.persistenceEnabled) { + NSString *repoHashString = + [NSString stringWithFormat:@"%@_%@", self.repoInfo.host, + self.repoInfo.namespace]; + NSString *persistencePrefix = + [NSString stringWithFormat:@"%@/%@", self.config.sessionIdentifier, + repoHashString]; + + id cachePolicy = [[FLRUCachePolicy alloc] + initWithMaxSize:self.config.persistenceCacheSizeBytes]; + + id engine; + if (self.config.forceStorageEngine != nil) { + engine = self.config.forceStorageEngine; + } else { + FLevelDBStorageEngine *levelDBEngine = + [[FLevelDBStorageEngine alloc] initWithPath:persistencePrefix]; + // We need the repo info to run the legacy migration. Future + // migrations will be managed by the database itself Remove this + // once we are confident that no-one is using legacy migration + // anymore... + [levelDBEngine runLegacyMigration:self.repoInfo]; + engine = levelDBEngine; + } + + self.persistenceManager = + [[FPersistenceManager alloc] initWithStorageEngine:engine + cachePolicy:cachePolicy]; + } else { + self.persistenceManager = nil; + } + + [self initTransactions]; + + // A list of data pieces and paths to be set when this client disconnects + self.onDisconnect = [[FSparseSnapshotTree alloc] init]; + self.infoData = [[FSnapshotHolder alloc] init]; + + FListenProvider *infoListenProvider = [[FListenProvider alloc] init]; + infoListenProvider.startListening = + ^(FQuerySpec *query, NSNumber *tagId, id hash, + fbt_nsarray_nsstring onComplete) { + NSArray *infoEvents = @[]; + FRepo *strongSelf = weakSelf; + id node = [strongSelf.infoData getNode:query.path]; + // This is possibly a hack, but we have different semantics for .info + // endpoints. We don't raise null events on initial data... + if (![node isEmpty]) { + infoEvents = + [strongSelf.infoSyncTree applyServerOverwriteAtPath:query.path + newData:node]; + [strongSelf.eventRaiser raiseCallback:^{ + onComplete(kFWPResponseForActionStatusOk); + }]; + } + return infoEvents; + }; + infoListenProvider.stopListening = ^(FQuerySpec *query, NSNumber *tagId) { + }; + self.infoSyncTree = + [[FSyncTree alloc] initWithListenProvider:infoListenProvider]; + + FListenProvider *serverListenProvider = [[FListenProvider alloc] init]; + serverListenProvider.startListening = + ^(FQuerySpec *query, NSNumber *tagId, id hash, + fbt_nsarray_nsstring onComplete) { + [weakSelf.connection listen:query + tagId:tagId + hash:hash + onComplete:^(NSString *status) { + NSArray *events = onComplete(status); + [weakSelf.eventRaiser raiseEvents:events]; + }]; + // No synchronous events for network-backed sync trees + return @[]; + }; + serverListenProvider.stopListening = ^(FQuerySpec *query, NSNumber *tag) { + [weakSelf.connection unlisten:query tagId:tag]; + }; + self.serverSyncTree = + [[FSyncTree alloc] initWithPersistenceManager:self.persistenceManager + listenProvider:serverListenProvider]; + + [self restoreWrites]; + + [self updateInfo:kDotInfoConnected withValue:@NO]; + + [self setupNotifications]; +} + +- (void)restoreWrites { + NSArray *writes = self.persistenceManager.userWrites; + + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + __block NSInteger lastWriteId = NSIntegerMin; + [writes enumerateObjectsUsingBlock:^(FWriteRecord *write, NSUInteger idx, + BOOL *stop) { + NSInteger writeId = write.writeId; + fbt_void_nsstring_nsstring callback = + ^(NSString *status, NSString *errorReason) { + [self warnIfWriteFailedAtPath:write.path + status:status + message:@"Persisted write"]; + [self ackWrite:writeId + rerunTransactionsAtPath:write.path + status:status]; + }; + if (lastWriteId >= writeId) { + [NSException raise:NSInternalInconsistencyException + format:@"Restored writes were not in order!"]; + } + lastWriteId = writeId; + self.writeIdCounter = writeId + 1; + + if ([write isOverwrite]) { + FFLog(@"I-RDB038001", @"Restoring overwrite with id %ld", + (long)write.writeId); + [self.connection putData:[write.overwrite valForExport:YES] + forPath:[write.path toString] + withHash:nil + withCallback:callback]; + id resolved = + [FServerValues resolveDeferredValueSnapshot:write.overwrite + withSyncTree:self.serverSyncTree + atPath:write.path + serverValues:serverValues]; + [self.serverSyncTree applyUserOverwriteAtPath:write.path + newData:resolved + writeId:writeId + isVisible:YES]; + } else { + FFLog(@"I-RDB038002", @"Restoring merge with id %ld", + (long)write.writeId); + [self.connection mergeData:[write.merge valForExport:YES] + forPath:[write.path toString] + withCallback:callback]; + FCompoundWrite *resolved = [FServerValues + resolveDeferredValueCompoundWrite:write.merge + withSyncTree:self.serverSyncTree + atPath:write.path + serverValues:serverValues]; + [self.serverSyncTree applyUserMergeAtPath:write.path + changedChildren:resolved + writeId:writeId]; + } + }]; +} + +- (NSString *)name { + return self.repoInfo.namespace; +} + +- (NSString *)description { + return [self.repoInfo description]; +} + +- (void)interrupt { + [self.connection interruptForReason:kFInterruptReasonRepoInterrupt]; +} + +- (void)resume { + [self.connection resumeForReason:kFInterruptReasonRepoInterrupt]; +} + +// NOTE: Typically if you're calling this, you should be in an @autoreleasepool +// block to make sure that ARC kicks in and cleans up things no longer +// referenced (i.e. pendingPutsDB). +- (void)dispose { + [self.connection interruptForReason:kFInterruptReasonRepoInterrupt]; + + // We need to nil out any references to LevelDB, to make sure the + // LevelDB exclusive locks are released. + [self.persistenceManager close]; +} + +- (NSInteger)nextWriteId { + return self->_writeIdCounter++; +} + +- (NSTimeInterval)serverTime { + return [self.serverClock currentTime]; +} + +- (void)set:(FPath *)path + withNode:(id)node + withCallback:(fbt_void_nserror_ref)onComplete { + id value = [node valForExport:YES]; + FFLog(@"I-RDB038003", @"Setting: %@ with %@ pri: %@", [path toString], + [value description], [[node getPriority] val]); + + // TODO: Optimize this behavior to either (a) store flag to skip resolving + // where possible and / or (b) store unresolved paths on JSON parse + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + id existing = [self.serverSyncTree calcCompleteEventCacheAtPath:path + excludeWriteIds:@[]]; + id newNode = + [FServerValues resolveDeferredValueSnapshot:node + withExisting:existing + serverValues:serverValues]; + + NSInteger writeId = [self nextWriteId]; + [self.persistenceManager saveUserOverwrite:node + atPath:path + writeId:writeId]; + NSArray *events = [self.serverSyncTree applyUserOverwriteAtPath:path + newData:newNode + writeId:writeId + isVisible:YES]; + [self.eventRaiser raiseEvents:events]; + + [self.connection putData:value + forPath:[path toString] + withHash:nil + withCallback:^(NSString *status, NSString *errorReason) { + [self warnIfWriteFailedAtPath:path + status:status + message:@"setValue: or removeValue:"]; + [self ackWrite:writeId + rerunTransactionsAtPath:path + status:status]; + [self callOnComplete:onComplete + withStatus:status + errorReason:errorReason + andPath:path]; + }]; + + FPath *affectedPath = [self abortTransactionsAtPath:path + error:kFTransactionSet]; + [self rerunTransactionsForPath:affectedPath]; +} + +- (void)update:(FPath *)path + withNodes:(FCompoundWrite *)nodes + withCallback:(fbt_void_nserror_ref)callback { + NSDictionary *values = [nodes valForExport:YES]; + + FFLog(@"I-RDB038004", @"Updating: %@ with %@", [path toString], + [values description]); + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + FCompoundWrite *resolved = + [FServerValues resolveDeferredValueCompoundWrite:nodes + withSyncTree:self.serverSyncTree + atPath:path + serverValues:serverValues]; + + if (!resolved.isEmpty) { + NSInteger writeId = [self nextWriteId]; + [self.persistenceManager saveUserMerge:nodes + atPath:path + writeId:writeId]; + NSArray *events = [self.serverSyncTree applyUserMergeAtPath:path + changedChildren:resolved + writeId:writeId]; + [self.eventRaiser raiseEvents:events]; + + [self.connection mergeData:values + forPath:[path description] + withCallback:^(NSString *status, NSString *errorReason) { + [self warnIfWriteFailedAtPath:path + status:status + message:@"updateChildValues:"]; + [self ackWrite:writeId + rerunTransactionsAtPath:path + status:status]; + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; + + [nodes enumerateWrites:^(FPath *childPath, id node, BOOL *stop) { + FPath *pathFromRoot = [path child:childPath]; + FFLog(@"I-RDB038005", @"Cancelling transactions at path: %@", + pathFromRoot); + FPath *affectedPath = [self abortTransactionsAtPath:pathFromRoot + error:kFTransactionSet]; + [self rerunTransactionsForPath:affectedPath]; + }]; + } else { + FFLog(@"I-RDB038006", @"update called with empty data. Doing nothing"); + // Do nothing, just call the callback + [self callOnComplete:callback + withStatus:@"ok" + errorReason:nil + andPath:path]; + } +} + +- (void)onDisconnectCancel:(FPath *)path + withCallback:(fbt_void_nserror_ref)callback { + [self.connection + onDisconnectCancelPath:path + withCallback:^(NSString *status, NSString *errorReason) { + BOOL success = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (success) { + [self.onDisconnect forgetPath:path]; + } else { + FFLog(@"I-RDB038007", + @"cancelDisconnectOperations: at %@ failed: %@", + path, status); + } + + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; +} + +- (void)onDisconnectSet:(FPath *)path + withNode:(id)node + withCallback:(fbt_void_nserror_ref)callback { + [self.connection + onDisconnectPutData:[node valForExport:YES] + forPath:path + withCallback:^(NSString *status, NSString *errorReason) { + BOOL success = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (success) { + [self.onDisconnect rememberData:node onPath:path]; + } else { + FFWarn(@"I-RDB038008", + @"onDisconnectSetValue: or " + @"onDisconnectRemoveValue: at %@ failed: %@", + path, status); + } + + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; +} + +- (void)onDisconnectUpdate:(FPath *)path + withNodes:(FCompoundWrite *)nodes + withCallback:(fbt_void_nserror_ref)callback { + if (!nodes.isEmpty) { + NSDictionary *values = [nodes valForExport:YES]; + + [self.connection + onDisconnectMergeData:values + forPath:path + withCallback:^(NSString *status, NSString *errorReason) { + BOOL success = [status + isEqualToString:kFWPResponseForActionStatusOk]; + if (success) { + [nodes enumerateWrites:^(FPath *relativePath, + id nodeUnresolved, + BOOL *stop) { + FPath *childPath = [path child:relativePath]; + [self.onDisconnect rememberData:nodeUnresolved + onPath:childPath]; + }]; + } else { + FFWarn(@"I-RDB038009", + @"onDisconnectUpdateChildValues: at %@ " + @"failed %@", + path, status); + } + + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; + } else { + // Do nothing, just call the callback + [self callOnComplete:callback + withStatus:@"ok" + errorReason:nil + andPath:path]; + } +} + +- (void)purgeOutstandingWrites { + FFLog(@"I-RDB038010", @"Purging outstanding writes"); + NSArray *events = [self.serverSyncTree removeAllWrites]; + [self.eventRaiser raiseEvents:events]; + // Abort any transactions + [self abortTransactionsAtPath:[FPath empty] error:kFErrorWriteCanceled]; + // Remove outstanding writes from connection + [self.connection purgeOutstandingWrites]; +} + +- (void)getData:(FIRDatabaseQuery *)query + withCompletionBlock: + (void (^_Nonnull)(NSError *__nullable error, + FIRDataSnapshot *__nullable snapshot))block { + FQuerySpec *querySpec = [query querySpec]; + id node = [self.serverSyncTree getServerValue:[query querySpec]]; + if (node != nil) { + [self.eventRaiser raiseCallback:^{ + block(nil, [[FIRDataSnapshot alloc] + initWithRef:query.ref + indexedNode:[FIndexedNode + indexedNodeWithNode:node + index:querySpec.index]]); + }]; + return; + } + [self.persistenceManager setQueryActive:querySpec]; + [self.connection + getDataAtPath:[query.path toString] + withParams:querySpec.params.wireProtocolParams + withCallback:^(NSString *status, id data, NSString *errorReason) { + id node; + if (![status isEqualToString:kFWPResponseForActionStatusOk]) { + FFLog(@"I-RDB038024", + @"getValue for query %@ falling back to disk cache", + [querySpec.path toString]); + FIndexedNode *node = + [self.serverSyncTree persistenceServerCache:querySpec]; + if (node == nil) { + NSDictionary *errorDict = @{ + NSLocalizedFailureReasonErrorKey : errorReason, + NSLocalizedDescriptionKey : [NSString + stringWithFormat: + @"Unable to get latest value for query %@, " + @"client offline with no active listeners " + @"and no matching disk cache entries", + querySpec] + }; + [self.eventRaiser raiseCallback:^{ + block([NSError errorWithDomain:kFirebaseCoreErrorDomain + code:1 + userInfo:errorDict], + nil); + }]; + return; + } + [self.eventRaiser raiseCallback:^{ + block(nil, [[FIRDataSnapshot alloc] initWithRef:query.ref + indexedNode:node]); + }]; + } else { + node = [FSnapshotUtilities nodeFrom:data]; + [self.eventRaiser + raiseEvents:[self.serverSyncTree + applyServerOverwriteAtPath:[query path] + newData:node]]; + [self.eventRaiser raiseCallback:^{ + block( + nil, + [[FIRDataSnapshot alloc] + initWithRef:query.ref + indexedNode:[FIndexedNode + indexedNodeWithNode:node + index:querySpec.index]]); + }]; + } + [self.persistenceManager setQueryInactive:querySpec]; + }]; +} + +- (void)addEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query { + NSArray *events = nil; + if ([[query.path getFront] isEqualToString:kDotInfoPrefix]) { + events = [self.infoSyncTree addEventRegistration:eventRegistration + forQuery:query]; + } else { + events = [self.serverSyncTree addEventRegistration:eventRegistration + forQuery:query]; + } + [self.eventRaiser raiseEvents:events]; +} + +- (void)removeEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query { + // These are guaranteed not to raise events, since we're not passing in a + // cancelError. However we can future-proof a little bit by handling the + // return values anyways. + FFLog(@"I-RDB038011", @"Removing event registration with hande: %lu", + (unsigned long)eventRegistration.handle); + NSArray *events = nil; + if ([[query.path getFront] isEqualToString:kDotInfoPrefix]) { + events = [self.infoSyncTree removeEventRegistration:eventRegistration + forQuery:query + cancelError:nil]; + } else { + events = [self.serverSyncTree removeEventRegistration:eventRegistration + forQuery:query + cancelError:nil]; + } + [self.eventRaiser raiseEvents:events]; +} + +- (void)keepQuery:(FQuerySpec *)query synced:(BOOL)synced { + NSAssert(![[query.path getFront] isEqualToString:kDotInfoPrefix], + @"Can't keep .info tree synced!"); + [self.serverSyncTree keepQuery:query synced:synced]; +} + +- (void)updateInfo:(NSString *)pathString withValue:(id)value { + // hack to make serverTimeOffset available in a threadsafe way. Property is + // marked as atomic + if ([pathString isEqualToString:kDotInfoServerTimeOffset]) { + NSTimeInterval offset = [(NSNumber *)value doubleValue] / 1000.0; + self.serverClock = + [[FOffsetClock alloc] initWithClock:[FSystemClock clock] + offset:offset]; + } + + FPath *path = [[FPath alloc] + initWith:[NSString + stringWithFormat:@"%@/%@", kDotInfoPrefix, pathString]]; + id newNode = [FSnapshotUtilities nodeFrom:value]; + [self.infoData updateSnapshot:path withNewSnapshot:newNode]; + NSArray *events = [self.infoSyncTree applyServerOverwriteAtPath:path + newData:newNode]; + [self.eventRaiser raiseEvents:events]; +} + +- (void)callOnComplete:(fbt_void_nserror_ref)onComplete + withStatus:(NSString *)status + errorReason:(NSString *)errorReason + andPath:(FPath *)path { + if (onComplete) { + FIRDatabaseReference *ref = + [[FIRDatabaseReference alloc] initWithRepo:self path:path]; + BOOL statusOk = [status isEqualToString:kFWPResponseForActionStatusOk]; + NSError *err = nil; + if (!statusOk) { + err = [FUtilities errorForStatus:status andReason:errorReason]; + } + [self.eventRaiser raiseCallback:^{ + onComplete(err, ref); + }]; + } +} + +- (void)ackWrite:(NSInteger)writeId + rerunTransactionsAtPath:(FPath *)path + status:(NSString *)status { + if ([status isEqualToString:kFErrorWriteCanceled]) { + // This write was already removed, we just need to ignore it... + } else { + BOOL success = [status isEqualToString:kFWPResponseForActionStatusOk]; + NSArray *clearEvents = + [self.serverSyncTree ackUserWriteWithWriteId:writeId + revert:!success + persist:YES + clock:self.serverClock]; + if ([clearEvents count] > 0) { + [self rerunTransactionsForPath:path]; + } + [self.eventRaiser raiseEvents:clearEvents]; + } +} + +- (void)warnIfWriteFailedAtPath:(FPath *)path + status:(NSString *)status + message:(NSString *)message { + if (!([status isEqualToString:kFWPResponseForActionStatusOk] || + [status isEqualToString:kFErrorWriteCanceled])) { + FFWarn(@"I-RDB038012", @"%@ at %@ failed: %@", message, path, status); + } +} + +#pragma mark - +#pragma mark FPersistentConnectionDelegate methods + +- (void)onDataUpdate:(FPersistentConnection *)fpconnection + forPath:(NSString *)pathString + message:(id)data + isMerge:(BOOL)isMerge + tagId:(NSNumber *)tagId { + FFLog(@"I-RDB038013", @"onDataUpdateForPath: %@ withMessage: %@", + pathString, data); + + // For testing. + self.dataUpdateCount++; + + FPath *path = [[FPath alloc] initWith:pathString]; + data = self.interceptServerDataCallback + ? self.interceptServerDataCallback(pathString, data) + : data; + NSArray *events = nil; + + if (tagId != nil) { + if (isMerge) { + NSDictionary *message = data; + FCompoundWrite *taggedChildren = + [FCompoundWrite compoundWriteWithValueDictionary:message]; + events = + [self.serverSyncTree applyTaggedQueryMergeAtPath:path + changedChildren:taggedChildren + tagId:tagId]; + } else { + id taggedSnap = [FSnapshotUtilities nodeFrom:data]; + events = + [self.serverSyncTree applyTaggedQueryOverwriteAtPath:path + newData:taggedSnap + tagId:tagId]; + } + } else if (isMerge) { + NSDictionary *message = data; + FCompoundWrite *changedChildren = + [FCompoundWrite compoundWriteWithValueDictionary:message]; + events = [self.serverSyncTree applyServerMergeAtPath:path + changedChildren:changedChildren]; + } else { + id snap = [FSnapshotUtilities nodeFrom:data]; + events = [self.serverSyncTree applyServerOverwriteAtPath:path + newData:snap]; + } + + if ([events count] > 0) { + // Since we have a listener outstanding for each transaction, receiving + // any events is a proxy for some change having occurred. + [self rerunTransactionsForPath:path]; + } + + [self.eventRaiser raiseEvents:events]; +} + +- (void)onRangeMerge:(NSArray *)ranges + forPath:(NSString *)pathString + tagId:(NSNumber *)tag { + FFLog(@"I-RDB038014", @"onRangeMerge: %@ => %@", pathString, ranges); + + // For testing + self.rangeMergeUpdateCount++; + + FPath *path = [[FPath alloc] initWith:pathString]; + NSArray *events; + if (tag != nil) { + events = [self.serverSyncTree applyTaggedServerRangeMergeAtPath:path + updates:ranges + tagId:tag]; + } else { + events = [self.serverSyncTree applyServerRangeMergeAtPath:path + updates:ranges]; + } + if (events.count > 0) { + // Since we have a listener outstanding for each transaction, receiving + // any events is a proxy for some change having occurred. + [self rerunTransactionsForPath:path]; + } + + [self.eventRaiser raiseEvents:events]; +} + +- (void)onConnect:(FPersistentConnection *)fpconnection { + [self updateInfo:kDotInfoConnected withValue:@YES]; +} + +- (void)onDisconnect:(FPersistentConnection *)fpconnection { + [self updateInfo:kDotInfoConnected withValue:@NO]; + [self runOnDisconnectEvents]; +} + +- (void)onServerInfoUpdate:(FPersistentConnection *)fpconnection + updates:(NSDictionary *)updates { + for (NSString *key in updates) { + id val = [updates objectForKey:key]; + [self updateInfo:key withValue:val]; + } +} + +- (void)setupNotifications { + NSString *const *backgroundConstant = (NSString *const *)dlsym( + RTLD_DEFAULT, "UIApplicationDidEnterBackgroundNotification"); + if (backgroundConstant) { + FFLog(@"I-RDB038015", @"Registering for background notification."); + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(didEnterBackground) + name:*backgroundConstant + object:nil]; + } else { + FFLog(@"I-RDB038016", + @"Skipped registering for background notification."); + } +} + +- (void)didEnterBackground { + if (!self.config.persistenceEnabled) + return; + +// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual +// release build. +#if TARGET_OS_IOS || TARGET_OS_TV + // The idea is to wait until any outstanding sets get written to disk. Since + // the sets might still be in our dispatch queue, we wait for the dispatch + // queue to catch up and for persistence to catch up. This may be + // undesirable though. The dispatch queue might just be processing a bunch + // of incoming data or something. We might want to keep track of whether + // there are any unpersisted sets or something. + FFLog(@"I-RDB038017", + @"Entering background. Starting background task to finish work."); + Class uiApplicationClass = NSClassFromString(@"UIApplication"); + assert(uiApplicationClass); // If we are here, we should be on iOS and + // UIApplication should be available. + + UIApplication *application = [uiApplicationClass sharedApplication]; + __block UIBackgroundTaskIdentifier bgTask = + [application beginBackgroundTaskWithExpirationHandler:^{ + [application endBackgroundTask:bgTask]; + }]; + + NSDate *start = [NSDate date]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + NSTimeInterval finishTime = [start timeIntervalSinceNow] * -1; + FFLog(@"I-RDB038018", @"Background task completed. Queue time: %f", + finishTime); + [application endBackgroundTask:bgTask]; + }); +#endif +} + +#pragma mark - +#pragma mark Internal methods + +/** + * Applies all the changes stored up in the onDisconnect tree + */ +- (void)runOnDisconnectEvents { + FFLog(@"I-RDB038019", @"Running onDisconnectEvents"); + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + NSMutableArray *events = [[NSMutableArray alloc] init]; + + [self.onDisconnect + forEachTreeAtPath:[FPath empty] + do:^(FPath *path, id node) { + id existing = [self.serverSyncTree + calcCompleteEventCacheAtPath:path + excludeWriteIds:@[]]; + id resolved = [FServerValues + resolveDeferredValueSnapshot:node + withExisting:existing + serverValues:serverValues]; + [events addObjectsFromArray: + [self.serverSyncTree + applyServerOverwriteAtPath:path + newData:resolved]]; + FPath *affectedPath = + [self abortTransactionsAtPath:path + error:kFTransactionSet]; + [self rerunTransactionsForPath:affectedPath]; + }]; + + self.onDisconnect = [[FSparseSnapshotTree alloc] init]; + [self.eventRaiser raiseEvents:events]; +} + +- (NSDictionary *)dumpListens { + return [self.connection dumpListens]; +} + +#pragma mark - +#pragma mark Transactions + +/** + * Setup the transaction data structures + */ +- (void)initTransactions { + self.transactionQueueTree = [[FTree alloc] init]; + self.hijackHash = NO; + self.loggedTransactionPersistenceWarning = NO; +} + +/** + * Creates a new transaction, add its to the transactions we're tracking, and + * sends it to the server if possible + */ +- (void)startTransactionOnPath:(FPath *)path + update:(fbt_transactionresult_mutabledata)update + onComplete:(fbt_void_nserror_bool_datasnapshot)onComplete + withLocalEvents:(BOOL)applyLocally { + if (self.config.persistenceEnabled && + !self.loggedTransactionPersistenceWarning) { + self.loggedTransactionPersistenceWarning = YES; + FFInfo(@"I-RDB038020", + @"runTransactionBlock: usage detected while persistence is " + @"enabled. Please be aware that transactions " + @"*will not* be persisted across app restarts. " + @"See " + @"https://www.firebase.com/docs/ios/guide/" + @"offline-capabilities.html#section-handling-transactions-" + @"offline for more details."); + } + + FIRDatabaseReference *watchRef = + [[FIRDatabaseReference alloc] initWithRepo:self path:path]; + // make sure we're listening on this node + // Note: we can't do this asynchronously. To preserve event ordering, it has + // to be done in this block. This is ok, this block is guaranteed to be our + // own event loop + NSUInteger handle = [[FUtilities LUIDGenerator] integerValue]; + fbt_void_datasnapshot cb = ^(FIRDataSnapshot *snapshot) { + }; + FValueEventRegistration *registration = + [[FValueEventRegistration alloc] initWithRepo:self + handle:handle + callback:cb + cancelCallback:nil]; + [watchRef.repo addEventRegistration:registration + forQuery:watchRef.querySpec]; + fbt_void_void unwatcher = ^{ + [watchRef removeObserverWithHandle:handle]; + }; + + // Save all the data that represents this transaction + FTupleTransaction *transaction = [[FTupleTransaction alloc] init]; + transaction.path = path; + transaction.update = update; + transaction.onComplete = onComplete; + transaction.status = FTransactionInitializing; + transaction.order = [FUtilities LUIDGenerator]; + transaction.applyLocally = applyLocally; + transaction.retryCount = 0; + transaction.unwatcher = unwatcher; + transaction.currentWriteId = nil; + transaction.currentInputSnapshot = nil; + transaction.currentOutputSnapshotRaw = nil; + transaction.currentOutputSnapshotResolved = nil; + + // Run transaction initially + id currentState = [self latestStateAtPath:path excludeWriteIds:nil]; + transaction.currentInputSnapshot = currentState; + FIRMutableData *mutableCurrent = + [[FIRMutableData alloc] initWithNode:currentState]; + FIRTransactionResult *result = transaction.update(mutableCurrent); + + if (!result.isSuccess) { + // Abort the transaction + transaction.unwatcher(); + transaction.currentOutputSnapshotRaw = nil; + transaction.currentOutputSnapshotResolved = nil; + if (transaction.onComplete) { + FIRDatabaseReference *ref = + [[FIRDatabaseReference alloc] initWithRepo:self + path:transaction.path]; + FIndexedNode *indexedNode = [FIndexedNode + indexedNodeWithNode:transaction.currentInputSnapshot]; + FIRDataSnapshot *snap = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:indexedNode]; + [self.eventRaiser raiseCallback:^{ + transaction.onComplete(nil, NO, snap); + }]; + } + } else { + // Note: different from js. We don't need to validate, FIRMutableData + // does validation. We also don't have to worry about priorities. Just + // mark as run and add to queue. + transaction.status = FTransactionRun; + FTree *queueNode = [self.transactionQueueTree subTree:transaction.path]; + NSMutableArray *nodeQueue = [queueNode getValue]; + if (nodeQueue == nil) { + nodeQueue = [[NSMutableArray alloc] init]; + } + [nodeQueue addObject:transaction]; + [queueNode setValue:nodeQueue]; + + // Update visibleData and raise events + // Note: We intentionally raise events after updating all of our + // transaction state, since the user could start new transactions from + // the event callbacks + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + id newValUnresolved = [result.update nodeValue]; + id newVal = + [FServerValues resolveDeferredValueSnapshot:newValUnresolved + withExisting:currentState + serverValues:serverValues]; + transaction.currentOutputSnapshotRaw = newValUnresolved; + transaction.currentOutputSnapshotResolved = newVal; + transaction.currentWriteId = + [NSNumber numberWithInteger:[self nextWriteId]]; + + NSArray *events = [self.serverSyncTree + applyUserOverwriteAtPath:path + newData:newVal + writeId:[transaction.currentWriteId integerValue] + isVisible:transaction.applyLocally]; + [self.eventRaiser raiseEvents:events]; + + [self sendAllReadyTransactions]; + } +} + +/** + * @param writeIdsToExclude A specific set to exclude + */ +- (id)latestStateAtPath:(FPath *)path + excludeWriteIds:(NSArray *)writeIdsToExclude { + id latestState = + [self.serverSyncTree calcCompleteEventCacheAtPath:path + excludeWriteIds:writeIdsToExclude]; + return latestState ? latestState : [FEmptyNode emptyNode]; +} + +/** + * Sends any already-run transactions that aren't waiting for outstanding + * transactions to complete. + * + * Externally, call the version with no arguments. + * Internally, calls itself recursively with a particular transactionQueueTree + * node to recurse through the tree + */ +- (void)sendAllReadyTransactions { + FTree *node = self.transactionQueueTree; + + [self pruneCompletedTransactionsBelowNode:node]; + [self sendReadyTransactionsForTree:node]; +} + +- (void)sendReadyTransactionsForTree:(FTree *)node { + NSMutableArray *queue = [node getValue]; + if (queue != nil) { + queue = [self buildTransactionQueueAtNode:node]; + NSAssert([queue count] > 0, @"Sending zero length transaction queue"); + + NSUInteger notRunIndex = [queue + indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + return ((FTupleTransaction *)obj).status != FTransactionRun; + }]; + + // If they're all run (and not sent), we can send them. Else, we must + // wait. + if (notRunIndex == NSNotFound) { + [self sendTransactionQueue:queue atPath:node.path]; + } + } else if ([node hasChildren]) { + [node forEachChild:^(FTree *child) { + [self sendReadyTransactionsForTree:child]; + }]; + } +} + +/** + * Given a list of run transactions, send them to the server and then handle the + * result (success or failure). + */ +- (void)sendTransactionQueue:(NSMutableArray *)queue atPath:(FPath *)path { + // Mark transactions as sent and bump the retry count + NSMutableArray *writeIdsToExclude = [[NSMutableArray alloc] init]; + for (FTupleTransaction *transaction in queue) { + [writeIdsToExclude addObject:transaction.currentWriteId]; + } + id latestState = [self latestStateAtPath:path + excludeWriteIds:writeIdsToExclude]; + id snapToSend = latestState; + NSString *latestHash = [latestState dataHash]; + for (FTupleTransaction *transaction in queue) { + NSAssert( + transaction.status == FTransactionRun, + @"[FRepo sendTransactionQueue:] items in queue should all be run."); + FFLog(@"I-RDB038021", @"Transaction at %@ set to SENT", + transaction.path); + transaction.status = FTransactionSent; + transaction.retryCount++; + FPath *relativePath = [FPath relativePathFrom:path to:transaction.path]; + // If we've gotten to this point, the output snapshot must be defined. + snapToSend = + [snapToSend updateChild:relativePath + withNewChild:transaction.currentOutputSnapshotRaw]; + } + + id dataToSend = [snapToSend valForExport:YES]; + NSString *pathToSend = [path description]; + latestHash = self.hijackHash ? @"badhash" : latestHash; + + // Send the put + [self.connection + putData:dataToSend + forPath:pathToSend + withHash:latestHash + withCallback:^(NSString *status, NSString *errorReason) { + FFLog(@"I-RDB038022", @"Transaction put response: %@ : %@", + pathToSend, status); + + NSMutableArray *events = [[NSMutableArray alloc] init]; + if ([status isEqualToString:kFWPResponseForActionStatusOk]) { + // Queue up the callbacks and fire them after cleaning up all of + // our transaction state, since the callback could trigger more + // transactions or sets. + NSMutableArray *callbacks = [[NSMutableArray alloc] init]; + for (FTupleTransaction *transaction in queue) { + transaction.status = FTransactionCompleted; + [events addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId: + [transaction.currentWriteId integerValue] + revert:NO + persist:NO + clock:self.serverClock]]; + if (transaction.onComplete) { + // We never unset the output snapshot, and given that this + // transaction is complete, it should be set + id node = + transaction.currentOutputSnapshotResolved; + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:node]; + FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] + initWithRepo:self + path:transaction.path]; + FIRDataSnapshot *snapshot = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:indexedNode]; + fbt_void_void cb = ^{ + transaction.onComplete(nil, YES, snapshot); + }; + [callbacks addObject:[cb copy]]; + } + transaction.unwatcher(); + } + + // Now remove the completed transactions. + [self + pruneCompletedTransactionsBelowNode:[self.transactionQueueTree + subTree:path]]; + // There may be pending transactions that we can now send. + [self sendAllReadyTransactions]; + + // Finally, trigger onComplete callbacks + [self.eventRaiser raiseCallbacks:callbacks]; + } else { + // transactions are no longer sent. Update their status + // appropriately. + if ([status + isEqualToString:kFWPResponseForActionStatusDataStale]) { + for (FTupleTransaction *transaction in queue) { + if (transaction.status == FTransactionSentNeedsAbort) { + transaction.status = FTransactionNeedsAbort; + } else { + transaction.status = FTransactionRun; + } + } + } else { + FFWarn(@"I-RDB038023", + @"runTransactionBlock: at %@ failed: %@", path, + status); + for (FTupleTransaction *transaction in queue) { + transaction.status = FTransactionNeedsAbort; + [transaction setAbortStatus:status reason:errorReason]; + } + } + } + + [self rerunTransactionsForPath:path]; + [self.eventRaiser raiseEvents:events]; + }]; +} + +/** + * Finds all transactions dependent on the data at changed Path and reruns them. + * + * Should be called any time cached data changes. + * + * Return the highest path that was affected by rerunning transactions. This is + * the path at which events need to be raised for. + */ +- (FPath *)rerunTransactionsForPath:(FPath *)changedPath { + // For the common case that there are no transactions going on, skip all + // this! + if ([self.transactionQueueTree isEmpty]) { + return changedPath; + } else { + FTree *rootMostTransactionNode = + [self getAncestorTransactionNodeForPath:changedPath]; + FPath *path = rootMostTransactionNode.path; + + NSArray *queue = + [self buildTransactionQueueAtNode:rootMostTransactionNode]; + [self rerunTransactionQueue:queue atPath:path]; + + return path; + } +} + +/** + * Does all the work of rerunning transactions (as well as cleans up aborted + * transactions and whatnot). + */ +- (void)rerunTransactionQueue:(NSArray *)queue atPath:(FPath *)path { + if (queue.count == 0) { + return; // nothing to do + } + + // Queue up the callbacks and fire them after cleaning up all of our + // transaction state, since the callback could trigger more transactions or + // sets. + NSMutableArray *events = [[NSMutableArray alloc] init]; + NSMutableArray *callbacks = [[NSMutableArray alloc] init]; + + // Ignore, by default, all of the sets in this queue, since we're re-running + // all of them. However, we want to include the results of new sets + // triggered as part of this re-run, so we don't want to ignore a range, + // just these specific sets. + NSMutableArray *writeIdsToExclude = [[NSMutableArray alloc] init]; + for (FTupleTransaction *transaction in queue) { + [writeIdsToExclude addObject:transaction.currentWriteId]; + } + + for (FTupleTransaction *transaction in queue) { + FPath *relativePath __unused = + [FPath relativePathFrom:path to:transaction.path]; + BOOL abortTransaction = NO; + NSAssert(relativePath != nil, @"[FRepo rerunTransactionsQueue:] " + @"relativePath should not be null."); + + if (transaction.status == FTransactionNeedsAbort) { + abortTransaction = YES; + if (![transaction.abortStatus + isEqualToString:kFErrorWriteCanceled]) { + NSArray *ackEvents = [self.serverSyncTree + ackUserWriteWithWriteId:[transaction.currentWriteId + integerValue] + revert:YES + persist:NO + clock:self.serverClock]; + [events addObjectsFromArray:ackEvents]; + } + } else if (transaction.status == FTransactionRun) { + if (transaction.retryCount >= kFTransactionMaxRetries) { + abortTransaction = YES; + [transaction setAbortStatus:kFTransactionTooManyRetries + reason:nil]; + [events + addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId:[transaction.currentWriteId + integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; + } else { + // This code reruns a transaction + id currentNode = + [self latestStateAtPath:transaction.path + excludeWriteIds:writeIdsToExclude]; + transaction.currentInputSnapshot = currentNode; + FIRMutableData *mutableCurrent = + [[FIRMutableData alloc] initWithNode:currentNode]; + FIRTransactionResult *result = + transaction.update(mutableCurrent); + if (result.isSuccess) { + NSNumber *oldWriteId = transaction.currentWriteId; + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + + id newVal = [result.update nodeValue]; + id newValResolved = [FServerValues + resolveDeferredValueSnapshot:newVal + withExisting:transaction + .currentInputSnapshot + serverValues:serverValues]; + + transaction.currentOutputSnapshotRaw = newVal; + transaction.currentOutputSnapshotResolved = newValResolved; + + transaction.currentWriteId = + [NSNumber numberWithInteger:[self nextWriteId]]; + // Mutates writeIdsToExclude in place + [writeIdsToExclude removeObject:oldWriteId]; + [events + addObjectsFromArray: + [self.serverSyncTree + applyUserOverwriteAtPath:transaction.path + newData: + transaction + .currentOutputSnapshotResolved + writeId: + [transaction.currentWriteId + integerValue] + isVisible:transaction + .applyLocally]]; + [events addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId:[oldWriteId + integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; + } else { + abortTransaction = YES; + // The user aborted the transaction. JS treats ths as a + // "nodata" abort, but it's not an error, so we don't send + // them an error. + [transaction setAbortStatus:nil reason:nil]; + [events + addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId: + [transaction.currentWriteId integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; + } + } + } + + [self.eventRaiser raiseEvents:events]; + events = nil; + + if (abortTransaction) { + // Abort + transaction.status = FTransactionCompleted; + transaction.unwatcher(); + if (transaction.onComplete) { + FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] + initWithRepo:self + path:transaction.path]; + FIndexedNode *lastInput = [FIndexedNode + indexedNodeWithNode:transaction.currentInputSnapshot]; + FIRDataSnapshot *snap = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:lastInput]; + fbt_void_void cb = ^{ + // Unlike JS, no need to check for "nodata" because ObjC has + // abortError = nil + transaction.onComplete(transaction.abortError, NO, snap); + }; + [callbacks addObject:[cb copy]]; + } + } + } + + // Note: unlike current js client, we don't need to preserve priority. Users + // can set priority via FIRMutableData + + // Clean up completed transactions. + [self pruneCompletedTransactionsBelowNode:self.transactionQueueTree]; + + // Now fire callbacks, now that we're in a good, known state. + [self.eventRaiser raiseCallbacks:callbacks]; + + // Try to send the transaction result to the server + [self sendAllReadyTransactions]; +} + +- (FTree *)getAncestorTransactionNodeForPath:(FPath *)path { + FTree *transactionNode = self.transactionQueueTree; + + while (![path isEmpty] && [transactionNode getValue] == nil) { + NSString *front = [path getFront]; + transactionNode = + [transactionNode subTree:[[FPath alloc] initWith:front]]; + path = [path popFront]; + } + + return transactionNode; +} + +- (NSMutableArray *)buildTransactionQueueAtNode:(FTree *)node { + NSMutableArray *queue = [[NSMutableArray alloc] init]; + [self aggregateTransactionQueuesForNode:node andQueue:queue]; + + [queue sortUsingComparator:^NSComparisonResult(FTupleTransaction *obj1, + FTupleTransaction *obj2) { + return [obj1.order compare:obj2.order]; + }]; + + return queue; +} + +- (void)aggregateTransactionQueuesForNode:(FTree *)node + andQueue:(NSMutableArray *)queue { + NSArray *nodeQueue = [node getValue]; + [queue addObjectsFromArray:nodeQueue]; + + [node forEachChild:^(FTree *child) { + [self aggregateTransactionQueuesForNode:child andQueue:queue]; + }]; +} + +/** + * Remove COMPLETED transactions at or below this node in the + * transactionQueueTree + */ +- (void)pruneCompletedTransactionsBelowNode:(FTree *)node { + NSMutableArray *queue = [node getValue]; + if (queue != nil) { + int i = 0; + // remove all of the completed transactions from the queue + while (i < queue.count) { + FTupleTransaction *transaction = [queue objectAtIndex:i]; + if (transaction.status == FTransactionCompleted) { + [queue removeObjectAtIndex:i]; + } else { + i++; + } + } + if (queue.count > 0) { + [node setValue:queue]; + } else { + [node setValue:nil]; + } + } + + [node forEachChildMutationSafe:^(FTree *child) { + [self pruneCompletedTransactionsBelowNode:child]; + }]; +} + +/** + * Aborts all transactions on ancestors or descendants of the specified path. + * Called when doing a setValue: or updateChildValues: since we consider them + * incompatible with transactions + * + * @param path path for which we want to abort related transactions. + */ +- (FPath *)abortTransactionsAtPath:(FPath *)path error:(NSString *)error { + // For the common case that there are no transactions going on, skip all + // this! + if ([self.transactionQueueTree isEmpty]) { + return path; + } else { + FPath *affectedPath = + [self getAncestorTransactionNodeForPath:path].path; + + FTree *transactionNode = [self.transactionQueueTree subTree:path]; + [transactionNode forEachAncestor:^BOOL(FTree *ancestor) { + [self abortTransactionsAtNode:ancestor error:error]; + return NO; + }]; + + [self abortTransactionsAtNode:transactionNode error:error]; + + [transactionNode forEachDescendant:^(FTree *child) { + [self abortTransactionsAtNode:child error:error]; + }]; + + return affectedPath; + } +} + +/** + * Abort transactions stored in this transactions queue node. + * + * @param node Node to abort transactions for. + */ +- (void)abortTransactionsAtNode:(FTree *)node error:(NSString *)error { + NSMutableArray *queue = [node getValue]; + if (queue != nil) { + + // Queue up the callbacks and fire them after cleaning up all of our + // transaction state, since can be immediately aborted and removed. + NSMutableArray *callbacks = [[NSMutableArray alloc] init]; + + // Go through queue. Any already-sent transactions must be marked for + // abort, while the unsent ones can be immediately aborted and removed + NSMutableArray *events = [[NSMutableArray alloc] init]; + int lastSent = -1; + // Note: all of the sent transactions will be at the front of the queue, + // so safe to increment lastSent + for (FTupleTransaction *transaction in queue) { + if (transaction.status == FTransactionSentNeedsAbort) { + // No-op. already marked. + } else if (transaction.status == FTransactionSent) { + // Mark this transaction for abort when it returns + lastSent++; + transaction.status = FTransactionSentNeedsAbort; + [transaction setAbortStatus:error reason:nil]; + } else { + // we can abort this immediately + transaction.unwatcher(); + if ([error isEqualToString:kFTransactionSet]) { + [events + addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId: + [transaction.currentWriteId integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; + } else { + // If it was cancelled it was already removed from the sync + // tree, no need to ack + NSAssert([error isEqualToString:kFErrorWriteCanceled], nil); + } + + if (transaction.onComplete) { + NSError *abortReason = [FUtilities errorForStatus:error + andReason:nil]; + FIRDataSnapshot *snapshot = nil; + fbt_void_void cb = ^{ + transaction.onComplete(abortReason, NO, snapshot); + }; + [callbacks addObject:[cb copy]]; + } + } + } + if (lastSent == -1) { + // We're not waiting for any sent transactions. We can clear the + // queue. + [node setValue:nil]; + } else { + // Remove the transactions we aborted + NSRange theRange; + theRange.location = lastSent + 1; + theRange.length = queue.count - theRange.location; + [queue removeObjectsInRange:theRange]; + } + + // Now fire the callbacks + [self.eventRaiser raiseEvents:events]; + [self.eventRaiser raiseCallbacks:callbacks]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.h new file mode 100644 index 0000000..4b1e40d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.h @@ -0,0 +1,53 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface FRepoInfo : NSObject + +/// The host that the database should connect to. +@property(nonatomic, readonly, copy) NSString *host; + +@property(nonatomic, readonly, copy) NSString *namespace; +@property(nonatomic, readwrite, copy) NSString *internalHost; +@property(nonatomic, readonly, assign) BOOL secure; + +/// Returns YES if the host is not a *.firebaseio.com host. +@property(nonatomic, readonly) BOOL isCustomHost; + +- (instancetype)initWithHost:(NSString *)host + isSecure:(BOOL)secure + withNamespace:(NSString *)namespace NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithInfo:(FRepoInfo *)info emulatedHost:(NSString *)host; + +- (NSString *)connectionURLWithLastSessionID:(NSString *_Nullable)lastSessionID; +- (NSString *)connectionURL; +- (void)clearInternalHostCache; +- (BOOL)isDemoHost; +- (BOOL)isCustomHost; + +- (id)copyWithZone:(NSZone *_Nullable)zone; +- (NSUInteger)hash; +- (BOOL)isEqual:(id)anObject; + +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.m new file mode 100644 index 0000000..82ca825 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.m @@ -0,0 +1,153 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" + +@interface FRepoInfo () + +@property(nonatomic, strong) NSString *domain; + +@end + +@implementation FRepoInfo + +@synthesize internalHost; + +- (instancetype)init { + [NSException + raise:@"FIRDatabaseInvalidInitializer" + format:@"Invalid initializer invoked. This is probably a bug in RTDB."]; + abort(); +} + +- (instancetype)initWithHost:(NSString *)aHost + isSecure:(BOOL)isSecure + withNamespace:(NSString *)aNamespace { + self = [super init]; + if (self) { + _host = [aHost copy]; + _domain = + [_host containsString:@"."] + ? [_host + substringFromIndex:[_host rangeOfString:@"."].location + + 1] + : _host; + _secure = isSecure; + _namespace = aNamespace; + + // Get cached internal host if it exists + NSString *internalHostKey = + [NSString stringWithFormat:@"firebase:host:%@", _host]; + NSString *cachedInternalHost = [[NSUserDefaults standardUserDefaults] + stringForKey:internalHostKey]; + if (cachedInternalHost != nil) { + internalHost = cachedInternalHost; + } else { + internalHost = [_host copy]; + } + } + return self; +} + +- (instancetype)initWithInfo:(FRepoInfo *)info emulatedHost:(NSString *)host { + self = [self initWithHost:host isSecure:NO withNamespace:info.namespace]; + return self; +} + +- (NSString *)description { + // The namespace is encoded in the hostname, so we can just return this. + return [NSString + stringWithFormat:@"http%@://%@", (_secure ? @"s" : @""), _host]; +} + +- (void)setInternalHost:(NSString *)newHost { + if (![internalHost isEqualToString:newHost]) { + internalHost = newHost; + + // Cache the internal host so we don't need to redirect later on + NSString *internalHostKey = + [NSString stringWithFormat:@"firebase:host:%@", self.host]; + NSUserDefaults *cache = [NSUserDefaults standardUserDefaults]; + [cache setObject:internalHost forKey:internalHostKey]; + [cache synchronize]; + } +} + +- (void)clearInternalHostCache { + self.internalHost = self.host; + + // Remove the cached entry + NSString *internalHostKey = + [NSString stringWithFormat:@"firebase:host:%@", self.host]; + NSUserDefaults *cache = [NSUserDefaults standardUserDefaults]; + [cache removeObjectForKey:internalHostKey]; + [cache synchronize]; +} + +- (BOOL)isDemoHost { + return [self.domain isEqualToString:@"firebaseio-demo.com"]; +} + +- (BOOL)isCustomHost { + return ![self.domain isEqualToString:@"firebaseio-demo.com"] && + ![self.domain isEqualToString:@"firebaseio.com"]; +} + +- (NSString *)connectionURL { + return [self connectionURLWithLastSessionID:nil]; +} + +- (NSString *)connectionURLWithLastSessionID:(NSString *)lastSessionID { + NSString *scheme; + if (self.secure) { + scheme = @"wss"; + } else { + scheme = @"ws"; + } + NSString *url = + [NSString stringWithFormat:@"%@://%@/.ws?%@=%@&ns=%@", scheme, + self.internalHost, kWireProtocolVersionParam, + kWebsocketProtocolVersion, self.namespace]; + + if (lastSessionID != nil) { + url = [NSString stringWithFormat:@"%@&ls=%@", url, lastSessionID]; + } + return url; +} + +- (id)copyWithZone:(NSZone *)zone { + return self; // Immutable +} + +- (NSUInteger)hash { + NSUInteger result = _host.hash; + result = 31 * result + (_secure ? 1 : 0); + result = 31 * result + _namespace.hash; + result = 31 * result + _host.hash; + return result; +} + +- (BOOL)isEqual:(id)anObject { + if (![anObject isKindOfClass:[FRepoInfo class]]) { + return NO; + } + FRepoInfo *other = (FRepoInfo *)anObject; + return _secure == other.secure && [_host isEqualToString:other.host] && + [_namespace isEqualToString:other.namespace]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.h new file mode 100644 index 0000000..bebfd0b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.h @@ -0,0 +1,34 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import + +@interface FRepoManager : NSObject + ++ (FRepo *)getRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config; ++ (FRepo *)createRepo:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config + database:(FIRDatabase *)database; ++ (void)interruptAll; ++ (void)interrupt:(FIRDatabaseConfig *)config; ++ (void)resumeAll; ++ (void)resume:(FIRDatabaseConfig *)config; ++ (void)disposeRepos:(FIRDatabaseConfig *)config; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.m new file mode 100644 index 0000000..b22cd25 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.m @@ -0,0 +1,148 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" + +@implementation FRepoManager + +typedef NSMutableDictionary *> + FRepoDictionary; + ++ (FRepoDictionary *)configs { + static dispatch_once_t pred = 0; + static FRepoDictionary *configs; + dispatch_once(&pred, ^{ + configs = [NSMutableDictionary dictionary]; + }); + return configs; +} + +/** + * Used for legacy unit tests. The public API should go through + * FirebaseDatabase which calls createRepo. + */ ++ (FRepo *)getRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config { + [config freeze]; + FRepoDictionary *configs = [FRepoManager configs]; + @synchronized(configs) { + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; + if (!repos || repos[repoInfo] == nil) { + // Calling this should create the repo. + [FIRDatabase createDatabaseForTests:repoInfo config:config]; + } + + return configs[config.sessionIdentifier][repoInfo]; + } +} + ++ (FRepo *)createRepo:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config + database:(FIRDatabase *)database { + [config freeze]; + FRepoDictionary *configs = [FRepoManager configs]; + @synchronized(configs) { + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; + if (!repos) { + repos = [NSMutableDictionary dictionary]; + configs[config.sessionIdentifier] = repos; + } + FRepo *repo = repos[repoInfo]; + if (repo == nil) { + repo = [[FRepo alloc] initWithRepoInfo:repoInfo + config:config + database:database]; + repos[repoInfo] = repo; + return repo; + } else { + [NSException + raise:@"RepoExists" + format:@"createRepo called for Repo that already exists."]; + return nil; + } + } +} + ++ (void)interrupt:(FIRDatabaseConfig *)config { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + FRepoDictionary *configs = [FRepoManager configs]; + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; + for (FRepo *repo in [repos allValues]) { + [repo interrupt]; + } + }); +} + ++ (void)interruptAll { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + FRepoDictionary *configs = [FRepoManager configs]; + for (NSMutableDictionary *repos in + [configs allValues]) { + for (FRepo *repo in [repos allValues]) { + [repo interrupt]; + } + } + }); +} + ++ (void)resume:(FIRDatabaseConfig *)config { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + FRepoDictionary *configs = [FRepoManager configs]; + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; + for (FRepo *repo in [repos allValues]) { + [repo resume]; + } + }); +} + ++ (void)resumeAll { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + FRepoDictionary *configs = [FRepoManager configs]; + for (NSMutableDictionary *repos in + [configs allValues]) { + for (FRepo *repo in [repos allValues]) { + [repo resume]; + } + } + }); +} + ++ (void)disposeRepos:(FIRDatabaseConfig *)config { + // Do this synchronously to make sure we release our references to LevelDB + // before returning, allowing LevelDB to close and release its exclusive + // locks. + dispatch_sync([FIRDatabaseQuery sharedQueue], ^{ + FFLog(@"I-RDB040001", @"Disposing all repos for Config with name %@", + config.sessionIdentifier); + NSMutableDictionary *configs = [FRepoManager configs]; + for (FRepo *repo in [configs[config.sessionIdentifier] allValues]) { + [repo dispose]; + } + [configs removeObjectForKey:config.sessionIdentifier]; + }); +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo_Private.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo_Private.h new file mode 100644 index 0000000..5d69d96 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo_Private.h @@ -0,0 +1,42 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h" + +@class FSyncTree; +@class FAtomicNumber; +@class FEventRaiser; +@class FSnapshotHolder; + +@interface FRepo () + +- (void)runOnDisconnectEvents; + +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FPersistentConnection *connection; +@property(nonatomic, strong) FSnapshotHolder *infoData; +@property(nonatomic, strong) FSparseSnapshotTree *onDisconnect; +@property(nonatomic, strong) FEventRaiser *eventRaiser; +@property(nonatomic, strong) FSyncTree *serverSyncTree; + +// For testing. +@property(nonatomic) long dataUpdateCount; +@property(nonatomic) long rangeMergeUpdateCount; + +- (NSInteger)nextWriteId; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.h new file mode 100644 index 0000000..aadd507 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.h @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h" +#import "FirebaseDatabase/Sources/Core/FSyncTree.h" +#import "FirebaseDatabase/Sources/FClock.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FServerValues : NSObject + ++ (NSDictionary *)generateServerValues:(id)clock; + ++ (FCompoundWrite *)resolveDeferredValueCompoundWrite:(FCompoundWrite *)write + withSyncTree:(FSyncTree *)tree + atPath:(FPath *)path + serverValues: + (NSDictionary *)serverValues; ++ (id)resolveDeferredValueSnapshot:(id)node + withSyncTree:(FSyncTree *)existing + atPath:(FPath *)path + serverValues:(NSDictionary *)serverValues; ++ (id)resolveDeferredValueSnapshot:(id)node + withExisting:(id)existing + serverValues:(NSDictionary *)serverValues; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.m new file mode 100644 index 0000000..88aadd3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.m @@ -0,0 +1,269 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FServerValues.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" + +const NSString *kTimestamp = @"timestamp"; +const NSString *kIncrement = @"increment"; + +BOOL canBeRepresentedAsLong(NSNumber *num) { + switch (num.objCType[0]) { + case 'f': // float; fallthrough + case 'd': // double + return NO; + case 'L': // unsigned long; fallthrough + case 'Q': // unsigned long long; fallthrough + // Only use ulong(long) if there isn't an overflow. + if (num.unsignedLongLongValue > LONG_MAX) { + return NO; + } + } + return YES; +} + +// Running through CompoundWrites for all update paths has been shown to +// be a 20% pessimization in microbenchmarks. This is because it slows +// down by O(N) of the write queue length. To eliminate the performance +// hit, we wrap around existing data of either snapshot or CompoundWrite +// (allowing us to share code) and read from the CompoundWrite only when/where +// we need to calculate an incremented value's prior state. +@protocol ValueProvider +- (id)getChild:(NSString *)pathSegment; +- (id)value; +@end + +@interface DeferredValueProvider : NSObject +- (instancetype)initWithSyncTree:(FSyncTree *)tree atPath:(FPath *)path; +- (id)getChild:(NSString *)pathSegment; +- (id)value; +@property FPath *path; +@property FSyncTree *tree; +@end + +@interface ExistingValueProvider : NSObject +- (instancetype)initWithSnapshot:(id)snapshot; +- (id)getChild:(NSString *)pathSegment; +- (id)value; +@property id snapshot; +@end + +@implementation DeferredValueProvider +- (instancetype)initWithSyncTree:(FSyncTree *)tree atPath:(FPath *)path { + self.tree = tree; + self.path = path; + return self; +} + +- (id)getChild:(NSString *)pathSegment { + FPath *child = [self.path childFromString:pathSegment]; + return [[DeferredValueProvider alloc] initWithSyncTree:self.tree + atPath:child]; +} + +- (id)value { + return [self.tree calcCompleteEventCacheAtPath:self.path + excludeWriteIds:@[]]; +} +@end + +@implementation ExistingValueProvider +- (instancetype)initWithSnapshot:(id)snapshot { + self.snapshot = snapshot; + return self; +} + +- (id)getChild:(NSString *)pathSegment { + return [[ExistingValueProvider alloc] + initWithSnapshot:[self.snapshot getImmediateChild:pathSegment]]; +} + +- (id)value { + return self.snapshot; +} +@end + +@interface FServerValues () ++ (id)resolveScalarServerOp:(NSString *)op + withServerValues:(NSDictionary *)serverValues; ++ (id)resolveComplexServerOp:(NSDictionary *)op + withValueProvider:(id)existing + serverValues:(NSDictionary *)serverValues; ++ (id)resolveDeferredValueSnapshot:(id)node + withValueProvider:(id)existing + serverValues:(NSDictionary *)serverValues; + +@end + +@implementation FServerValues + ++ (NSDictionary *)generateServerValues:(id)clock { + long long millis = (long long)([clock currentTime] * 1000); + return @{kTimestamp : [NSNumber numberWithLongLong:millis]}; +} + ++ (id)resolveDeferredValue:(id)val + withExisting:(id)existing + serverValues:(NSDictionary *)serverValues { + if (![val isKindOfClass:[NSDictionary class]]) { + return val; + } + NSDictionary *dict = val; + id op = dict[kServerValueSubKey]; + + if (op == nil) { + return val; + } else if ([op isKindOfClass:NSString.class]) { + return [FServerValues resolveScalarServerOp:op + withServerValues:serverValues]; + } else if ([op isKindOfClass:NSDictionary.class]) { + return [FServerValues resolveComplexServerOp:op + withValueProvider:existing + serverValues:serverValues]; + } + return val; +} + ++ (id)resolveScalarServerOp:(NSString *)op + withServerValues:(NSDictionary *)serverValues { + return serverValues[op]; +} + ++ (id)resolveComplexServerOp:(NSDictionary *)op + withValueProvider:(id)jitExisting + serverValues:(NSDictionary *)serverValues { + // Only increment is supported as of now + if (op[kIncrement] == nil) { + return nil; + } + + // Incrementing a non-number sets the value to the incremented amount + NSNumber *delta = op[kIncrement]; + id existing = jitExisting.value; + if (![existing isLeafNode]) { + return delta; + } + FLeafNode *existingLeaf = existing; + if (![existingLeaf.value isKindOfClass:NSNumber.class]) { + return delta; + } + + NSNumber *existingNum = existingLeaf.value; + BOOL incrLong = canBeRepresentedAsLong(delta); + BOOL baseLong = canBeRepresentedAsLong(existingNum); + + if (incrLong && baseLong) { + long x = delta.longValue; + long y = existingNum.longValue; + long r = x + y; + + // See "Hacker's Delight" 2-12: Overflow if both arguments have the + // opposite sign of the result + if (((x ^ r) & (y ^ r)) >= 0) { + return @(r); + } + } + return @(delta.doubleValue + existingNum.doubleValue); +} + ++ (FCompoundWrite *)resolveDeferredValueCompoundWrite:(FCompoundWrite *)write + withSyncTree:(FSyncTree *)tree + atPath:(FPath *)path + serverValues: + (NSDictionary *)serverValues { + __block FCompoundWrite *resolved = write; + [write enumerateWrites:^(FPath *subPath, id node, BOOL *stop) { + id existing = + [[DeferredValueProvider alloc] initWithSyncTree:tree + atPath:[path child:subPath]]; + id resolvedNode = + [FServerValues resolveDeferredValueSnapshot:node + withValueProvider:existing + serverValues:serverValues]; + // Node actually changed, use pointer inequality here + if (resolvedNode != node) { + resolved = [resolved addWrite:resolvedNode atPath:subPath]; + } + }]; + return resolved; +} + ++ (id)resolveDeferredValueSnapshot:(id)node + withSyncTree:(FSyncTree *)tree + atPath:(FPath *)path + serverValues:(NSDictionary *)serverValues { + id jitExisting = + [[DeferredValueProvider alloc] initWithSyncTree:tree atPath:path]; + return [FServerValues resolveDeferredValueSnapshot:node + withValueProvider:jitExisting + serverValues:serverValues]; +} + ++ (id)resolveDeferredValueSnapshot:(id)node + withExisting:(id)existing + serverValues:(NSDictionary *)serverValues { + id jitExisting = + [[ExistingValueProvider alloc] initWithSnapshot:existing]; + return [FServerValues resolveDeferredValueSnapshot:node + withValueProvider:jitExisting + serverValues:serverValues]; +} + ++ (id)resolveDeferredValueSnapshot:(id)node + withValueProvider:(id)existing + serverValues:(NSDictionary *)serverValues { + id priorityVal = + [FServerValues resolveDeferredValue:[[node getPriority] val] + withExisting:[existing getChild:@".priority"] + serverValues:serverValues]; + id priority = [FSnapshotUtilities nodeFrom:priorityVal]; + + if ([node isLeafNode]) { + id value = [self resolveDeferredValue:[node val] + withExisting:existing + serverValues:serverValues]; + if (![value isEqual:[node val]] || + ![priority isEqual:[node getPriority]]) { + return [[FLeafNode alloc] initWithValue:value + withPriority:priority]; + } else { + return node; + } + } else { + __block FChildrenNode *newNode = node; + if (![priority isEqual:[node getPriority]]) { + newNode = [newNode updatePriority:priority]; + } + + [node enumerateChildrenUsingBlock:^(NSString *childKey, + id childNode, BOOL *stop) { + id newChildNode = [FServerValues + resolveDeferredValueSnapshot:childNode + withValueProvider:[existing getChild:childKey] + serverValues:serverValues]; + if (![newChildNode isEqual:childNode]) { + newNode = [newNode updateImmediateChild:childKey + withNewChild:newChildNode]; + } + }]; + return newNode; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.h new file mode 100644 index 0000000..34214ab --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FSnapshotHolder : NSObject + +- (id)getNode:(FPath *)path; +- (void)updateSnapshot:(FPath *)path withNewSnapshot:(id)newSnapshotNode; + +@property(nonatomic, strong) id rootNode; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.m new file mode 100644 index 0000000..491ccae --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.m @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseDatabase/Sources/Core/FSnapshotHolder.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" + +@interface FSnapshotHolder () + +@end + +@implementation FSnapshotHolder + +@synthesize rootNode; + +- (id)init { + self = [super init]; + if (self) { + self.rootNode = [FEmptyNode emptyNode]; + } + return self; +} + +- (id)getNode:(FPath *)path { + return [self.rootNode getChild:path]; +} + +- (void)updateSnapshot:(FPath *)path + withNewSnapshot:(id)newSnapshotNode { + self.rootNode = [self.rootNode updateChild:path + withNewChild:newSnapshotNode]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h new file mode 100644 index 0000000..8ea9293 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h @@ -0,0 +1,34 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@class FSparseSnapshotTree; + +typedef void (^fbt_void_nsstring_sstree)(NSString *, FSparseSnapshotTree *); + +@interface FSparseSnapshotTree : NSObject + +- (id)findPath:(FPath *)path; +- (void)rememberData:(id)data onPath:(FPath *)path; +- (BOOL)forgetPath:(FPath *)path; +- (void)forEachTreeAtPath:(FPath *)prefixPath do:(fbt_void_path_node)func; +- (void)forEachChild:(fbt_void_nsstring_sstree)func; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.m new file mode 100644 index 0000000..1b16d51 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.m @@ -0,0 +1,144 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" + +@interface FSparseSnapshotTree () { + id value; + NSMutableDictionary *children; +} + +@end + +@implementation FSparseSnapshotTree + +- (id)init { + self = [super init]; + if (self) { + value = nil; + children = nil; + } + return self; +} + +- (id)findPath:(FPath *)path { + if (value != nil) { + return [value getChild:path]; + } else if (![path isEmpty] && children != nil) { + NSString *childKey = [path getFront]; + path = [path popFront]; + FSparseSnapshotTree *childTree = children[childKey]; + if (childTree != nil) { + return [childTree findPath:path]; + } else { + return nil; + } + } else { + return nil; + } +} + +- (void)rememberData:(id)data onPath:(FPath *)path { + if ([path isEmpty]) { + value = data; + children = nil; + } else if (value != nil) { + value = [value updateChild:path withNewChild:data]; + } else { + if (children == nil) { + children = [[NSMutableDictionary alloc] init]; + } + + NSString *childKey = [path getFront]; + if (children[childKey] == nil) { + children[childKey] = [[FSparseSnapshotTree alloc] init]; + } + + FSparseSnapshotTree *child = children[childKey]; + path = [path popFront]; + [child rememberData:data onPath:path]; + } +} + +- (BOOL)forgetPath:(FPath *)path { + if ([path isEmpty]) { + value = nil; + children = nil; + return YES; + } else { + if (value != nil) { + if ([value isLeafNode]) { + // non-empty path at leaf. the path leads to nowhere + return NO; + } else { + id tmp = value; + value = nil; + + [tmp enumerateChildrenUsingBlock:^(NSString *key, + id node, BOOL *stop) { + [self rememberData:node onPath:[[FPath alloc] initWith:key]]; + }]; + + // we've cleared out the value and set children. Call ourself + // again to hit the next case + return [self forgetPath:path]; + } + } else if (children != nil) { + NSString *childKey = [path getFront]; + path = [path popFront]; + + if (children[childKey] != nil) { + FSparseSnapshotTree *child = children[childKey]; + BOOL safeToRemove = [child forgetPath:path]; + if (safeToRemove) { + [children removeObjectForKey:childKey]; + } + } + + if ([children count] == 0) { + children = nil; + return YES; + } else { + return NO; + } + } else { + return YES; + } + } +} + +- (void)forEachTreeAtPath:(FPath *)prefixPath do:(fbt_void_path_node)func { + if (value != nil) { + func(prefixPath, value); + } else { + [self forEachChild:^(NSString *key, FSparseSnapshotTree *tree) { + FPath *path = [prefixPath childFromString:key]; + [tree forEachTreeAtPath:path do:func]; + }]; + } +} + +- (void)forEachChild:(fbt_void_nsstring_sstree)func { + if (children != nil) { + for (NSString *key in children) { + FSparseSnapshotTree *tree = [children objectForKey:key]; + func(key, tree); + } + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.h new file mode 100644 index 0000000..f8f19c1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.h @@ -0,0 +1,74 @@ +/* + * 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 + +@protocol FOperation; +@class FWriteTreeRef; +@protocol FNode; +@protocol FEventRegistration; +@class FQuerySpec; +@class FChildrenNode; +@class FTupleRemovedQueriesEvents; +@class FView; +@class FPath; +@class FCacheNode; +@class FPersistenceManager; + +@interface FSyncPoint : NSObject + +- (id)initWithPersistenceManager:(FPersistenceManager *)persistence; + +- (BOOL)isEmpty; + +/** + * Returns array of FEvent + */ +- (NSArray *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache; + +- (FView *)getView:(FQuerySpec *)query + writesCache:(FWriteTreeRef *)writesCache + serverCache:(FCacheNode *)serverCache; + +/** + * Returns array of FEvent + */ +- (NSArray *)addEventRegistration:(id)eventRegistration + forNonExistingViewForQuery:(FQuerySpec *)query + writesCache:(FWriteTreeRef *)writesCache + serverCache:(FCacheNode *)serverCache; + +- (NSArray *)addEventRegistration:(id)eventRegistration + forExistingViewForQuery:(FQuerySpec *)query; + +- (FTupleRemovedQueriesEvents *)removeEventRegistration: + (id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError; +/** + * Returns array of FViews + */ +- (NSArray *)queryViews; +- (id)completeServerCacheAtPath:(FPath *)path; +- (id)completeEventCacheAtPath:(FPath *)path; +- (FView *)viewForQuery:(FQuerySpec *)query; +- (BOOL)viewExistsForQuery:(FQuerySpec *)query; +- (BOOL)hasCompleteView; +- (FView *)completeView; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.m new file mode 100644 index 0000000..31d32a6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.m @@ -0,0 +1,325 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FSyncPoint.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperation.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Core/View/FDataEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FView.h" +#import "FirebaseDatabase/Sources/Core/View/FViewCache.h" +#import "FirebaseDatabase/Sources/Persistence/FPersistenceManager.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h" + +/** + * SyncPoint represents a single location in a SyncTree with 1 or more event + * registrations, meaning we need to maintain 1 or more Views at this location + * to cache server data and raise appropriate events for server changes and user + * writes (set, transaction, update). + * + * It's responsible for: + * - Maintaining the set of 1 or more views necessary at this location (a + * SyncPoint with 0 views should be removed). + * - Proxying user / server operations to the views as appropriate (i.e. + * applyServerOverwrite, applyUserOverwrite, etc.) + */ +@interface FSyncPoint () +/** + * The Views being tracked at this location in the tree, stored as a map where + * the key is a queryParams and the value is the View for that query. + * + * NOTE: This list will be quite small (usually 1, but perhaps 2 or 3; any more + * is an odd use case). + * + * Maps NSString -> FView + */ +@property(nonatomic, strong) NSMutableDictionary *views; + +@property(nonatomic, strong) FPersistenceManager *persistenceManager; +@end + +@implementation FSyncPoint + +- (id)initWithPersistenceManager:(FPersistenceManager *)persistence { + self = [super init]; + if (self) { + self.persistenceManager = persistence; + self.views = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (BOOL)isEmpty { + return [self.views count] == 0; +} + +- (NSArray *)applyOperation:(id)operation + toView:(FView *)view + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache { + FViewOperationResult *result = [view applyOperation:operation + writesCache:writesCache + serverCache:optCompleteServerCache]; + if (!view.query.loadsAllData) { + NSMutableSet *removed = [NSMutableSet set]; + NSMutableSet *added = [NSMutableSet set]; + [result.changes enumerateObjectsUsingBlock:^( + FChange *change, NSUInteger idx, BOOL *stop) { + if (change.type == FIRDataEventTypeChildAdded) { + [added addObject:change.childKey]; + } else if (change.type == FIRDataEventTypeChildRemoved) { + [removed addObject:change.childKey]; + } + }]; + if ([removed count] > 0 || [added count] > 0) { + [self.persistenceManager + updateTrackedQueryKeysWithAddedKeys:added + removedKeys:removed + forQuery:view.query]; + } + } + return result.events; +} + +- (NSArray *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache { + FQueryParams *queryParams = operation.source.queryParams; + if (queryParams != nil) { + FView *view = [self.views objectForKey:queryParams]; + NSAssert(view != nil, @"SyncTree gave us an op for an invalid query."); + return [self applyOperation:operation + toView:view + writesCache:writesCache + serverCache:optCompleteServerCache]; + } else { + NSMutableArray *events = [[NSMutableArray alloc] init]; + [self.views enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *key, FView *view, BOOL *stop) { + NSArray *eventsForView = [self applyOperation:operation + toView:view + writesCache:writesCache + serverCache:optCompleteServerCache]; + [events addObjectsFromArray:eventsForView]; + }]; + return events; + } +} + +- (FView *)getView:(FQuerySpec *)query + writesCache:(FWriteTreeRef *)writesCache + serverCache:(FCacheNode *)serverCache { + FView *view = self.views[query.params]; + if (view != nil) { + return view; + } + id eventCache = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + serverCache.isFullyInitialized ? serverCache.node : nil]; + BOOL eventCacheComplete; + if (eventCache != nil) { + eventCacheComplete = YES; + } else { + eventCache = [writesCache + calculateCompleteEventChildrenWithCompleteServerChildren: + serverCache.node != nil ? serverCache.node + : [FEmptyNode emptyNode]]; + eventCacheComplete = NO; + } + + FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:eventCache + index:query.index]; + FCacheNode *eventCacheNode = + [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:eventCacheComplete + isFiltered:NO]; + FViewCache *viewCache = + [[FViewCache alloc] initWithEventCache:eventCacheNode + serverCache:serverCache]; + return [[FView alloc] initWithQuery:query initialViewCache:viewCache]; +} + +/** + * Add an event callback for the specified query + * Returns an array of events to raise. + */ +- (NSArray *)addEventRegistration:(id)eventRegistration + forNonExistingViewForQuery:(FQuerySpec *)query + writesCache:(FWriteTreeRef *)writesCache + serverCache:(FCacheNode *)serverCache { + NSAssert(self.views[query.params] == nil, @"Found view for query: %@", + query.params); + // TODO: make writesCache take flag for complete server node + FView *view = [self getView:query + writesCache:writesCache + serverCache:serverCache]; + + // If this is a non-default query we need to tell persistence our current + // view of the data + if (!query.loadsAllData) { + NSMutableSet *allKeys = [NSMutableSet set]; + [view.eventCache enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + [allKeys addObject:key]; + }]; + [self.persistenceManager setTrackedQueryKeys:allKeys forQuery:query]; + } + self.views[query.params] = view; + return [self addEventRegistration:eventRegistration + forExistingViewForQuery:query]; +} + +- (NSArray *)addEventRegistration:(id)eventRegistration + forExistingViewForQuery:(FQuerySpec *)query { + FView *view = self.views[query.params]; + NSAssert(view != nil, @"No view for query: %@", query); + [view addEventRegistration:eventRegistration]; + return [view initialEvents:eventRegistration]; +} + +/** + * Remove event callback(s). Return cancelEvents if a cancelError is specified. + * + * If query is the default query, we'll check all views for the specified + * eventRegistration. If eventRegistration is nil, we'll remove all callbacks + * for the specified view(s). + * + * @return FTupleRemovedQueriesEvents removed queries and any cancel events + */ +- (FTupleRemovedQueriesEvents *)removeEventRegistration: + (id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError { + NSMutableArray *removedQueries = [[NSMutableArray alloc] init]; + __block NSMutableArray *cancelEvents = [[NSMutableArray alloc] init]; + BOOL hadCompleteView = [self hasCompleteView]; + if ([query isDefault]) { + // When you do [ref removeObserverWithHandle:], we search all views for + // the registration to remove. + [self.views enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *viewQueryParams, FView *view, + BOOL *stop) { + [cancelEvents + addObjectsFromArray:[view + removeEventRegistration:eventRegistration + cancelError:cancelError]]; + if ([view isEmpty]) { + [self.views removeObjectForKey:viewQueryParams]; + + // We'll deal with complete views later + if (![view.query loadsAllData]) { + [removedQueries addObject:view.query]; + } + } + }]; + } else { + // remove the callback from the specific view + FView *view = [self.views objectForKey:query.params]; + if (view != nil) { + [cancelEvents addObjectsFromArray: + [view removeEventRegistration:eventRegistration + cancelError:cancelError]]; + + if ([view isEmpty]) { + [self.views removeObjectForKey:query.params]; + + // We'll deal with complete views later + if (![view.query loadsAllData]) { + [removedQueries addObject:view.query]; + } + } + } + } + + if (hadCompleteView && ![self hasCompleteView]) { + // We removed our last complete view + [removedQueries addObject:[FQuerySpec defaultQueryAtPath:query.path]]; + } + + return [[FTupleRemovedQueriesEvents alloc] + initWithRemovedQueries:removedQueries + cancelEvents:cancelEvents]; +} + +- (NSArray *)queryViews { + __block NSMutableArray *filteredViews = [[NSMutableArray alloc] init]; + + [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, + FView *view, BOOL *stop) { + if (![view.query loadsAllData]) { + [filteredViews addObject:view]; + } + }]; + + return filteredViews; +} + +- (id)completeServerCacheAtPath:(FPath *)path { + __block id serverCache = nil; + [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, + FView *view, BOOL *stop) { + serverCache = [view completeServerCacheFor:path]; + *stop = (serverCache != nil); + }]; + return serverCache; +} + +- (id)completeEventCacheAtPath:(FPath *)path { + __block id eventCache = nil; + [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, + FView *view, BOOL *stop) { + eventCache = [view completeEventCacheFor:path]; + *stop = (eventCache != nil); + }]; + return eventCache; +} + +- (FView *)viewForQuery:(FQuerySpec *)query { + return [self.views objectForKey:query.params]; +} + +- (BOOL)viewExistsForQuery:(FQuerySpec *)query { + return [self viewForQuery:query] != nil; +} + +- (BOOL)hasCompleteView { + return [self completeView] != nil; +} + +- (FView *)completeView { + __block FView *completeView = nil; + + [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, + FView *view, BOOL *stop) { + if ([view.query loadsAllData]) { + completeView = view; + *stop = YES; + } + }]; + + return completeView; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.h new file mode 100644 index 0000000..62ccf4d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.h @@ -0,0 +1,85 @@ +/* + * 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 + +@class FIndexedNode; +@class FListenProvider; +@protocol FNode; +@class FPath; +@protocol FEventRegistration; +@protocol FPersistedServerCache; +@class FQuerySpec; +@class FCompoundWrite; +@class FPersistenceManager; +@class FCompoundHash; +@protocol FClock; + +@protocol FSyncTreeHash + +- (NSString *)simpleHash; +- (FCompoundHash *)compoundHash; +- (BOOL)includeCompoundHash; + +@end + +@interface FSyncTree : NSObject + +- (id)initWithListenProvider:(FListenProvider *)provider; +- (id)initWithPersistenceManager:(FPersistenceManager *)persistenceManager + listenProvider:(FListenProvider *)provider; + +// These methods all return NSArray of FEvent +- (NSArray *)applyUserOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible; +- (NSArray *)applyUserMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId; +- (NSArray *)ackUserWriteWithWriteId:(NSInteger)writeId + revert:(BOOL)revert + persist:(BOOL)persist + clock:(id)clock; +- (NSArray *)applyServerOverwriteAtPath:(FPath *)path + newData:(id)newData; +- (NSArray *)applyServerMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren; +- (NSArray *)applyServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges; +- (NSArray *)applyTaggedQueryOverwriteAtPath:(FPath *)path + newData:(id)newData + tagId:(NSNumber *)tagId; +- (NSArray *)applyTaggedQueryMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + tagId:(NSNumber *)tagId; +- (NSArray *)applyTaggedServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges + tagId:(NSNumber *)tagId; +- (NSArray *)addEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query; +- (NSArray *)removeEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError; +- (void)keepQuery:(FQuerySpec *)query synced:(BOOL)keepSynced; +- (NSArray *)removeAllWrites; + +- (FIndexedNode *)persistenceServerCache:(FQuerySpec *)querySpec; +- (id)getServerValue:(FQuerySpec *)query; +- (id)calcCompleteEventCacheAtPath:(FPath *)path + excludeWriteIds:(NSArray *)writeIdsToExclude; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.m new file mode 100644 index 0000000..864e96e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.m @@ -0,0 +1,1093 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FSyncTree.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Core/FCompoundHash.h" +#import "FirebaseDatabase/Sources/Core/FListenProvider.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FRangeMerge.h" +#import "FirebaseDatabase/Sources/Core/FServerValues.h" +#import "FirebaseDatabase/Sources/Core/FSnapshotHolder.h" +#import "FirebaseDatabase/Sources/Core/FSyncPoint.h" +#import "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Core/FWriteTree.h" +#import "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h" +#import "FirebaseDatabase/Sources/Core/Operation/FMerge.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperation.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOverwrite.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRaiser.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FView.h" +#import "FirebaseDatabase/Sources/FListenComplete.h" +#import "FirebaseDatabase/Sources/Persistence/FPersistenceManager.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h" + +// Size after which we start including the compound hash +static const NSUInteger kFSizeThresholdForCompoundHash = 1024; + +@interface FListenContainer : NSObject + +@property(nonatomic, strong) FView *view; +@property(nonatomic, copy) fbt_nsarray_nsstring onComplete; + +@end + +@implementation FListenContainer + +- (instancetype)initWithView:(FView *)view + onComplete:(fbt_nsarray_nsstring)onComplete { + self = [super init]; + if (self != nil) { + self->_view = view; + self->_onComplete = onComplete; + } + return self; +} + +- (id)serverCache { + return self.view.serverCache; +} + +- (FCompoundHash *)compoundHash { + return [FCompoundHash fromNode:[self serverCache]]; +} + +- (NSString *)simpleHash { + return [[self serverCache] dataHash]; +} + +- (BOOL)includeCompoundHash { + return [FSnapshotUtilities estimateSerializedNodeSize:[self serverCache]] > + kFSizeThresholdForCompoundHash; +} + +@end + +@interface FSyncTree () + +/** + * Tree of SyncPoints. There's a SyncPoint at any location that has 1 or more + * views. + */ +@property(nonatomic, strong) FImmutableTree *syncPointTree; + +/** + * A tree of all pending user writes (user-initiated set, transactions, updates, + * etc) + */ +@property(nonatomic, strong) FWriteTree *pendingWriteTree; + +/** + * Maps tagId -> FTuplePathQueryParams + */ +@property(nonatomic, strong) NSMutableDictionary *tagToQueryMap; +@property(nonatomic, strong) NSMutableDictionary *queryToTagMap; +@property(nonatomic, strong) FListenProvider *listenProvider; +@property(nonatomic, strong) FPersistenceManager *persistenceManager; +@property(nonatomic, strong) FAtomicNumber *queryTagCounter; +@property(nonatomic, strong) NSMutableSet *keepSyncedQueries; + +@end + +/** + * SyncTree is the central class for managing event callback registration, data + * caching, views (query processing), and event generation. There are typically + * two SyncTree instances for each Repo, one for the normal Firebase data, and + * one for the .info data. + * + * It has a number of responsibilities, including: + * - Tracking all user event callbacks (registered via addEventRegistration: + * and removeEventRegistration:). + * - Applying and caching data changes for user setValue:, + * runTransactionBlock:, and updateChildValues: calls + * (applyUserOverwriteAtPath:, applyUserMergeAtPath:). + * - Applying and caching data changes for server data changes + * (applyServerOverwriteAtPath:, applyServerMergeAtPath:). + * - Generating user-facing events for server and user changes (all of the + * apply* methods return the set of events that need to be raised as a result). + * - Maintaining the appropriate set of server listens to ensure we are always + * subscribed to the correct set of paths and queries to satisfy the current set + * of user event callbacks (listens are started/stopped using the provided + * listenProvider). + * + * NOTE: Although SyncTree tracks event callbacks and calculates events to + * raise, the actual events are returned to the caller rather than raised + * synchronously. + */ +@implementation FSyncTree + +- (id)initWithListenProvider:(FListenProvider *)provider { + return [self initWithPersistenceManager:nil listenProvider:provider]; +} + +- (id)initWithPersistenceManager:(FPersistenceManager *)persistenceManager + listenProvider:(FListenProvider *)provider { + self = [super init]; + if (self) { + self.syncPointTree = [FImmutableTree empty]; + self.pendingWriteTree = [[FWriteTree alloc] init]; + self.tagToQueryMap = [[NSMutableDictionary alloc] init]; + self.queryToTagMap = [[NSMutableDictionary alloc] init]; + self.listenProvider = provider; + self.persistenceManager = persistenceManager; + self.queryTagCounter = [[FAtomicNumber alloc] init]; + self.keepSyncedQueries = [NSMutableSet set]; + } + return self; +} + +#pragma mark - +#pragma mark Apply Operations + +/** + * Apply data changes for a user-generated setValue: runTransactionBlock: + * updateChildValues:, etc. + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyUserOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible { + // Record pending write + [self.pendingWriteTree addOverwriteAtPath:path + newData:newData + writeId:writeId + isVisible:visible]; + if (!visible) { + return @[]; + } else { + FOverwrite *operation = + [[FOverwrite alloc] initWithSource:[FOperationSource userInstance] + path:path + snap:newData]; + return [self applyOperationToSyncPoints:operation]; + } +} + +/** + * Apply the data from a user-generated updateChildValues: call + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyUserMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId { + // Record pending merge + [self.pendingWriteTree addMergeAtPath:path + changedChildren:changedChildren + writeId:writeId]; + + FMerge *operation = + [[FMerge alloc] initWithSource:[FOperationSource userInstance] + path:path + children:changedChildren]; + return [self applyOperationToSyncPoints:operation]; +} + +/** + * Acknowledge a pending user write that was previously registered with + * applyUserOverwriteAtPath: or applyUserMergeAtPath: + * TODO[offline]: Taking a serverClock here is awkward, but server values are + * awkward. :-( + * @return NSArray of FEvent to raise. + */ +- (NSArray *)ackUserWriteWithWriteId:(NSInteger)writeId + revert:(BOOL)revert + persist:(BOOL)persist + clock:(id)clock { + FWriteRecord *write = [self.pendingWriteTree writeForId:writeId]; + BOOL needToReevaluate = [self.pendingWriteTree removeWriteId:writeId]; + if (write.visible) { + if (persist) { + [self.persistenceManager removeUserWrite:writeId]; + } + if (!revert) { + NSDictionary *serverValues = + [FServerValues generateServerValues:clock]; + if ([write isOverwrite]) { + id resolvedNode = + [FServerValues resolveDeferredValueSnapshot:write.overwrite + withSyncTree:self + atPath:write.path + serverValues:serverValues]; + [self.persistenceManager applyUserWrite:resolvedNode + toServerCacheAtPath:write.path]; + } else { + FCompoundWrite *resolvedMerge = [FServerValues + resolveDeferredValueCompoundWrite:write.merge + withSyncTree:self + atPath:write.path + serverValues:serverValues]; + [self.persistenceManager applyUserMerge:resolvedMerge + toServerCacheAtPath:write.path]; + } + } + } + if (!needToReevaluate) { + return @[]; + } else { + __block FImmutableTree *affectedTree = [FImmutableTree empty]; + if (write.isOverwrite) { + affectedTree = [affectedTree setValue:@YES atPath:[FPath empty]]; + } else { + [write.merge + enumerateWrites:^(FPath *path, id node, BOOL *stop) { + affectedTree = [affectedTree setValue:@YES atPath:path]; + }]; + } + FAckUserWrite *operation = + [[FAckUserWrite alloc] initWithPath:write.path + affectedTree:affectedTree + revert:revert]; + return [self applyOperationToSyncPoints:operation]; + } +} + +/** + * Apply new server data for the specified path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyServerOverwriteAtPath:(FPath *)path + newData:(id)newData { + [self.persistenceManager + updateServerCacheWithNode:newData + forQuery:[FQuerySpec defaultQueryAtPath:path]]; + FOverwrite *operation = + [[FOverwrite alloc] initWithSource:[FOperationSource serverInstance] + path:path + snap:newData]; + return [self applyOperationToSyncPoints:operation]; +} + +/** + * Applied new server data to be merged in at the specified path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyServerMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren { + [self.persistenceManager updateServerCacheWithMerge:changedChildren + atPath:path]; + FMerge *operation = + [[FMerge alloc] initWithSource:[FOperationSource serverInstance] + path:path + children:changedChildren]; + return [self applyOperationToSyncPoints:operation]; +} + +- (NSArray *)applyServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges { + FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; + if (syncPoint == nil) { + // Removed view, so it's safe to just ignore this update + return @[]; + } else { + // This could be for any "complete" (unfiltered) view, and if there is + // more than one complete view, they should each have the same cache so + // it doesn't matter which one we use. + FView *view = [syncPoint completeView]; + if (view != nil) { + id serverNode = [view serverCache]; + for (FRangeMerge *merge in ranges) { + serverNode = [merge applyToNode:serverNode]; + } + return [self applyServerOverwriteAtPath:path newData:serverNode]; + } else { + // There doesn't exist a view for this update, so it was removed and + // it's safe to just ignore this range merge + return @[]; + } + } +} + +/** + * Apply a listen complete to a path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyListenCompleteAtPath:(FPath *)path { + [self.persistenceManager + setQueryComplete:[FQuerySpec defaultQueryAtPath:path]]; + id operation = [[FListenComplete alloc] + initWithSource:[FOperationSource serverInstance] + path:path]; + return [self applyOperationToSyncPoints:operation]; +} + +/** + * Apply a listen complete to a path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyTaggedListenCompleteAtPath:(FPath *)path + tagId:(NSNumber *)tagId { + FQuerySpec *query = [self queryForTag:tagId]; + if (query != nil) { + [self.persistenceManager setQueryComplete:query]; + FPath *relativePath = [FPath relativePathFrom:query.path to:path]; + id op = [[FListenComplete alloc] + initWithSource:[FOperationSource forServerTaggedQuery:query.params] + path:relativePath]; + return [self applyTaggedOperation:op atPath:query.path]; + } else { + // We've already removed the query. No big deal, ignore the update. + return @[]; + } +} + +/** + * Internal helper method to apply tagged operation + */ +- (NSArray *)applyTaggedOperation:(id)operation + atPath:(FPath *)path { + FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; + NSAssert(syncPoint != nil, + @"Missing sync point for query tag that we're tracking."); + FWriteTreeRef *writesCache = + [self.pendingWriteTree childWritesForPath:path]; + return [syncPoint applyOperation:operation + writesCache:writesCache + serverCache:nil]; +} + +/** + * Apply new server data for the specified tagged query + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyTaggedQueryOverwriteAtPath:(FPath *)path + newData:(id)newData + tagId:(NSNumber *)tagId { + FQuerySpec *query = [self queryForTag:tagId]; + if (query != nil) { + FPath *relativePath = [FPath relativePathFrom:query.path to:path]; + FQuerySpec *queryToOverwrite = + relativePath.isEmpty ? query : [FQuerySpec defaultQueryAtPath:path]; + [self.persistenceManager updateServerCacheWithNode:newData + forQuery:queryToOverwrite]; + FOverwrite *operation = [[FOverwrite alloc] + initWithSource:[FOperationSource forServerTaggedQuery:query.params] + path:relativePath + snap:newData]; + return [self applyTaggedOperation:operation atPath:query.path]; + } else { + // Query must have been removed already + return @[]; + } +} + +/** + * Apply server data to be merged in for the specified tagged query + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyTaggedQueryMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + tagId:(NSNumber *)tagId { + FQuerySpec *query = [self queryForTag:tagId]; + if (query != nil) { + FPath *relativePath = [FPath relativePathFrom:query.path to:path]; + [self.persistenceManager updateServerCacheWithMerge:changedChildren + atPath:path]; + FMerge *operation = [[FMerge alloc] + initWithSource:[FOperationSource forServerTaggedQuery:query.params] + path:relativePath + children:changedChildren]; + return [self applyTaggedOperation:operation atPath:query.path]; + } else { + // We've already removed the query. No big deal, ignore the update. + return @[]; + } +} + +- (NSArray *)applyTaggedServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges + tagId:(NSNumber *)tagId { + FQuerySpec *query = [self queryForTag:tagId]; + if (query != nil) { + NSAssert([path isEqual:query.path], + @"Tagged update path and query path must match"); + FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; + NSAssert(syncPoint != nil, + @"Missing sync point for query tag that we're tracking."); + FView *view = [syncPoint viewForQuery:query]; + NSAssert(view != nil, + @"Missing view for query tag that we're tracking"); + id serverNode = [view serverCache]; + for (FRangeMerge *merge in ranges) { + serverNode = [merge applyToNode:serverNode]; + } + return [self applyTaggedQueryOverwriteAtPath:path + newData:serverNode + tagId:tagId]; + } else { + // We've already removed the query. No big deal, ignore the update. + return @[]; + } +} + +/** + * Add an event callback for the specified query + * @return NSArray of FEvent to raise. + */ +- (NSArray *)addEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query { + FPath *path = query.path; + + __block BOOL foundAncestorDefaultView = NO; + [self.syncPointTree + forEachOnPath:query.path + whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) { + foundAncestorDefaultView = + foundAncestorDefaultView || [syncPoint hasCompleteView]; + return !foundAncestorDefaultView; + }]; + + [self.persistenceManager setQueryActive:query]; + + FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; + if (syncPoint == nil) { + syncPoint = [[FSyncPoint alloc] + initWithPersistenceManager:self.persistenceManager]; + self.syncPointTree = [self.syncPointTree setValue:syncPoint + atPath:path]; + } + + BOOL viewAlreadyExists = [syncPoint viewExistsForQuery:query]; + NSArray *events; + if (viewAlreadyExists) { + events = [syncPoint addEventRegistration:eventRegistration + forExistingViewForQuery:query]; + } else { + if (![query loadsAllData]) { + // We need to track a tag for this query + NSAssert(self.queryToTagMap[query] == nil, + @"View does not exist, but we have a tag"); + NSNumber *tagId = [self.queryTagCounter getAndIncrement]; + self.queryToTagMap[query] = tagId; + self.tagToQueryMap[tagId] = query; + } + + FWriteTreeRef *writesCache = + [self.pendingWriteTree childWritesForPath:path]; + FCacheNode *serverCache = [self serverCacheForQuery:query]; + events = [syncPoint addEventRegistration:eventRegistration + forNonExistingViewForQuery:query + writesCache:writesCache + serverCache:serverCache]; + + // There was no view and no default listen + if (!foundAncestorDefaultView) { + FView *view = [syncPoint viewForQuery:query]; + NSMutableArray *mutableEvents = [events mutableCopy]; + [mutableEvents + addObjectsFromArray:[self setupListenerOnQuery:query + view:view]]; + events = mutableEvents; + } + } + + return events; +} + +- (FCacheNode *)serverCacheForQuery:(FQuerySpec *)query { + __block id serverCacheNode = nil; + + [self.syncPointTree + forEachOnPath:query.path + whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) { + FPath *relativePath = [FPath relativePathFrom:pathToSyncPoint + to:query.path]; + serverCacheNode = + [syncPoint completeServerCacheAtPath:relativePath]; + return serverCacheNode == nil; + }]; + + FCacheNode *serverCache; + if (serverCacheNode != nil) { + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:serverCacheNode + index:query.index]; + serverCache = [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:YES + isFiltered:NO]; + } else { + FCacheNode *persistenceServerCache = + [self.persistenceManager serverCacheForQuery:query]; + if (persistenceServerCache.isFullyInitialized) { + serverCache = persistenceServerCache; + } else { + serverCacheNode = [FEmptyNode emptyNode]; + + FImmutableTree *subtree = + [self.syncPointTree subtreeAtPath:query.path]; + [subtree + forEachChild:^(NSString *childKey, FSyncPoint *childSyncPoint) { + id completeCache = + [childSyncPoint completeServerCacheAtPath:[FPath empty]]; + if (completeCache) { + serverCacheNode = + [serverCacheNode updateImmediateChild:childKey + withNewChild:completeCache]; + } + }]; + // Fill the node with any available children we have + [persistenceServerCache.node + enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + if (![serverCacheNode hasChild:key]) { + serverCacheNode = + [serverCacheNode updateImmediateChild:key + withNewChild:node]; + } + }]; + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:serverCacheNode + index:query.index]; + serverCache = [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:NO + isFiltered:NO]; + } + } + + return serverCache; +} + +/** + * Remove event callback(s). + * + * If query is the default query, we'll check all queries for the specified + * eventRegistration. If eventRegistration is null, we'll remove all callbacks + * for the specified query/queries. + * + * @param eventRegistration if nil, all callbacks are removed + * @param cancelError If provided, appropriate cancel events will be returned + * @return NSArray of FEvent to raise. + */ +- (NSArray *)removeEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError { + // Find the syncPoint first. Then deal with whether or not it has matching + // listeners + FPath *path = query.path; + FSyncPoint *maybeSyncPoint = [self.syncPointTree valueAtPath:path]; + NSArray *cancelEvents = @[]; + + // A removal on a default query affects all queries at that location. A + // removal on an indexed query, even one without other query constraints, + // does *not* affect all queries at that location. So this check must be for + // 'default', and not loadsAllData: + if (maybeSyncPoint && + ([query isDefault] || [maybeSyncPoint viewExistsForQuery:query])) { + FTupleRemovedQueriesEvents *removedAndEvents = + [maybeSyncPoint removeEventRegistration:eventRegistration + forQuery:query + cancelError:cancelError]; + if ([maybeSyncPoint isEmpty]) { + self.syncPointTree = [self.syncPointTree removeValueAtPath:path]; + } + NSArray *removed = removedAndEvents.removedQueries; + cancelEvents = removedAndEvents.cancelEvents; + + // We may have just removed one of many listeners and can short-circuit + // this whole process We may also not have removed a default listener, + // in which case all of the descendant listeners should already be + // properly set up. + // + // Since indexed queries can shadow if they don't have other query + // constraints, check for loadsAllData: instead of isDefault: + NSUInteger defaultQueryIndex = [removed + indexOfObjectPassingTest:^BOOL(FQuerySpec *q, NSUInteger idx, + BOOL *stop) { + return [q loadsAllData]; + }]; + BOOL removingDefault = defaultQueryIndex != NSNotFound; + [removed enumerateObjectsUsingBlock:^(FQuerySpec *query, NSUInteger idx, + BOOL *stop) { + [self.persistenceManager setQueryInactive:query]; + }]; + NSNumber *covered = [self.syncPointTree + findOnPath:path + andApplyBlock:^id(FPath *relativePath, + FSyncPoint *parentSyncPoint) { + return + [NSNumber numberWithBool:[parentSyncPoint hasCompleteView]]; + }]; + + if (removingDefault && ![covered boolValue]) { + FImmutableTree *subtree = [self.syncPointTree subtreeAtPath:path]; + // There are potentially child listeners. Determine what if any + // listens we need to send before executing the removal + if (![subtree isEmpty]) { + // We need to fold over our subtree and collect the listeners to + // send + NSArray *newViews = + [self collectDistinctViewsForSubTree:subtree]; + + // Ok, we've collected all the listens we need. Set them up. + [newViews enumerateObjectsUsingBlock:^( + FView *view, NSUInteger idx, BOOL *stop) { + FQuerySpec *newQuery = view.query; + FListenContainer *listenContainer = + [self createListenerForView:view]; + self.listenProvider.startListening( + [self queryForListening:newQuery], + [self tagForQuery:newQuery], listenContainer, + listenContainer.onComplete); + }]; + } else { + // There's nothing below us, so nothing we need to start + // listening on + } + } + + // If we removed anything and we're not covered by a higher up listen, + // we need to stop listening on this query. The above block has us + // covered in terms of making sure we're set up on listens lower in the + // tree. Also, note that if we have a cancelError, it's already been + // removed at the provider level. + if (![covered boolValue] && [removed count] > 0 && cancelError == nil) { + // If we removed a default, then we weren't listening on any of the + // other queries here. Just cancel the one default. Otherwise, we + // need to iterate through and cancel each individual query + if (removingDefault) { + // We don't tag default listeners + self.listenProvider.stopListening( + [self queryForListening:query], nil); + } else { + [removed + enumerateObjectsUsingBlock:^(FQuerySpec *queryToRemove, + NSUInteger idx, BOOL *stop) { + NSNumber *tagToRemove = + [self.queryToTagMap objectForKey:queryToRemove]; + self.listenProvider.stopListening( + [self queryForListening:queryToRemove], tagToRemove); + }]; + } + } + // Now, clear all the tags we're tracking for the removed listens. + [self removeTags:removed]; + } else { + // No-op, this listener must've been already removed + } + return cancelEvents; +} + +- (void)keepQuery:(FQuerySpec *)query synced:(BOOL)keepSynced { + // Only do something if we actually need to add/remove an event registration + if (keepSynced && ![self.keepSyncedQueries containsObject:query]) { + [self addEventRegistration:[FKeepSyncedEventRegistration instance] + forQuery:query]; + [self.keepSyncedQueries addObject:query]; + } else if (!keepSynced && [self.keepSyncedQueries containsObject:query]) { + [self removeEventRegistration:[FKeepSyncedEventRegistration instance] + forQuery:query + cancelError:nil]; + [self.keepSyncedQueries removeObject:query]; + } +} + +- (NSArray *)removeAllWrites { + [self.persistenceManager removeAllUserWrites]; + NSArray *removedWrites = [self.pendingWriteTree removeAllWrites]; + if (removedWrites.count > 0) { + FImmutableTree *affectedTree = + [[FImmutableTree empty] setValue:@YES atPath:[FPath empty]]; + return [self applyOperationToSyncPoints:[[FAckUserWrite alloc] + initWithPath:[FPath empty] + affectedTree:affectedTree + revert:YES]]; + } else { + return @[]; + } +} + +/** Returns a non-empty cache node if one exists. Otherwise returns null. */ +- (FIndexedNode *)persistenceServerCache:(FQuerySpec *)querySpec { + FCacheNode *cacheNode = + [self.persistenceManager serverCacheForQuery:querySpec]; + if (cacheNode == nil || cacheNode.node.isEmpty) { + return nil; + } + return cacheNode.indexedNode; +} + +- (id)getServerValue:(FQuerySpec *)query { + __block id serverCacheNode = nil; + __block FSyncPoint *targetSyncPoint = nil; + [self.syncPointTree + forEachOnPath:query.path + whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) { + FPath *relativePath = [FPath relativePathFrom:pathToSyncPoint + to:query.path]; + serverCacheNode = + [syncPoint completeEventCacheAtPath:relativePath]; + targetSyncPoint = syncPoint; + return serverCacheNode == nil; + }]; + + if (targetSyncPoint == nil) { + targetSyncPoint = [[FSyncPoint alloc] + initWithPersistenceManager:self.persistenceManager]; + self.syncPointTree = [self.syncPointTree setValue:targetSyncPoint + atPath:[query path]]; + } else { + serverCacheNode = + serverCacheNode != nil + ? serverCacheNode + : [targetSyncPoint completeServerCacheAtPath:[FPath empty]]; + } + + FIndexedNode *indexed = [FIndexedNode + indexedNodeWithNode:serverCacheNode != nil ? serverCacheNode + : [FEmptyNode emptyNode] + index:query.index]; + FCacheNode *serverCache = + [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:serverCacheNode != nil + isFiltered:NO]; + FView *view = [targetSyncPoint + getView:query + writesCache:[_pendingWriteTree childWritesForPath:[query path]] + serverCache:serverCache]; + return [view completeEventCache]; +} + +/** + * Returns a complete cache, if we have one, of the data at a particular path. + * The location must have a listener above it, but as this is only used by + * transaction code, that should always be the case anyways. + * + * Note: this method will *include* hidden writes from transaction with + * applyLocally set to false. + * @param path The path to the data we want + * @param writeIdsToExclude A specific set to be excluded + */ +- (id)calcCompleteEventCacheAtPath:(FPath *)path + excludeWriteIds:(NSArray *)writeIdsToExclude { + BOOL includeHiddenSets = YES; + FWriteTree *writeTree = self.pendingWriteTree; + id serverCache = [self.syncPointTree + findOnPath:path + andApplyBlock:^id(FPath *pathSoFar, FSyncPoint *syncPoint) { + FPath *relativePath = [FPath relativePathFrom:pathSoFar to:path]; + id serverCache = + [syncPoint completeServerCacheAtPath:relativePath]; + if (serverCache) { + return serverCache; + } else { + return nil; + } + }]; + return [writeTree calculateCompleteEventCacheAtPath:path + completeServerCache:serverCache + excludeWriteIds:writeIdsToExclude + includeHiddenWrites:includeHiddenSets]; +} + +#pragma mark - +#pragma mark Private Methods +/** + * This collapses multiple unfiltered views into a single view, since we only + * need a single listener for them. + * @return NSArray of FView + */ +- (NSArray *)collectDistinctViewsForSubTree:(FImmutableTree *)subtree { + return [subtree foldWithBlock:^NSArray *(FPath *relativePath, + FSyncPoint *maybeChildSyncPoint, + NSDictionary *childMap) { + if (maybeChildSyncPoint && [maybeChildSyncPoint hasCompleteView]) { + FView *completeView = [maybeChildSyncPoint completeView]; + return @[ completeView ]; + } else { + // No complete view here, flatten any deeper listens into an array + NSMutableArray *views = [[NSMutableArray alloc] init]; + if (maybeChildSyncPoint) { + views = [[maybeChildSyncPoint queryViews] mutableCopy]; + } + [childMap enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, NSArray *childViews, BOOL *stop) { + [views addObjectsFromArray:childViews]; + }]; + return views; + } + }]; +} + +/** + * @param queries NSArray of FQuerySpec + */ +- (void)removeTags:(NSArray *)queries { + [queries enumerateObjectsUsingBlock:^(FQuerySpec *removedQuery, + NSUInteger idx, BOOL *stop) { + if (![removedQuery loadsAllData]) { + // We should have a tag for this + NSNumber *removedQueryTag = self.queryToTagMap[removedQuery]; + [self.queryToTagMap removeObjectForKey:removedQuery]; + [self.tagToQueryMap removeObjectForKey:removedQueryTag]; + } + }]; +} + +- (FQuerySpec *)queryForListening:(FQuerySpec *)query { + if (query.loadsAllData && !query.isDefault) { + // We treat queries that load all data as default queries + return [FQuerySpec defaultQueryAtPath:query.path]; + } else { + return query; + } +} + +/** + * For a given new listen, manage the de-duplication of outstanding + * subscriptions. + * @return NSArray of FEvent events to support synchronous data sources + */ +- (NSArray *)setupListenerOnQuery:(FQuerySpec *)query view:(FView *)view { + FPath *path = query.path; + NSNumber *tagId = [self tagForQuery:query]; + FListenContainer *listenContainer = [self createListenerForView:view]; + + NSArray *events = self.listenProvider.startListening( + [self queryForListening:query], tagId, listenContainer, + listenContainer.onComplete); + + FImmutableTree *subtree = [self.syncPointTree subtreeAtPath:path]; + // The root of this subtree has our query. We're here because we definitely + // need to send a listen for that, but we may need to shadow other listens + // as well. + if (tagId != nil) { + NSAssert(![subtree.value hasCompleteView], + @"If we're adding a query, it shouldn't be shadowed"); + } else { + // Shadow everything at or below this location, this is a default + // listener. + NSArray *queriesToStop = + [subtree foldWithBlock:^id(FPath *relativePath, + FSyncPoint *maybeChildSyncPoint, + NSDictionary *childMap) { + if (![relativePath isEmpty] && maybeChildSyncPoint != nil && + [maybeChildSyncPoint hasCompleteView]) { + return @[ [maybeChildSyncPoint completeView].query ]; + } else { + // No default listener here, flatten any deeper queries into + // an array + NSMutableArray *queries = [[NSMutableArray alloc] init]; + if (maybeChildSyncPoint != nil) { + for (FView *view in [maybeChildSyncPoint queryViews]) { + [queries addObject:view.query]; + } + } + [childMap + enumerateKeysAndObjectsUsingBlock:^( + NSString *key, NSArray *childQueries, BOOL *stop) { + [queries addObjectsFromArray:childQueries]; + }]; + return queries; + } + }]; + for (FQuerySpec *queryToStop in queriesToStop) { + self.listenProvider.stopListening( + [self queryForListening:queryToStop], + [self tagForQuery:queryToStop]); + } + } + return events; +} + +- (FListenContainer *)createListenerForView:(FView *)view { + FQuerySpec *query = view.query; + NSNumber *tagId = [self tagForQuery:query]; + + FListenContainer *listenContainer = [[FListenContainer alloc] + initWithView:view + onComplete:^(NSString *status) { + if ([status isEqualToString:@"ok"]) { + if (tagId != nil) { + return [self applyTaggedListenCompleteAtPath:query.path + tagId:tagId]; + } else { + return [self applyListenCompleteAtPath:query.path]; + } + } else { + // If a listen failed, kill all of the listeners here, not just + // the one that triggered the error. Note that this may need to + // be scoped to just this listener if we change permissions on + // filtered children + NSError *error = [FUtilities errorForStatus:status + andReason:nil]; + FFWarn(@"I-RDB038012", @"Listener at %@ failed: %@", query.path, + status); + return [self removeEventRegistration:nil + forQuery:query + cancelError:error]; + } + }]; + + return listenContainer; +} + +/** + * @return The query associated with the given tag, if we have one + */ +- (FQuerySpec *)queryForTag:(NSNumber *)tagId { + return self.tagToQueryMap[tagId]; +} + +/** + * @return The tag associated with the given query + */ +- (NSNumber *)tagForQuery:(FQuerySpec *)query { + return self.queryToTagMap[query]; +} + +#pragma mark - +#pragma mark applyOperation Helpers + +/** +* A helper method that visits all descendant and ancestor SyncPoints, applying +the operation. +* +* NOTES: +* - Descendant SyncPoints will be visited first (since we raise events +depth-first). + +* - We call applyOperation: on each SyncPoint passing three things: +* 1. A version of the Operation that has been made relative to the SyncPoint +location. +* 2. A WriteTreeRef of any writes we have cached at the SyncPoint location. +* 3. A snapshot Node with cached server data, if we have it. + +* - We concatenate all of the events returned by each SyncPoint and return the +result. +* +* @return Array of FEvent +*/ +- (NSArray *)applyOperationToSyncPoints:(id)operation { + return [self applyOperationHelper:operation + syncPointTree:self.syncPointTree + serverCache:nil + writesCache:[self.pendingWriteTree + childWritesForPath:[FPath empty]]]; +} + +/** + * Recursive helper for applyOperationToSyncPoints_ + */ +- (NSArray *)applyOperationHelper:(id)operation + syncPointTree:(FImmutableTree *)syncPointTree + serverCache:(id)serverCache + writesCache:(FWriteTreeRef *)writesCache { + if ([operation.path isEmpty]) { + return [self applyOperationDescendantsHelper:operation + syncPointTree:syncPointTree + serverCache:serverCache + writesCache:writesCache]; + } else { + FSyncPoint *syncPoint = syncPointTree.value; + + // If we don't have cached server data, see if we can get it from this + // SyncPoint + if (serverCache == nil && syncPoint != nil) { + serverCache = [syncPoint completeServerCacheAtPath:[FPath empty]]; + } + + NSMutableArray *events = [[NSMutableArray alloc] init]; + NSString *childKey = [operation.path getFront]; + id childOperation = [operation operationForChild:childKey]; + FImmutableTree *childTree = [syncPointTree.children get:childKey]; + if (childTree != nil && childOperation != nil) { + id childServerCache = + serverCache ? [serverCache getImmediateChild:childKey] : nil; + FWriteTreeRef *childWritesCache = + [writesCache childWriteTreeRef:childKey]; + [events + addObjectsFromArray:[self + applyOperationHelper:childOperation + syncPointTree:childTree + serverCache:childServerCache + writesCache:childWritesCache]]; + } + + if (syncPoint) { + [events addObjectsFromArray:[syncPoint applyOperation:operation + writesCache:writesCache + serverCache:serverCache]]; + } + + return events; + } +} + +/** + * Recursive helper for applyOperationToSyncPoints: + */ +- (NSArray *)applyOperationDescendantsHelper:(id)operation + syncPointTree:(FImmutableTree *)syncPointTree + serverCache:(id)serverCache + writesCache:(FWriteTreeRef *)writesCache { + FSyncPoint *syncPoint = syncPointTree.value; + + // If we don't have cached server data, see if we can get it from this + // SyncPoint + id resolvedServerCache; + if (serverCache == nil & syncPoint != nil) { + resolvedServerCache = + [syncPoint completeServerCacheAtPath:[FPath empty]]; + } else { + resolvedServerCache = serverCache; + } + + NSMutableArray *events = [[NSMutableArray alloc] init]; + [syncPointTree.children enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, + BOOL *stop) { + id childServerCache = nil; + if (resolvedServerCache != nil) { + childServerCache = [resolvedServerCache getImmediateChild:childKey]; + } + FWriteTreeRef *childWritesCache = + [writesCache childWriteTreeRef:childKey]; + id childOperation = [operation operationForChild:childKey]; + if (childOperation != nil) { + [events addObjectsFromArray: + [self applyOperationDescendantsHelper:childOperation + syncPointTree:childTree + serverCache:childServerCache + writesCache:childWritesCache]]; + } + }]; + + if (syncPoint) { + [events + addObjectsFromArray:[syncPoint applyOperation:operation + writesCache:writesCache + serverCache:resolvedServerCache]]; + } + + return events; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.h new file mode 100644 index 0000000..435fb6a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.h @@ -0,0 +1,45 @@ +/* + * 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 + +@class FPath; +@class FCompoundWrite; +@protocol FNode; + +@interface FWriteRecord : NSObject + +- initWithPath:(FPath *)path + overwrite:(id)overwrite + writeId:(NSInteger)writeId + visible:(BOOL)isVisible; +- initWithPath:(FPath *)path + merge:(FCompoundWrite *)merge + writeId:(NSInteger)writeId; + +@property(nonatomic, readonly) NSInteger writeId; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) id overwrite; +/** + * Maps NSString -> id + */ +@property(nonatomic, strong, readonly) FCompoundWrite *merge; +@property(nonatomic, readonly) BOOL visible; + +- (BOOL)isMerge; +- (BOOL)isOverwrite; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.m new file mode 100644 index 0000000..3f5e657 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.m @@ -0,0 +1,139 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FWriteRecord () +@property(nonatomic, readwrite) NSInteger writeId; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong, readwrite) id overwrite; +@property(nonatomic, strong, readwrite) FCompoundWrite *merge; +@property(nonatomic, readwrite) BOOL visible; +@end + +@implementation FWriteRecord + +- (id)initWithPath:(FPath *)path + overwrite:(id)overwrite + writeId:(NSInteger)writeId + visible:(BOOL)isVisible { + self = [super init]; + if (self) { + self.path = path; + if (overwrite == nil) { + [NSException raise:NSInvalidArgumentException + format:@"Can't pass nil as overwrite parameter to an " + @"overwrite write record"]; + } + self.overwrite = overwrite; + self.merge = nil; + self.writeId = writeId; + self.visible = isVisible; + } + return self; +} + +- (id)initWithPath:(FPath *)path + merge:(FCompoundWrite *)merge + writeId:(NSInteger)writeId { + self = [super init]; + if (self) { + self.path = path; + if (merge == nil) { + [NSException raise:NSInvalidArgumentException + format:@"Can't pass nil as merge parameter to an merge " + @"write record"]; + } + self.overwrite = nil; + self.merge = merge; + self.writeId = writeId; + self.visible = YES; + } + return self; +} + +- (id)overwrite { + if (self->_overwrite == nil) { + [NSException raise:NSInvalidArgumentException + format:@"Can't get overwrite for merge write record!"]; + } + return self->_overwrite; +} + +- (FCompoundWrite *)compoundWrite { + if (self->_merge == nil) { + [NSException raise:NSInvalidArgumentException + format:@"Can't get merge for overwrite write record!"]; + } + return self->_merge; +} + +- (BOOL)isMerge { + return self->_merge != nil; +} + +- (BOOL)isOverwrite { + return self->_overwrite != nil; +} + +- (NSString *)description { + if (self.isOverwrite) { + return + [NSString stringWithFormat:@"FWriteRecord { writeId = %lu, path = " + @"%@, overwrite = %@, visible = %d }", + (unsigned long)self.writeId, self.path, + self.overwrite, self.visible]; + } else { + return [NSString + stringWithFormat: + @"FWriteRecord { writeId = %lu, path = %@, merge = %@ }", + (unsigned long)self.writeId, self.path, self.merge]; + } +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[self class]]) { + return NO; + } + FWriteRecord *other = (FWriteRecord *)object; + if (self->_writeId != other->_writeId) + return NO; + if (self->_path != other->_path && ![self->_path isEqual:other->_path]) + return NO; + if (self->_overwrite != other->_overwrite && + ![self->_overwrite isEqual:other->_overwrite]) + return NO; + if (self->_merge != other->_merge && ![self->_merge isEqual:other->_merge]) + return NO; + if (self->_visible != other->_visible) + return NO; + + return YES; +} + +- (NSUInteger)hash { + NSUInteger hash = self->_writeId * 17; + hash = hash * 31 + self->_path.hash; + hash = hash * 31 + self->_overwrite.hash; + hash = hash * 31 + self->_merge.hash; + hash = hash * 31 + ((self->_visible) ? 1 : 0); + return hash; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.h new file mode 100644 index 0000000..178946b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.h @@ -0,0 +1,70 @@ +/* + * 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 + +@class FPath; +@protocol FNode; +@class FCompoundWrite; +@class FWriteTreeRef; +@class FChildrenNode; +@class FNamedNode; +@class FWriteRecord; +@protocol FIndex; +@class FCacheNode; + +@interface FWriteTree : NSObject + +- (FWriteTreeRef *)childWritesForPath:(FPath *)path; +- (void)addOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible; +- (void)addMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId; +- (BOOL)removeWriteId:(NSInteger)writeId; +- (NSArray *)removeAllWrites; +- (FWriteRecord *)writeForId:(NSInteger)writeId; + +- (id)calculateCompleteEventCacheAtPath:(FPath *)treePath + completeServerCache:(id)completeServerCache + excludeWriteIds:(NSArray *)writeIdsToExclude + includeHiddenWrites:(BOOL)includeHiddenWrites; + +- (id)calculateCompleteEventChildrenAtPath:(FPath *)treePath + completeServerChildren: + (id)completeServerChildren; + +- (id) + calculateEventCacheAfterServerOverwriteAtPath:(FPath *)treePath + childPath:(FPath *)childPath + existingEventSnap:(id)existingEventSnap + existingServerSnap:(id)existingServerSnap; + +- (id)calculateCompleteChildAtPath:(FPath *)treePath + childKey:(NSString *)childKey + cache:(FCacheNode *)existingServerCache; + +- (id)shadowingWriteAtPath:(FPath *)path; + +- (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post + atPath:(FPath *)path + completeServerData:(id)completeServerData + reverse:(BOOL)reverse + index:(id)index; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.m new file mode 100644 index 0000000..9cea890 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.m @@ -0,0 +1,577 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FWriteTree.h" +#import "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FWriteTree () +/** + * A tree tracking the results of applying all visible writes. This does not + * include transactions with applyLocally=false or writes that are completely + * shadowed by other writes. Contains id as values. + */ +@property(nonatomic, strong) FCompoundWrite *visibleWrites; +/** + * A list of pending writes, regardless of visibility and shadowed-ness. Used to + * calcuate arbitrary sets of the changed data, such as hidden writes (from + * transactions) or changes with certain writes excluded (also used by + * transactions). Contains FWriteRecords. + */ +@property(nonatomic, strong) NSMutableArray *allWrites; +@property(nonatomic) NSInteger lastWriteId; +@end + +/** + * FWriteTree tracks all pending user-initiated writes and has methods to + * calcuate the result of merging them with underlying server data (to create + * "event cache" data). Pending writes are added with addOverwriteAtPath: and + * addMergeAtPath: and removed with removeWriteId:. + */ +@implementation FWriteTree + +@synthesize allWrites; +@synthesize lastWriteId; + +- (id)init { + self = [super init]; + if (self) { + self.visibleWrites = [FCompoundWrite emptyWrite]; + self.allWrites = [[NSMutableArray alloc] init]; + self.lastWriteId = -1; + } + return self; +} + +/** + * Create a new WriteTreeRef for the given path. For use with a new sync point + * at the given path. + */ +- (FWriteTreeRef *)childWritesForPath:(FPath *)path { + return [[FWriteTreeRef alloc] initWithPath:path writeTree:self]; +} + +/** + * Record a new overwrite from user code. + * @param visible Is set to false by some transactions. It should be excluded + * from event caches. + */ +- (void)addOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible { + NSAssert(writeId > self.lastWriteId, + @"Stacking an older write on top of a newer one"); + FWriteRecord *record = [[FWriteRecord alloc] initWithPath:path + overwrite:newData + writeId:writeId + visible:visible]; + [self.allWrites addObject:record]; + + if (visible) { + self.visibleWrites = [self.visibleWrites addWrite:newData atPath:path]; + } + + self.lastWriteId = writeId; +} + +/** + * Record a new merge from user code. + * @param changedChildren maps NSString -> id + */ +- (void)addMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId { + NSAssert(writeId > self.lastWriteId, + @"Stacking an older merge on top of newer one"); + FWriteRecord *record = [[FWriteRecord alloc] initWithPath:path + merge:changedChildren + writeId:writeId]; + [self.allWrites addObject:record]; + + self.visibleWrites = [self.visibleWrites addCompoundWrite:changedChildren + atPath:path]; + self.lastWriteId = writeId; +} + +- (FWriteRecord *)writeForId:(NSInteger)writeId { + NSUInteger index = [self.allWrites + indexOfObjectPassingTest:^BOOL(FWriteRecord *write, NSUInteger idx, + BOOL *stop) { + return write.writeId == writeId; + }]; + return (index == NSNotFound) ? nil : self.allWrites[index]; +} + +/** + * Remove a write (either an overwrite or merge) that has been successfully + * acknowledged by the server. Recalculates the tree if necessary. We return the + * path of the write and whether it may have been visible, meaning views need to + * reevaluate. + * + * @return YES if the write may have been visible (meaning we'll need to + * reevaluate / raise events as a result). + */ +- (BOOL)removeWriteId:(NSInteger)writeId { + NSUInteger index = [self.allWrites + indexOfObjectPassingTest:^BOOL(FWriteRecord *record, NSUInteger idx, + BOOL *stop) { + if (record.writeId == writeId) { + return YES; + } else { + return NO; + } + }]; + NSAssert(index != NSNotFound, + @"[FWriteTree removeWriteId:] called with nonexistent writeId."); + FWriteRecord *writeToRemove = self.allWrites[index]; + [self.allWrites removeObjectAtIndex:index]; + + BOOL removedWriteWasVisible = writeToRemove.visible; + BOOL removedWriteOverlapsWithOtherWrites = NO; + NSInteger i = [self.allWrites count] - 1; + + while (removedWriteWasVisible && i >= 0) { + FWriteRecord *currentWrite = [self.allWrites objectAtIndex:i]; + if (currentWrite.visible) { + if (i >= index && [self record:currentWrite + containsPath:writeToRemove.path]) { + // The removed write was completely shadowed by a subsequent + // write. + removedWriteWasVisible = NO; + } else if ([writeToRemove.path contains:currentWrite.path]) { + // Either we're covering some writes or they're covering part of + // us (depending on which came first). + removedWriteOverlapsWithOtherWrites = YES; + } + } + i--; + } + + if (!removedWriteWasVisible) { + return NO; + } else if (removedWriteOverlapsWithOtherWrites) { + // There's some shadowing going on. Just rebuild the visible writes from + // scratch. + [self resetTree]; + return YES; + } else { + // There's no shadowing. We can safely just remove the write(s) from + // visibleWrites. + if ([writeToRemove isOverwrite]) { + self.visibleWrites = + [self.visibleWrites removeWriteAtPath:writeToRemove.path]; + } else { + FCompoundWrite *merge = writeToRemove.merge; + [merge enumerateWrites:^(FPath *path, id node, BOOL *stop) { + self.visibleWrites = [self.visibleWrites + removeWriteAtPath:[writeToRemove.path child:path]]; + }]; + } + return YES; + } +} + +- (NSArray *)removeAllWrites { + NSArray *writes = self.allWrites; + self.visibleWrites = [FCompoundWrite emptyWrite]; + self.allWrites = [NSMutableArray array]; + return writes; +} + +/** + * @return A complete snapshot for the given path if there's visible write data + * at that path, else nil. No server data is considered. + */ +- (id)completeWriteDataAtPath:(FPath *)path { + return [self.visibleWrites completeNodeAtPath:path]; +} + +/** + * Given optional, underlying server data, and an optional set of constraints + * (exclude some sets, include hidden writes), attempt to calculate a complete + * snapshot for the given path + * @param includeHiddenWrites Defaults to false, whether or not to layer on + * writes with visible set to false + */ +- (id)calculateCompleteEventCacheAtPath:(FPath *)treePath + completeServerCache:(id)completeServerCache + excludeWriteIds:(NSArray *)writeIdsToExclude + includeHiddenWrites:(BOOL)includeHiddenWrites { + if (writeIdsToExclude == nil && !includeHiddenWrites) { + id shadowingNode = + [self.visibleWrites completeNodeAtPath:treePath]; + if (shadowingNode != nil) { + return shadowingNode; + } else { + // No cache here. Can't claim complete knowledge. + FCompoundWrite *subMerge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; + if (subMerge.isEmpty) { + return completeServerCache; + } else if (completeServerCache == nil && + ![subMerge hasCompleteWriteAtPath:[FPath empty]]) { + // We wouldn't have a complete snapshot since there's no + // underlying data and no complete shadow + return nil; + } else { + id layeredCache = completeServerCache != nil + ? completeServerCache + : [FEmptyNode emptyNode]; + return [subMerge applyToNode:layeredCache]; + } + } + } else { + FCompoundWrite *merge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; + if (!includeHiddenWrites && merge.isEmpty) { + return completeServerCache; + } else { + // If the server cache is null and we don't have a complete cache, + // we need to return nil + if (!includeHiddenWrites && completeServerCache == nil && + ![merge hasCompleteWriteAtPath:[FPath empty]]) { + return nil; + } else { + BOOL (^filter)(FWriteRecord *) = ^(FWriteRecord *record) { + return (BOOL)((record.visible || includeHiddenWrites) && + (writeIdsToExclude == nil || + ![writeIdsToExclude + containsObject:[NSNumber + numberWithInteger: + record.writeId]]) && + ([record.path contains:treePath] || + [treePath contains:record.path])); + }; + FCompoundWrite *mergeAtPath = + [FWriteTree layerTreeFromWrites:self.allWrites + filter:filter + treeRoot:treePath]; + id layeredCache = completeServerCache + ? completeServerCache + : [FEmptyNode emptyNode]; + return [mergeAtPath applyToNode:layeredCache]; + } + } + } +} + +/** + * With optional, underlying server data, attempt to return a children node of + * children that we have complete data for. Used when creating new views, to + * pre-fill their complete event children snapshot. + */ +- (FChildrenNode *)calculateCompleteEventChildrenAtPath:(FPath *)treePath + completeServerChildren: + (id)completeServerChildren { + __block id completeChildren = [FEmptyNode emptyNode]; + id topLevelSet = [self.visibleWrites completeNodeAtPath:treePath]; + if (topLevelSet != nil) { + if (![topLevelSet isLeafNode]) { + // We're shadowing everything. Return the children. + FChildrenNode *topChildrenNode = topLevelSet; + [topChildrenNode enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + completeChildren = [completeChildren updateImmediateChild:key + withNewChild:node]; + }]; + } + return completeChildren; + } else { + // Layer any children we have on top of this + // We know we don't have a top-level set, so just enumerate existing + // children, and apply any updates + FCompoundWrite *merge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; + [completeServerChildren enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + FCompoundWrite *childMerge = + [merge childCompoundWriteAtPath:[[FPath alloc] initWith:key]]; + id newChildNode = [childMerge applyToNode:node]; + completeChildren = + [completeChildren updateImmediateChild:key + withNewChild:newChildNode]; + }]; + // Add any complete children we have from the set. + for (FNamedNode *node in merge.completeChildren) { + completeChildren = + [completeChildren updateImmediateChild:node.name + withNewChild:node.node]; + } + return completeChildren; + } +} + +/** + * Given that the underlying server data has updated, determine what, if + * anything, needs to be applied to the event cache. + * + * Possibilities + * + * 1. No write are shadowing. Events should be raised, the snap to be applied + * comes from the server data. + * + * 2. Some write is completely shadowing. No events to be raised. + * + * 3. Is partially shadowed. Events .. + * + * Either existingEventSnap or existingServerSnap must exist. + */ +- (id)calculateEventCacheAfterServerOverwriteAtPath:(FPath *)treePath + childPath:(FPath *)childPath + existingEventSnap: + (id)existingEventSnap + existingServerSnap: + (id)existingServerSnap { + NSAssert(existingEventSnap != nil || existingServerSnap != nil, + @"Either existingEventSnap or existingServerSanp must exist."); + + FPath *path = [treePath child:childPath]; + if ([self.visibleWrites hasCompleteWriteAtPath:path]) { + // At this point we can probably guarantee that we're in case 2, meaning + // no events May need to check visibility while doing the + // findRootMostValueAndPath call + return nil; + } else { + // This could be more efficient if the serverNode + updates doesn't + // change the eventSnap However this is tricky to find out, since user + // updates don't necessary change the server snap, e.g. priority updates + // on empty nodes, or deep deletes. Another special case is if the + // server adds nodes, but doesn't change any existing writes. It is + // therefore not enough to only check if the updates change the + // serverNode. Maybe check if the merge tree contains these special + // cases and only do a full overwrite in that case? + FCompoundWrite *childMerge = + [self.visibleWrites childCompoundWriteAtPath:path]; + if (childMerge.isEmpty) { + // We're not shadowing at all. Case 1 + return [existingServerSnap getChild:childPath]; + } else { + return [childMerge + applyToNode:[existingServerSnap getChild:childPath]]; + } + } +} + +/** + * Returns a complete child for a given server snap after applying all user + * writes or nil if there is no complete child for this child key. + */ +- (id)calculateCompleteChildAtPath:(FPath *)treePath + childKey:(NSString *)childKey + cache:(FCacheNode *)existingServerCache { + FPath *path = [treePath childFromString:childKey]; + id shadowingNode = [self.visibleWrites completeNodeAtPath:path]; + if (shadowingNode != nil) { + return shadowingNode; + } else { + if ([existingServerCache isCompleteForChild:childKey]) { + FCompoundWrite *childMerge = + [self.visibleWrites childCompoundWriteAtPath:path]; + return [childMerge applyToNode:[existingServerCache.node + getImmediateChild:childKey]]; + } else { + return nil; + } + } +} + +/** + * Returns a node if there is a complete overwrite for this path. More + * specifically, if there is a write at a higher path, this will return the + * child of that write relative to the write and this path. Returns null if + * there is no write at this path. + */ +- (id)shadowingWriteAtPath:(FPath *)path { + return [self.visibleWrites completeNodeAtPath:path]; +} + +/** + * This method is used when processing child remove events on a query. If we + * can, we pull in children that were outside the window, but may now be in the + * window. + */ +- (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post + atPath:(FPath *)treePath + completeServerData:(id)completeServerData + reverse:(BOOL)reverse + index:(id)index { + __block id toIterate; + FCompoundWrite *merge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; + id shadowingNode = [merge completeNodeAtPath:[FPath empty]]; + if (shadowingNode != nil) { + toIterate = shadowingNode; + } else if (completeServerData != nil) { + toIterate = [merge applyToNode:completeServerData]; + } else { + return nil; + } + + __block NSString *currentNextKey = nil; + __block id currentNextNode = nil; + [toIterate enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + if ([index compareKey:key + andNode:node + toOtherKey:post.name + andNode:post.node + reverse:reverse] > NSOrderedSame && + (!currentNextKey || [index compareKey:key + andNode:node + toOtherKey:currentNextKey + andNode:currentNextNode + reverse:reverse] < NSOrderedSame)) { + currentNextKey = key; + currentNextNode = node; + } + }]; + + if (currentNextKey != nil) { + return [FNamedNode nodeWithName:currentNextKey node:currentNextNode]; + } else { + return nil; + } +} + +#pragma mark - +#pragma mark Private Methods + +- (BOOL)record:(FWriteRecord *)record containsPath:(FPath *)path { + if ([record isOverwrite]) { + return [record.path contains:path]; + } else { + __block BOOL contains = NO; + [record.merge + enumerateWrites:^(FPath *childPath, id node, BOOL *stop) { + contains = [[record.path child:childPath] contains:path]; + *stop = contains; + }]; + return contains; + } +} + +/** + * Re-layer the writes and merges into a tree so we can efficiently calculate + * event snapshots + */ +- (void)resetTree { + self.visibleWrites = + [FWriteTree layerTreeFromWrites:self.allWrites + filter:[FWriteTree defaultFilter] + treeRoot:[FPath empty]]; + if ([self.allWrites count] > 0) { + FWriteRecord *lastRecord = self.allWrites[[self.allWrites count] - 1]; + self.lastWriteId = lastRecord.writeId; + } else { + self.lastWriteId = -1; + } +} + +/** + * The default filter used when constructing the tree. Keep everything that's + * visible. + */ ++ (BOOL (^)(FWriteRecord *record))defaultFilter { + static BOOL (^filter)(FWriteRecord *); + static dispatch_once_t filterToken; + dispatch_once(&filterToken, ^{ + filter = ^(FWriteRecord *record) { + return YES; + }; + }); + return filter; +} + +/** + * Static method. Given an array of WriteRecords, a filter for which ones to + * include, and a path, construct a merge at that path + * @return An FImmutableTree of ids. + */ ++ (FCompoundWrite *)layerTreeFromWrites:(NSArray *)writes + filter:(BOOL (^)(FWriteRecord *record))filter + treeRoot:(FPath *)treeRoot { + __block FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite]; + [writes enumerateObjectsUsingBlock:^(FWriteRecord *record, NSUInteger idx, + BOOL *stop) { + // Theory, a later set will either: + // a) abort a relevant transaction, so no need to worry about excluding it + // from calculating that transaction b) not be relevant to a transaction + // (separate branch), so again will not affect the data for that + // transaction + if (filter(record)) { + FPath *writePath = record.path; + if ([record isOverwrite]) { + if ([treeRoot contains:writePath]) { + FPath *relativePath = [FPath relativePathFrom:treeRoot + to:writePath]; + compoundWrite = [compoundWrite addWrite:record.overwrite + atPath:relativePath]; + } else if ([writePath contains:treeRoot]) { + id child = [record.overwrite + getChild:[FPath relativePathFrom:writePath to:treeRoot]]; + compoundWrite = [compoundWrite addWrite:child + atPath:[FPath empty]]; + } else { + // There is no overlap between root path and write path, + // ignore write + } + } else { + if ([treeRoot contains:writePath]) { + FPath *relativePath = [FPath relativePathFrom:treeRoot + to:writePath]; + compoundWrite = [compoundWrite addCompoundWrite:record.merge + atPath:relativePath]; + } else if ([writePath contains:treeRoot]) { + FPath *relativePath = [FPath relativePathFrom:writePath + to:treeRoot]; + if (relativePath.isEmpty) { + compoundWrite = + [compoundWrite addCompoundWrite:record.merge + atPath:[FPath empty]]; + } else { + id child = + [record.merge completeNodeAtPath:relativePath]; + if (child != nil) { + // There exists a child in this node that matches the + // root path + id deepNode = + [child getChild:[relativePath popFront]]; + compoundWrite = + [compoundWrite addWrite:deepNode + atPath:[FPath empty]]; + } + } + } else { + // There is no overlap between root path and write path, + // ignore write + } + } + } + }]; + return compoundWrite; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.h new file mode 100644 index 0000000..962ad5c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.h @@ -0,0 +1,57 @@ +/* + * 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 + +@protocol FNode; +@class FChildrenNode; +@class FPath; +@class FNamedNode; +@class FWriteRecord; +@class FWriteTree; +@protocol FIndex; +@class FCacheNode; + +@interface FWriteTreeRef : NSObject + +- (id)initWithPath:(FPath *)aPath writeTree:(FWriteTree *)tree; + +- (id)calculateCompleteEventCacheWithCompleteServerCache: + (id)completeServerCache; + +- (FChildrenNode *)calculateCompleteEventChildrenWithCompleteServerChildren: + (FChildrenNode *)completeServerChildren; + +- (id) + calculateEventCacheAfterServerOverwriteWithChildPath:(FPath *)childPath + existingEventSnap: + (id)existingEventSnap + existingServerSnap: + (id)existingServerSnap; + +- (id)shadowingWriteAtPath:(FPath *)path; + +- (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post + completeServerData:(id)completeServerData + reverse:(BOOL)reverse + index:(id)index; + +- (id)calculateCompleteChild:(NSString *)childKey + cache:(FCacheNode *)existingServerCache; + +- (FWriteTreeRef *)childWriteTreeRef:(NSString *)childKey; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.m new file mode 100644 index 0000000..6edb684 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.m @@ -0,0 +1,159 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Core/FWriteTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FWriteTreeRef () +/** + * The path to this particular FWriteTreeRef. Used for calling methods on + * writeTree while exposing a simpler interface to callers. + */ +@property(nonatomic, strong) FPath *path; +/** + * A reference to the actual tree of the write data. All methods are + * pass-through to the tree, but with the appropriate path prefixed. + * + * This lets us make cheap references to points in the tree for sync points + * without having to copy and maintain all of the data. + */ +@property(nonatomic, strong) FWriteTree *writeTree; +@end + +/** + * A FWriteTreeRef wraps a FWriteTree and a FPath, for convenient access to a + * particular subtree. All the methods just proxy to the underlying FWriteTree. + */ +@implementation FWriteTreeRef +- (id)initWithPath:(FPath *)aPath writeTree:(FWriteTree *)tree { + self = [super init]; + if (self) { + self.path = aPath; + self.writeTree = tree; + } + return self; +} + +/** + * @return If possible, returns a complete event cache, using the underlying + * server data if possible. In addition, can be used to get a cache that + * includes hidden writes, and excludes arbitrary writes. Note that customizing + * the returned node can lead to a more expensive calculation. + */ +- (id)calculateCompleteEventCacheWithCompleteServerCache: + (id)completeServerCache { + return [self.writeTree calculateCompleteEventCacheAtPath:self.path + completeServerCache:completeServerCache + excludeWriteIds:nil + includeHiddenWrites:NO]; +} + +/** + * @return If possible, returns a children node containing all of the complete + * children we have data for. The returned data is a mix of the given server + * data and write data. + */ +- (FChildrenNode *)calculateCompleteEventChildrenWithCompleteServerChildren: + (id)completeServerChildren { + return [self.writeTree + calculateCompleteEventChildrenAtPath:self.path + completeServerChildren:completeServerChildren]; +} + +/** + * Given that either the underlying server data has updated or the outstanding + * writes have been updating, determine what, if anything, needs to be applied + * to the event cache. + * + * Possibilities: + * + * 1. No writes are shadowing. Events should be raised, the snap to be applied + * comes from the server data. + * + * 2. Some writes are completly shadowing. No events to be raised. + * + * 3. Is partially shadowed. Events should be raised. + * + * Either existingEventSnap or existingServerSnap must exist, this is validated + * via an assert. + */ +- (id) + calculateEventCacheAfterServerOverwriteWithChildPath:(FPath *)childPath + existingEventSnap: + (id)existingEventSnap + existingServerSnap: + (id)existingServerSnap { + return [self.writeTree + calculateEventCacheAfterServerOverwriteAtPath:self.path + childPath:childPath + existingEventSnap:existingEventSnap + existingServerSnap:existingServerSnap]; +} + +/** + * Returns a node if there is a complete overwrite for this path. More + * specifically, if there is a write at a higher path, this will return the + * child of that write relative to the write and this path. Returns nil if there + * is no write at this path. + */ +- (id)shadowingWriteAtPath:(FPath *)path { + return [self.writeTree shadowingWriteAtPath:[self.path child:path]]; +} + +/** + * This method is used when processing child remove events on a query. If we + * can, we pull in children that are outside the window, but may now be in the + * window. + */ +- (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post + completeServerData:(id)completeServerData + reverse:(BOOL)reverse + index:(id)index { + return [self.writeTree calculateNextNodeAfterPost:post + atPath:self.path + completeServerData:completeServerData + reverse:reverse + index:index]; +} + +/** + * Returns a complete child for a given server snap after applying all user + * writes or nil if there is no complete child for this child key. + */ +- (id)calculateCompleteChild:(NSString *)childKey + cache:(FCacheNode *)existingServerCache { + return [self.writeTree calculateCompleteChildAtPath:self.path + childKey:childKey + cache:existingServerCache]; +} + +/** + * @return a WriteTreeref for a child. + */ +- (FWriteTreeRef *)childWriteTreeRef:(NSString *)childKey { + return + [[FWriteTreeRef alloc] initWithPath:[self.path childFromString:childKey] + writeTree:self.writeTree]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h new file mode 100644 index 0000000..2d1223c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h @@ -0,0 +1,37 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOperation.h" + +@class FPath; +@class FOperationSource; +@class FImmutableTree; + +@interface FAckUserWrite : NSObject + +- initWithPath:(FPath *)operationPath + affectedTree:(FImmutableTree *)affectedTree + revert:(BOOL)shouldRevert; + +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +// A FImmutableTree, containing @YES for each affected path. Affected paths +// can't overlap. +@property(nonatomic, strong, readonly) FImmutableTree *affectedTree; +@property(nonatomic, readonly) BOOL revert; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.m new file mode 100644 index 0000000..bf65f4d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.m @@ -0,0 +1,66 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +@implementation FAckUserWrite + +- (id)initWithPath:(FPath *)operationPath + affectedTree:(FImmutableTree *)tree + revert:(BOOL)shouldRevert { + self = [super init]; + if (self) { + self->_source = [FOperationSource userInstance]; + self->_type = FOperationTypeAckUserWrite; + self->_path = operationPath; + self->_affectedTree = tree; + self->_revert = shouldRevert; + } + return self; +} + +- (FAckUserWrite *)operationForChild:(NSString *)childKey { + if (![self.path isEmpty]) { + NSAssert([self.path.getFront isEqualToString:childKey], + @"operationForChild called for unrelated child."); + return [[FAckUserWrite alloc] initWithPath:[self.path popFront] + affectedTree:self.affectedTree + revert:self.revert]; + } else if (self.affectedTree.value != nil) { + NSAssert(self.affectedTree.children.isEmpty, + @"affectedTree should not have overlapping affected paths."); + // All child locations are affected as well; just return same operation. + return self; + } else { + FImmutableTree *childTree = + [self.affectedTree subtreeAtPath:[[FPath alloc] initWith:childKey]]; + return [[FAckUserWrite alloc] initWithPath:[FPath empty] + affectedTree:childTree + revert:self.revert]; + } +} + +- (NSString *)description { + return + [NSString stringWithFormat: + @"FAckUserWrite { path=%@, revert=%d, affectedTree=%@ }", + self.path, self.revert, self.affectedTree]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.h new file mode 100644 index 0000000..9b6534d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.h @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOperation.h" + +@class FCompoundWrite; + +@interface FMerge : NSObject + +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + children:(FCompoundWrite *)children; + +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) FCompoundWrite *children; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.m new file mode 100644 index 0000000..88cee3e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.m @@ -0,0 +1,85 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FMerge.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOverwrite.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FMerge () +@property(nonatomic, strong, readwrite) FOperationSource *source; +@property(nonatomic, readwrite) FOperationType type; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong) FCompoundWrite *children; +@end + +@implementation FMerge + +@synthesize source; +@synthesize type; +@synthesize path; +@synthesize children; + +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + children:(FCompoundWrite *)someChildren { + self = [super init]; + if (self) { + self.source = aSource; + self.type = FOperationTypeMerge; + self.path = aPath; + self.children = someChildren; + } + return self; +} + +- (id)operationForChild:(NSString *)childKey { + if ([self.path isEmpty]) { + FCompoundWrite *childTree = [self.children + childCompoundWriteAtPath:[[FPath alloc] initWith:childKey]]; + if (childTree.isEmpty) { + return nil; + } else if (childTree.rootWrite != nil) { + // We have a snapshot for the child in question. This becomes an + // overwrite of the child. + return [[FOverwrite alloc] initWithSource:self.source + path:[FPath empty] + snap:childTree.rootWrite]; + } else { + // This is a merge at a deeper level + return [[FMerge alloc] initWithSource:self.source + path:[FPath empty] + children:childTree]; + } + } else { + NSAssert( + [self.path.getFront isEqualToString:childKey], + @"Can't get a merge for a child not on the path of the operation"); + return [[FMerge alloc] initWithSource:self.source + path:[self.path popFront] + children:self.children]; + } +} + +- (NSString *)description { + return + [NSString stringWithFormat:@"FMerge { path=%@, soruce=%@ children=%@}", + self.path, self.source, self.children]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperation.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperation.h new file mode 100644 index 0000000..41f6054 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperation.h @@ -0,0 +1,34 @@ +/* + * 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 + +@class FOperationSource; +@class FPath; + +typedef NS_ENUM(NSInteger, FOperationType) { + FOperationTypeOverwrite = 0, + FOperationTypeMerge = 1, + FOperationTypeAckUserWrite = 2, + FOperationTypeListenComplete = 3 +}; + +@protocol FOperation +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +- (id)operationForChild:(NSString *)childKey; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.h new file mode 100644 index 0000000..747487b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.h @@ -0,0 +1,37 @@ +/* + * 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 + +@class FQueryParams; + +@interface FOperationSource : NSObject + +@property(nonatomic, readonly) BOOL fromUser; +@property(nonatomic, readonly) BOOL fromServer; +@property(nonatomic, readonly) BOOL isTagged; +@property(nonatomic, strong, readonly) FQueryParams *queryParams; + +- initWithFromUser:(BOOL)isFromUser + fromServer:(BOOL)isFromServer + queryParams:(FQueryParams *)params + tagged:(BOOL)isTagged; + ++ (FOperationSource *)userInstance; ++ (FOperationSource *)serverInstance; ++ (FOperationSource *)forServerTaggedQuery:(FQueryParams *)params; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.m new file mode 100644 index 0000000..ce23987 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.m @@ -0,0 +1,86 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +@interface FOperationSource () +@property(nonatomic, readwrite) BOOL fromUser; +@property(nonatomic, readwrite) BOOL fromServer; +@property(nonatomic, readwrite) BOOL isTagged; +@property(nonatomic, strong, readwrite) FQueryParams *queryParams; +@end + +@implementation FOperationSource + +@synthesize fromUser; +@synthesize fromServer; +@synthesize queryParams; + +- (id)initWithFromUser:(BOOL)isFromUser + fromServer:(BOOL)isFromServer + queryParams:(FQueryParams *)params + tagged:(BOOL)tagged { + self = [super init]; + if (self) { + self.fromUser = isFromUser; + self.fromServer = isFromServer; + self.queryParams = params; + self.isTagged = tagged; + } + return self; +} + ++ (FOperationSource *)userInstance { + static FOperationSource *user = nil; + static dispatch_once_t userToken; + dispatch_once(&userToken, ^{ + user = [[FOperationSource alloc] initWithFromUser:YES + fromServer:NO + queryParams:nil + tagged:NO]; + }); + return user; +} + ++ (FOperationSource *)serverInstance { + static FOperationSource *server = nil; + static dispatch_once_t serverToken; + dispatch_once(&serverToken, ^{ + server = [[FOperationSource alloc] initWithFromUser:NO + fromServer:YES + queryParams:nil + tagged:NO]; + }); + return server; +} + ++ (FOperationSource *)forServerTaggedQuery:(FQueryParams *)params { + return [[FOperationSource alloc] initWithFromUser:NO + fromServer:YES + queryParams:params + tagged:YES]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FOperationSource { fromUser=%d, " + @"fromServer=%d, queryId=%@, tagged=%d }", + self.fromUser, self.fromServer, + self.queryParams, self.isTagged]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.h new file mode 100644 index 0000000..a828667 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.h @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOperation.h" + +@protocol FNode; + +@interface FOverwrite : NSObject + +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + snap:(id)aSnap; + +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) id snap; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.m new file mode 100644 index 0000000..7094028 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.m @@ -0,0 +1,67 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOverwrite.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FOverwrite () +@property(nonatomic, strong, readwrite) FOperationSource *source; +@property(nonatomic, readwrite) FOperationType type; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong) id snap; +@end + +@implementation FOverwrite + +@synthesize source; +@synthesize type; +@synthesize path; +@synthesize snap; + +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + snap:(id)aSnap { + self = [super init]; + if (self) { + self.source = aSource; + self.type = FOperationTypeOverwrite; + self.path = aPath; + self.snap = aSnap; + } + return self; +} + +- (FOverwrite *)operationForChild:(NSString *)childKey { + if ([self.path isEmpty]) { + return [[FOverwrite alloc] + initWithSource:self.source + path:[FPath empty] + snap:[self.snap getImmediateChild:childKey]]; + } else { + return [[FOverwrite alloc] initWithSource:self.source + path:[self.path popFront] + snap:self.snap]; + } +} + +- (NSString *)description { + return [NSString + stringWithFormat:@"FOverwrite { path=%@, source=%@, snapshot=%@ }", + self.path, self.source, self.snap]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h new file mode 100644 index 0000000..a63d0d8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h @@ -0,0 +1,33 @@ +/* + * 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 + +@interface FIRRetryHelper : NSObject + +- (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue + minRetryDelayAfterFailure:(NSTimeInterval)minRetryDelayAfterFailure + maxRetryDelay:(NSTimeInterval)maxRetryDelay + retryExponent:(double)retryExponent + jitterFactor:(double)jitterFactor; + +- (void)retry:(void (^)(void))block; + +- (void)cancel; + +- (void)signalSuccess; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.m new file mode 100644 index 0000000..810a047 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.m @@ -0,0 +1,140 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FIRRetryHelperTask : NSObject + +@property(nonatomic, strong) void (^block)(void); + +@end + +@implementation FIRRetryHelperTask + +- (instancetype)initWithBlock:(void (^)(void))block { + self = [super init]; + if (self != nil) { + self->_block = [block copy]; + } + return self; +} + +- (BOOL)isCanceled { + return self.block == nil; +} + +- (void)cancel { + self.block = nil; +} + +- (void)execute { + if (self.block) { + self.block(); + } +} + +@end + +@interface FIRRetryHelper () + +@property(nonatomic, strong) dispatch_queue_t dispatchQueue; +@property(nonatomic) NSTimeInterval minRetryDelayAfterFailure; +@property(nonatomic) NSTimeInterval maxRetryDelay; +@property(nonatomic) double retryExponent; +@property(nonatomic) double jitterFactor; + +@property(nonatomic) BOOL lastWasSuccess; +@property(nonatomic) NSTimeInterval currentRetryDelay; + +@property(nonatomic, strong) FIRRetryHelperTask *scheduledRetry; + +@end + +@implementation FIRRetryHelper + +- (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue + minRetryDelayAfterFailure:(NSTimeInterval)minRetryDelayAfterFailure + maxRetryDelay:(NSTimeInterval)maxRetryDelay + retryExponent:(double)retryExponent + jitterFactor:(double)jitterFactor { + self = [super init]; + if (self != nil) { + self->_dispatchQueue = dispatchQueue; + self->_minRetryDelayAfterFailure = minRetryDelayAfterFailure; + self->_maxRetryDelay = maxRetryDelay; + self->_retryExponent = retryExponent; + self->_jitterFactor = jitterFactor; + self->_lastWasSuccess = YES; + } + return self; +} + +- (void)retry:(void (^)(void))block { + if (self.scheduledRetry != nil) { + FFLog(@"I-RDB054001", @"Canceling existing retry attempt"); + [self.scheduledRetry cancel]; + self.scheduledRetry = nil; + } + + NSTimeInterval delay; + if (self.lastWasSuccess) { + delay = 0; + } else { + if (self.currentRetryDelay == 0) { + self.currentRetryDelay = self.minRetryDelayAfterFailure; + } else { + NSTimeInterval newDelay = + (self.currentRetryDelay * self.retryExponent); + self.currentRetryDelay = MIN(newDelay, self.maxRetryDelay); + } + + delay = ((1 - self.jitterFactor) * self.currentRetryDelay) + + (self.jitterFactor * self.currentRetryDelay * + [FUtilities randomDouble]); + FFLog(@"I-RDB054002", @"Scheduling retry in %fs", delay); + } + self.lastWasSuccess = NO; + FIRRetryHelperTask *task = [[FIRRetryHelperTask alloc] initWithBlock:block]; + self.scheduledRetry = task; + dispatch_time_t popTime = + dispatch_time(DISPATCH_TIME_NOW, (long long)(delay * NSEC_PER_SEC)); + dispatch_after(popTime, self.dispatchQueue, ^{ + if (![task isCanceled]) { + self.scheduledRetry = nil; + [task execute]; + } + }); +} + +- (void)signalSuccess { + self.lastWasSuccess = YES; + self.currentRetryDelay = 0; +} + +- (void)cancel { + if (self.scheduledRetry != nil) { + FFLog(@"I-RDB054003", @"Canceling existing retry attempt"); + [self.scheduledRetry cancel]; + self.scheduledRetry = nil; + } else { + FFLog(@"I-RDB054004", @"No existing retry attempt to cancel"); + } + self.currentRetryDelay = 0; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h new file mode 100644 index 0000000..a08a440 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h @@ -0,0 +1,59 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" + +@interface FImmutableTree : NSObject + +- (id)initWithValue:(id)aValue; +- (id)initWithValue:(id)aValue + children:(FImmutableSortedDictionary *)childrenMap; + ++ (FImmutableTree *)empty; +- (BOOL)isEmpty; + +- (FTuplePathValue *)findRootMostMatchingPath:(FPath *)relativePath + predicate:(BOOL (^)(id))predicate; +- (FTuplePathValue *)findRootMostValueAndPath:(FPath *)relativePath; +- (FImmutableTree *)subtreeAtPath:(FPath *)relativePath; +- (FImmutableTree *)setValue:(id)newValue atPath:(FPath *)relativePath; +- (FImmutableTree *)removeValueAtPath:(FPath *)relativePath; +- (id)valueAtPath:(FPath *)relativePath; +- (id)rootMostValueOnPath:(FPath *)path; +- (id)rootMostValueOnPath:(FPath *)path matching:(BOOL (^)(id))predicate; +- (id)leafMostValueOnPath:(FPath *)path; +- (id)leafMostValueOnPath:(FPath *)relativePath + matching:(BOOL (^)(id))predicate; +- (BOOL)containsValueMatching:(BOOL (^)(id))predicate; +- (FImmutableTree *)setTree:(FImmutableTree *)newTree + atPath:(FPath *)relativePath; +- (id)foldWithBlock:(id (^)(FPath *path, id value, + NSDictionary *foldedChildren))block; +- (id)findOnPath:(FPath *)path + andApplyBlock:(id (^)(FPath *path, id value))block; +- (FPath *)forEachOnPath:(FPath *)path + whileBlock:(BOOL (^)(FPath *path, id value))block; +- (FImmutableTree *)forEachOnPath:(FPath *)path + performBlock:(void (^)(FPath *path, id value))block; +- (void)forEach:(void (^)(FPath *path, id value))block; +- (void)forEachChild:(void (^)(NSString *childKey, id childValue))block; + +@property(nonatomic, strong, readonly) id value; +@property(nonatomic, strong, readonly) FImmutableSortedDictionary *children; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.m new file mode 100644 index 0000000..fe8a924 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.m @@ -0,0 +1,486 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" + +@interface FImmutableTree () +@property(nonatomic, strong, readwrite) id value; +/** + * Maps NSString -> FImmutableTree, where is type of value. + */ +@property(nonatomic, strong, readwrite) FImmutableSortedDictionary *children; +@end + +@implementation FImmutableTree +@synthesize value; +@synthesize children; + +- (id)initWithValue:(id)aValue { + self = [super init]; + if (self) { + self.value = aValue; + self.children = [FImmutableTree emptyChildren]; + } + return self; +} + +- (id)initWithValue:(id)aValue + children:(FImmutableSortedDictionary *)childrenMap { + self = [super init]; + if (self) { + self.value = aValue; + self.children = childrenMap; + } + return self; +} + ++ (FImmutableSortedDictionary *)emptyChildren { + static dispatch_once_t emptyChildrenToken; + static FImmutableSortedDictionary *emptyChildren; + dispatch_once(&emptyChildrenToken, ^{ + emptyChildren = [FImmutableSortedDictionary + dictionaryWithComparator:[FUtilities stringComparator]]; + }); + return emptyChildren; +} + ++ (FImmutableTree *)empty { + static dispatch_once_t emptyImmutableTreeToken; + static FImmutableTree *emptyTree = nil; + dispatch_once(&emptyImmutableTreeToken, ^{ + emptyTree = [[FImmutableTree alloc] initWithValue:nil]; + }); + return emptyTree; +} + +- (BOOL)isEmpty { + return self.value == nil && [self.children isEmpty]; +} + +/** + * Given a path and a predicate, return the first node and the path to that node + * where the predicate returns true + * // TODO Do a perf test. If we're creating a bunch of FTuplePathValue objects + * on the way back out, it may be better to pass down a pathSoFar FPath + */ +- (FTuplePathValue *)findRootMostMatchingPath:(FPath *)relativePath + predicate:(BOOL (^)(id value))predicate { + if (self.value != nil && predicate(self.value)) { + return [[FTuplePathValue alloc] initWithPath:[FPath empty] + value:self.value]; + } else { + if ([relativePath isEmpty]) { + return nil; + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *child = [self.children get:front]; + if (child != nil) { + FTuplePathValue *childExistingPathAndValue = + [child findRootMostMatchingPath:[relativePath popFront] + predicate:predicate]; + if (childExistingPathAndValue != nil) { + FPath *fullPath = [[[FPath alloc] initWith:front] + child:childExistingPathAndValue.path]; + return [[FTuplePathValue alloc] + initWithPath:fullPath + value:childExistingPathAndValue.value]; + } else { + return nil; + } + } else { + // No child matching path + return nil; + } + } + } +} + +/** + * Find, if it exists, the shortest subpath of the given path that points a + * defined value in the tree + */ +- (FTuplePathValue *)findRootMostValueAndPath:(FPath *)relativePath { + return [self findRootMostMatchingPath:relativePath + predicate:^BOOL(__unsafe_unretained id value) { + return YES; + }]; +} + +- (id)rootMostValueOnPath:(FPath *)path { + return [self rootMostValueOnPath:path + matching:^BOOL(id value) { + return YES; + }]; +} + +- (id)rootMostValueOnPath:(FPath *)path matching:(BOOL (^)(id))predicate { + if (self.value != nil && predicate(self.value)) { + return self.value; + } else if (path.isEmpty) { + return nil; + } else { + return [[self.children get:path.getFront] + rootMostValueOnPath:[path popFront] + matching:predicate]; + } +} + +- (id)leafMostValueOnPath:(FPath *)path { + return [self leafMostValueOnPath:path + matching:^BOOL(id value) { + return YES; + }]; +} + +- (id)leafMostValueOnPath:(FPath *)relativePath + matching:(BOOL (^)(id))predicate { + __block id currentValue = self.value; + __block FImmutableTree *currentTree = self; + [relativePath enumerateComponentsUsingBlock:^(NSString *key, BOOL *stop) { + currentTree = [currentTree.children get:key]; + if (currentTree == nil) { + *stop = YES; + } else { + id treeValue = currentTree.value; + if (treeValue != nil && predicate(treeValue)) { + currentValue = treeValue; + } + } + }]; + return currentValue; +} + +- (BOOL)containsValueMatching:(BOOL (^)(id))predicate { + if (self.value != nil && predicate(self.value)) { + return YES; + } else { + __block BOOL found = NO; + [self.children enumerateKeysAndObjectsUsingBlock:^( + NSString *key, FImmutableTree *subtree, BOOL *stop) { + found = [subtree containsValueMatching:predicate]; + if (found) + *stop = YES; + }]; + return found; + } +} + +- (FImmutableTree *)subtreeAtPath:(FPath *)relativePath { + if ([relativePath isEmpty]) { + return self; + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *childTree = [self.children get:front]; + if (childTree != nil) { + return [childTree subtreeAtPath:[relativePath popFront]]; + } else { + return [FImmutableTree empty]; + } + } +} + +/** + * Sets a value at the specified path + */ +- (FImmutableTree *)setValue:(id)newValue atPath:(FPath *)relativePath { + if ([relativePath isEmpty]) { + return [[FImmutableTree alloc] initWithValue:newValue + children:self.children]; + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *child = [self.children get:front]; + if (child == nil) { + child = [FImmutableTree empty]; + } + FImmutableTree *newChild = [child setValue:newValue + atPath:[relativePath popFront]]; + FImmutableSortedDictionary *newChildren = + [self.children insertKey:front withValue:newChild]; + return [[FImmutableTree alloc] initWithValue:self.value + children:newChildren]; + } +} + +/** + * Remove the value at the specified path + */ +- (FImmutableTree *)removeValueAtPath:(FPath *)relativePath { + if ([relativePath isEmpty]) { + if ([self.children isEmpty]) { + return [FImmutableTree empty]; + } else { + return [[FImmutableTree alloc] initWithValue:nil + children:self.children]; + } + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *child = [self.children get:front]; + if (child) { + FImmutableTree *newChild = + [child removeValueAtPath:[relativePath popFront]]; + FImmutableSortedDictionary *newChildren; + if ([newChild isEmpty]) { + newChildren = [self.children removeKey:front]; + } else { + newChildren = [self.children insertKey:front + withValue:newChild]; + } + if (self.value == nil && [newChildren isEmpty]) { + return [FImmutableTree empty]; + } else { + return [[FImmutableTree alloc] initWithValue:self.value + children:newChildren]; + } + } else { + return self; + } + } +} + +/** + * Gets a value from the tree + */ +- (id)valueAtPath:(FPath *)relativePath { + if ([relativePath isEmpty]) { + return self.value; + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *child = [self.children get:front]; + if (child) { + return [child valueAtPath:[relativePath popFront]]; + } else { + return nil; + } + } +} + +/** + * Replaces the subtree at the specified path with the given new tree + */ +- (FImmutableTree *)setTree:(FImmutableTree *)newTree + atPath:(FPath *)relativePath { + if ([relativePath isEmpty]) { + return newTree; + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *child = [self.children get:front]; + if (child == nil) { + child = [FImmutableTree empty]; + } + FImmutableTree *newChild = [child setTree:newTree + atPath:[relativePath popFront]]; + FImmutableSortedDictionary *newChildren; + if ([newChild isEmpty]) { + newChildren = [self.children removeKey:front]; + } else { + newChildren = [self.children insertKey:front withValue:newChild]; + } + return [[FImmutableTree alloc] initWithValue:self.value + children:newChildren]; + } +} + +/** + * Performs a depth first fold on this tree. Transforms a tree into a single + * value, given a function that operates on the path to a node, an optional + * current value, and a map of the child names to folded subtrees + */ +- (id)foldWithBlock:(id (^)(FPath *path, id value, + NSDictionary *foldedChildren))block { + return [self foldWithPathSoFar:[FPath empty] withBlock:block]; +} + +/** + * Recursive helper for public facing foldWithBlock: method + */ +- (id)foldWithPathSoFar:(FPath *)pathSoFar + withBlock:(id (^)(FPath *path, id value, + NSDictionary *foldedChildren))block { + __block NSMutableDictionary *accum = [[NSMutableDictionary alloc] init]; + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + accum[childKey] = + [childTree foldWithPathSoFar:[pathSoFar childFromString:childKey] + withBlock:block]; + }]; + return block(pathSoFar, self.value, accum); +} + +/** + * Find the first matching value on the given path. Return the result of + * applying block to it. + */ +- (id)findOnPath:(FPath *)path + andApplyBlock:(id (^)(FPath *path, id value))block { + return [self findOnPath:path pathSoFar:[FPath empty] andApplyBlock:block]; +} + +- (id)findOnPath:(FPath *)pathToFollow + pathSoFar:(FPath *)pathSoFar + andApplyBlock:(id (^)(FPath *path, id value))block { + id result = self.value ? block(pathSoFar, self.value) : nil; + if (result != nil) { + return result; + } else { + if ([pathToFollow isEmpty]) { + return nil; + } else { + NSString *front = [pathToFollow getFront]; + FImmutableTree *nextChild = [self.children get:front]; + if (nextChild != nil) { + return [nextChild findOnPath:[pathToFollow popFront] + pathSoFar:[pathSoFar childFromString:front] + andApplyBlock:block]; + } else { + return nil; + } + } + } +} +/** + * Call the block on each value along the path for as long as that function + * returns true + * @return The path to the deepest location inspected + */ +- (FPath *)forEachOnPath:(FPath *)path whileBlock:(BOOL (^)(FPath *, id))block { + return [self forEachOnPath:path pathSoFar:[FPath empty] whileBlock:block]; +} + +- (FPath *)forEachOnPath:(FPath *)pathToFollow + pathSoFar:(FPath *)pathSoFar + whileBlock:(BOOL (^)(FPath *, id))block { + if ([pathToFollow isEmpty]) { + if (self.value) { + block(pathSoFar, self.value); + } + return pathSoFar; + } else { + BOOL shouldContinue = YES; + if (self.value) { + shouldContinue = block(pathSoFar, self.value); + } + if (shouldContinue) { + NSString *front = [pathToFollow getFront]; + FImmutableTree *nextChild = [self.children get:front]; + if (nextChild) { + return + [nextChild forEachOnPath:[pathToFollow popFront] + pathSoFar:[pathSoFar childFromString:front] + whileBlock:block]; + } else { + return pathSoFar; + } + } else { + return pathSoFar; + } + } +} + +- (FImmutableTree *)forEachOnPath:(FPath *)path + performBlock:(void (^)(FPath *path, id value))block { + return [self forEachOnPath:path pathSoFar:[FPath empty] performBlock:block]; +} + +- (FImmutableTree *)forEachOnPath:(FPath *)pathToFollow + pathSoFar:(FPath *)pathSoFar + performBlock:(void (^)(FPath *path, id value))block { + if ([pathToFollow isEmpty]) { + return self; + } else { + if (self.value) { + block(pathSoFar, self.value); + } + NSString *front = [pathToFollow getFront]; + FImmutableTree *nextChild = [self.children get:front]; + if (nextChild) { + return [nextChild forEachOnPath:[pathToFollow popFront] + pathSoFar:[pathSoFar childFromString:front] + performBlock:block]; + } else { + return [FImmutableTree empty]; + } + } +} +/** + * Calls the given block for each node in the tree that has a value. Called in + * depth-first order + */ +- (void)forEach:(void (^)(FPath *path, id value))block { + [self forEachPathSoFar:[FPath empty] withBlock:block]; +} + +- (void)forEachPathSoFar:(FPath *)pathSoFar + withBlock:(void (^)(FPath *path, id value))block { + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + [childTree forEachPathSoFar:[pathSoFar childFromString:childKey] + withBlock:block]; + }]; + if (self.value) { + block(pathSoFar, self.value); + } +} + +- (void)forEachChild:(void (^)(NSString *childKey, id childValue))block { + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if (childTree.value) { + block(childKey, childTree.value); + } + }]; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[FImmutableTree class]]) { + return NO; + } + FImmutableTree *other = (FImmutableTree *)object; + return (self.value == other.value || [self.value isEqual:other.value]) && + [self.children isEqual:other.children]; +} + +- (NSUInteger)hash { + return self.children.hash * 31 + [self.value hash]; +} + +- (NSString *)description { + NSMutableString *string = [[NSMutableString alloc] init]; + [string appendString:@"FImmutableTree { value="]; + [string appendString:(self.value ? [self.value description] : @"")]; + [string appendString:@", children={"]; + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + [string appendString:@" "]; + [string appendString:childKey]; + [string appendString:@"="]; + [string appendString:[childTree.value description]]; + }]; + [string appendString:@" } }"]; + return [NSString stringWithString:string]; +} + +- (NSString *)debugDescription { + return [self description]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.h new file mode 100644 index 0000000..cfa86aa --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@interface FPath : NSObject + ++ (FPath *)relativePathFrom:(FPath *)outer to:(FPath *)inner; ++ (FPath *)empty; ++ (FPath *)pathWithString:(NSString *)string; + +- (id)initWith:(NSString *)path; +- (id)initWithPieces:(NSArray *)somePieces andPieceNum:(NSInteger)aPieceNum; + +- (id)copyWithZone:(NSZone *)zone; + +- (void)enumerateComponentsUsingBlock:(void (^)(NSString *key, + BOOL *stop))block; +- (NSString *)getFront; +- (NSUInteger)length; +- (FPath *)popFront; +- (NSString *)getBack; +- (NSString *)toString; +- (NSString *)toStringWithTrailingSlash; +- (NSString *)wireFormat; +- (FPath *)parent; +- (FPath *)child:(FPath *)childPathObj; +- (FPath *)childFromString:(NSString *)childPath; +- (BOOL)isEmpty; +- (BOOL)contains:(FPath *)other; +- (NSComparisonResult)compare:(FPath *)other; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.m new file mode 100644 index 0000000..0fa734b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.m @@ -0,0 +1,304 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FPath () + +@property(nonatomic, readwrite, assign) NSInteger pieceNum; +@property(nonatomic, strong) NSArray *pieces; + +@end + +@implementation FPath + +#pragma mark - +#pragma mark Initializers + ++ (FPath *)relativePathFrom:(FPath *)outer to:(FPath *)inner { + NSString *outerFront = [outer getFront]; + NSString *innerFront = [inner getFront]; + if (outerFront == nil) { + return inner; + } else if ([outerFront isEqualToString:innerFront]) { + return [self relativePathFrom:[outer popFront] to:[inner popFront]]; + } else { + @throw [[NSException alloc] + initWithName:@"FirebaseDatabaseInternalError" + reason:[NSString + stringWithFormat: + @"innerPath (%@) is not within outerPath (%@)", + inner, outer] + userInfo:nil]; + } +} + ++ (FPath *)pathWithString:(NSString *)string { + return [[FPath alloc] initWith:string]; +} + +- (id)initWith:(NSString *)path { + self = [super init]; + if (self) { + NSArray *pathPieces = [path componentsSeparatedByString:@"/"]; + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; + for (NSInteger i = 0; i < pathPieces.count; i++) { + NSString *piece = [pathPieces objectAtIndex:i]; + if (piece.length > 0) { + [newPieces addObject:piece]; + } + } + + self.pieces = newPieces; + self.pieceNum = 0; + } + return self; +} + +- (id)initWithPieces:(NSArray *)somePieces andPieceNum:(NSInteger)aPieceNum { + self = [super init]; + if (self) { + self.pieceNum = aPieceNum; + self.pieces = somePieces; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + // Immutable, so it's safe to return self + return self; +} + +- (NSString *)description { + return [self toString]; +} + +#pragma mark - +#pragma mark Public methods + +- (NSString *)getFront { + if (self.pieceNum >= self.pieces.count) { + return nil; + } + return [self.pieces objectAtIndex:self.pieceNum]; +} + +/** + * @return The number of segments in this path + */ +- (NSUInteger)length { + return self.pieces.count - self.pieceNum; +} + +- (FPath *)popFront { + NSInteger newPieceNum = self.pieceNum; + if (newPieceNum < self.pieces.count) { + newPieceNum++; + } + return [[FPath alloc] initWithPieces:self.pieces andPieceNum:newPieceNum]; +} + +- (NSString *)getBack { + if (self.pieceNum < self.pieces.count) { + return [self.pieces lastObject]; + } else { + return nil; + } +} + +- (NSString *)toString { + return [self toStringWithTrailingSlash:NO]; +} + +- (NSString *)toStringWithTrailingSlash { + return [self toStringWithTrailingSlash:YES]; +} + +- (NSString *)toStringWithTrailingSlash:(BOOL)trailingSlash { + NSMutableString *pathString = [[NSMutableString alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { + [pathString appendString:@"/"]; + [pathString appendString:[self.pieces objectAtIndex:i]]; + } + if ([pathString length] == 0) { + return @"/"; + } else { + if (trailingSlash) { + [pathString appendString:@"/"]; + } + return pathString; + } +} + +- (NSString *)wireFormat { + if ([self isEmpty]) { + return @"/"; + } else { + NSMutableString *pathString = [[NSMutableString alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { + if (i > self.pieceNum) { + [pathString appendString:@"/"]; + } + [pathString appendString:[self.pieces objectAtIndex:i]]; + } + return pathString; + } +} + +- (FPath *)parent { + if (self.pieceNum >= self.pieces.count) { + return nil; + } else { + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count - 1; i++) { + [newPieces addObject:[self.pieces objectAtIndex:i]]; + } + return [[FPath alloc] initWithPieces:newPieces andPieceNum:0]; + } +} + +- (FPath *)child:(FPath *)childPathObj { + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { + [newPieces addObject:[self.pieces objectAtIndex:i]]; + } + + for (NSInteger i = childPathObj.pieceNum; i < childPathObj.pieces.count; + i++) { + [newPieces addObject:[childPathObj.pieces objectAtIndex:i]]; + } + + return [[FPath alloc] initWithPieces:newPieces andPieceNum:0]; +} + +- (FPath *)childFromString:(NSString *)childPath { + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { + [newPieces addObject:[self.pieces objectAtIndex:i]]; + } + + NSArray *pathPieces = [childPath componentsSeparatedByString:@"/"]; + for (unsigned int i = 0; i < pathPieces.count; i++) { + NSString *piece = [pathPieces objectAtIndex:i]; + if (piece.length > 0) { + [newPieces addObject:piece]; + } + } + + return [[FPath alloc] initWithPieces:newPieces andPieceNum:0]; +} + +/** + * @return True if there are no segments in this path + */ +- (BOOL)isEmpty { + return self.pieceNum >= self.pieces.count; +} + +/** + * @return Singleton to represent an empty path + */ ++ (FPath *)empty { + static dispatch_once_t oneEmptyPath; + static FPath *emptyPath; + dispatch_once(&oneEmptyPath, ^{ + emptyPath = [[FPath alloc] initWith:@""]; + }); + return emptyPath; +} + +- (BOOL)contains:(FPath *)other { + if (self.length > other.length) { + return NO; + } + + NSInteger i = self.pieceNum; + NSInteger j = other.pieceNum; + while (i < self.pieces.count) { + NSString *thisSeg = [self.pieces objectAtIndex:i]; + NSString *otherSeg = [other.pieces objectAtIndex:j]; + if (![thisSeg isEqualToString:otherSeg]) { + return NO; + } + ++i; + ++j; + } + return YES; +} + +- (void)enumerateComponentsUsingBlock:(void (^)(NSString *, BOOL *))block { + BOOL stop = NO; + for (NSInteger i = self.pieceNum; !stop && i < self.pieces.count; i++) { + block(self.pieces[i], &stop); + } +} + +- (NSComparisonResult)compare:(FPath *)other { + NSInteger myCount = self.pieces.count; + NSInteger otherCount = other.pieces.count; + for (NSInteger i = self.pieceNum, j = other.pieceNum; + i < myCount && j < otherCount; i++, j++) { + NSComparisonResult comparison = [FUtilities compareKey:self.pieces[i] + toKey:other.pieces[j]]; + if (comparison != NSOrderedSame) { + return comparison; + } + } + if (self.length < other.length) { + return NSOrderedAscending; + } else if (other.length < self.length) { + return NSOrderedDescending; + } else { + NSAssert(self.length == other.length, + @"Paths must be the same lengths"); + return NSOrderedSame; + } +} + +/** + * @return YES if paths are the same + */ +- (BOOL)isEqual:(id)other { + if (other == self) { + return YES; + } + if (!other || ![other isKindOfClass:[self class]]) { + return NO; + } + FPath *otherPath = (FPath *)other; + if (self.length != otherPath.length) { + return NO; + } + for (NSUInteger i = self.pieceNum, j = otherPath.pieceNum; + i < self.pieces.count; i++, j++) { + if (![self.pieces[i] isEqualToString:otherPath.pieces[j]]) { + return NO; + } + } + return YES; +} + +- (NSUInteger)hash { + NSUInteger hashCode = 0; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { + hashCode = hashCode * 37 + [self.pieces[i] hash]; + } + return hashCode; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.h new file mode 100644 index 0000000..7eea6bf --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.h @@ -0,0 +1,52 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h" +#import + +@interface FTree : NSObject + +- (id)init; +- (id)initWithName:(NSString *)aName + withParent:(FTree *)aParent + withNode:(FTreeNode *)aNode; + +- (FTree *)subTree:(FPath *)path; +- (id)getValue; +- (void)setValue:(id)value; +- (void)clear; +- (BOOL)hasChildren; +- (BOOL)isEmpty; +- (void)forEachChildMutationSafe:(void (^)(FTree *))action; +- (void)forEachChild:(void (^)(FTree *))action; +- (void)forEachDescendant:(void (^)(FTree *))action; +- (void)forEachDescendant:(void (^)(FTree *))action + includeSelf:(BOOL)incSelf + childrenFirst:(BOOL)childFirst; +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action; +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action includeSelf:(BOOL)incSelf; +- (void)forEachImmediateDescendantWithValue:(void (^)(FTree *))action; +- (BOOL)valueExistsAtOrAbove:(FPath *)path; +- (FPath *)path; +- (void)updateParents; +- (void)updateChild:(NSString *)childName withNode:(FTree *)child; + +@property(nonatomic, strong) NSString *name; +@property(nonatomic, strong) FTree *parent; +@property(nonatomic, strong) FTreeNode *node; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.m new file mode 100644 index 0000000..4eabb08 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.m @@ -0,0 +1,193 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@implementation FTree + +@synthesize name; +@synthesize parent; +@synthesize node; + +- (id)init { + self = [super init]; + if (self) { + self.name = @""; + self.parent = nil; + self.node = [[FTreeNode alloc] init]; + } + return self; +} + +- (id)initWithName:(NSString *)aName + withParent:(FTree *)aParent + withNode:(FTreeNode *)aNode { + self = [super init]; + if (self) { + self.name = aName != nil ? aName : @""; + self.parent = aParent != nil ? aParent : nil; + self.node = aNode != nil ? aNode : [[FTreeNode alloc] init]; + } + return self; +} + +- (FTree *)subTree:(FPath *)path { + FTree *child = self; + NSString *next = [path getFront]; + while (next != nil) { + FTreeNode *childNode = child.node.children[next]; + if (childNode == nil) { + childNode = [[FTreeNode alloc] init]; + } + child = [[FTree alloc] initWithName:next + withParent:child + withNode:childNode]; + path = [path popFront]; + next = [path getFront]; + } + return child; +} + +- (id)getValue { + return self.node.value; +} + +- (void)setValue:(id)value { + self.node.value = value; + [self updateParents]; +} + +- (void)clear { + self.node.value = nil; + [self.node.children removeAllObjects]; + self.node.childCount = 0; + [self updateParents]; +} + +- (BOOL)hasChildren { + return self.node.childCount > 0; +} + +- (BOOL)isEmpty { + return [self getValue] == nil && ![self hasChildren]; +} + +- (void)forEachChild:(void (^)(FTree *))action { + for (NSString *key in self.node.children) { + action([[FTree alloc] + initWithName:key + withParent:self + withNode:[self.node.children objectForKey:key]]); + } +} + +- (void)forEachChildMutationSafe:(void (^)(FTree *))action { + for (NSString *key in [self.node.children copy]) { + action([[FTree alloc] + initWithName:key + withParent:self + withNode:[self.node.children objectForKey:key]]); + } +} + +- (void)forEachDescendant:(void (^)(FTree *))action { + [self forEachDescendant:action includeSelf:NO childrenFirst:NO]; +} + +- (void)forEachDescendant:(void (^)(FTree *))action + includeSelf:(BOOL)incSelf + childrenFirst:(BOOL)childFirst { + if (incSelf && !childFirst) { + action(self); + } + + [self forEachChild:^(FTree *child) { + [child forEachDescendant:action includeSelf:YES childrenFirst:childFirst]; + }]; + + if (incSelf && childFirst) { + action(self); + } +} + +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action { + return [self forEachAncestor:action includeSelf:NO]; +} + +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action includeSelf:(BOOL)incSelf { + FTree *aNode = (incSelf) ? self : self.parent; + while (aNode != nil) { + if (action(aNode)) { + return YES; + } + aNode = aNode.parent; + } + return NO; +} + +- (void)forEachImmediateDescendantWithValue:(void (^)(FTree *))action { + [self forEachChild:^(FTree *child) { + if ([child getValue] != nil) { + action(child); + } else { + [child forEachImmediateDescendantWithValue:action]; + } + }]; +} + +- (BOOL)valueExistsAtOrAbove:(FPath *)path { + FTreeNode *aNode = self.node; + while (aNode != nil) { + if (aNode.value != nil) { + return YES; + } + aNode = [aNode.children objectForKey:path.getFront]; + path = [path popFront]; + } + // XXX Check with Michael if this is correct; deviates from JS. + return NO; +} + +- (FPath *)path { + return [[FPath alloc] + initWith:(self.parent == nil) + ? self.name + : [NSString stringWithFormat:@"%@/%@", [self.parent path], + self.name]]; +} + +- (void)updateParents { + [self.parent updateChild:self.name withNode:self]; +} + +- (void)updateChild:(NSString *)childName withNode:(FTree *)child { + BOOL childEmpty = [child isEmpty]; + BOOL childExists = self.node.children[childName] != nil; + if (childEmpty && childExists) { + [self.node.children removeObjectForKey:childName]; + self.node.childCount = self.node.childCount - 1; + [self updateParents]; + } else if (!childEmpty && !childExists) { + [self.node.children setObject:child.node forKey:childName]; + self.node.childCount = self.node.childCount + 1; + [self updateParents]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h new file mode 100644 index 0000000..549f3b1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h @@ -0,0 +1,25 @@ +/* + * 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 + +@interface FTreeNode : NSObject + +@property(nonatomic, strong) NSMutableDictionary *children; +@property(nonatomic, readwrite, assign) int childCount; +@property(nonatomic, strong) id value; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.m new file mode 100644 index 0000000..cfd3fa4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h" + +@implementation FTreeNode + +@synthesize children; +@synthesize childCount; +@synthesize value; + +- (id)init { + self = [super init]; + if (self) { + self.children = [[NSMutableDictionary alloc] init]; + self.childCount = 0; + self.value = nil; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.h new file mode 100644 index 0000000..eff0cb0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@protocol FNode; +@class FIndexedNode; +@class FPath; + +/** + * A cache node only stores complete children. Additionally it holds a flag + * whether the node can be considered fully initialized in the sense that we + * know at one point in time, this represented a valid state of the world, e.g. + * initialized with data from the server, or a complete overwrite by the client. + * It is not necessarily complete because it may have been from a tagged query. + * The filtered flag also tracks whether a node potentially had children removed + * due to a filter. + */ +@interface FCacheNode : NSObject + +- (id)initWithIndexedNode:(FIndexedNode *)indexedNode + isFullyInitialized:(BOOL)fullyInitialized + isFiltered:(BOOL)filtered; + +- (BOOL)isCompleteForPath:(FPath *)path; +- (BOOL)isCompleteForChild:(NSString *)childKey; + +@property(nonatomic, readonly) BOOL isFullyInitialized; +@property(nonatomic, readonly) BOOL isFiltered; +@property(nonatomic, strong, readonly) FIndexedNode *indexedNode; +@property(nonatomic, strong, readonly) id node; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.m new file mode 100644 index 0000000..6129995 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.m @@ -0,0 +1,60 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FCacheNode () +@property(nonatomic, readwrite) BOOL isFullyInitialized; +@property(nonatomic, readwrite) BOOL isFiltered; +@property(nonatomic, strong, readwrite) FIndexedNode *indexedNode; +@end + +@implementation FCacheNode +- (id)initWithIndexedNode:(FIndexedNode *)indexedNode + isFullyInitialized:(BOOL)fullyInitialized + isFiltered:(BOOL)filtered { + self = [super init]; + if (self) { + self.indexedNode = indexedNode; + self.isFullyInitialized = fullyInitialized; + self.isFiltered = filtered; + } + return self; +} + +- (BOOL)isCompleteForPath:(FPath *)path { + if (path.isEmpty) { + return self.isFullyInitialized && !self.isFiltered; + } else { + NSString *childKey = [path getFront]; + return [self isCompleteForChild:childKey]; + } +} + +- (BOOL)isCompleteForChild:(NSString *)childKey { + return (self.isFullyInitialized && !self.isFiltered) || + [self.node hasChild:childKey]; +} + +- (id)node { + return self.indexedNode.node; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.h new file mode 100644 index 0000000..bd762b8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.h @@ -0,0 +1,31 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FEvent.h" +#import + +@protocol FEventRegistration; + +@interface FCancelEvent : NSObject + +- initWithEventRegistration:(id)eventRegistration + error:(NSError *)error + path:(FPath *)path; + +@property(nonatomic, strong, readonly) NSError *error; +@property(nonatomic, strong, readonly) FPath *path; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.m new file mode 100644 index 0000000..1ddd436 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.m @@ -0,0 +1,57 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FCancelEvent.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" + +@interface FCancelEvent () +@property(nonatomic, strong) id eventRegistration; +@property(nonatomic, strong, readwrite) NSError *error; +@property(nonatomic, strong, readwrite) FPath *path; +@end + +@implementation FCancelEvent + +@synthesize eventRegistration; +@synthesize error; +@synthesize path; + +- (id)initWithEventRegistration:(id)registration + error:(NSError *)anError + path:(FPath *)aPath { + self = [super init]; + if (self) { + self.eventRegistration = registration; + self.error = anError; + self.path = aPath; + } + return self; +} + +- (void)fireEventOnQueue:(dispatch_queue_t)queue { + [self.eventRegistration fireEvent:self queue:queue]; +} + +- (BOOL)isCancelEvent { + return YES; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@: cancel", self.path]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.h new file mode 100644 index 0000000..7fbdfbe --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.h @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FChange : NSObject + +@property(nonatomic, readonly) FIRDataEventType type; +@property(nonatomic, strong, readonly) FIndexedNode *indexedNode; +@property(nonatomic, strong, readonly) NSString *childKey; +@property(nonatomic, strong, readonly) NSString *prevKey; +@property(nonatomic, strong, readonly) FIndexedNode *oldIndexedNode; + +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode; +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode + childKey:(NSString *)childKey; +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode + childKey:(NSString *)childKey + oldIndexedNode:(FIndexedNode *)oldIndexedNode; + +- (FChange *)changeWithPrevKey:(NSString *)prevKey; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.m new file mode 100644 index 0000000..e67d078 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.m @@ -0,0 +1,72 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FChange.h" + +@interface FChange () + +@property(nonatomic, strong, readwrite) NSString *prevKey; + +@end + +@implementation FChange + +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode { + return [self initWithType:type + indexedNode:indexedNode + childKey:nil + oldIndexedNode:nil]; +} + +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode + childKey:(NSString *)childKey { + return [self initWithType:type + indexedNode:indexedNode + childKey:childKey + oldIndexedNode:nil]; +} + +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode + childKey:(NSString *)childKey + oldIndexedNode:(FIndexedNode *)oldIndexedNode { + self = [super init]; + if (self != nil) { + self->_type = type; + self->_indexedNode = indexedNode; + self->_childKey = childKey; + self->_oldIndexedNode = oldIndexedNode; + } + return self; +} + +- (FChange *)changeWithPrevKey:(NSString *)prevKey { + FChange *newChange = [[FChange alloc] initWithType:self.type + indexedNode:self.indexedNode + childKey:self.childKey + oldIndexedNode:self.oldIndexedNode]; + newChange.prevKey = prevKey; + return newChange; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"event: %d, data: %@", (int)self.type, + [self.indexedNode.node val]]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h new file mode 100644 index 0000000..d7d200d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h @@ -0,0 +1,37 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@class FRepo; + +@interface FChildEventRegistration : NSObject + +- (id)initWithRepo:(FRepo *)repo + handle:(FIRDatabaseHandle)fHandle + callbacks:(NSDictionary *)callbackBlocks + cancelCallback:(fbt_void_nserror)cancelCallbackBlock; + +/** + * Maps FIRDataEventType (as NSNumber) to fbt_void_datasnapshot_nsstring + */ +@property(nonatomic, copy, readonly) NSDictionary *callbacks; +@property(nonatomic, copy, readonly) fbt_void_nserror cancelCallback; +@property(nonatomic, readonly) FIRDatabaseHandle handle; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.m new file mode 100644 index 0000000..eb25430 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.m @@ -0,0 +1,112 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/View/FCancelEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FDataEvent.h" + +@interface FChildEventRegistration () +@property(nonatomic, strong) FRepo *repo; +@property(nonatomic, copy, readwrite) NSDictionary *callbacks; +@property(nonatomic, copy, readwrite) fbt_void_nserror cancelCallback; +@property(nonatomic, readwrite) FIRDatabaseHandle handle; +@end + +@implementation FChildEventRegistration + +- (id)initWithRepo:(id)repo + handle:(FIRDatabaseHandle)fHandle + callbacks:(NSDictionary *)callbackBlocks + cancelCallback:(fbt_void_nserror)cancelCallbackBlock { + self = [super init]; + if (self) { + self.repo = repo; + self.handle = fHandle; + self.callbacks = callbackBlocks; + self.cancelCallback = cancelCallbackBlock; + } + return self; +} + +- (BOOL)responseTo:(FIRDataEventType)eventType { + return self.callbacks != nil && + [self.callbacks + objectForKey:[NSNumber numberWithInteger:eventType]] != nil; +} + +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query { + FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] + initWithRepo:self.repo + path:[query.path childFromString:change.childKey]]; + FIRDataSnapshot *snapshot = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:change.indexedNode]; + + FDataEvent *eventData = + [[FDataEvent alloc] initWithEventType:change.type + eventRegistration:self + dataSnapshot:snapshot + prevName:change.prevKey]; + return eventData; +} + +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue { + if ([event isCancelEvent]) { + FCancelEvent *cancelEvent = event; + FFLog(@"I-RDB061001", @"Raising cancel value event on %@", event.path); + NSAssert( + self.cancelCallback != nil, + @"Raising a cancel event on a listener with no cancel callback"); + dispatch_async(queue, ^{ + self.cancelCallback(cancelEvent.error); + }); + } else if (self.callbacks != nil) { + FDataEvent *dataEvent = event; + FFLog(@"I-RDB061002", @"Raising event callback (%ld) on %@", + (long)dataEvent.eventType, dataEvent.path); + fbt_void_datasnapshot_nsstring callback = [self.callbacks + objectForKey:[NSNumber numberWithInteger:dataEvent.eventType]]; + + if (callback != nil) { + dispatch_async(queue, ^{ + callback(dataEvent.snapshot, dataEvent.prevName); + }); + } + } +} + +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path { + if (self.cancelCallback != nil) { + return [[FCancelEvent alloc] initWithEventRegistration:self + error:error + path:path]; + } else { + return nil; + } +} + +- (BOOL)matches:(id)other { + return self.handle == NSNotFound || other.handle == NSNotFound || + self.handle == other.handle; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.h new file mode 100644 index 0000000..360c364 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.h @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FEvent.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h" +#import + +@protocol FEventRegistration; +@protocol FIndex; + +@interface FDataEvent : NSObject + +- initWithEventType:(FIRDataEventType)type + eventRegistration:(id)eventRegistration + dataSnapshot:(FIRDataSnapshot *)dataSnapshot; +- initWithEventType:(FIRDataEventType)type + eventRegistration:(id)eventRegistration + dataSnapshot:(FIRDataSnapshot *)snapshot + prevName:(NSString *)prevName; + +@property(nonatomic, strong, readonly) id eventRegistration; +@property(nonatomic, strong, readonly) FIRDataSnapshot *snapshot; +@property(nonatomic, strong, readonly) NSString *prevName; +@property(nonatomic, readonly) FIRDataEventType eventType; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.m new file mode 100644 index 0000000..60a467e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.m @@ -0,0 +1,83 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FDataEvent.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/FIndex.h" + +@interface FDataEvent () +@property(nonatomic, strong, readwrite) id + eventRegistration; +@property(nonatomic, strong, readwrite) FIRDataSnapshot *snapshot; +@property(nonatomic, strong, readwrite) NSString *prevName; +@property(nonatomic, readwrite) FIRDataEventType eventType; +@end + +@implementation FDataEvent + +@synthesize eventRegistration; +@synthesize snapshot; +@synthesize prevName; +@synthesize eventType; + +- (id)initWithEventType:(FIRDataEventType)type + eventRegistration:(id)registration + dataSnapshot:(FIRDataSnapshot *)dataSnapshot { + return [self initWithEventType:type + eventRegistration:registration + dataSnapshot:dataSnapshot + prevName:nil]; +} + +- (id)initWithEventType:(FIRDataEventType)type + eventRegistration:(id)registration + dataSnapshot:(FIRDataSnapshot *)dataSnapshot + prevName:(NSString *)previousName { + self = [super init]; + if (self) { + self.eventRegistration = registration; + self.snapshot = dataSnapshot; + self.prevName = previousName; + self.eventType = type; + } + return self; +} + +- (FPath *)path { + // Used for logging, so delay calculation + FIRDatabaseReference *ref = self.snapshot.ref; + if (self.eventType == FIRDataEventTypeValue) { + return ref.path; + } else { + return ref.parent.path; + } +} + +- (void)fireEventOnQueue:(dispatch_queue_t)queue { + [self.eventRegistration fireEvent:self queue:queue]; +} + +- (BOOL)isCancelEvent { + return NO; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"event %d, data: %@", (int)eventType, + [snapshot value]]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEvent.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEvent.h new file mode 100644 index 0000000..f4fa4d6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEvent.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import + +@class FPath; + +@protocol FEvent +- (FPath *)path; +- (void)fireEventOnQueue:(dispatch_queue_t)queue; +- (BOOL)isCancelEvent; +- (NSString *)description; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.h new file mode 100644 index 0000000..186bb24 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.h @@ -0,0 +1,36 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FTypedefs.h" + +@class FPath; +@class FRepo; +@class FIRDatabaseConfig; + +/** + * Left as instance methods rather than class methods so that we could + * potentially callback on different queues for different repos. This is + * semi-parallel to JS's FEventQueue + */ +@interface FEventRaiser : NSObject + +- (id)initWithQueue:(dispatch_queue_t)queue; + +- (void)raiseEvents:(NSArray *)eventDataList; +- (void)raiseCallback:(fbt_void_void)callback; +- (void)raiseCallbacks:(NSArray *)callbackList; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.m new file mode 100644 index 0000000..2e6ebe6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.m @@ -0,0 +1,74 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FEventRaiser.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseDatabase/Sources/Core/View/FDataEvent.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h" + +@interface FEventRaiser () + +@property(nonatomic, strong) dispatch_queue_t queue; + +@end + +/** + * This class exists for symmetry with other clients, but since events are + * async, we don't need to do the complicated stuff the JS client does to + * preserve event order. + */ +@implementation FEventRaiser + +- (id)init { + [NSException raise:NSInternalInconsistencyException + format:@"Can't use default constructor"]; + return nil; +} + +- (id)initWithQueue:(dispatch_queue_t)queue { + self = [super init]; + if (self != nil) { + self->_queue = queue; + } + return self; +} + +- (void)raiseEvents:(NSArray *)eventDataList { + for (id event in eventDataList) { + [event fireEventOnQueue:self.queue]; + } +} + +- (void)raiseCallback:(fbt_void_void)callback { + dispatch_async(self.queue, callback); +} + +- (void)raiseCallbacks:(NSArray *)callbackList { + for (fbt_void_void callback in callbackList) { + dispatch_async(self.queue, callback); + } +} + ++ (void)raiseCallbacks:(NSArray *)callbackList queue:(dispatch_queue_t)queue { + for (fbt_void_void callback in callbackList) { + dispatch_async(queue, callback); + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRegistration.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRegistration.h new file mode 100644 index 0000000..a1d9c05 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRegistration.h @@ -0,0 +1,38 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import + +@protocol FEvent; +@class FDataEvent; +@class FCancelEvent; +@class FQuerySpec; + +@protocol FEventRegistration +- (BOOL)responseTo:(FIRDataEventType)eventType; +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query; +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue; +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path; +/** + * Used to figure out what event registration match the event registration that + * needs to be removed. + */ +- (BOOL)matches:(id)other; +@property(nonatomic, readonly) FIRDatabaseHandle handle; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h new file mode 100644 index 0000000..5111b20 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h @@ -0,0 +1,28 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" + +/** + * A singleton event registration to mark a query as keep synced + */ +@interface FKeepSyncedEventRegistration : NSObject + ++ (FKeepSyncedEventRegistration *)instance; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.m new file mode 100644 index 0000000..9c26f44 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.m @@ -0,0 +1,70 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h" + +@interface FKeepSyncedEventRegistration () + +@end + +@implementation FKeepSyncedEventRegistration + ++ (FKeepSyncedEventRegistration *)instance { + static dispatch_once_t onceToken; + static FKeepSyncedEventRegistration *keepSynced; + dispatch_once(&onceToken, ^{ + keepSynced = [[FKeepSyncedEventRegistration alloc] init]; + }); + return keepSynced; +} + +- (BOOL)responseTo:(FIRDataEventType)eventType { + return NO; +} + +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query { + [NSException + raise:NSInternalInconsistencyException + format:@"Should never create event for FKeepSyncedEventRegistration"]; + return nil; +} + +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue { + [NSException + raise:NSInternalInconsistencyException + format:@"Should never raise event for FKeepSyncedEventRegistration"]; +} + +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path { + // Don't create cancel events.... + return nil; +} + +- (FIRDatabaseHandle)handle { + // TODO[offline]: returning arbitray, can't return NSNotFound since that is + // used to match other event registrations We should really redo this to + // match on different kind of events (single observer, all observers, + // cancelled) rather than on a NSNotFound handle... + return NSNotFound - 1; +} + +- (BOOL)matches:(id)other { + // Only matches singleton instance + return self == other; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h new file mode 100644 index 0000000..dea4736 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h @@ -0,0 +1,34 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@class FRepo; + +@interface FValueEventRegistration : NSObject + +- (id)initWithRepo:(FRepo *)repo + handle:(FIRDatabaseHandle)fHandle + callback:(fbt_void_datasnapshot)callbackBlock + cancelCallback:(fbt_void_nserror)cancelCallbackBlock; + +@property(nonatomic, copy, readonly) fbt_void_datasnapshot callback; +@property(nonatomic, copy, readonly) fbt_void_nserror cancelCallback; +@property(nonatomic, readonly) FIRDatabaseHandle handle; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.m new file mode 100644 index 0000000..c839f01 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.m @@ -0,0 +1,102 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/View/FCancelEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FDataEvent.h" + +@interface FValueEventRegistration () +@property(nonatomic, strong) FRepo *repo; +@property(nonatomic, copy, readwrite) fbt_void_datasnapshot callback; +@property(nonatomic, copy, readwrite) fbt_void_nserror cancelCallback; +@property(nonatomic, readwrite) FIRDatabaseHandle handle; +@end + +@implementation FValueEventRegistration + +- (id)initWithRepo:(FRepo *)repo + handle:(FIRDatabaseHandle)fHandle + callback:(fbt_void_datasnapshot)callbackBlock + cancelCallback:(fbt_void_nserror)cancelCallbackBlock { + self = [super init]; + if (self) { + self.repo = repo; + self.handle = fHandle; + self.callback = callbackBlock; + self.cancelCallback = cancelCallbackBlock; + } + return self; +} + +- (BOOL)responseTo:(FIRDataEventType)eventType { + return eventType == FIRDataEventTypeValue; +} + +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query { + FIRDatabaseReference *ref = + [[FIRDatabaseReference alloc] initWithRepo:self.repo path:query.path]; + FIRDataSnapshot *snapshot = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:change.indexedNode]; + FDataEvent *eventData = + [[FDataEvent alloc] initWithEventType:FIRDataEventTypeValue + eventRegistration:self + dataSnapshot:snapshot]; + return eventData; +} + +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue { + if ([event isCancelEvent]) { + FCancelEvent *cancelEvent = event; + FFLog(@"I-RDB065001", @"Raising cancel value event on %@", event.path); + NSAssert( + self.cancelCallback != nil, + @"Raising a cancel event on a listener with no cancel callback"); + dispatch_async(queue, ^{ + self.cancelCallback(cancelEvent.error); + }); + } else if (self.callback != nil) { + FDataEvent *dataEvent = event; + FFLog(@"I-RDB065002", @"Raising value event on %@", + dataEvent.snapshot.key); + dispatch_async(queue, ^{ + self.callback(dataEvent.snapshot); + }); + } +} + +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path { + if (self.cancelCallback != nil) { + return [[FCancelEvent alloc] initWithEventRegistration:self + error:error + path:path]; + } else { + return nil; + } +} + +- (BOOL)matches:(id)other { + return self.handle == NSNotFound || other.handle == NSNotFound || + self.handle == other.handle; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.h new file mode 100644 index 0000000..ba31209 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.h @@ -0,0 +1,58 @@ +/* + * 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 + +@protocol FNode; +@protocol FOperation; +@protocol FEventRegistration; +@class FWriteTreeRef; +@class FQuerySpec; +@class FChange; +@class FPath; +@class FViewCache; + +@interface FViewOperationResult : NSObject + +@property(nonatomic, strong, readonly) NSArray *changes; +@property(nonatomic, strong, readonly) NSArray *events; + +@end + +@interface FView : NSObject + +@property(nonatomic, strong, readonly) FQuerySpec *query; + +- (id)initWithQuery:(FQuerySpec *)query + initialViewCache:(FViewCache *)initialViewCache; + +- (id)eventCache; +- (id)serverCache; +- (id)completeEventCache; +- (id)completeServerCacheFor:(FPath *)path; +- (id)completeEventCacheFor:(FPath *)path; +- (BOOL)isEmpty; + +- (void)addEventRegistration:(id)eventRegistration; +- (NSArray *)removeEventRegistration:(id)eventRegistration + cancelError:(NSError *)cancelError; + +- (FViewOperationResult *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache; +- (NSArray *)initialEvents:(id)registration; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.m new file mode 100644 index 0000000..8612def --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.m @@ -0,0 +1,285 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FView.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperation.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Core/View/FCancelEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FViewCache.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h" +#import "FirebaseDatabase/Sources/FEventGenerator.h" +#import "FirebaseDatabase/Sources/FViewProcessor.h" +#import "FirebaseDatabase/Sources/FViewProcessorResult.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FViewOperationResult () + +@property(nonatomic, strong, readwrite) NSArray *changes; +@property(nonatomic, strong, readwrite) NSArray *events; + +@end + +@implementation FViewOperationResult + +- (id)initWithChanges:(NSArray *)changes events:(NSArray *)events { + self = [super init]; + if (self != nil) { + self->_changes = changes; + self->_events = events; + } + return self; +} + +@end + +/** + * A view represents a specific location and query that has 1 or more event + * registrations. + * + * It does several things: + * - Maintains the list of event registration for this location/query. + * - Maintains a cache of the data visible for this location/query. + * - Applies new operations (via applyOperation), updates the cache, and based + * on the event registrations returns the set of events to be raised. + */ +@interface FView () + +@property(nonatomic, strong, readwrite) FQuerySpec *query; +@property(nonatomic, strong) FViewProcessor *processor; +@property(nonatomic, strong) FViewCache *viewCache; +@property(nonatomic, strong) NSMutableArray *eventRegistrations; +@property(nonatomic, strong) FEventGenerator *eventGenerator; + +@end + +@implementation FView +- (id)initWithQuery:(FQuerySpec *)query + initialViewCache:(FViewCache *)initialViewCache { + self = [super init]; + if (self) { + self.query = query; + + FIndexedFilter *indexFilter = + [[FIndexedFilter alloc] initWithIndex:query.index]; + id filter = query.params.nodeFilter; + self.processor = [[FViewProcessor alloc] initWithFilter:filter]; + FCacheNode *initialServerCache = initialViewCache.cachedServerSnap; + FCacheNode *initialEventCache = initialViewCache.cachedEventSnap; + + // Don't filter server node with other filter than index, wait for + // tagged listen + FIndexedNode *emptyIndexedNode = + [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] + index:query.index]; + FIndexedNode *serverSnap = + [indexFilter updateFullNode:emptyIndexedNode + withNewNode:initialServerCache.indexedNode + accumulator:nil]; + FIndexedNode *eventSnap = + [filter updateFullNode:emptyIndexedNode + withNewNode:initialEventCache.indexedNode + accumulator:nil]; + FCacheNode *newServerCache = [[FCacheNode alloc] + initWithIndexedNode:serverSnap + isFullyInitialized:initialServerCache.isFullyInitialized + isFiltered:indexFilter.filtersNodes]; + FCacheNode *newEventCache = [[FCacheNode alloc] + initWithIndexedNode:eventSnap + isFullyInitialized:initialEventCache.isFullyInitialized + isFiltered:filter.filtersNodes]; + + self.viewCache = [[FViewCache alloc] initWithEventCache:newEventCache + serverCache:newServerCache]; + + self.eventRegistrations = [[NSMutableArray alloc] init]; + + self.eventGenerator = [[FEventGenerator alloc] initWithQuery:query]; + } + + return self; +} + +- (id)serverCache { + return self.viewCache.cachedServerSnap.node; +} + +- (id)eventCache { + return self.viewCache.cachedEventSnap.node; +} + +- (id)completeEventCache { + return self.viewCache.completeEventSnap; +} + +- (id)completeServerCacheFor:(FPath *)path { + id cache = self.viewCache.completeServerSnap; + if (cache) { + // If this isn't a "loadsAllData" view, then cache isn't actually a + // complete cache and we need to see if it contains the child we're + // interested in. + if ([self.query loadsAllData] || + (!path.isEmpty && + ![cache getImmediateChild:path.getFront].isEmpty)) { + return [cache getChild:path]; + } + } + return nil; +} + +- (id)completeEventCacheFor:(FPath *)path { + id cache = self.viewCache.completeEventSnap; + if (cache) { + // If this isn't a "loadsAllData" view, then cache isn't actually a + // complete cache and we need to see if it contains the child we're + // interested in. + if ([self.query loadsAllData] || + (!path.isEmpty && + ![cache getImmediateChild:path.getFront].isEmpty)) { + return [cache getChild:path]; + } + } + return nil; +} + +- (BOOL)isEmpty { + return self.eventRegistrations.count == 0; +} + +- (void)addEventRegistration:(id)eventRegistration { + [self.eventRegistrations addObject:eventRegistration]; +} + +/** + * @param eventRegistration If null, remove all callbacks. + * @param cancelError If a cancelError is provided, appropriate cancel events + * will be returned. + * @return Cancel events, if cancelError was provided. + */ +- (NSArray *)removeEventRegistration:(id)eventRegistration + cancelError:(NSError *)cancelError { + NSMutableArray *cancelEvents = [[NSMutableArray alloc] init]; + if (cancelError != nil) { + NSAssert(eventRegistration == nil, + @"A cancel should cancel all event registrations."); + FPath *path = self.query.path; + for (id registration in self.eventRegistrations) { + FCancelEvent *maybeEvent = + [registration createCancelEventFromError:cancelError path:path]; + if (maybeEvent) { + [cancelEvents addObject:maybeEvent]; + } + } + } + + if (eventRegistration) { + NSUInteger i = 0; + while (i < self.eventRegistrations.count) { + id existing = self.eventRegistrations[i]; + if ([existing matches:eventRegistration]) { + [self.eventRegistrations removeObjectAtIndex:i]; + } else { + i++; + } + } + } else { + [self.eventRegistrations removeAllObjects]; + } + return cancelEvents; +} + +/** + * Applies the given Operation, updates our cache, and returns the appropriate + * events and changes + */ +- (FViewOperationResult *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache { + if (operation.type == FOperationTypeMerge && + operation.source.queryParams != nil) { + NSAssert(self.viewCache.completeServerSnap != nil, + @"We should always have a full cache before handling merges"); + NSAssert(self.viewCache.completeEventSnap != nil, + @"Missing event cache, even though we have a server cache"); + } + FViewCache *oldViewCache = self.viewCache; + FViewProcessorResult *result = + [self.processor applyOperationOn:oldViewCache + operation:operation + writesCache:writesCache + completeCache:optCompleteServerCache]; + + NSAssert(result.viewCache.cachedServerSnap.isFullyInitialized || + !oldViewCache.cachedServerSnap.isFullyInitialized, + @"Once a server snap is complete, it should never go back."); + + self.viewCache = result.viewCache; + NSArray *events = [self + generateEventsForChanges:result.changes + eventCache:result.viewCache.cachedEventSnap.indexedNode + registration:nil]; + return [[FViewOperationResult alloc] initWithChanges:result.changes + events:events]; +} + +- (NSArray *)initialEvents:(id)registration { + FCacheNode *eventSnap = self.viewCache.cachedEventSnap; + NSMutableArray *initialChanges = [[NSMutableArray alloc] init]; + [eventSnap.indexedNode.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:node]; + FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded + indexedNode:indexed + childKey:key]; + [initialChanges addObject:change]; + }]; + if (eventSnap.isFullyInitialized) { + FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeValue + indexedNode:eventSnap.indexedNode]; + [initialChanges addObject:change]; + } + return [self generateEventsForChanges:initialChanges + eventCache:eventSnap.indexedNode + registration:registration]; +} + +- (NSArray *)generateEventsForChanges:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + registration:(id)registration { + NSArray *registrations; + if (registration == nil) { + registrations = [[NSArray alloc] initWithArray:self.eventRegistrations]; + } else { + registrations = [[NSArray alloc] initWithObjects:registration, nil]; + } + return [self.eventGenerator generateEventsForChanges:changes + eventCache:eventCache + eventRegistrations:registrations]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FView (%@)", self.query]; +} +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.h new file mode 100644 index 0000000..62618d2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.h @@ -0,0 +1,40 @@ +#/* +* Copyright 2017 Google +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#import + +@protocol FNode; +@class FCacheNode; +@class FIndexedNode; + +@interface FViewCache : NSObject + +- (id)initWithEventCache:(FCacheNode *)eventCache + serverCache:(FCacheNode *)serverCache; + +- (FViewCache *)updateEventSnap:(FIndexedNode *)eventSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered; +- (FViewCache *)updateServerSnap:(FIndexedNode *)serverSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered; + +@property(nonatomic, strong, readonly) FCacheNode *cachedEventSnap; +@property(nonatomic, strong, readonly) id completeEventSnap; +@property(nonatomic, strong, readonly) FCacheNode *cachedServerSnap; +@property(nonatomic, strong, readonly) id completeServerSnap; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.m new file mode 100644 index 0000000..c81be09 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.m @@ -0,0 +1,72 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FViewCache.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FViewCache () +@property(nonatomic, strong, readwrite) FCacheNode *cachedEventSnap; +@property(nonatomic, strong, readwrite) FCacheNode *cachedServerSnap; +@end + +@implementation FViewCache + +- (id)initWithEventCache:(FCacheNode *)eventCache + serverCache:(FCacheNode *)serverCache { + self = [super init]; + if (self) { + self.cachedEventSnap = eventCache; + self.cachedServerSnap = serverCache; + } + return self; +} + +- (FViewCache *)updateEventSnap:(FIndexedNode *)eventSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered { + FCacheNode *updatedEventCache = + [[FCacheNode alloc] initWithIndexedNode:eventSnap + isFullyInitialized:complete + isFiltered:filtered]; + return [[FViewCache alloc] initWithEventCache:updatedEventCache + serverCache:self.cachedServerSnap]; +} + +- (FViewCache *)updateServerSnap:(FIndexedNode *)serverSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered { + FCacheNode *updatedServerCache = + [[FCacheNode alloc] initWithIndexedNode:serverSnap + isFullyInitialized:complete + isFiltered:filtered]; + return [[FViewCache alloc] initWithEventCache:self.cachedEventSnap + serverCache:updatedServerCache]; +} + +- (id)completeEventSnap { + return (self.cachedEventSnap.isFullyInitialized) ? self.cachedEventSnap.node + : nil; +} + +- (id)completeServerSnap { + return (self.cachedServerSnap.isFullyInitialized) + ? self.cachedServerSnap.node + : nil; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h new file mode 100644 index 0000000..bf25163 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h @@ -0,0 +1,27 @@ +/* + * 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 + +@class FChange; + +@interface FChildChangeAccumulator : NSObject + +- (id)init; +- (void)trackChildChange:(FChange *)change; +- (NSArray *)changes; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.m new file mode 100644 index 0000000..b39366f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.m @@ -0,0 +1,99 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h" +#import "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/FIndex.h" + +@interface FChildChangeAccumulator () +@property(nonatomic, strong) NSMutableDictionary *changeMap; +@end + +@implementation FChildChangeAccumulator + +- (id)init { + self = [super init]; + if (self) { + self.changeMap = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)trackChildChange:(FChange *)change { + FIRDataEventType type = change.type; + NSString *childKey = change.childKey; + NSAssert(type == FIRDataEventTypeChildAdded || + type == FIRDataEventTypeChildChanged || + type == FIRDataEventTypeChildRemoved, + @"Only child changes supported for tracking."); + NSAssert(![change.childKey isEqualToString:@".priority"], + @"Changes not tracked on priority"); + if (self.changeMap[childKey] != nil) { + FChange *oldChange = [self.changeMap objectForKey:childKey]; + FIRDataEventType oldType = oldChange.type; + if (type == FIRDataEventTypeChildAdded && + oldType == FIRDataEventTypeChildRemoved) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildChanged + indexedNode:change.indexedNode + childKey:childKey + oldIndexedNode:oldChange.indexedNode]; + [self.changeMap setObject:newChange forKey:childKey]; + } else if (type == FIRDataEventTypeChildRemoved && + oldType == FIRDataEventTypeChildAdded) { + [self.changeMap removeObjectForKey:childKey]; + } else if (type == FIRDataEventTypeChildRemoved && + oldType == FIRDataEventTypeChildChanged) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildRemoved + indexedNode:oldChange.oldIndexedNode + childKey:childKey]; + [self.changeMap setObject:newChange forKey:childKey]; + } else if (type == FIRDataEventTypeChildChanged && + oldType == FIRDataEventTypeChildAdded) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildAdded + indexedNode:change.indexedNode + childKey:childKey]; + [self.changeMap setObject:newChange forKey:childKey]; + } else if (type == FIRDataEventTypeChildChanged && + oldType == FIRDataEventTypeChildChanged) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildChanged + indexedNode:change.indexedNode + childKey:childKey + oldIndexedNode:oldChange.oldIndexedNode]; + [self.changeMap setObject:newChange forKey:childKey]; + } else { + NSString *reason = [NSString + stringWithFormat: + @"Illegal combination of changes: %@ occurred after %@", + change, oldChange]; + @throw [[NSException alloc] + initWithName:@"FirebaseDatabaseInternalError" + reason:reason + userInfo:nil]; + } + } else { + [self.changeMap setObject:change forKey:childKey]; + } +} + +- (NSArray *)changes { + return [self.changeMap allValues]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h new file mode 100644 index 0000000..0c04bc1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h @@ -0,0 +1,30 @@ +/* + * 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 + +@protocol FNode; +@class FNamedNode; +@protocol FIndex; + +@protocol FCompleteChildSource + +- (id)completeChild:(NSString *)childKey; +- (FNamedNode *)childByIndex:(id)index + afterChild:(FNamedNode *)child + isReverse:(BOOL)reverse; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h new file mode 100644 index 0000000..c42d228 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h @@ -0,0 +1,26 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h" +#import + +@protocol FIndex; + +@interface FIndexedFilter : NSObject + +- (id)initWithIndex:(id)theIndex; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.m new file mode 100644 index 0000000..0a5f0ef --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.m @@ -0,0 +1,164 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h" +#import "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FIndexedFilter () +@property(nonatomic, strong, readwrite) id index; +@end + +@implementation FIndexedFilter +- (id)initWithIndex:(id)theIndex { + self = [super init]; + if (self) { + self.index = theIndex; + } + return self; +} + +- (FIndexedNode *)updateChildIn:(FIndexedNode *)indexedNode + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + affectedPath:(FPath *)affectedPath + fromSource:(id)source + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + NSAssert([indexedNode hasIndex:self.index], + @"The index in FIndexedNode must match the index of the filter"); + id node = indexedNode.node; + id oldChildSnap = [node getImmediateChild:childKey]; + + // Check if anything actually changed. + if ([[oldChildSnap getChild:affectedPath] + isEqual:[newChildSnap getChild:affectedPath]]) { + // There's an edge case where a child can enter or leave the view + // because affectedPath was set to null. In this case, affectedPath will + // appear null in both the old and new snapshots. So we need to avoid + // treating these cases as "nothing changed." + if (oldChildSnap.isEmpty == newChildSnap.isEmpty) { +// Nothing changed. +#ifdef DEBUG + NSAssert([oldChildSnap isEqual:newChildSnap], + @"Old and new snapshots should be equal."); +#endif + + return indexedNode; + } + } + if (optChangeAccumulator) { + if (newChildSnap.isEmpty) { + if ([node hasChild:childKey]) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } else { + NSAssert(node.isLeafNode, + @"A child remove without an old child only makes " + @"sense on a leaf node."); + } + } else if (oldChildSnap.isEmpty) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } else { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildChanged + indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] + childKey:childKey + oldIndexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap]]; + [optChangeAccumulator trackChildChange:change]; + } + } + if (node.isLeafNode && newChildSnap.isEmpty) { + return indexedNode; + } else { + return [indexedNode updateChild:childKey withNewChild:newChildSnap]; + } +} + +- (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap + withNewNode:(FIndexedNode *)newSnap + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + if (optChangeAccumulator) { + [oldSnap.node enumerateChildrenUsingBlock:^( + NSString *childKey, id childNode, BOOL *stop) { + if (![newSnap.node hasChild:childKey]) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode indexedNodeWithNode:childNode] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } + }]; + + [newSnap.node enumerateChildrenUsingBlock:^( + NSString *childKey, id childNode, BOOL *stop) { + if ([oldSnap.node hasChild:childKey]) { + id oldChildSnap = + [oldSnap.node getImmediateChild:childKey]; + if (![oldChildSnap isEqual:childNode]) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildChanged + indexedNode:[FIndexedNode + indexedNodeWithNode:childNode] + childKey:childKey + oldIndexedNode:[FIndexedNode + indexedNodeWithNode:oldChildSnap]]; + [optChangeAccumulator trackChildChange:change]; + } + } else { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode indexedNodeWithNode:childNode] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } + }]; + } + return newSnap; +} + +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap { + if ([oldSnap.node isEmpty]) { + return oldSnap; + } else { + return [oldSnap updatePriority:priority]; + } +} + +- (BOOL)filtersNodes { + return NO; +} + +- (id)indexedFilter { + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h new file mode 100644 index 0000000..ac0af3e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h" +#import + +@class FQueryParams; + +@interface FLimitedFilter : NSObject + +- (id)initWithQueryParams:(FQueryParams *)params; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.m new file mode 100644 index 0000000..776f9c5 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.m @@ -0,0 +1,285 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/FRangedFilter.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h" + +@interface FLimitedFilter () +@property(nonatomic, strong) FRangedFilter *rangedFilter; +@property(nonatomic, strong, readwrite) id index; +@property(nonatomic) NSInteger limit; +@property(nonatomic) BOOL reverse; + +@end + +@implementation FLimitedFilter +- (id)initWithQueryParams:(FQueryParams *)params { + self = [super init]; + if (self) { + self.rangedFilter = [[FRangedFilter alloc] initWithQueryParams:params]; + self.index = params.index; + self.limit = params.limit; + self.reverse = !params.isViewFromLeft; + } + return self; +} + +- (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + affectedPath:(FPath *)affectedPath + fromSource:(id)source + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + if (![self.rangedFilter matchesKey:childKey andNode:newChildSnap]) { + newChildSnap = [FEmptyNode emptyNode]; + } + if ([[oldSnap.node getImmediateChild:childKey] isEqual:newChildSnap]) { + // No change + return oldSnap; + } else if (oldSnap.node.numChildren < self.limit) { + return [[self.rangedFilter indexedFilter] + updateChildIn:oldSnap + forChildKey:childKey + newChild:newChildSnap + affectedPath:affectedPath + fromSource:source + accumulator:optChangeAccumulator]; + } else { + return [self fullLimitUpdateNode:oldSnap + forChildKey:childKey + newChild:newChildSnap + fromSource:source + accumulator:optChangeAccumulator]; + } +} + +- (FIndexedNode *)fullLimitUpdateNode:(FIndexedNode *)oldIndexed + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + fromSource:(id)source + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + NSAssert(oldIndexed.node.numChildren == self.limit, + @"Should have number of children equal to limit."); + + FNamedNode *windowBoundary = + self.reverse ? oldIndexed.firstChild : oldIndexed.lastChild; + + BOOL inRange = [self.rangedFilter matchesKey:childKey andNode:newChildSnap]; + if ([oldIndexed.node hasChild:childKey]) { + // `childKey` was already in `oldSnap`. Figure out if it remains in the + // window or needs to be replaced. + id oldChildSnap = [oldIndexed.node getImmediateChild:childKey]; + + // In case the `newChildSnap` falls outside the window, get the + // `nextChild` that might replace it. + FNamedNode *nextChild = [source childByIndex:self.index + afterChild:windowBoundary + isReverse:(BOOL)self.reverse]; + if (nextChild != nil && ([nextChild.name isEqualToString:childKey] || + [oldIndexed.node hasChild:nextChild.name])) { + // There is a weird edge case where a node is updated as part of a + // merge in the write tree, but hasn't been applied to the limited + // filter yet. Ignore this next child which will be updated later in + // the limited filter... + nextChild = [source childByIndex:self.index + afterChild:nextChild + isReverse:self.reverse]; + } + + // Figure out if `newChildSnap` is in range and ordered before + // `nextChild` + BOOL remainsInWindow = inRange && !newChildSnap.isEmpty; + remainsInWindow = remainsInWindow && + (!nextChild || [self.index compareKey:nextChild.name + andNode:nextChild.node + toOtherKey:childKey + andNode:newChildSnap + reverse:self.reverse] >= + NSOrderedSame); + if (remainsInWindow) { + // `newChildSnap` is ordered before `nextChild`, so it's a child + // changed event + if (optChangeAccumulator != nil) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildChanged + indexedNode:[FIndexedNode + indexedNodeWithNode:newChildSnap] + childKey:childKey + oldIndexedNode:[FIndexedNode + indexedNodeWithNode:oldChildSnap]]; + [optChangeAccumulator trackChildChange:change]; + } + return [oldIndexed updateChild:childKey withNewChild:newChildSnap]; + } else { + // `newChildSnap` is ordered after `nextChild`, so it's a child + // removed event + if (optChangeAccumulator != nil) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } + FIndexedNode *newIndexed = + [oldIndexed updateChild:childKey + withNewChild:[FEmptyNode emptyNode]]; + + // We need to check if the `nextChild` is actually in range before + // adding it + BOOL nextChildInRange = + (nextChild != nil) && + [self.rangedFilter matchesKey:nextChild.name + andNode:nextChild.node]; + if (nextChildInRange) { + if (optChangeAccumulator != nil) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode + indexedNodeWithNode:nextChild.node] + childKey:nextChild.name]; + [optChangeAccumulator trackChildChange:change]; + } + return [newIndexed updateChild:nextChild.name + withNewChild:nextChild.node]; + } else { + return newIndexed; + } + } + } else if (newChildSnap.isEmpty) { + // We're deleting a node, but it was not in the window, so ignore it. + return oldIndexed; + } else if (inRange) { + // `newChildSnap` is in range, but was ordered after `windowBoundary`. + // If this has changed, we bump out the `windowBoundary` and add the + // `newChildSnap` + if ([self.index compareKey:windowBoundary.name + andNode:windowBoundary.node + toOtherKey:childKey + andNode:newChildSnap + reverse:self.reverse] >= NSOrderedSame) { + if (optChangeAccumulator != nil) { + FChange *removedChange = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode + indexedNodeWithNode:windowBoundary.node] + childKey:windowBoundary.name]; + FChange *addedChange = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] + childKey:childKey]; + [optChangeAccumulator trackChildChange:removedChange]; + [optChangeAccumulator trackChildChange:addedChange]; + } + return [[oldIndexed updateChild:childKey withNewChild:newChildSnap] + updateChild:windowBoundary.name + withNewChild:[FEmptyNode emptyNode]]; + } else { + return oldIndexed; + } + } else { + // `newChildSnap` was not in range and remains not in range, so ignore + // it. + return oldIndexed; + } +} + +- (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap + withNewNode:(FIndexedNode *)newSnap + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + __block FIndexedNode *filtered; + if (newSnap.node.isLeafNode || newSnap.node.isEmpty) { + // Make sure we have a children node with the correct index, not a leaf + // node + filtered = [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] + index:self.index]; + } else { + filtered = newSnap; + // Don't support priorities on queries. + filtered = [filtered updatePriority:[FEmptyNode emptyNode]]; + FNamedNode *startPost = nil; + FNamedNode *endPost = nil; + if (self.reverse) { + startPost = self.rangedFilter.endPost; + endPost = self.rangedFilter.startPost; + } else { + startPost = self.rangedFilter.startPost; + endPost = self.rangedFilter.endPost; + } + __block BOOL foundStartPost = NO; + __block NSUInteger count = 0; + [newSnap + enumerateChildrenReverse:self.reverse + usingBlock:^(NSString *childKey, id childNode, + BOOL *stop) { + if (!foundStartPost && + [self.index + compareKey:startPost.name + andNode:startPost.node + toOtherKey:childKey + andNode:childNode + reverse:self.reverse] <= NSOrderedSame) { + // Start adding + foundStartPost = YES; + } + BOOL inRange = foundStartPost && count < self.limit; + inRange = inRange && + [self.index compareKey:childKey + andNode:childNode + toOtherKey:endPost.name + andNode:endPost.node + reverse:self.reverse] <= + NSOrderedSame; + if (inRange) { + count++; + } else { + filtered = [filtered + updateChild:childKey + withNewChild:[FEmptyNode emptyNode]]; + } + }]; + } + return [self.indexedFilter updateFullNode:oldSnap + withNewNode:filtered + accumulator:optChangeAccumulator]; +} + +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap { + // Don't support priorities on queries. + return oldSnap; +} + +- (BOOL)filtersNodes { + return YES; +} + +- (id)indexedFilter { + return self.rangedFilter.indexedFilter; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h new file mode 100644 index 0000000..d19c6fb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h @@ -0,0 +1,77 @@ +/* + * 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 + +@protocol FNode; +@class FIndexedNode; +@protocol FCompleteChildSource; +@class FChildChangeAccumulator; +@protocol FIndex; +@class FPath; + +/** + * FNodeFilter is used to update nodes and complete children of nodes while + * applying queries on the fly and keeping track of any child changes. This + * class does not track value changes as value changes depend on more than just + * the node itself. Different kind of queries require different kind of + * implementations of this interface. + */ +@protocol FNodeFilter + +/** + * Update a single complete child in the snap. If the child equals the old child + * in the snap, this is a no-op. The method expects an indexed snap. + */ +- (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + affectedPath:(FPath *)affectedPath + fromSource:(id)source + accumulator:(FChildChangeAccumulator *)optChangeAccumulator; + +/** + * Update a node in full and output any resulting change from this complete + * update. + */ +- (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap + withNewNode:(FIndexedNode *)newSnap + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator; + +/** + * Update the priority of the root node + */ +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap; + +/** + * Returns true if children might be filtered due to query critiera + */ +- (BOOL)filtersNodes; + +/** + * Returns the index filter that this filter uses to get a NodeFilter that + * doesn't filter any children. + */ +@property(nonatomic, strong, readonly) id indexedFilter; + +/** + * Returns the index that this filter uses + */ +@property(nonatomic, strong, readonly) id index; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.h new file mode 100644 index 0000000..e85cb2a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.h @@ -0,0 +1,35 @@ +/* + * 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 + +@protocol FClock + +- (NSTimeInterval)currentTime; + +@end + +@interface FSystemClock : NSObject + ++ (FSystemClock *)clock; + +@end + +@interface FOffsetClock : NSObject + +- (id)initWithClock:(id)clock offset:(NSTimeInterval)offset; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.m new file mode 100644 index 0000000..0733b6c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.m @@ -0,0 +1,58 @@ +/* + * 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 "FirebaseDatabase/Sources/FClock.h" + +@implementation FSystemClock + +- (NSTimeInterval)currentTime { + return [[NSDate date] timeIntervalSince1970]; +} + ++ (FSystemClock *)clock { + static dispatch_once_t onceToken; + static FSystemClock *clock; + dispatch_once(&onceToken, ^{ + clock = [[FSystemClock alloc] init]; + }); + return clock; +} + +@end + +@interface FOffsetClock () + +@property(nonatomic, strong) id clock; +@property(nonatomic) NSTimeInterval offset; + +@end + +@implementation FOffsetClock + +- (NSTimeInterval)currentTime { + return [self.clock currentTime] + self.offset; +} + +- (id)initWithClock:(id)clock offset:(NSTimeInterval)offset { + self = [super init]; + if (self != nil) { + self->_clock = clock; + self->_offset = offset; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.h new file mode 100644 index 0000000..443664e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.h @@ -0,0 +1,28 @@ +/* + * 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 + +@class FQuerySpec; +@class FIndexedNode; +@protocol FNode; + +@interface FEventGenerator : NSObject +- (id)initWithQuery:(FQuerySpec *)query; +- (NSArray *)generateEventsForChanges:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.m new file mode 100644 index 0000000..815aed1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.m @@ -0,0 +1,169 @@ +/* + * 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 "FirebaseDatabase/Sources/FEventGenerator.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/Core/View/FDataEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FEventGenerator () +@property(nonatomic, strong) FQuerySpec *query; +@end + +/** + * An EventGenerator is used to convert "raw" changes (fb.core.view.Change) as + * computed by the CacheDiffer into actual events (fb.core.view.Event) that can + * be raised. See generateEventsForChanges() for details. + */ +@implementation FEventGenerator + +- (id)initWithQuery:(FQuerySpec *)query { + self = [super init]; + if (self) { + self.query = query; + } + return self; +} + +/** + * Given a set of raw changes (no moved events, and prevName not specified yet), + * and a set of EventRegistrations that should be notified of these changes, + * generate the actual events to be raised. + * + * Notes: + * - child_moved events will be synthesized at this time for any child_changed + * events that affect our index + * - prevName will be calculated based on the index ordering + * + * @param changes NSArray of FChange, not necessarily in order. + * @param registrations is NSArray of FEventRegistration. + * @return NSArray of FEvent. + */ +- (NSArray *)generateEventsForChanges:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations { + NSMutableArray *events = [[NSMutableArray alloc] init]; + + // child_moved is index-specific, so check all our child_changed events to + // see if we need to materialize child_moved events with this view's index + NSMutableArray *moves = [[NSMutableArray alloc] init]; + for (FChange *change in changes) { + if (change.type == FIRDataEventTypeChildChanged && + [self.query.index + indexedValueChangedBetween:change.oldIndexedNode.node + and:change.indexedNode.node]) { + FChange *moveChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildMoved + indexedNode:change.indexedNode + childKey:change.childKey + oldIndexedNode:nil]; + [moves addObject:moveChange]; + } + } + + [self generateEvents:events + forType:FIRDataEventTypeChildRemoved + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeChildAdded + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeChildMoved + changes:moves + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeChildChanged + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeValue + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + + return events; +} + +- (void)generateEvents:(NSMutableArray *)events + forType:(FIRDataEventType)eventType + changes:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations { + NSMutableArray *filteredChanges = [[NSMutableArray alloc] init]; + for (FChange *change in changes) { + if (change.type == eventType) { + [filteredChanges addObject:change]; + } + } + + id index = self.query.index; + + [filteredChanges + sortUsingComparator:^NSComparisonResult(FChange *one, FChange *two) { + if (one.childKey == nil || two.childKey == nil) { + @throw [[NSException alloc] + initWithName:@"InternalInconsistencyError" + reason:@"Should only compare child_ events" + userInfo:nil]; + } + return [index compareKey:one.childKey + andNode:one.indexedNode.node + toOtherKey:two.childKey + andNode:two.indexedNode.node]; + }]; + + for (FChange *change in filteredChanges) { + for (id registration in registrations) { + if ([registration responseTo:eventType]) { + id event = [self generateEventForChange:change + registration:registration + eventCache:eventCache]; + [events addObject:event]; + } + } + } +} + +- (id)generateEventForChange:(FChange *)change + registration:(id)registration + eventCache:(FIndexedNode *)eventCache { + FChange *materializedChange; + if (change.type == FIRDataEventTypeValue || + change.type == FIRDataEventTypeChildRemoved) { + materializedChange = change; + } else { + NSString *prevChildKey = + [eventCache predecessorForChildKey:change.childKey + childNode:change.indexedNode.node + index:self.query.index]; + materializedChange = [change changeWithPrevKey:prevChildKey]; + } + return [registration createEventFrom:materializedChange query:self.query]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h new file mode 100644 index 0000000..96c57db --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h" + +@protocol FStorageEngine; + +@interface FIRDatabaseConfig () + +@property(nonatomic, readonly) BOOL isFrozen; +@property(nonatomic, strong, readonly) NSString *sessionIdentifier; +@property(nonatomic, strong, readonly) NSString *googleAppID; +@property(nonatomic, strong) id + contextProvider; +@property(nonatomic, strong) id forceStorageEngine; + +- (void)freeze; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseReference.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseReference.m new file mode 100644 index 0000000..bb0ed6d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseReference.m @@ -0,0 +1,542 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FNextPushId.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +@implementation FIRDatabaseReference + +#pragma mark - +#pragma mark Constructors + +- (id)initWithConfig:(FIRDatabaseConfig *)config { + FParsedUrl *parsedUrl = + [FUtilities parseUrl:[[FIRApp defaultApp] options].databaseURL]; + [FValidation validateFrom:@"initWithUrl:" validURL:parsedUrl]; + return [self initWithRepo:[FRepoManager getRepo:parsedUrl.repoInfo + config:config] + path:parsedUrl.path]; +} + +- (id)initWithRepo:(FRepo *)repo path:(FPath *)path { + return [super initWithRepo:repo + path:path + params:[FQueryParams defaultInstance] + orderByCalled:NO + priorityMethodCalled:NO]; +} + +#pragma mark - +#pragma mark Ancillary methods + +- (nullable NSString *)key { + if ([self.path isEmpty]) { + return nil; + } else { + return [self.path getBack]; + } +} + +- (FIRDatabase *)database { + return self.repo.database; +} + +- (FIRDatabaseReference *)parent { + FPath *parentPath = [self.path parent]; + FIRDatabaseReference *parent = nil; + if (parentPath != nil) { + parent = [[FIRDatabaseReference alloc] initWithRepo:self.repo + path:parentPath]; + } + return parent; +} + +- (NSString *)URL { + FIRDatabaseReference *parent = [self parent]; + return parent == nil + ? [self.repo description] + : [NSString + stringWithFormat:@"%@/%@", [parent description], + [FStringUtilities urlEncoded:self.key]]; +} + +- (NSString *)description { + return [self URL]; +} + +- (FIRDatabaseReference *)root { + return [[FIRDatabaseReference alloc] + initWithRepo:self.repo + path:[[FPath alloc] initWith:@""]]; +} + +#pragma mark - +#pragma mark Child methods + +- (FIRDatabaseReference *)child:(NSString *)pathString { + if ([self.path getFront] == nil) { + // we're at the root + [FValidation validateFrom:@"child:" validRootPathString:pathString]; + } else { + [FValidation validateFrom:@"child:" validPathString:pathString]; + } + FPath *path = [self.path childFromString:pathString]; + FIRDatabaseReference *firebaseRef = + [[FIRDatabaseReference alloc] initWithRepo:self.repo path:path]; + return firebaseRef; +} + +- (FIRDatabaseReference *)childByAutoId { + [FValidation validateFrom:@"childByAutoId:" writablePath:self.path]; + + NSString *name = [FNextPushId get:self.repo.serverTime]; + return [self child:name]; +} + +#pragma mark - +#pragma mark Basic write methods + +- (void)setValue:(id)value { + [self setValueInternal:value + andPriority:nil + withCompletionBlock:nil + from:@"setValue:"]; +} + +- (void)setValue:(id)value withCompletionBlock:(fbt_void_nserror_ref)block { + [self setValueInternal:value + andPriority:nil + withCompletionBlock:block + from:@"setValue:withCompletionBlock:"]; +} + +- (void)setValue:(id)value andPriority:(id)priority { + [self setValueInternal:value + andPriority:priority + withCompletionBlock:nil + from:@"setValue:andPriority:"]; +} + +- (void)setValue:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block { + [self setValueInternal:value + andPriority:priority + withCompletionBlock:block + from:@"setValue:andPriority:withCompletionBlock:"]; +} + +- (void)setValueInternal:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { + [FValidation validateFrom:fn writablePath:self.path]; + + fbt_void_nserror_ref userCallback = [block copy]; + id newNode = [FSnapshotUtilities nodeFrom:value + priority:priority + withValidationFrom:fn]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo set:self.path withNode:newNode withCallback:userCallback]; + }); +} + +- (void)removeValue { + [self setValueInternal:nil + andPriority:nil + withCompletionBlock:nil + from:@"removeValue:"]; +} + +- (void)removeValueWithCompletionBlock:(fbt_void_nserror_ref)block { + [self setValueInternal:nil + andPriority:nil + withCompletionBlock:block + from:@"removeValueWithCompletionBlock:"]; +} + +- (void)setPriority:(id)priority { + [self setPriorityInternal:priority + withCompletionBlock:nil + from:@"setPriority:"]; +} + +- (void)setPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block { + + [self setPriorityInternal:priority + withCompletionBlock:block + from:@"setPriority:withCompletionBlock:"]; +} + +- (void)setPriorityInternal:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { + [FValidation validateFrom:fn writablePath:self.path]; + + fbt_void_nserror_ref userCallback = [block copy]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo set:[self.path childFromString:@".priority"] + withNode:[FSnapshotUtilities nodeFrom:priority] + withCallback:userCallback]; + }); +} + +- (void)updateChildValues:(NSDictionary *)values { + [self updateChildValuesInternal:values + withCompletionBlock:nil + from:@"updateChildValues:"]; +} + +- (void)updateChildValues:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block { + [self updateChildValuesInternal:values + withCompletionBlock:block + from:@"updateChildValues:withCompletionBlock:"]; +} + +- (void)updateChildValuesInternal:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { + [FValidation validateFrom:fn writablePath:self.path]; + + FCompoundWrite *merge = + [FSnapshotUtilities compoundWriteFromDictionary:values + withValidationFrom:fn]; + + fbt_void_nserror_ref userCallback = [block copy]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo update:self.path withNodes:merge withCallback:userCallback]; + }); +} + +#pragma mark - +#pragma mark Disconnect Operations + +- (void)onDisconnectSetValue:(id)value { + [self onDisconnectSetValueInternal:value + andPriority:nil + withCompletionBlock:nil + from:@"onDisconnectSetValue:"]; +} + +- (void)onDisconnectSetValue:(id)value + withCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectSetValueInternal:value + andPriority:nil + withCompletionBlock:block + from:@"onDisconnectSetValue:" + @"withCompletionBlock:"]; +} + +- (void)onDisconnectSetValue:(id)value andPriority:(id)priority { + [self onDisconnectSetValueInternal:value + andPriority:priority + withCompletionBlock:nil + from:@"onDisconnectSetValue:andPriority:"]; +} + +- (void)onDisconnectSetValue:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectSetValueInternal:value + andPriority:priority + withCompletionBlock:block + from:@"onDisconnectSetValue:andPriority:" + @"withCompletionBlock:"]; +} + +- (void)onDisconnectSetValueInternal:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { + [FValidation validateFrom:fn writablePath:self.path]; + + id newNodeUnresolved = [FSnapshotUtilities nodeFrom:value + priority:priority + withValidationFrom:fn]; + + fbt_void_nserror_ref userCallback = [block copy]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo onDisconnectSet:self.path + withNode:newNodeUnresolved + withCallback:userCallback]; + }); +} + +- (void)onDisconnectRemoveValue { + [self onDisconnectSetValueInternal:nil + andPriority:nil + withCompletionBlock:nil + from:@"onDisconnectRemoveValue:"]; +} + +- (void)onDisconnectRemoveValueWithCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectSetValueInternal:nil + andPriority:nil + withCompletionBlock:block + from:@"onDisconnectRemoveValueWithCompletionB" + @"lock:"]; +} + +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values { + [self + onDisconnectUpdateChildValuesInternal:values + withCompletionBlock:nil + from: + @"onDisconnectUpdateChildValues:"]; +} + +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectUpdateChildValuesInternal:values + withCompletionBlock:block + from:@"onDisconnectUpdateChildValues" + @":withCompletionBlock:"]; +} + +- (void)onDisconnectUpdateChildValuesInternal:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { + [FValidation validateFrom:fn writablePath:self.path]; + + FCompoundWrite *merge = + [FSnapshotUtilities compoundWriteFromDictionary:values + withValidationFrom:fn]; + + fbt_void_nserror_ref userCallback = [block copy]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo onDisconnectUpdate:self.path + withNodes:merge + withCallback:userCallback]; + }); +} + +- (void)cancelDisconnectOperations { + [self cancelDisconnectOperationsWithCompletionBlock:nil]; +} + +- (void)cancelDisconnectOperationsWithCompletionBlock: + (fbt_void_nserror_ref)block { + fbt_void_nserror_ref callback = nil; + if (block != nil) { + callback = [block copy]; + } + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo onDisconnectCancel:self.path withCallback:callback]; + }); +} + +#pragma mark - +#pragma mark Connection management methods + ++ (void)goOffline { + [FRepoManager interruptAll]; +} + ++ (void)goOnline { + [FRepoManager resumeAll]; +} + +#pragma mark - +#pragma mark Data reading methods deferred to FQuery + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block { + return [self observeEventType:eventType + withBlock:block + withCancelBlock:nil]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + return [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + return [super observeEventType:eventType + withBlock:block + withCancelBlock:cancelBlock]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + return [super observeEventType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:cancelBlock]; +} + +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle { + [super removeObserverWithHandle:handle]; +} + +- (void)removeAllObservers { + [super removeAllObservers]; +} + +- (void)keepSynced:(BOOL)keepSynced { + [super keepSynced:keepSynced]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block { + [self observeSingleEventOfType:eventType + withBlock:block + withCancelBlock:nil]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + [self observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [super observeSingleEventOfType:eventType + withBlock:block + withCancelBlock:cancelBlock]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [super observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:cancelBlock]; +} + +#pragma mark - +#pragma mark Query methods +// These methods suppress warnings from having method definitions in +// FIRDatabaseReference.h for docs generation. + +- (void)getDataWithCompletionBlock: + (void (^_Nonnull)(NSError *__nullable error, + FIRDataSnapshot *snapshot))block { + [super getDataWithCompletionBlock:block]; +} + +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit { + return [super queryLimitedToFirst:limit]; +} + +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit { + return [super queryLimitedToLast:limit]; +} + +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key { + return [super queryOrderedByChild:key]; +} + +- (FIRDatabaseQuery *)queryOrderedByKey { + return [super queryOrderedByKey]; +} + +- (FIRDatabaseQuery *)queryOrderedByPriority { + return [super queryOrderedByPriority]; +} + +- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue { + return [super queryStartingAtValue:startValue]; +} + +- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue + childKey:(NSString *)childKey { + return [super queryStartingAtValue:startValue childKey:childKey]; +} + +- (FIRDatabaseQuery *)queryStartingAfterValue:(id)startAfterValue { + return [super queryStartingAfterValue:startAfterValue]; +} + +- (FIRDatabaseQuery *)queryStartingAfterValue:(id)startAfterValue + childKey:(NSString *)childKey { + return [super queryStartingAfterValue:startAfterValue childKey:childKey]; +} + +- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue { + return [super queryEndingAtValue:endValue]; +} + +- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue + childKey:(NSString *)childKey { + return [super queryEndingAtValue:endValue childKey:childKey]; +} + +- (FIRDatabaseQuery *)queryEqualToValue:(id)value { + return [super queryEqualToValue:value]; +} + +- (FIRDatabaseQuery *)queryEqualToValue:(id)value + childKey:(NSString *)childKey { + return [super queryEqualToValue:value childKey:childKey]; +} + +#pragma mark - +#pragma mark Transaction methods + +- (void)runTransactionBlock:(fbt_transactionresult_mutabledata)block { + [FValidation validateFrom:@"runTransactionBlock:" writablePath:self.path]; + [self runTransactionBlock:block andCompletionBlock:nil withLocalEvents:YES]; +} + +- (void)runTransactionBlock:(fbt_transactionresult_mutabledata)update + andCompletionBlock: + (fbt_void_nserror_bool_datasnapshot)completionBlock { + [FValidation validateFrom:@"runTransactionBlock:andCompletionBlock:" + writablePath:self.path]; + [self runTransactionBlock:update + andCompletionBlock:completionBlock + withLocalEvents:YES]; +} + +- (void)runTransactionBlock:(fbt_transactionresult_mutabledata)block + andCompletionBlock:(fbt_void_nserror_bool_datasnapshot)completionBlock + withLocalEvents:(BOOL)localEvents { + [FValidation + validateFrom:@"runTransactionBlock:andCompletionBlock:withLocalEvents:" + writablePath:self.path]; + fbt_transactionresult_mutabledata updateCopy = [block copy]; + fbt_void_nserror_bool_datasnapshot onCompleteCopy = [completionBlock copy]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo startTransactionOnPath:self.path + update:updateCopy + onComplete:onCompleteCopy + withLocalEvents:localEvents]; + }); +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.h new file mode 100644 index 0000000..89bec76 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.h @@ -0,0 +1,51 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FImmutableSortedDictionary; +@class FNamedNode; +@protocol FNode; + +@protocol FIndex +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2; + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse; + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2; + +- (BOOL)isDefinedOn:(id)node; +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode; +- (FNamedNode *)minPost; +- (FNamedNode *)maxPost; +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name; +- (NSString *)queryDefinition; + +@end + +@interface FIndex : NSObject + ++ (id)indexFromQueryDefinition:(NSString *)string; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.m new file mode 100644 index 0000000..0f6761e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.m @@ -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. + */ + +#import "FirebaseDatabase/Sources/FIndex.h" + +#import "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/FPathIndex.h" +#import "FirebaseDatabase/Sources/FPriorityIndex.h" +#import "FirebaseDatabase/Sources/FValueIndex.h" + +@implementation FIndex + ++ (id)indexFromQueryDefinition:(NSString *)string { + if ([string isEqualToString:@".key"]) { + return [FKeyIndex keyIndex]; + } else if ([string isEqualToString:@".value"]) { + return [FValueIndex valueIndex]; + } else if ([string isEqualToString:@".priority"]) { + return [FPriorityIndex priorityIndex]; + } else { + return + [[FPathIndex alloc] initWithPath:[[FPath alloc] initWith:string]]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.h new file mode 100644 index 0000000..3a5195b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.h @@ -0,0 +1,22 @@ +/* + * 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 "FirebaseDatabase/Sources/FIndex.h" +#import + +@interface FKeyIndex : NSObject ++ (id)keyIndex; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.m new file mode 100644 index 0000000..9f5147d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.m @@ -0,0 +1,123 @@ +/* + * 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 "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FKeyIndex () + +@property(nonatomic, strong) FNamedNode *maxPost; + +@end + +@implementation FKeyIndex + +- (id)init { + self = [super init]; + if (self) { + self.maxPost = [[FNamedNode alloc] initWithName:[FUtilities maxName] + andNode:[FEmptyNode emptyNode]]; + } + return self; +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { + return [FUtilities compareKey:key1 toKey:key2]; +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { + if (reverse) { + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; + } else { + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; + } +} + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; +} + +- (BOOL)isDefinedOn:(id)node { + return YES; +} + +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { + return NO; // The key for a node never changes. +} + +- (FNamedNode *)minPost { + return [FNamedNode min]; +} + +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { + NSString *key = indexValue.val; + NSAssert([key isKindOfClass:[NSString class]], + @"KeyIndex indexValue must always be a string."); + // We just use empty node, but it'll never be compared, since our comparator + // only looks at name. + return [[FNamedNode alloc] initWithName:key andNode:[FEmptyNode emptyNode]]; +} + +- (NSString *)queryDefinition { + return @".key"; +} + +- (NSString *)description { + return @"FKeyIndex"; +} + +- (id)copyWithZone:(NSZone *)zone { + return self; +} + +- (BOOL)isEqual:(id)other { + // since we're a singleton. + return (other == self); +} + +- (NSUInteger)hash { + return [@".key" hash]; +} + ++ (id)keyIndex { + static id keyIndex; + static dispatch_once_t once; + dispatch_once(&once, ^{ + keyIndex = [[FKeyIndex alloc] init]; + }); + return keyIndex; +} +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.h new file mode 100644 index 0000000..e3cdd4e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.h @@ -0,0 +1,28 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOperation.h" +#import + +@interface FListenComplete : NSObject + +- (id)initWithSource:(FOperationSource *)aSource path:(FPath *)aPath; + +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, readonly) FOperationType type; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.m new file mode 100644 index 0000000..70a4c5c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.m @@ -0,0 +1,55 @@ +/* + * 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 "FirebaseDatabase/Sources/FListenComplete.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +@interface FListenComplete () +@property(nonatomic, strong, readwrite) FOperationSource *source; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, readwrite) FOperationType type; +@end + +@implementation FListenComplete +- (id)initWithSource:(FOperationSource *)aSource path:(FPath *)aPath { + NSAssert(!aSource.fromUser, + @"Can't have a listen complete from a user source"); + self = [super init]; + if (self) { + self.source = aSource; + self.path = aPath; + self.type = FOperationTypeListenComplete; + } + return self; +} + +- (id)operationForChild:(NSString *)childKey { + if ([self.path isEmpty]) { + return [[FListenComplete alloc] initWithSource:self.source + path:[FPath empty]]; + } else { + return [[FListenComplete alloc] initWithSource:self.source + path:[self.path popFront]]; + } +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FListenComplete { path=%@, source=%@ }", + self.path, self.source]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.h new file mode 100644 index 0000000..16f3d08 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.h @@ -0,0 +1,22 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import + +@interface FMaxNode : FChildrenNode ++ (id)maxNode; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.m new file mode 100644 index 0000000..159583e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.m @@ -0,0 +1,58 @@ +/* + * 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 "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@implementation FMaxNode { +} +- (id)init { + self = [super init]; + if (self) { + } + return self; +} + ++ (id)maxNode { + static FMaxNode *maxNode = nil; + static dispatch_once_t once; + dispatch_once(&once, ^{ + maxNode = [[FMaxNode alloc] init]; + }); + return maxNode; +} + +- (NSComparisonResult)compare:(id)other { + if (other == self) { + return NSOrderedSame; + } else { + return NSOrderedDescending; + } +} + +- (BOOL)isEqual:(id)other { + return other == self; +} + +- (id)getImmediateChild:(NSString *)childName { + return [FEmptyNode emptyNode]; +} + +- (BOOL)isEmpty { + return NO; +} +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.h new file mode 100644 index 0000000..b91e57d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.h @@ -0,0 +1,31 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FNamedNode : NSObject + +@property(nonatomic, strong, readonly) NSString *name; +@property(nonatomic, strong, readonly) id node; + +- (id)initWithName:(NSString *)name andNode:(id)node; + ++ (FNamedNode *)nodeWithName:(NSString *)name node:(id)node; + ++ (FNamedNode *)min; ++ (FNamedNode *)max; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.m new file mode 100644 index 0000000..d1092e8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.m @@ -0,0 +1,102 @@ +/* + * 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 "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FNamedNode () +@property(nonatomic, strong, readwrite) NSString *name; +@property(nonatomic, strong, readwrite) id node; +@end + +@implementation FNamedNode + ++ (FNamedNode *)nodeWithName:(NSString *)name node:(id)node { + return [[FNamedNode alloc] initWithName:name andNode:node]; +} + +- (id)initWithName:(NSString *)name andNode:(id)node { + self = [super init]; + if (self) { + self.name = name; + self.node = node; + } + return self; +} + +- (id)copy { + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + return self; +} + ++ (FNamedNode *)min { + static FNamedNode *min = nil; + static dispatch_once_t once; + dispatch_once(&once, ^{ + min = [[FNamedNode alloc] initWithName:[FUtilities minName] + andNode:[FEmptyNode emptyNode]]; + }); + return min; +} + ++ (FNamedNode *)max { + static FNamedNode *max = nil; + static dispatch_once_t once; + dispatch_once(&once, ^{ + max = [[FNamedNode alloc] initWithName:[FUtilities maxName] + andNode:[FMaxNode maxNode]]; + }); + return max; +} + +- (NSString *)description { + return + [NSString stringWithFormat:@"NamedNode[%@] %@", self.name, self.node]; +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (object == nil || ![object isKindOfClass:[FNamedNode class]]) { + return NO; + } + + FNamedNode *namedNode = object; + if (![self.name isEqualToString:namedNode.name]) { + return NO; + } + if (![self.node isEqual:namedNode.node]) { + return NO; + } + + return YES; +} + +- (NSUInteger)hash { + NSUInteger nameHash = [self.name hash]; + NSUInteger nodeHash = [self.node hash]; + NSUInteger result = 31 * nameHash + nodeHash; + return result; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.h new file mode 100644 index 0000000..20c18a0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.h @@ -0,0 +1,23 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import + +@interface FPathIndex : NSObject +- (id)initWithPath:(FPath *)path; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.m new file mode 100644 index 0000000..20e276d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.m @@ -0,0 +1,135 @@ +/* + * 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 "FirebaseDatabase/Sources/FPathIndex.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FPathIndex () +@property(nonatomic, strong) FPath *path; +@end + +@implementation FPathIndex + +- (id)initWithPath:(FPath *)path { + self = [super init]; + if (self) { + if (path.isEmpty || [path.getFront isEqualToString:@".priority"]) { + [NSException raise:NSInvalidArgumentException + format:@"Invalid path for PathIndex: %@", path]; + } + _path = path; + } + return self; +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { + id child1 = [node1 getChild:self.path]; + id child2 = [node2 getChild:self.path]; + NSComparisonResult indexCmp = [child1 compare:child2]; + if (indexCmp == NSOrderedSame) { + return [FUtilities compareKey:key1 toKey:key2]; + } else { + return indexCmp; + } +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { + if (reverse) { + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; + } else { + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; + } +} + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; +} + +- (BOOL)isDefinedOn:(id)node { + return ![node getChild:self.path].isEmpty; +} + +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { + id oldValue = [oldNode getChild:self.path]; + id newValue = [newNode getChild:self.path]; + return [oldValue compare:newValue] != NSOrderedSame; +} + +- (FNamedNode *)minPost { + return FNamedNode.min; +} + +- (FNamedNode *)maxPost { + id maxNode = [[FEmptyNode emptyNode] updateChild:self.path + withNewChild:[FMaxNode maxNode]]; + + return [[FNamedNode alloc] initWithName:[FUtilities maxName] + andNode:maxNode]; +} + +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { + id node = [[FEmptyNode emptyNode] updateChild:self.path + withNewChild:indexValue]; + return [[FNamedNode alloc] initWithName:name andNode:node]; +} + +- (NSString *)queryDefinition { + return [self.path wireFormat]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FPathIndex(%@)", self.path]; +} + +- (id)copyWithZone:(NSZone *)zone { + // Safe since we're immutable. + return self; +} + +- (BOOL)isEqual:(id)other { + if (![other isKindOfClass:[FPathIndex class]]) { + return NO; + } + return ([self.path isEqual:((FPathIndex *)other).path]); +} + +- (NSUInteger)hash { + return [self.path hash]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.h new file mode 100644 index 0000000..262f686 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.h @@ -0,0 +1,23 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/FIndex.h" + +@interface FPriorityIndex : NSObject ++ (id)priorityIndex; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.m new file mode 100644 index 0000000..db3220a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.m @@ -0,0 +1,126 @@ +/* + * 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 "FirebaseDatabase/Sources/FPriorityIndex.h" + +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +// TODO: Abstract into some common base class? + +@implementation FPriorityIndex + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { + id child1 = [node1 getPriority]; + id child2 = [node2 getPriority]; + NSComparisonResult indexCmp = [child1 compare:child2]; + if (indexCmp == NSOrderedSame) { + return [FUtilities compareKey:key1 toKey:key2]; + } else { + return indexCmp; + } +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { + if (reverse) { + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; + } else { + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; + } +} + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; +} + +- (BOOL)isDefinedOn:(id)node { + return !node.getPriority.isEmpty; +} + +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { + id oldValue = [oldNode getPriority]; + id newValue = [newNode getPriority]; + return ![oldValue isEqual:newValue]; +} + +- (FNamedNode *)minPost { + return FNamedNode.min; +} + +- (FNamedNode *)maxPost { + return [self makePost:[FMaxNode maxNode] name:[FUtilities maxName]]; +} + +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { + id node = [[FLeafNode alloc] initWithValue:@"[PRIORITY-POST]" + withPriority:indexValue]; + return [[FNamedNode alloc] initWithName:name andNode:node]; +} + +- (NSString *)queryDefinition { + return @".priority"; +} + +- (NSString *)description { + return @"FPriorityIndex"; +} + +- (id)copyWithZone:(NSZone *)zone { + // Safe since we're immutable. + return self; +} + +- (BOOL)isEqual:(id)other { + return [other isKindOfClass:[FPriorityIndex class]]; +} + +- (NSUInteger)hash { + // chosen by a fair dice roll. Guaranteed to be random + return 3155577; +} + ++ (id)priorityIndex { + static id index; + static dispatch_once_t once; + dispatch_once(&once, ^{ + index = [[FPriorityIndex alloc] init]; + }); + + return index; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.h new file mode 100644 index 0000000..4c535ea --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.h @@ -0,0 +1,31 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h" +#import + +@class FQueryParams; +@class FNamedNode; + +@interface FRangedFilter : NSObject + +- (id)initWithQueryParams:(FQueryParams *)params; +- (BOOL)matchesKey:(NSString *)key andNode:(id)node; + +@property(nonatomic, strong, readonly) FNamedNode *startPost; +@property(nonatomic, strong, readonly) FNamedNode *endPost; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.m new file mode 100644 index 0000000..99095d8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.m @@ -0,0 +1,129 @@ +/* + * 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 "FirebaseDatabase/Sources/FRangedFilter.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" + +@interface FRangedFilter () +@property(nonatomic, strong, readwrite) id indexedFilter; +@property(nonatomic, strong, readwrite) id index; +@property(nonatomic, strong, readwrite) FNamedNode *startPost; +@property(nonatomic, strong, readwrite) FNamedNode *endPost; +@end + +@implementation FRangedFilter +- (id)initWithQueryParams:(FQueryParams *)params { + self = [super init]; + if (self) { + self.indexedFilter = + [[FIndexedFilter alloc] initWithIndex:params.index]; + self.index = params.index; + self.startPost = [FRangedFilter startPostFromQueryParams:params]; + self.endPost = [FRangedFilter endPostFromQueryParams:params]; + } + return self; +} + ++ (FNamedNode *)startPostFromQueryParams:(FQueryParams *)params { + if ([params hasStart]) { + NSString *startKey = params.indexStartKey; + return [params.index makePost:params.indexStartValue name:startKey]; + } else { + return params.index.minPost; + } +} + ++ (FNamedNode *)endPostFromQueryParams:(FQueryParams *)params { + if ([params hasEnd]) { + NSString *endKey = params.indexEndKey; + return [params.index makePost:params.indexEndValue name:endKey]; + } else { + return params.index.maxPost; + } +} + +- (BOOL)matchesKey:(NSString *)key andNode:(id)node { + return ([self.index compareKey:self.startPost.name + andNode:self.startPost.node + toOtherKey:key + andNode:node] <= NSOrderedSame && + [self.index compareKey:key + andNode:node + toOtherKey:self.endPost.name + andNode:self.endPost.node] <= NSOrderedSame); +} + +- (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + affectedPath:(FPath *)affectedPath + fromSource:(id)source + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + if (![self matchesKey:childKey andNode:newChildSnap]) { + newChildSnap = [FEmptyNode emptyNode]; + } + return [self.indexedFilter updateChildIn:oldSnap + forChildKey:childKey + newChild:newChildSnap + affectedPath:affectedPath + fromSource:source + accumulator:optChangeAccumulator]; +} + +- (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap + withNewNode:(FIndexedNode *)newSnap + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + __block FIndexedNode *filtered; + if (newSnap.node.isLeafNode) { + // Make sure we have a children node with the correct index, not a leaf + // node + filtered = [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] + index:self.index]; + } else { + // Dont' support priorities on queries + filtered = [newSnap updatePriority:[FEmptyNode emptyNode]]; + [newSnap.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + if (![self matchesKey:key andNode:node]) { + filtered = [filtered updateChild:key + withNewChild:[FEmptyNode emptyNode]]; + } + }]; + } + return [self.indexedFilter updateFullNode:oldSnap + withNewNode:filtered + accumulator:optChangeAccumulator]; +} + +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap { + // Don't support priorities on queries + return oldSnap; +} + +- (BOOL)filtersNodes { + return YES; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.h new file mode 100644 index 0000000..25a59b4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.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 + +@interface FTransformedEnumerator : NSEnumerator +- (id)initWithEnumerator:(NSEnumerator *)enumerator + andTransform:(id (^)(id))transform; +- (id)nextObject; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.m new file mode 100644 index 0000000..decb980 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.m @@ -0,0 +1,44 @@ +/* + * 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 "FirebaseDatabase/Sources/FTransformedEnumerator.h" + +@interface FTransformedEnumerator () +@property(nonatomic, strong) NSEnumerator *enumerator; +@property(nonatomic, copy) id (^transform)(id); +@end + +@implementation FTransformedEnumerator +- (id)initWithEnumerator:(NSEnumerator *)enumerator + andTransform:(id (^)(id))transform { + self = [super init]; + if (self) { + self.enumerator = enumerator; + self.transform = transform; + } + return self; +} + +- (id)nextObject { + id next = self.enumerator.nextObject; + if (next != nil) { + return self.transform(next); + } else { + return nil; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.h new file mode 100644 index 0000000..260d566 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.h @@ -0,0 +1,22 @@ +/* + * 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 "FirebaseDatabase/Sources/FIndex.h" +#import + +@interface FValueIndex : NSObject ++ (id)valueIndex; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.m new file mode 100644 index 0000000..6dde938 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.m @@ -0,0 +1,112 @@ +/* + * 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 "FirebaseDatabase/Sources/FValueIndex.h" +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@implementation FValueIndex + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { + NSComparisonResult indexCmp = [node1 compare:node2]; + if (indexCmp == NSOrderedSame) { + return [FUtilities compareKey:key1 toKey:key2]; + } else { + return indexCmp; + } +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { + if (reverse) { + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; + } else { + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; + } +} + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; +} + +- (BOOL)isDefinedOn:(id)node { + return YES; +} + +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { + return ![oldNode isEqual:newNode]; +} + +- (FNamedNode *)minPost { + return FNamedNode.min; +} + +- (FNamedNode *)maxPost { + return FNamedNode.max; +} + +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { + return [[FNamedNode alloc] initWithName:name andNode:indexValue]; +} + +- (NSString *)queryDefinition { + return @".value"; +} + +- (NSString *)description { + return @"FValueIndex"; +} + +- (id)copyWithZone:(NSZone *)zone { + return self; +} + +- (BOOL)isEqual:(id)other { + // since we're a singleton. + return (other == self); +} + +- (NSUInteger)hash { + return [@".value" hash]; +} + ++ (id)valueIndex { + static id valueIndex; + static dispatch_once_t once; + dispatch_once(&once, ^{ + valueIndex = [[FValueIndex alloc] init]; + }); + return valueIndex; +} +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.h new file mode 100644 index 0000000..ea6676e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.h @@ -0,0 +1,42 @@ +/* + * 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 + +@class FViewCache; +@class FViewProcessorResult; +@class FChildChangeAccumulator; +@protocol FNode; +@class FWriteTreeRef; +@class FPath; +@protocol FOperation; +@protocol FNodeFilter; + +@interface FViewProcessor : NSObject + +- (id)initWithFilter:(id)nodeFilter; + +- (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache + operation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache; +- (FViewCache *)revertUserWriteOn:(FViewCache *)viewCache + path:(FPath *)path + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.m new file mode 100644 index 0000000..35ec642 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.m @@ -0,0 +1,831 @@ +/* + * 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 "FirebaseDatabase/Sources/FViewProcessor.h" +#import "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h" +#import "FirebaseDatabase/Sources/Core/Operation/FMerge.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperation.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOverwrite.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/Core/View/FViewCache.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h" +#import "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/FViewProcessorResult.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +/** + * An implementation of FCompleteChildSource that never returns any additional + * children + */ +@interface FNoCompleteChildSource : NSObject +@end + +@implementation FNoCompleteChildSource ++ (FNoCompleteChildSource *)instance { + static FNoCompleteChildSource *source = nil; + static dispatch_once_t once; + dispatch_once(&once, ^{ + source = [[FNoCompleteChildSource alloc] init]; + }); + return source; +} + +- (id)completeChild:(NSString *)childKey { + return nil; +} + +- (FNamedNode *)childByIndex:(id)index + afterChild:(FNamedNode *)child + isReverse:(BOOL)reverse { + return nil; +} +@end + +/** + * An implementation of FCompleteChildSource that uses a FWriteTree in addition + * to any other server data or old event caches available to calculate complete + * children. + */ +@interface FWriteTreeCompleteChildSource : NSObject +@property(nonatomic, strong) FWriteTreeRef *writes; +@property(nonatomic, strong) FViewCache *viewCache; +@property(nonatomic, strong) id optCompleteServerCache; +@end + +@implementation FWriteTreeCompleteChildSource +- (id)initWithWrites:(FWriteTreeRef *)writes + viewCache:(FViewCache *)viewCache + serverCache:(id)optCompleteServerCache { + self = [super init]; + if (self) { + self.writes = writes; + self.viewCache = viewCache; + self.optCompleteServerCache = optCompleteServerCache; + } + return self; +} + +- (id)completeChild:(NSString *)childKey { + FCacheNode *node = self.viewCache.cachedEventSnap; + if ([node isCompleteForChild:childKey]) { + return [node.node getImmediateChild:childKey]; + } else { + FCacheNode *serverNode; + if (self.optCompleteServerCache) { + // Since we're only ever getting child nodes, we can use the key + // index here + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:self.optCompleteServerCache + index:[FKeyIndex keyIndex]]; + serverNode = [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:YES + isFiltered:NO]; + } else { + serverNode = self.viewCache.cachedServerSnap; + } + return [self.writes calculateCompleteChild:childKey cache:serverNode]; + } +} + +- (FNamedNode *)childByIndex:(id)index + afterChild:(FNamedNode *)child + isReverse:(BOOL)reverse { + id completeServerData = self.optCompleteServerCache != nil + ? self.optCompleteServerCache + : self.viewCache.completeServerSnap; + return [self.writes calculateNextNodeAfterPost:child + completeServerData:completeServerData + reverse:reverse + index:index]; +} + +@end + +@interface FViewProcessor () +@property(nonatomic, strong) id filter; +@end + +@implementation FViewProcessor + +- (id)initWithFilter:(id)nodeFilter { + self = [super init]; + if (self) { + self.filter = nodeFilter; + } + return self; +} + +- (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache + operation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache { + FChildChangeAccumulator *accumulator = + [[FChildChangeAccumulator alloc] init]; + FViewCache *newViewCache; + + if (operation.type == FOperationTypeOverwrite) { + FOverwrite *overwrite = (FOverwrite *)operation; + if (operation.source.fromUser) { + newViewCache = [self applyUserOverwriteTo:oldViewCache + changePath:overwrite.path + changedSnap:overwrite.snap + writesCache:writesCache + completeCache:optCompleteCache + accumulator:accumulator]; + } else { + NSAssert(operation.source.fromServer, + @"Unknown source for overwrite."); + // We filter the node if it's a tagged update or the node has been + // previously filtered and the update is not at the root in which + // case it is ok (and necessary) to mark the node unfiltered again + BOOL filterServerNode = overwrite.source.isTagged || + (oldViewCache.cachedServerSnap.isFiltered && + !overwrite.path.isEmpty); + newViewCache = [self applyServerOverwriteTo:oldViewCache + changePath:overwrite.path + snap:overwrite.snap + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } + } else if (operation.type == FOperationTypeMerge) { + FMerge *merge = (FMerge *)operation; + if (operation.source.fromUser) { + newViewCache = [self applyUserMergeTo:oldViewCache + path:merge.path + changedChildren:merge.children + writesCache:writesCache + completeCache:optCompleteCache + accumulator:accumulator]; + } else { + NSAssert(operation.source.fromServer, @"Unknown source for merge."); + // We filter the node if it's a tagged update or the node has been + // previously filtered + BOOL filterServerNode = merge.source.isTagged || + oldViewCache.cachedServerSnap.isFiltered; + newViewCache = [self applyServerMergeTo:oldViewCache + path:merge.path + changedChildren:merge.children + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } + } else if (operation.type == FOperationTypeAckUserWrite) { + FAckUserWrite *ackWrite = (FAckUserWrite *)operation; + if (!ackWrite.revert) { + newViewCache = [self ackUserWriteOn:oldViewCache + ackPath:ackWrite.path + affectedTree:ackWrite.affectedTree + writesCache:writesCache + completeCache:optCompleteCache + accumulator:accumulator]; + } else { + newViewCache = [self revertUserWriteOn:oldViewCache + path:ackWrite.path + writesCache:writesCache + completeCache:optCompleteCache + accumulator:accumulator]; + } + } else if (operation.type == FOperationTypeListenComplete) { + newViewCache = [self listenCompleteOldCache:oldViewCache + path:operation.path + writesCache:writesCache + serverCache:optCompleteCache + accumulator:accumulator]; + } else { + [NSException + raise:NSInternalInconsistencyException + format:@"Unknown operation encountered %ld.", (long)operation.type]; + return nil; + } + + NSArray *changes = [self maybeAddValueFromOldViewCache:oldViewCache + newViewCache:newViewCache + changes:accumulator.changes]; + FViewProcessorResult *results = + [[FViewProcessorResult alloc] initWithViewCache:newViewCache + changes:changes]; + return results; +} + +- (NSArray *)maybeAddValueFromOldViewCache:(FViewCache *)oldViewCache + newViewCache:(FViewCache *)newViewCache + changes:(NSArray *)changes { + NSArray *newChanges = changes; + FCacheNode *eventSnap = newViewCache.cachedEventSnap; + if (eventSnap.isFullyInitialized) { + BOOL isLeafOrEmpty = + eventSnap.node.isLeafNode || eventSnap.node.isEmpty; + if ([changes count] > 0 || + !oldViewCache.cachedEventSnap.isFullyInitialized || + (isLeafOrEmpty && + ![eventSnap.node isEqual:oldViewCache.completeEventSnap]) || + ![eventSnap.node.getPriority + isEqual:oldViewCache.completeEventSnap.getPriority]) { + FChange *valueChange = + [[FChange alloc] initWithType:FIRDataEventTypeValue + indexedNode:eventSnap.indexedNode]; + NSMutableArray *mutableChanges = [changes mutableCopy]; + [mutableChanges addObject:valueChange]; + newChanges = mutableChanges; + } + } + return newChanges; +} + +- (FViewCache *) + generateEventCacheAfterServerEvent:(FViewCache *)viewCache + path:(FPath *)changePath + writesCache:(FWriteTreeRef *)writesCache + source:(id)source + accumulator:(FChildChangeAccumulator *)accumulator { + FCacheNode *oldEventSnap = viewCache.cachedEventSnap; + if ([writesCache shadowingWriteAtPath:changePath] != nil) { + // we have a shadowing write, ignore changes. + return viewCache; + } else { + FIndexedNode *newEventCache; + if (changePath.isEmpty) { + // TODO: figure out how this plays with "sliding ack windows" + NSAssert( + viewCache.cachedServerSnap.isFullyInitialized, + @"If change path is empty, we must have complete server data"); + id nodeWithLocalWrites; + if (viewCache.cachedServerSnap.isFiltered) { + // We need to special case this, because we need to only apply + // writes to complete children, or we might end up raising + // events for incomplete children. If the server data is + // filtered deep writes cannot be guaranteed to be complete + id serverCache = viewCache.completeServerSnap; + FChildrenNode *completeChildren = + ([serverCache isKindOfClass:[FChildrenNode class]]) + ? serverCache + : [FEmptyNode emptyNode]; + nodeWithLocalWrites = [writesCache + calculateCompleteEventChildrenWithCompleteServerChildren: + completeChildren]; + } else { + nodeWithLocalWrites = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + viewCache.completeServerSnap]; + } + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:nodeWithLocalWrites + index:self.filter.index]; + newEventCache = [self.filter + updateFullNode:viewCache.cachedEventSnap.indexedNode + withNewNode:indexedNode + accumulator:accumulator]; + } else { + NSString *childKey = [changePath getFront]; + if ([childKey isEqualToString:@".priority"]) { + NSAssert( + changePath.length == 1, + @"Can't have a priority with additional path components"); + id oldEventNode = oldEventSnap.node; + id serverNode = viewCache.cachedServerSnap.node; + // we might have overwrites for this priority + id updatedPriority = [writesCache + calculateEventCacheAfterServerOverwriteWithChildPath: + changePath + existingEventSnap: + oldEventNode + existingServerSnap: + serverNode]; + if (updatedPriority != nil) { + newEventCache = + [self.filter updatePriority:updatedPriority + forNode:oldEventSnap.indexedNode]; + } else { + // priority didn't change, keep old node + newEventCache = oldEventSnap.indexedNode; + } + } else { + FPath *childChangePath = [changePath popFront]; + id newEventChild; + if ([oldEventSnap isCompleteForChild:childKey]) { + id serverNode = viewCache.cachedServerSnap.node; + id eventChildUpdate = [writesCache + calculateEventCacheAfterServerOverwriteWithChildPath: + changePath + existingEventSnap: + oldEventSnap.node + existingServerSnap: + serverNode]; + if (eventChildUpdate != nil) { + newEventChild = + [[oldEventSnap.node getImmediateChild:childKey] + updateChild:childChangePath + withNewChild:eventChildUpdate]; + } else { + // Nothing changed, just keep the old child + newEventChild = + [oldEventSnap.node getImmediateChild:childKey]; + } + } else { + newEventChild = [writesCache + calculateCompleteChild:childKey + cache:viewCache.cachedServerSnap]; + } + if (newEventChild != nil) { + newEventCache = + [self.filter updateChildIn:oldEventSnap.indexedNode + forChildKey:childKey + newChild:newEventChild + affectedPath:childChangePath + fromSource:source + accumulator:accumulator]; + } else { + // No complete children available or no change + newEventCache = oldEventSnap.indexedNode; + } + } + } + return [viewCache updateEventSnap:newEventCache + isComplete:(oldEventSnap.isFullyInitialized || + changePath.isEmpty) + isFiltered:self.filter.filtersNodes]; + } +} + +- (FViewCache *)applyServerOverwriteTo:(FViewCache *)oldViewCache + changePath:(FPath *)changePath + snap:(id)changedSnap + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + filterServerNode:(BOOL)filterServerNode + accumulator:(FChildChangeAccumulator *)accumulator { + FCacheNode *oldServerSnap = oldViewCache.cachedServerSnap; + FIndexedNode *newServerCache; + id serverFilter = + filterServerNode ? self.filter : self.filter.indexedFilter; + + if (changePath.isEmpty) { + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:changedSnap + index:serverFilter.index]; + newServerCache = [serverFilter updateFullNode:oldServerSnap.indexedNode + withNewNode:indexed + accumulator:nil]; + } else if (serverFilter.filtersNodes && !oldServerSnap.isFiltered) { + // We want to filter the server node, but we didn't filter the server + // node yet, so simulate a full update + NSAssert(![changePath isEmpty], + @"An empty path should been caught in the other branch"); + NSString *childKey = [changePath getFront]; + FPath *updatePath = [changePath popFront]; + id newChild = [[oldServerSnap.node getImmediateChild:childKey] + updateChild:updatePath + withNewChild:changedSnap]; + FIndexedNode *indexed = + [oldServerSnap.indexedNode updateChild:childKey + withNewChild:newChild]; + newServerCache = [serverFilter updateFullNode:oldServerSnap.indexedNode + withNewNode:indexed + accumulator:nil]; + } else { + NSString *childKey = [changePath getFront]; + if (![oldServerSnap isCompleteForPath:changePath] && + changePath.length > 1) { + // We don't update incomplete nodes with updates intended for other + // listeners. + return oldViewCache; + } + FPath *childChangePath = [changePath popFront]; + id childNode = [oldServerSnap.node getImmediateChild:childKey]; + id newChildNode = [childNode updateChild:childChangePath + withNewChild:changedSnap]; + if ([childKey isEqualToString:@".priority"]) { + newServerCache = + [serverFilter updatePriority:newChildNode + forNode:oldServerSnap.indexedNode]; + } else { + newServerCache = + [serverFilter updateChildIn:oldServerSnap.indexedNode + forChildKey:childKey + newChild:newChildNode + affectedPath:childChangePath + fromSource:[FNoCompleteChildSource instance] + accumulator:nil]; + } + } + FViewCache *newViewCache = + [oldViewCache updateServerSnap:newServerCache + isComplete:(oldServerSnap.isFullyInitialized || + changePath.isEmpty) + isFiltered:serverFilter.filtersNodes]; + id source = + [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache + viewCache:newViewCache + serverCache:optCompleteCache]; + return [self generateEventCacheAfterServerEvent:newViewCache + path:changePath + writesCache:writesCache + source:source + accumulator:accumulator]; +} + +- (FViewCache *)applyUserOverwriteTo:(FViewCache *)oldViewCache + changePath:(FPath *)changePath + changedSnap:(id)changedSnap + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator { + FCacheNode *oldEventSnap = oldViewCache.cachedEventSnap; + FViewCache *newViewCache; + id source = + [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache + viewCache:oldViewCache + serverCache:optCompleteCache]; + if (changePath.isEmpty) { + FIndexedNode *newIndexed = + [FIndexedNode indexedNodeWithNode:changedSnap + index:self.filter.index]; + FIndexedNode *newEventCache = + [self.filter updateFullNode:oldEventSnap.indexedNode + withNewNode:newIndexed + accumulator:accumulator]; + newViewCache = [oldViewCache updateEventSnap:newEventCache + isComplete:YES + isFiltered:self.filter.filtersNodes]; + } else { + NSString *childKey = [changePath getFront]; + if ([childKey isEqualToString:@".priority"]) { + FIndexedNode *newEventCache = [self.filter + updatePriority:changedSnap + forNode:oldViewCache.cachedEventSnap.indexedNode]; + newViewCache = + [oldViewCache updateEventSnap:newEventCache + isComplete:oldEventSnap.isFullyInitialized + isFiltered:oldEventSnap.isFiltered]; + } else { + FPath *childChangePath = [changePath popFront]; + id oldChild = [oldEventSnap.node getImmediateChild:childKey]; + id newChild; + if (childChangePath.isEmpty) { + // Child overwrite, we can replace the child + newChild = changedSnap; + } else { + id childNode = [source completeChild:childKey]; + if (childNode != nil) { + if ([[childChangePath getBack] + isEqualToString:@".priority"] && + [childNode getChild:[childChangePath parent]].isEmpty) { + // This is a priority update on an empty node. If this + // node exists on the server, the server will send down + // the priority in the update, so ignore for now + newChild = childNode; + } else { + newChild = [childNode updateChild:childChangePath + withNewChild:changedSnap]; + } + } else { + newChild = [FEmptyNode emptyNode]; + } + } + if (![oldChild isEqual:newChild]) { + FIndexedNode *newEventSnap = + [self.filter updateChildIn:oldEventSnap.indexedNode + forChildKey:childKey + newChild:newChild + affectedPath:childChangePath + fromSource:source + accumulator:accumulator]; + newViewCache = [oldViewCache + updateEventSnap:newEventSnap + isComplete:oldEventSnap.isFullyInitialized + isFiltered:self.filter.filtersNodes]; + } else { + newViewCache = oldViewCache; + } + } + } + return newViewCache; +} + ++ (BOOL)cache:(FViewCache *)viewCache hasChild:(NSString *)childKey { + return [viewCache.cachedEventSnap isCompleteForChild:childKey]; +} + +/** + * @param changedChildren NSDictionary of child name (NSString*) to child value + * (id) + */ +- (FViewCache *)applyUserMergeTo:(FViewCache *)viewCache + path:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)serverCache + accumulator:(FChildChangeAccumulator *)accumulator { + // HACK: In the case of a limit query, there may be some changes that bump + // things out of the window leaving room for new items. It's important we + // process these changes first, so we iterate the changes twice, first + // processing any that affect items currently in view. + // TODO: I consider an item "in view" if cacheHasChild is true, which checks + // both the server and event snap. I'm not sure if this will result in edge + // cases when a child is in one but not the other. + __block FViewCache *curViewCache = viewCache; + + [changedChildren enumerateWrites:^(FPath *relativePath, id childNode, + BOOL *stop) { + FPath *writePath = [path child:relativePath]; + if ([FViewProcessor cache:viewCache hasChild:[writePath getFront]]) { + curViewCache = [self applyUserOverwriteTo:curViewCache + changePath:writePath + changedSnap:childNode + writesCache:writesCache + completeCache:serverCache + accumulator:accumulator]; + } + }]; + + [changedChildren enumerateWrites:^(FPath *relativePath, id childNode, + BOOL *stop) { + FPath *writePath = [path child:relativePath]; + if (![FViewProcessor cache:viewCache hasChild:[writePath getFront]]) { + curViewCache = [self applyUserOverwriteTo:curViewCache + changePath:writePath + changedSnap:childNode + writesCache:writesCache + completeCache:serverCache + accumulator:accumulator]; + } + }]; + + return curViewCache; +} + +- (FViewCache *)applyServerMergeTo:(FViewCache *)viewCache + path:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)serverCache + filterServerNode:(BOOL)filterServerNode + accumulator:(FChildChangeAccumulator *)accumulator { + // If we don't have a cache yet, this merge was intended for a previously + // listen in the same location. Ignore it and wait for the complete data + // update coming soon. + if (viewCache.cachedServerSnap.node.isEmpty && + !viewCache.cachedServerSnap.isFullyInitialized) { + return viewCache; + } + + // HACK: In the case of a limit query, there may be some changes that bump + // things out of the window leaving room for new items. It's important we + // process these changes first, so we iterate the changes twice, first + // processing any that affect items currently in view. + // TODO: I consider an item "in view" if cacheHasChild is true, which checks + // both the server and event snap. I'm not sure if this will result in edge + // cases when a child is in one but not the other. + __block FViewCache *curViewCache = viewCache; + FCompoundWrite *actualMerge; + if (path.isEmpty) { + actualMerge = changedChildren; + } else { + actualMerge = + [[FCompoundWrite emptyWrite] addCompoundWrite:changedChildren + atPath:path]; + } + id serverNode = viewCache.cachedServerSnap.node; + + NSDictionary *childCompoundWrites = actualMerge.childCompoundWrites; + [childCompoundWrites + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FCompoundWrite *childMerge, BOOL *stop) { + if ([serverNode hasChild:childKey]) { + id serverChild = + [viewCache.cachedServerSnap.node getImmediateChild:childKey]; + id newChild = [childMerge applyToNode:serverChild]; + curViewCache = + [self applyServerOverwriteTo:curViewCache + changePath:[[FPath alloc] initWith:childKey] + snap:newChild + writesCache:writesCache + completeCache:serverCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } + }]; + + [childCompoundWrites + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FCompoundWrite *childMerge, BOOL *stop) { + bool isUnknownDeepMerge = + ![viewCache.cachedServerSnap isCompleteForChild:childKey] && + childMerge.rootWrite == nil; + if (![serverNode hasChild:childKey] && !isUnknownDeepMerge) { + id serverChild = + [viewCache.cachedServerSnap.node getImmediateChild:childKey]; + id newChild = [childMerge applyToNode:serverChild]; + curViewCache = + [self applyServerOverwriteTo:curViewCache + changePath:[[FPath alloc] initWith:childKey] + snap:newChild + writesCache:writesCache + completeCache:serverCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } + }]; + + return curViewCache; +} + +- (FViewCache *)ackUserWriteOn:(FViewCache *)viewCache + ackPath:(FPath *)ackPath + affectedTree:(FImmutableTree *)affectedTree + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator { + + if ([writesCache shadowingWriteAtPath:ackPath] != nil) { + return viewCache; + } + + // Only filter server node if it is currently filtered + BOOL filterServerNode = viewCache.cachedServerSnap.isFiltered; + + // Essentially we'll just get our existing server cache for the affected + // paths and re-apply it as a server update now that it won't be shadowed. + FCacheNode *serverCache = viewCache.cachedServerSnap; + if (affectedTree.value != nil) { + // This is an overwrite. + if ((ackPath.isEmpty && serverCache.isFullyInitialized) || + [serverCache isCompleteForPath:ackPath]) { + return + [self applyServerOverwriteTo:viewCache + changePath:ackPath + snap:[serverCache.node getChild:ackPath] + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } else if (ackPath.isEmpty) { + // This is a goofy edge case where we are acking data at this + // location but don't have full data. We should just re-apply + // whatever we have in our cache as a merge. + FCompoundWrite *changedChildren = [FCompoundWrite emptyWrite]; + for (FNamedNode *child in serverCache.node.childEnumerator) { + changedChildren = [changedChildren addWrite:child.node + atKey:child.name]; + } + return [self applyServerMergeTo:viewCache + path:ackPath + changedChildren:changedChildren + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } else { + return viewCache; + } + } else { + // This is a merge. + __block FCompoundWrite *changedChildren = [FCompoundWrite emptyWrite]; + [affectedTree forEach:^(FPath *mergePath, id value) { + FPath *serverCachePath = [ackPath child:mergePath]; + if ([serverCache isCompleteForPath:serverCachePath]) { + changedChildren = [changedChildren + addWrite:[serverCache.node getChild:serverCachePath] + atPath:mergePath]; + } + }]; + return [self applyServerMergeTo:viewCache + path:ackPath + changedChildren:changedChildren + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } +} + +- (FViewCache *)revertUserWriteOn:(FViewCache *)viewCache + path:(FPath *)path + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator { + if ([writesCache shadowingWriteAtPath:path] != nil) { + return viewCache; + } else { + id source = [[FWriteTreeCompleteChildSource alloc] + initWithWrites:writesCache + viewCache:viewCache + serverCache:optCompleteCache]; + FIndexedNode *oldEventCache = viewCache.cachedEventSnap.indexedNode; + FIndexedNode *newEventCache; + if (path.isEmpty || [[path getFront] isEqualToString:@".priority"]) { + id newNode; + if (viewCache.cachedServerSnap.isFullyInitialized) { + newNode = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + viewCache.completeServerSnap]; + } else { + newNode = [writesCache + calculateCompleteEventChildrenWithCompleteServerChildren: + viewCache.cachedServerSnap.node]; + } + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:newNode + index:self.filter.index]; + newEventCache = [self.filter updateFullNode:oldEventCache + withNewNode:indexedNode + accumulator:accumulator]; + } else { + NSString *childKey = [path getFront]; + id newChild = + [writesCache calculateCompleteChild:childKey + cache:viewCache.cachedServerSnap]; + if (newChild == nil && + [viewCache.cachedServerSnap isCompleteForChild:childKey]) { + newChild = [oldEventCache.node getImmediateChild:childKey]; + } + if (newChild != nil) { + newEventCache = [self.filter updateChildIn:oldEventCache + forChildKey:childKey + newChild:newChild + affectedPath:[path popFront] + fromSource:source + accumulator:accumulator]; + } else if (newChild == nil && + [viewCache.cachedEventSnap.node hasChild:childKey]) { + // No complete child available, delete the existing one, if any + newEventCache = + [self.filter updateChildIn:oldEventCache + forChildKey:childKey + newChild:[FEmptyNode emptyNode] + affectedPath:[path popFront] + fromSource:source + accumulator:accumulator]; + } else { + newEventCache = oldEventCache; + } + if (newEventCache.node.isEmpty && + viewCache.cachedServerSnap.isFullyInitialized) { + // We might have reverted all child writes. Maybe the old event + // was a leaf node. + id complete = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + viewCache.completeServerSnap]; + if (complete.isLeafNode) { + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:complete]; + newEventCache = [self.filter updateFullNode:newEventCache + withNewNode:indexed + accumulator:accumulator]; + } + } + } + BOOL complete = viewCache.cachedServerSnap.isFullyInitialized || + [writesCache shadowingWriteAtPath:[FPath empty]] != nil; + return [viewCache updateEventSnap:newEventCache + isComplete:complete + isFiltered:self.filter.filtersNodes]; + } +} + +- (FViewCache *)listenCompleteOldCache:(FViewCache *)viewCache + path:(FPath *)path + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)servercache + accumulator:(FChildChangeAccumulator *)accumulator { + FCacheNode *oldServerNode = viewCache.cachedServerSnap; + FViewCache *newViewCache = [viewCache + updateServerSnap:oldServerNode.indexedNode + isComplete:(oldServerNode.isFullyInitialized || path.isEmpty) + isFiltered:oldServerNode.isFiltered]; + return [self + generateEventCacheAfterServerEvent:newViewCache + path:path + writesCache:writesCache + source:[FNoCompleteChildSource instance] + accumulator:accumulator]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.h new file mode 100644 index 0000000..8d3e2ef --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.h @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FViewCache; + +@interface FViewProcessorResult : NSObject +@property(nonatomic, strong, readonly) FViewCache *viewCache; +/** + * List of FChanges. + */ +@property(nonatomic, strong, readonly) NSArray *changes; + +- (id)initWithViewCache:(FViewCache *)viewCache changes:(NSArray *)changes; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.m new file mode 100644 index 0000000..8cfe7f3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseDatabase/Sources/FViewProcessorResult.h" +#import "FirebaseDatabase/Sources/Core/View/FViewCache.h" + +@interface FViewProcessorResult () +@property(nonatomic, strong, readwrite) FViewCache *viewCache; +@property(nonatomic, strong, readwrite) NSArray *changes; +@end + +@implementation FViewProcessorResult +- (id)initWithViewCache:(FViewCache *)viewCache changes:(NSArray *)changes { + self = [super init]; + if (self) { + self.viewCache = viewCache; + self.changes = changes; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h new file mode 100644 index 0000000..5f025e1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h @@ -0,0 +1,70 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" + +@protocol FIRAppCheckInterop; +@protocol FIRAuthInterop; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRDatabaseConnectionContext : NSObject +/// Auth token if available. +@property(nonatomic, nullable) NSString *authToken; + +/// App check token if available. +@property(nonatomic, nullable) NSString *appCheckToken; + +- (instancetype)initWithAuthToken:(nullable NSString *)authToken + appCheckToken:(nullable NSString *)appCheckToken; + +@end + +@protocol FIRDatabaseConnectionContextProvider + +- (void) + fetchContextForcingRefresh:(BOOL)forceRefresh + withCallback: + (void (^)(FIRDatabaseConnectionContext *_Nullable context, + NSError *_Nullable error))callback; + +/// Adds a listener to the Auth token updates. +/// @param listener A block that will be invoked each time the Auth token is +/// updated. +- (void)listenForAuthTokenChanges:(fbt_void_nsstring)listener; + +/// Adds a listener to the FAC token updates. +/// @param listener A block that will be invoked each time the FAC token is +/// updated. +- (void)listenForAppCheckTokenChanges:(fbt_void_nsstring)listener; + +@end + +@interface FIRDatabaseConnectionContextProvider + : NSObject + ++ (id) + contextProviderWithAuth:(nullable id)auth + appCheck:(nullable id)appCheck; + +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.m new file mode 100644 index 0000000..e6260f5 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.m @@ -0,0 +1,225 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h" + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h" +#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h" +#import "Interop/Auth/Public/FIRAuthInterop.h" + +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FAuthStateListenerWrapper : NSObject + +@property(nonatomic, copy) fbt_void_nsstring listener; +@property(nonatomic, weak) id auth; + +@end + +@implementation FAuthStateListenerWrapper + +- (instancetype)initWithListener:(fbt_void_nsstring)listener + auth:(id)auth { + self = [super init]; + if (self != nil) { + self->_listener = listener; + self->_auth = auth; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(authStateDidChangeNotification:) + name:FIRAuthStateDidChangeInternalNotification + object:nil]; + } + return self; +} + +- (void)authStateDidChangeNotification:(NSNotification *)notification { + NSDictionary *userInfo = notification.userInfo; + if (notification.object == self.auth) { + NSString *token = + userInfo[FIRAuthStateDidChangeInternalNotificationTokenKey]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + self.listener(token); + }); + } +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end + +@implementation FIRDatabaseConnectionContext + +- (instancetype)initWithAuthToken:(nullable NSString *)authToken + appCheckToken:(nullable NSString *)appCheckToken { + self = [super init]; + if (self) { + _authToken = [authToken copy]; + _appCheckToken = [appCheckToken copy]; + } + return self; +} + +@end + +@interface FIRDatabaseConnectionContextProvider () + +@property(nonatomic, strong) id appCheck; +@property(nonatomic, strong) id auth; + +/// Strong references to the auth listeners as they are only weak in +/// FIRFirebaseApp. +@property(nonatomic, readonly) NSMutableArray *authListeners; + +/// Observer objects returned by +/// `-[NSNotificationCenter addObserverForName:object:queue:usingBlock:]` +/// method. Required to cleanup the observers on dealloc. +@property(nonatomic, readonly) NSMutableArray *appCheckNotificationObservers; + +/// An NSOperationQueue to call listeners on. +@property(nonatomic, readonly) NSOperationQueue *listenerQueue; + +@end + +@implementation FIRDatabaseConnectionContextProvider + +- (instancetype)initWithAuth:(nullable id)auth + appCheck:(nullable id)appCheck { + self = [super init]; + if (self != nil) { + self->_appCheck = appCheck; + self->_auth = auth; + self->_authListeners = [NSMutableArray array]; + self->_appCheckNotificationObservers = [NSMutableArray array]; + self->_listenerQueue = [[NSOperationQueue alloc] init]; + self->_listenerQueue.underlyingQueue = [FIRDatabaseQuery sharedQueue]; + } + return self; +} + +- (void)dealloc { + @synchronized(self) { + // Make sure notification observers are removed from + // NSNotificationCenter. + for (id notificationObserver in self.appCheckNotificationObservers) { + [NSNotificationCenter.defaultCenter + removeObserver:notificationObserver]; + } + } +} + +- (void) + fetchContextForcingRefresh:(BOOL)forceRefresh + withCallback: + (void (^)(FIRDatabaseConnectionContext *_Nullable context, + NSError *_Nullable error))callback { + + if (self.auth == nil && self.appCheck == nil) { + // Nothing to fetch. Finish straight away. + callback(nil, nil); + return; + } + + // Use dispatch group to call the callback when both Auth and FAC operations + // finished. + dispatch_group_t dispatchGroup = dispatch_group_create(); + + __block NSString *authToken; + __block NSString *appCheckToken; + __block NSError *authError; + + if (self.auth) { + dispatch_group_enter(dispatchGroup); + [self.auth getTokenForcingRefresh:forceRefresh + withCallback:^(NSString *_Nullable token, + NSError *_Nullable error) { + authToken = token; + authError = error; + + dispatch_group_leave(dispatchGroup); + }]; + } + + if (self.appCheck) { + dispatch_group_enter(dispatchGroup); + [self.appCheck + getTokenForcingRefresh:forceRefresh + completion:^( + id _Nonnull tokenResult) { + appCheckToken = tokenResult.token; + if (tokenResult.error) { + FFLog(@"I-RDB096001", + @"Failed to fetch App Check token: %@", + tokenResult.error); + } + dispatch_group_leave(dispatchGroup); + }]; + } + + dispatch_group_notify(dispatchGroup, [FIRDatabaseQuery sharedQueue], ^{ + __auto_type context = [[FIRDatabaseConnectionContext alloc] + initWithAuthToken:authToken + appCheckToken:appCheckToken]; + // Pass only a possible Auth error. App Check errors should not change the + // database SDK behaviour at this point as the App Check enforcement is + // controlled on the backend. + callback(context, authError); + }); +} + +- (void)listenForAuthTokenChanges:(_Nonnull fbt_void_nsstring)listener { + FAuthStateListenerWrapper *wrapper = + [[FAuthStateListenerWrapper alloc] initWithListener:listener + auth:self.auth]; + [self.authListeners addObject:wrapper]; +} + +- (void)listenForAppCheckTokenChanges:(fbt_void_nsstring)listener { + if (self.appCheck == nil) { + return; + } + NSString *appCheckTokenKey = [self.appCheck notificationTokenKey]; + __auto_type notificationObserver = [NSNotificationCenter.defaultCenter + addObserverForName:[self.appCheck tokenDidChangeNotificationName] + object:self.appCheck + queue:self.listenerQueue + usingBlock:^(NSNotification *_Nonnull notification) { + NSString *appCheckToken = + notification.userInfo[appCheckTokenKey]; + listener(appCheckToken); + }]; + + @synchronized(self) { + [self.appCheckNotificationObservers addObject:notificationObserver]; + } +} + ++ (id) + contextProviderWithAuth:(nullable id)auth + appCheck:(nullable id)appCheck { + return [[self alloc] initWithAuth:auth appCheck:appCheck]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.h new file mode 100644 index 0000000..6305d34 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.h @@ -0,0 +1,41 @@ +/* + * 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 + +@protocol FCachePolicy + +- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize + numberOfTrackedQueries:(NSUInteger)numTrackedQueries; +- (BOOL)shouldCheckCacheSize:(NSUInteger)serverUpdatesSinceLastCheck; +- (float)percentOfQueriesToPruneAtOnce; +- (NSUInteger)maxNumberOfQueriesToKeep; + +@end + +@interface FLRUCachePolicy : NSObject + +@property(nonatomic, readonly) NSUInteger maxSize; + +- (id)initWithMaxSize:(NSUInteger)maxSize; + +@end + +@interface FNoCachePolicy : NSObject + ++ (FNoCachePolicy *)noCachePolicy; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.m new file mode 100644 index 0000000..83ef516 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.m @@ -0,0 +1,82 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FCachePolicy.h" + +@interface FLRUCachePolicy () + +@property(nonatomic, readwrite) NSUInteger maxSize; + +@end + +static const NSUInteger kFServerUpdatesBetweenCacheSizeChecks = 1000; +static const NSUInteger kFMaxNumberOfPrunableQueriesToKeep = 1000; +static const float kFPercentOfQueriesToPruneAtOnce = 0.2f; + +@implementation FLRUCachePolicy + +- (id)initWithMaxSize:(NSUInteger)maxSize { + self = [super init]; + if (self != nil) { + self->_maxSize = maxSize; + } + return self; +} + +- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize + numberOfTrackedQueries:(NSUInteger)numTrackedQueries { + return cacheSize > self.maxSize || + numTrackedQueries > kFMaxNumberOfPrunableQueriesToKeep; +} + +- (BOOL)shouldCheckCacheSize:(NSUInteger)serverUpdatesSinceLastCheck { + return serverUpdatesSinceLastCheck > kFServerUpdatesBetweenCacheSizeChecks; +} + +- (float)percentOfQueriesToPruneAtOnce { + return kFPercentOfQueriesToPruneAtOnce; +} + +- (NSUInteger)maxNumberOfQueriesToKeep { + return kFMaxNumberOfPrunableQueriesToKeep; +} + +@end + +@implementation FNoCachePolicy + ++ (FNoCachePolicy *)noCachePolicy { + return [[FNoCachePolicy alloc] init]; +} + +- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize + numberOfTrackedQueries:(NSUInteger)numTrackedQueries { + return NO; +} + +- (BOOL)shouldCheckCacheSize:(NSUInteger)serverUpdatesSinceLastCheck { + return NO; +} + +- (float)percentOfQueriesToPruneAtOnce { + return 0; +} + +- (NSUInteger)maxNumberOfQueriesToKeep { + return NSUIntegerMax; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h new file mode 100644 index 0000000..82b340e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.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. + */ + +#import + +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Persistence/FStorageEngine.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@class FCacheNode; +@class FTrackedQuery; +@class FPruneForest; +@class FRepoInfo; + +@interface FLevelDBStorageEngine : NSObject + ++ (NSString *)firebaseDir; + +- (id)initWithPath:(NSString *)path; + +- (void)runLegacyMigration:(FRepoInfo *)info; +- (void)purgeEverything; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.m new file mode 100644 index 0000000..f23dcec --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.m @@ -0,0 +1,1002 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h" + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Persistence/FPendingPut.h" +#import "FirebaseDatabase/Sources/Persistence/FPruneForest.h" +#import "FirebaseDatabase/Sources/Persistence/FTrackedQuery.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h" + +@interface FLevelDBStorageEngine () + +@property(nonatomic, strong) NSString *basePath; +@property(nonatomic, strong) APLevelDB *writesDB; +@property(nonatomic, strong) APLevelDB *serverCacheDB; + +@end + +// WARNING: If you change this, you need to write a migration script +static NSString *const kFPersistenceVersion = @"1"; + +static NSString *const kFServerDBPath = @"server_data"; +static NSString *const kFWritesDBPath = @"writes"; + +static NSString *const kFUserWriteId = @"id"; +static NSString *const kFUserWritePath = @"path"; +static NSString *const kFUserWriteOverwrite = @"o"; +static NSString *const kFUserWriteMerge = @"m"; + +static NSString *const kFTrackedQueryId = @"id"; +static NSString *const kFTrackedQueryPath = @"path"; +static NSString *const kFTrackedQueryParams = @"p"; +static NSString *const kFTrackedQueryLastUse = @"lu"; +static NSString *const kFTrackedQueryIsComplete = @"c"; +static NSString *const kFTrackedQueryIsActive = @"a"; + +static NSString *const kFServerCachePrefix = @"/server_cache/"; +// '~' is the last non-control character in the ASCII table until 127 +// We wan't the entire range of thing stored in the DB +static NSString *const kFServerCacheRangeEnd = @"/server_cache~"; +static NSString *const kFTrackedQueriesPrefix = @"/tracked_queries/"; +static NSString *const kFTrackedQueryKeysPrefix = @"/tracked_query_keys/"; + +// Failed to load JSON because a valid JSON turns out to be NaN while +// deserializing +static const NSInteger kFNanFailureCode = 3840; + +static NSString *writeRecordKey(NSUInteger writeId) { + return [NSString stringWithFormat:@"%lu", (unsigned long)(writeId)]; +} + +static NSString *serverCacheKey(FPath *path) { + return [NSString stringWithFormat:@"%@%@", kFServerCachePrefix, + ([path toStringWithTrailingSlash])]; +} + +static NSString *trackedQueryKey(NSUInteger trackedQueryId) { + return [NSString stringWithFormat:@"%@%lu", kFTrackedQueriesPrefix, + (unsigned long)trackedQueryId]; +} + +static NSString *trackedQueryKeysKeyPrefix(NSUInteger trackedQueryId) { + return [NSString stringWithFormat:@"%@%lu/", kFTrackedQueryKeysPrefix, + (unsigned long)trackedQueryId]; +} + +static NSString *trackedQueryKeysKey(NSUInteger trackedQueryId, NSString *key) { + return [NSString stringWithFormat:@"%@%lu/%@", kFTrackedQueryKeysPrefix, + (unsigned long)trackedQueryId, key]; +} + +@implementation FLevelDBStorageEngine +#pragma mark - Constructors + +- (id)initWithPath:(NSString *)dbPath { + self = [super init]; + if (self) { + self.basePath = [[FLevelDBStorageEngine firebaseDir] + stringByAppendingPathComponent:dbPath]; + /* For reference: + serverDataDB = [aPersistence createDbByName:@"server_data"]; + FPangolinDB *completenessDb = [aPersistence + createDbByName:@"server_complete"]; + */ + [FLevelDBStorageEngine ensureDir:self.basePath markAsDoNotBackup:YES]; + [self runMigration]; + [self openDatabases]; + } + return self; +} + +- (void)runMigration { + // Currently we're at version 1, so all we need to do is write that to a + // file + NSString *versionFile = + [self.basePath stringByAppendingPathComponent:@"version"]; + NSError *error; + NSString *oldVersion = + [NSString stringWithContentsOfFile:versionFile + encoding:NSUTF8StringEncoding + error:&error]; + if (!oldVersion) { + // This is probably fine, we don't have a version file yet + BOOL success = [kFPersistenceVersion writeToFile:versionFile + atomically:NO + encoding:NSUTF8StringEncoding + error:&error]; + if (!success) { + FFWarn(@"I-RDB076001", @"Failed to write version for database: %@", + error); + } + } else if ([oldVersion isEqualToString:kFPersistenceVersion]) { + // Everythings fine no need for migration + } else if ([oldVersion length] == 0) { + FFWarn(@"I-RDB076036", + @"Version file empty. Assuming database version 1."); + } else { + // If we add more versions in the future, we need to run migration here + [NSException raise:NSInternalInconsistencyException + format:@"Unrecognized database version: %@", oldVersion]; + } +} + +- (void)runLegacyMigration:(FRepoInfo *)info { + NSArray *dirPaths = NSSearchPathForDirectoriesInDomains( + NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDir = [dirPaths objectAtIndex:0]; + NSString *firebaseDir = + [documentsDir stringByAppendingPathComponent:@"firebase"]; + NSString *repoHashString = + [NSString stringWithFormat:@"%@_%@", info.host, info.namespace]; + NSString *legacyBaseDir = + [NSString stringWithFormat:@"%@/1/%@/v1", firebaseDir, repoHashString]; + if ([[NSFileManager defaultManager] fileExistsAtPath:legacyBaseDir]) { + FFWarn(@"I-RDB076002", @"Legacy database found, migrating..."); + // We only need to migrate writes + NSError *error = nil; + APLevelDB *writes = [APLevelDB + levelDBWithPath:[legacyBaseDir stringByAppendingPathComponent: + @"outstanding_puts"] + error:&error]; + if (writes != nil) { + __block NSUInteger numberOfWritesRestored = 0; + // Maybe we could use write batches, but what the heck, I'm sure + // it'll go fine :P + [writes enumerateKeysAndValuesAsData:^(NSString *key, NSData *data, + BOOL *stop) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + // Update the deprecated API when minimum iOS version is 11+. + id pendingPut = [NSKeyedUnarchiver unarchiveObjectWithData:data]; +#pragma clang diagnostic pop + if ([pendingPut isKindOfClass:[FPendingPut class]]) { + FPendingPut *put = pendingPut; + id newNode = + [FSnapshotUtilities nodeFrom:put.data + priority:put.priority]; + [self saveUserOverwrite:newNode + atPath:put.path + writeId:[key integerValue]]; + numberOfWritesRestored++; + } else if ([pendingPut + isKindOfClass:[FPendingPutPriority class]]) { + // This is for backwards compatibility. Older clients will + // save FPendingPutPriority. New ones will need to read it and + // translate. + FPendingPutPriority *putPriority = pendingPut; + FPath *priorityPath = + [putPriority.path childFromString:@".priority"]; + id newNode = + [FSnapshotUtilities nodeFrom:putPriority.priority + priority:nil]; + [self saveUserOverwrite:newNode + atPath:priorityPath + writeId:[key integerValue]]; + numberOfWritesRestored++; + } else if ([pendingPut isKindOfClass:[FPendingUpdate class]]) { + FPendingUpdate *update = pendingPut; + FCompoundWrite *merge = [FCompoundWrite + compoundWriteWithValueDictionary:update.data]; + [self saveUserMerge:merge + atPath:update.path + writeId:[key integerValue]]; + numberOfWritesRestored++; + } else { + FFWarn(@"I-RDB076003", + @"Failed to migrate legacy write, meh!"); + } + }]; + FFWarn(@"I-RDB076004", @"Migrated %lu writes", + (unsigned long)numberOfWritesRestored); + [writes close]; + FFWarn(@"I-RDB076005", @"Deleting legacy database..."); + BOOL success = + [[NSFileManager defaultManager] removeItemAtPath:legacyBaseDir + error:&error]; + if (!success) { + FFWarn(@"I-RDB076006", @"Failed to delete legacy database: %@", + error); + } else { + FFWarn(@"I-RDB076007", @"Finished migrating legacy database."); + } + } else { + FFWarn(@"I-RDB076008", @"Failed to migrate old database: %@", + error); + } + } +} + +- (void)openDatabases { + self.serverCacheDB = [self createDB:kFServerDBPath]; + self.writesDB = [self createDB:kFWritesDBPath]; +} + +- (void)purgeDatabase:(NSString *)dbPath { + NSString *path = [self.basePath stringByAppendingPathComponent:dbPath]; + NSError *error; + FFWarn(@"I-RDB076009", @"Deleting database at path %@", path); + BOOL success = [[NSFileManager defaultManager] removeItemAtPath:path + error:&error]; + if (!success) { + [NSException raise:NSInternalInconsistencyException + format:@"Failed to delete database files: %@", error]; + } +} + +- (void)purgeEverything { + [self close]; + [@[ kFServerDBPath, kFWritesDBPath ] + enumerateObjectsUsingBlock:^(NSString *dbPath, NSUInteger idx, + BOOL *stop) { + [self purgeDatabase:dbPath]; + }]; + + [self openDatabases]; +} + +- (void)close { + // autoreleasepool will cause deallocation which will close the DB + @autoreleasepool { + [self.serverCacheDB close]; + self.serverCacheDB = nil; + [self.writesDB close]; + self.writesDB = nil; + } +} + ++ (NSString *)firebaseDir { +#if TARGET_OS_IOS || TARGET_OS_WATCH + NSArray *dirPaths = NSSearchPathForDirectoriesInDomains( + NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDir = [dirPaths objectAtIndex:0]; + return [documentsDir stringByAppendingPathComponent:@"firebase"]; +#elif TARGET_OS_TV + NSArray *dirPaths = NSSearchPathForDirectoriesInDomains( + NSCachesDirectory, NSUserDomainMask, YES); + NSString *cachesDir = [dirPaths objectAtIndex:0]; + return [cachesDir stringByAppendingPathComponent:@"firebase"]; +#elif TARGET_OS_OSX + return [NSHomeDirectory() stringByAppendingPathComponent:@".firebase"]; +#endif +} + +- (APLevelDB *)createDB:(NSString *)dbName { + NSError *err = nil; + NSString *path = [self.basePath stringByAppendingPathComponent:dbName]; + APLevelDB *db = [APLevelDB levelDBWithPath:path error:&err]; + + if (err) { + FFWarn(@"I-RDB076036", + @"Failed to read database persistence file '%@': %@", dbName, + [err localizedDescription]); + err = nil; + + // Delete the database and try again. + [self purgeDatabase:dbName]; + db = [APLevelDB levelDBWithPath:path error:&err]; + + if (err) { + NSString *reason = [NSString + stringWithFormat:@"Error initializing persistence: %@", + [err description]]; + @throw [NSException + exceptionWithName:@"FirebaseDatabasePersistenceFailure" + reason:reason + userInfo:nil]; + } + } + + return db; +} + +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId { + NSDictionary *write = @{ + kFUserWriteId : @(writeId), + kFUserWritePath : [path toStringWithTrailingSlash], + kFUserWriteOverwrite : [node valForExport:YES] + }; + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:write + options:0 + error:&error]; + NSAssert(data, @"Failed to serialize user overwrite: %@, (Error: %@)", + write, error); + [self.writesDB setData:data forKey:writeRecordKey(writeId)]; +} + +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId { + NSDictionary *write = @{ + kFUserWriteId : @(writeId), + kFUserWritePath : [path toStringWithTrailingSlash], + kFUserWriteMerge : [merge valForExport:YES] + }; + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:write + options:0 + error:&error]; + NSAssert(data, @"Failed to serialize user merge: %@ (Error: %@)", write, + error); + [self.writesDB setData:data forKey:writeRecordKey(writeId)]; +} + +- (void)removeUserWrite:(NSUInteger)writeId { + [self.writesDB removeKey:writeRecordKey(writeId)]; +} + +- (void)removeAllUserWrites { + __block NSUInteger count = 0; + NSDate *start = [NSDate date]; + id batch = [self.writesDB beginWriteBatch]; + [self.writesDB enumerateKeys:^(NSString *key, BOOL *stop) { + [batch removeKey:key]; + count++; + }]; + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076010", @"Failed to remove all users writes on disk!"); + } else { + FFDebug(@"I-RDB076011", @"Removed %lu writes in %fms", + (unsigned long)count, [start timeIntervalSinceNow] * -1000); + } +} + +- (NSArray *)userWrites { + NSDate *date = [NSDate date]; + NSMutableArray *writes = [NSMutableArray array]; + [self.writesDB enumerateKeysAndValuesAsData:^(NSString *key, NSData *data, + BOOL *stop) { + NSError *error = nil; + NSDictionary *writeJSON = [NSJSONSerialization JSONObjectWithData:data + options:0 + error:&error]; + if (writeJSON == nil) { + if (error.code == kFNanFailureCode) { + FFWarn(@"I-RDB076012", + @"Failed to deserialize write (%@), likely because of out " + @"of range doubles (Error: %@)", + [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding], + error); + FFWarn(@"I-RDB076013", @"Removing failed write with key %@", key); + [self.writesDB removeKey:key]; + } else { + [NSException raise:NSInternalInconsistencyException + format:@"Failed to deserialize write: %@", error]; + } + } else { + NSInteger writeId = + ((NSNumber *)writeJSON[kFUserWriteId]).integerValue; + FPath *path = [FPath pathWithString:writeJSON[kFUserWritePath]]; + FWriteRecord *writeRecord; + if (writeJSON[kFUserWriteMerge] != nil) { + // It's a merge + FCompoundWrite *merge = [FCompoundWrite + compoundWriteWithValueDictionary:writeJSON[kFUserWriteMerge]]; + writeRecord = [[FWriteRecord alloc] initWithPath:path + merge:merge + writeId:writeId]; + } else { + // It's an overwrite + NSAssert(writeJSON[kFUserWriteOverwrite] != nil, + @"Persisted write did not contain merge or overwrite!"); + id node = + [FSnapshotUtilities nodeFrom:writeJSON[kFUserWriteOverwrite]]; + writeRecord = [[FWriteRecord alloc] initWithPath:path + overwrite:node + writeId:writeId + visible:YES]; + } + [writes addObject:writeRecord]; + } + }]; + // Make sure writes are sorted + [writes sortUsingComparator:^NSComparisonResult(FWriteRecord *one, + FWriteRecord *two) { + if (one.writeId < two.writeId) { + return NSOrderedAscending; + } else if (one.writeId > two.writeId) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]; + FFDebug(@"I-RDB076014", @"Loaded %lu writes in %fms", + (unsigned long)writes.count, [date timeIntervalSinceNow] * -1000); + return writes; +} + +- (id)serverCacheAtPath:(FPath *)path { + NSDate *start = [NSDate date]; + id data = [self internalNestedDataForPath:path]; + id node = [FSnapshotUtilities nodeFrom:data]; + FFDebug(@"I-RDB076015", @"Loaded node with %d children at %@ in %fms", + [node numChildren], path, [start timeIntervalSinceNow] * -1000); + return node; +} + +- (id)serverCacheForKeys:(NSSet *)keys atPath:(FPath *)path { + NSDate *start = [NSDate date]; + __block id node = [FEmptyNode emptyNode]; + [keys enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) { + id data = [self internalNestedDataForPath:[path childFromString:key]]; + node = [node updateImmediateChild:key + withNewChild:[FSnapshotUtilities nodeFrom:data]]; + }]; + FFDebug(@"I-RDB076016", + @"Loaded node with %d children for %lu keys at %@ in %fms", + [node numChildren], (unsigned long)keys.count, path, + [start timeIntervalSinceNow] * -1000); + return node; +} + +- (void)updateServerCache:(id)node + atPath:(FPath *)path + merge:(BOOL)merge { + NSDate *start = [NSDate date]; + id batch = [self.serverCacheDB beginWriteBatch]; + // Remove any leaf nodes that might be higher up + [self removeAllLeafNodesOnPath:path batch:batch]; + __block NSUInteger counter = 0; + if (merge) { + // remove any children that exist + [node enumerateChildrenUsingBlock:^(NSString *childKey, + id childNode, BOOL *stop) { + FPath *childPath = [path childFromString:childKey]; + [self removeAllWithPrefix:serverCacheKey(childPath) + batch:batch + database:self.serverCacheDB]; + [self saveNodeInternal:childNode + atPath:childPath + batch:batch + counter:&counter]; + }]; + } else { + // remove everything + [self removeAllWithPrefix:serverCacheKey(path) + batch:batch + database:self.serverCacheDB]; + [self saveNodeInternal:node atPath:path batch:batch counter:&counter]; + } + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076017", @"Failed to update server cache on disk!"); + } else { + FFDebug(@"I-RDB076018", @"Saved %lu leaf nodes for overwrite in %fms", + (unsigned long)counter, [start timeIntervalSinceNow] * -1000); + } +} + +- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge + atPath:(FPath *)path { + NSDate *start = [NSDate date]; + __block NSUInteger counter = 0; + id batch = [self.serverCacheDB beginWriteBatch]; + // Remove any leaf nodes that might be higher up + [self removeAllLeafNodesOnPath:path batch:batch]; + [merge enumerateWrites:^(FPath *relativePath, id node, BOOL *stop) { + FPath *childPath = [path child:relativePath]; + [self removeAllWithPrefix:serverCacheKey(childPath) + batch:batch + database:self.serverCacheDB]; + [self saveNodeInternal:node + atPath:childPath + batch:batch + counter:&counter]; + }]; + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076019", @"Failed to update server cache on disk!"); + } else { + FFDebug(@"I-RDB076020", @"Saved %lu leaf nodes for merge in %fms", + (unsigned long)counter, [start timeIntervalSinceNow] * -1000); + } +} + +- (void)saveNodeInternal:(id)node + atPath:(FPath *)path + batch:(id)batch + counter:(NSUInteger *)counter { + id data = [node valForExport:YES]; + if (data != nil && ![data isKindOfClass:[NSNull class]]) { + [self internalSetNestedData:data + forKey:serverCacheKey(path) + withBatch:batch + counter:counter]; + } +} + +- (NSUInteger)serverCacheEstimatedSizeInBytes { + // Use the exact size, because for pruning the approximate size can lead to + // weird situations where we prune everything because no compaction is ever + // run + return [self.serverCacheDB exactSizeFrom:kFServerCachePrefix + to:kFServerCacheRangeEnd]; +} + +- (void)pruneCache:(FPruneForest *)pruneForest atPath:(FPath *)path { + // TODO: be more intelligent, don't scan entire database... + + __block NSUInteger pruned = 0; + __block NSUInteger kept = 0; + NSDate *start = [NSDate date]; + + NSString *prefix = serverCacheKey(path); + id batch = [self.serverCacheDB beginWriteBatch]; + + [self.serverCacheDB + enumerateKeysWithPrefix:prefix + usingBlock:^(NSString *dbKey, BOOL *stop) { + NSString *pathStr = + [dbKey substringFromIndex:prefix.length]; + FPath *relativePath = [[FPath alloc] initWith:pathStr]; + if ([pruneForest shouldPruneUnkeptDescendantsAtPath: + relativePath]) { + pruned++; + [batch removeKey:dbKey]; + } else { + kept++; + } + }]; + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076021", @"Failed to prune cache on disk!"); + } else { + FFDebug(@"I-RDB076022", @"Pruned %lu paths, kept %lu paths in %fms", + (unsigned long)pruned, (unsigned long)kept, + [start timeIntervalSinceNow] * -1000); + } +} + +#pragma mark - Tracked Queries + +- (NSArray *)loadTrackedQueries { + NSDate *date = [NSDate date]; + NSMutableArray *trackedQueries = [NSMutableArray array]; + [self.serverCacheDB + enumerateKeysWithPrefix:kFTrackedQueriesPrefix + asData:^(NSString *key, NSData *data, BOOL *stop) { + NSError *error = nil; + NSDictionary *queryJSON = + [NSJSONSerialization JSONObjectWithData:data + options:0 + error:&error]; + if (queryJSON == nil) { + if (error.code == kFNanFailureCode) { + FFWarn( + @"I-RDB076023", + @"Failed to deserialize tracked query " + @"(%@), likely because of out of range " + @"doubles (Error: %@)", + [[NSString alloc] + initWithData:data + encoding:NSUTF8StringEncoding], + error); + FFWarn(@"I-RDB076024", + @"Removing failed tracked query with " + @"key %@", + key); + [self.serverCacheDB removeKey:key]; + } else { + [NSException + raise:NSInternalInconsistencyException + format:@"Failed to deserialize tracked " + @"query: %@", + error]; + } + } else { + NSUInteger queryId = + ((NSNumber *)queryJSON[kFTrackedQueryId]) + .unsignedIntegerValue; + FPath *path = + [FPath pathWithString: + queryJSON[kFTrackedQueryPath]]; + FQueryParams *params = [FQueryParams + fromQueryObject:queryJSON + [kFTrackedQueryParams]]; + FQuerySpec *query = + [[FQuerySpec alloc] initWithPath:path + params:params]; + BOOL isComplete = + [queryJSON[kFTrackedQueryIsComplete] + boolValue]; + BOOL isActive = + [queryJSON[kFTrackedQueryIsActive] + boolValue]; + NSTimeInterval lastUse = + [queryJSON[kFTrackedQueryLastUse] + doubleValue]; + + FTrackedQuery *trackedQuery = + [[FTrackedQuery alloc] + initWithId:queryId + query:query + lastUse:lastUse + isActive:isActive + isComplete:isComplete]; + + [trackedQueries addObject:trackedQuery]; + } + }]; + FFDebug(@"I-RDB076025", @"Loaded %lu tracked queries in %fms", + (unsigned long)trackedQueries.count, + [date timeIntervalSinceNow] * -1000); + return trackedQueries; +} + +- (void)removeTrackedQuery:(NSUInteger)queryId { + NSDate *start = [NSDate date]; + id batch = [self.serverCacheDB beginWriteBatch]; + [batch removeKey:trackedQueryKey(queryId)]; + __block NSUInteger keyCount = 0; + [self.serverCacheDB + enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) + usingBlock:^(NSString *key, BOOL *stop) { + [batch removeKey:key]; + keyCount++; + }]; + + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076026", @"Failed to remove tracked query on disk!"); + } else { + FFDebug(@"I-RDB076027", + @"Removed query with id %lu (and removed %lu keys) in %fms", + (unsigned long)queryId, (unsigned long)keyCount, + [start timeIntervalSinceNow] * -1000); + } +} + +- (void)saveTrackedQuery:(FTrackedQuery *)query { + NSDate *start = [NSDate date]; + NSDictionary *trackedQuery = @{ + kFTrackedQueryId : @(query.queryId), + kFTrackedQueryPath : [query.query.path toStringWithTrailingSlash], + kFTrackedQueryParams : [query.query.params wireProtocolParams], + kFTrackedQueryLastUse : @(query.lastUse), + kFTrackedQueryIsComplete : @(query.isComplete), + kFTrackedQueryIsActive : @(query.isActive) + }; + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:trackedQuery + options:0 + error:&error]; + NSAssert(data, @"Failed to serialize tracked query (Error: %@)", error); + [self.serverCacheDB setData:data forKey:trackedQueryKey(query.queryId)]; + FFDebug(@"I-RDB076028", @"Saved tracked query %lu in %fms", + (unsigned long)query.queryId, [start timeIntervalSinceNow] * -1000); +} + +- (void)setTrackedQueryKeys:(NSSet *)keys forQueryId:(NSUInteger)queryId { + NSDate *start = [NSDate date]; + __block NSUInteger removed = 0; + __block NSUInteger added = 0; + id batch = [self.serverCacheDB beginWriteBatch]; + NSMutableSet *seenKeys = [NSMutableSet set]; + // First, delete any keys that might be stored and are not part of the + // current keys + [self.serverCacheDB + enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) + asStrings:^(NSString *dbKey, NSString *actualKey, + BOOL *stop) { + if ([keys containsObject:actualKey]) { + // Already in DB + [seenKeys addObject:actualKey]; + } else { + // Not part of set, delete key + [batch removeKey:dbKey]; + removed++; + } + }]; + + // Next add any keys that are missing in the database + [keys enumerateObjectsUsingBlock:^(NSString *childKey, BOOL *stop) { + if (![seenKeys containsObject:childKey]) { + [batch setString:childKey + forKey:trackedQueryKeysKey(queryId, childKey)]; + added++; + } + }]; + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076029", @"Failed to set tracked queries on disk!"); + } else { + FFDebug(@"I-RDB076030", + @"Set %lu tracked keys (%lu added, %lu removed) for query %lu " + @"in %fms", + (unsigned long)keys.count, (unsigned long)added, + (unsigned long)removed, (unsigned long)queryId, + [start timeIntervalSinceNow] * -1000); + } +} + +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQueryId:(NSUInteger)queryId { + NSDate *start = [NSDate date]; + id batch = [self.serverCacheDB beginWriteBatch]; + [removed enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) { + [batch removeKey:trackedQueryKeysKey(queryId, key)]; + }]; + [added enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) { + [batch setString:key forKey:trackedQueryKeysKey(queryId, key)]; + }]; + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076031", @"Failed to update tracked queries on disk!"); + } else { + FFDebug(@"I-RDB076032", + @"Added %lu tracked keys, removed %lu for query %lu in %fms", + (unsigned long)added.count, (unsigned long)removed.count, + (unsigned long)queryId, [start timeIntervalSinceNow] * -1000); + } +} + +- (NSSet *)trackedQueryKeysForQuery:(NSUInteger)queryId { + NSDate *start = [NSDate date]; + NSMutableSet *set = [NSMutableSet set]; + [self.serverCacheDB + enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) + asStrings:^(NSString *dbKey, NSString *actualKey, + BOOL *stop) { + [set addObject:actualKey]; + }]; + FFDebug(@"I-RDB076033", @"Loaded %lu tracked keys for query %lu in %fms", + (unsigned long)set.count, (unsigned long)queryId, + [start timeIntervalSinceNow] * -1000); + return set; +} + +#pragma mark - Internal methods + +- (void)removeAllLeafNodesOnPath:(FPath *)path + batch:(id)batch { + while (!path.isEmpty) { + [batch removeKey:serverCacheKey(path)]; + path = [path parent]; + } + // Make sure to delete any nodes at the root + [batch removeKey:serverCacheKey([FPath empty])]; +} + +- (void)removeAllWithPrefix:(NSString *)prefix + batch:(id)batch + database:(APLevelDB *)database { + assert(prefix != nil); + + [database enumerateKeysWithPrefix:prefix + usingBlock:^(NSString *key, BOOL *stop) { + [batch removeKey:key]; + }]; +} + +#pragma mark - Internal helper methods + +- (void)internalSetNestedData:(id)value + forKey:(NSString *)key + withBatch:(id)batch + counter:(NSUInteger *)counter { + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictionary = value; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id childKey, id obj, + BOOL *stop) { + assert(obj != nil); + NSString *childPath = + [NSString stringWithFormat:@"%@%@/", key, childKey]; + [self internalSetNestedData:obj + forKey:childPath + withBatch:batch + counter:counter]; + }]; + } else { + NSData *data = [self serializePrimitive:value]; + [batch setData:data forKey:key]; + (*counter)++; + } +} + +- (id)internalNestedDataForPath:(FPath *)path { + NSAssert(path != nil, @"Path was nil!"); + + NSString *baseKey = serverCacheKey(path); + + // HACK to make sure iter is freed now to avoid race conditions (if self.db + // is deleted before iter, you get an access violation). + @autoreleasepool { + APLevelDBIterator *iter = + [APLevelDBIterator iteratorWithLevelDB:self.serverCacheDB]; + + [iter seekToKey:baseKey]; + if (iter.key == nil || ![iter.key hasPrefix:baseKey]) { + // No data. + return nil; + } else { + return [self internalNestedDataFromIterator:iter + andKeyPrefix:baseKey]; + } + } +} + +- (id)internalNestedDataFromIterator:(APLevelDBIterator *)iterator + andKeyPrefix:(NSString *)prefix { + NSString *key = iterator.key; + + if ([key isEqualToString:prefix]) { + id result = [self deserializePrimitive:iterator.valueAsData]; + [iterator nextKey]; + return result; + } else { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + while (key != nil && [key hasPrefix:prefix]) { + NSString *relativePath = [key substringFromIndex:prefix.length]; + NSArray *pathPieces = + [relativePath componentsSeparatedByString:@"/"]; + assert(pathPieces.count > 0); + NSString *childName = pathPieces[0]; + NSString *childPath = + [NSString stringWithFormat:@"%@%@/", prefix, childName]; + id childValue = [self internalNestedDataFromIterator:iterator + andKeyPrefix:childPath]; + [dict setValue:childValue forKey:childName]; + + key = iterator.key; + } + return dict; + } +} + +- (NSData *)serializePrimitive:(id)value { + // HACK: The built-in serialization only works on dicts and arrays. So we + // create an array and then strip off the leading / trailing byte (the [ and + // ]). + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:@[ value ] + options:0 + error:&error]; + NSAssert(data, @"Failed to serialize primitive: %@", error); + + return [data subdataWithRange:NSMakeRange(1, data.length - 2)]; +} + +- (id)fixDoubleParsing:(id)value + __attribute__((no_sanitize("float-cast-overflow"))) { + if ([value isKindOfClass:[NSDecimalNumber class]]) { + // In case the value is an NSDecimalNumber, we may be dealing with + // precisions that are higher than what can be represented in a double. + // In this case it does not suffice to check for integral numbers by + // casting the [value doubleValue] to an int64_t, because this will + // cause the compared values to be rounded to double precision. + // Coupled with a bug in [NSDecimalNumber longLongValue] that triggers + // when converting values with high precision, this would cause + // values of high precision, but with an integral 'doubleValue' + // representation to be converted to bogus values. + // A radar for the NSDecimalNumber issue can be found here: + // http://www.openradar.me/radar?id=5007005597040640 + // Consider the NSDecimalNumber value: 999.9999999999999487 + // This number has a 'doubleValue' of 1000. Using the previous version + // of this method would cause the value to be interpreted to be integral + // and then the resulting value would be based on the longLongValue + // which due to the NSDecimalNumber issue would turn out as -844. + // By using NSDecimal logic to test for integral values, + // 999.9999999999999487 will not be considered integral, and instead + // of triggering the 'longLongValue' issue, it will be returned as + // the 'doubleValue' representation (1000). + // Please note, that even without the NSDecimalNumber issue, the + // 'correct' longLongValue of 999.9999999999999487 is 999 and not 1000, + // so the previous code would cause issues even without the bug + // referenced in the radar. + NSDecimal original = [(NSDecimalNumber *)value decimalValue]; + NSDecimal rounded; + NSDecimalRound(&rounded, &original, 0, NSRoundPlain); + if (NSDecimalCompare(&original, &rounded) != NSOrderedSame) { + NSString *doubleString = [value stringValue]; + return [NSNumber numberWithDouble:[doubleString doubleValue]]; + } else { + return [NSNumber numberWithLongLong:[value longLongValue]]; + } + } else if ([value isKindOfClass:[NSNumber class]]) { + // The parser for double values in JSONSerialization at the root takes + // some short-cuts and delivers wrong results (wrong rounding) for some + // double values, including 2.47. Because we use the exact bytes for + // hashing on the server this will lead to hash mismatches. The parser + // of NSNumber seems to be more in line with what the server expects, so + // we use that here + CFNumberType type = CFNumberGetType((CFNumberRef)value); + if (type == kCFNumberDoubleType || type == kCFNumberFloatType) { + // The NSJSON parser returns all numbers as double values, even + // those that contain no exponent. To make sure that the String + // conversion below doesn't unexpectedly reduce precision, we make + // sure that our number is indeed not an integer. + if ((double)(int64_t)[value doubleValue] != [value doubleValue]) { + NSString *doubleString = [value stringValue]; + return [NSNumber numberWithDouble:[doubleString doubleValue]]; + } else { + return [NSNumber numberWithLongLong:[value longLongValue]]; + } + } + } + return value; +} + +- (id)deserializePrimitive:(NSData *)data { + NSError *error = nil; + id result = + [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingAllowFragments + error:&error]; + if (result != nil) { + return [self fixDoubleParsing:result]; + } else { + if (error.code == kFNanFailureCode) { + FFWarn(@"I-RDB076034", + @"Failed to load primitive %@, likely because doubles where " + @"out of range (Error: %@)", + [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding], + error); + return [NSNull null]; + } else { + [NSException raise:NSInternalInconsistencyException + format:@"Failed to deserialiaze primitive: %@", error]; + return nil; + } + } +} + ++ (void)ensureDir:(NSString *)path markAsDoNotBackup:(BOOL)markAsDoNotBackup { + NSError *error; + BOOL success = + [[NSFileManager defaultManager] createDirectoryAtPath:path + withIntermediateDirectories:YES + attributes:nil + error:&error]; + if (!success) { + @throw [NSException + exceptionWithName:@"FailedToCreatePersistenceDir" + reason:@"Failed to create persistence directory." + userInfo:@{@"path" : path}]; + } + + if (markAsDoNotBackup) { + NSURL *firebaseDirURL = [NSURL fileURLWithPath:path]; + success = [firebaseDirURL setResourceValue:@YES + forKey:NSURLIsExcludedFromBackupKey + error:&error]; + if (!success) { + FFWarn( + @"I-RDB076035", + @"Failed to mark firebase database folder as do not backup: %@", + error); + [NSException raise:@"Error marking as do not backup" + format:@"Failed to mark folder %@ as do not backup", + firebaseDirURL]; + } + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.h new file mode 100644 index 0000000..deeeca2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.h @@ -0,0 +1,53 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import + +// These are all legacy classes and are used to migrate older persistence data +// base to newer ones These classes should not be used in newer code + +@interface FPendingPut : NSObject + +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) id data; +@property(nonatomic, strong) id priority; + +- (id)initWithPath:(FPath *)aPath andData:(id)aData andPriority:aPriority; +- (void)encodeWithCoder:(NSCoder *)aCoder; +- (id)initWithCoder:(NSCoder *)aDecoder; +@end + +@interface FPendingPutPriority : NSObject + +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) id priority; + +- (id)initWithPath:(FPath *)aPath andPriority:(id)aPriority; +- (void)encodeWithCoder:(NSCoder *)aCoder; +- (id)initWithCoder:(NSCoder *)aDecoder; + +@end + +@interface FPendingUpdate : NSObject + +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) NSDictionary *data; + +- (id)initWithPath:(FPath *)aPath andData:(NSDictionary *)aData; +- (void)encodeWithCoder:(NSCoder *)aCoder; +- (id)initWithCoder:(NSCoder *)aDecoder; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.m new file mode 100644 index 0000000..c596dde --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.m @@ -0,0 +1,113 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FPendingPut.h" + +@implementation FPendingPut + +@synthesize path; +@synthesize data; + +- (id)initWithPath:(FPath *)aPath andData:(id)aData andPriority:(id)aPriority { + self = [super init]; + if (self) { + self.path = aPath; + self.data = aData; + self.priority = aPriority; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:[self.path description] forKey:@"path"]; + [aCoder encodeObject:self.data forKey:@"data"]; + [aCoder encodeObject:self.priority forKey:@"priority"]; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [super init]; + if (self) { + self.path = + [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; + self.data = [aDecoder decodeObjectForKey:@"data"]; + self.priority = [aDecoder decodeObjectForKey:@"priority"]; + } + return self; +} + +@end + +@implementation FPendingPutPriority + +@synthesize path; +@synthesize priority; + +- (id)initWithPath:(FPath *)aPath andPriority:(id)aPriority { + self = [super init]; + if (self) { + self.path = aPath; + self.priority = aPriority; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:[self.path description] forKey:@"path"]; + [aCoder encodeObject:self.priority forKey:@"priority"]; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [super init]; + if (self) { + self.path = + [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; + self.priority = [aDecoder decodeObjectForKey:@"priority"]; + } + return self; +} + +@end + +@implementation FPendingUpdate + +@synthesize path; +@synthesize data; + +- (id)initWithPath:(FPath *)aPath andData:(id)aData { + self = [super init]; + if (self) { + self.path = aPath; + self.data = aData; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:[self.path description] forKey:@"path"]; + [aCoder encodeObject:self.data forKey:@"data"]; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [super init]; + if (self) { + self.path = + [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; + self.data = [aDecoder decodeObjectForKey:@"data"]; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.h new file mode 100644 index 0000000..fb35ec6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.h @@ -0,0 +1,60 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Persistence/FCachePolicy.h" +#import "FirebaseDatabase/Sources/Persistence/FStorageEngine.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FPersistenceManager : NSObject + +- (id)initWithStorageEngine:(id)storageEngine + cachePolicy:(id)cachePolicy; +- (void)close; + +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId; +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId; +- (void)removeUserWrite:(NSUInteger)writeId; +- (void)removeAllUserWrites; +- (NSArray *)userWrites; + +- (FCacheNode *)serverCacheForQuery:(FQuerySpec *)spec; +- (void)updateServerCacheWithNode:(id)node forQuery:(FQuerySpec *)spec; +- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge atPath:(FPath *)path; + +- (void)applyUserWrite:(id)write toServerCacheAtPath:(FPath *)path; +- (void)applyUserMerge:(FCompoundWrite *)merge + toServerCacheAtPath:(FPath *)path; + +- (void)setQueryComplete:(FQuerySpec *)spec; +- (void)setQueryActive:(FQuerySpec *)spec; +- (void)setQueryInactive:(FQuerySpec *)spec; + +- (void)setTrackedQueryKeys:(NSSet *)keys forQuery:(FQuerySpec *)query; +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQuery:(FQuerySpec *)query; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.m new file mode 100644 index 0000000..1b6ae11 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.m @@ -0,0 +1,231 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FPersistenceManager.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/FClock.h" +#import "FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h" +#import "FirebaseDatabase/Sources/Persistence/FPruneForest.h" +#import "FirebaseDatabase/Sources/Persistence/FTrackedQuery.h" +#import "FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FPersistenceManager () + +@property(nonatomic, strong) id storageEngine; +@property(nonatomic, strong) id cachePolicy; +@property(nonatomic, strong) FTrackedQueryManager *trackedQueryManager; +@property(nonatomic) NSUInteger serverCacheUpdatesSinceLastPruneCheck; + +@end + +@implementation FPersistenceManager + +- (id)initWithStorageEngine:(id)storageEngine + cachePolicy:(id)cachePolicy { + self = [super init]; + if (self != nil) { + self->_storageEngine = storageEngine; + self->_cachePolicy = cachePolicy; + self->_trackedQueryManager = [[FTrackedQueryManager alloc] + initWithStorageEngine:self.storageEngine + clock:[FSystemClock clock]]; + } + return self; +} + +- (void)close { + [self.storageEngine close]; + self.storageEngine = nil; + self.trackedQueryManager = nil; +} + +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId { + [self.storageEngine saveUserOverwrite:node atPath:path writeId:writeId]; +} + +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId { + [self.storageEngine saveUserMerge:merge atPath:path writeId:writeId]; +} + +- (void)removeUserWrite:(NSUInteger)writeId { + [self.storageEngine removeUserWrite:writeId]; +} + +- (void)removeAllUserWrites { + [self.storageEngine removeAllUserWrites]; +} + +- (NSArray *)userWrites { + return [self.storageEngine userWrites]; +} + +- (FCacheNode *)serverCacheForQuery:(FQuerySpec *)query { + NSSet *trackedKeys; + BOOL complete; + // TODO[offline]: Should we use trackedKeys to find out if this location is + // a child of a complete query? + if ([self.trackedQueryManager isQueryComplete:query]) { + complete = YES; + FTrackedQuery *trackedQuery = + [self.trackedQueryManager findTrackedQuery:query]; + if (!query.loadsAllData && trackedQuery.isComplete) { + trackedKeys = [self.storageEngine + trackedQueryKeysForQuery:trackedQuery.queryId]; + } else { + trackedKeys = nil; + } + } else { + complete = NO; + trackedKeys = + [self.trackedQueryManager knownCompleteChildrenAtPath:query.path]; + } + + id node; + if (trackedKeys != nil) { + node = [self.storageEngine serverCacheForKeys:trackedKeys + atPath:query.path]; + } else { + node = [self.storageEngine serverCacheAtPath:query.path]; + } + + FIndexedNode *indexedNode = [FIndexedNode indexedNodeWithNode:node + index:query.index]; + return [[FCacheNode alloc] initWithIndexedNode:indexedNode + isFullyInitialized:complete + isFiltered:(trackedKeys != nil)]; +} + +- (void)updateServerCacheWithNode:(id)node forQuery:(FQuerySpec *)query { + BOOL merge = !query.loadsAllData; + [self.storageEngine updateServerCache:node atPath:query.path merge:merge]; + [self setQueryComplete:query]; + [self doPruneCheckAfterServerUpdate]; +} + +- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge + atPath:(FPath *)path { + [self.storageEngine updateServerCacheWithMerge:merge atPath:path]; + [self doPruneCheckAfterServerUpdate]; +} + +- (void)applyUserMerge:(FCompoundWrite *)merge + toServerCacheAtPath:(FPath *)path { + // TODO[offline]: rework this to be more efficient + [merge enumerateWrites:^(FPath *relativePath, id node, BOOL *stop) { + [self applyUserWrite:node toServerCacheAtPath:[path child:relativePath]]; + }]; +} + +- (void)applyUserWrite:(id)write toServerCacheAtPath:(FPath *)path { + // This is a hack to guess whether we already cached this because we got a + // server data update for this write via an existing active default query. + // If we didn't, then we'll manually cache this and add a tracked query to + // mark it complete and keep it cached. Unfortunately this is just a guess + // and it's possible that we *did* get an update (e.g. via a filtered query) + // and by overwriting the cache here, we'll actually store an incorrect + // value (e.g. in the case that we wrote a ServerValue.TIMESTAMP and the + // server resolved it to a different value). + // TODO[offline]: Consider reworking. + if (![self.trackedQueryManager hasActiveDefaultQueryAtPath:path]) { + [self.storageEngine updateServerCache:write atPath:path merge:NO]; + [self.trackedQueryManager ensureCompleteTrackedQueryAtPath:path]; + } +} + +- (void)setQueryComplete:(FQuerySpec *)query { + if (query.loadsAllData) { + [self.trackedQueryManager setQueriesCompleteAtPath:query.path]; + } else { + [self.trackedQueryManager setQueryComplete:query]; + } +} + +- (void)setQueryActive:(FQuerySpec *)spec { + [self.trackedQueryManager setQueryActive:spec]; +} + +- (void)setQueryInactive:(FQuerySpec *)spec { + [self.trackedQueryManager setQueryInactive:spec]; +} + +- (void)doPruneCheckAfterServerUpdate { + self.serverCacheUpdatesSinceLastPruneCheck++; + if ([self.cachePolicy + shouldCheckCacheSize:self.serverCacheUpdatesSinceLastPruneCheck]) { + FFDebug(@"I-RDB078001", @"Reached prune check threshold. Checking..."); + NSDate *date = [NSDate date]; + self.serverCacheUpdatesSinceLastPruneCheck = 0; + BOOL canPrune = YES; + NSUInteger cacheSize = + [self.storageEngine serverCacheEstimatedSizeInBytes]; + FFDebug(@"I-RDB078002", @"Server cache size: %lu", + (unsigned long)cacheSize); + while (canPrune && + [self.cachePolicy + shouldPruneCacheWithSize:cacheSize + numberOfTrackedQueries:self.trackedQueryManager + .numberOfPrunableQueries]) { + FPruneForest *pruneForest = + [self.trackedQueryManager pruneOldQueries:self.cachePolicy]; + if (pruneForest.prunesAnything) { + [self.storageEngine pruneCache:pruneForest + atPath:[FPath empty]]; + } else { + canPrune = NO; + } + cacheSize = [self.storageEngine serverCacheEstimatedSizeInBytes]; + FFDebug(@"I-RDB078003", @"Cache size after pruning: %lu", + (unsigned long)cacheSize); + } + FFDebug(@"I-RDB078004", @"Pruning round took %fms", + [date timeIntervalSinceNow] * -1000); + } +} + +- (void)setTrackedQueryKeys:(NSSet *)keys forQuery:(FQuerySpec *)query { + NSAssert(!query.loadsAllData, + @"We should only track keys for filtered queries"); + FTrackedQuery *trackedQuery = + [self.trackedQueryManager findTrackedQuery:query]; + NSAssert(trackedQuery.isActive, + @"We only expect tracked keys for currently-active queries."); + [self.storageEngine setTrackedQueryKeys:keys + forQueryId:trackedQuery.queryId]; +} + +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQuery:(FQuerySpec *)query { + NSAssert(!query.loadsAllData, + @"We should only track keys for filtered queries"); + FTrackedQuery *trackedQuery = + [self.trackedQueryManager findTrackedQuery:query]; + NSAssert(trackedQuery.isActive, + @"We only expect tracked keys for currently-active queries."); + [self.storageEngine + updateTrackedQueryKeysWithAddedKeys:added + removedKeys:removed + forQueryId:trackedQuery.queryId]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.h new file mode 100644 index 0000000..9e77217 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.h @@ -0,0 +1,38 @@ +/* + * 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 + +@class FPath; + +@interface FPruneForest : NSObject + ++ (FPruneForest *)empty; + +- (BOOL)prunesAnything; +- (BOOL)shouldPruneUnkeptDescendantsAtPath:(FPath *)path; +- (BOOL)shouldKeepPath:(FPath *)path; +- (BOOL)affectsPath:(FPath *)path; +- (FPruneForest *)child:(NSString *)childKey; +- (FPruneForest *)childAtPath:(FPath *)childKey; +- (FPruneForest *)prunePath:(FPath *)path; +- (FPruneForest *)keepPath:(FPath *)path; +- (FPruneForest *)keepAll:(NSSet *)children atPath:(FPath *)path; +- (FPruneForest *)pruneAll:(NSSet *)children atPath:(FPath *)path; + +- (void)enumarateKeptNodesUsingBlock:(void (^)(FPath *path))block; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.m new file mode 100644 index 0000000..b777ba9 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.m @@ -0,0 +1,194 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FPruneForest.h" + +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" + +@interface FPruneForest () + +@property(nonatomic, strong) FImmutableTree *pruneForest; + +@end + +@implementation FPruneForest + +static BOOL (^kFPrunePredicate)(id) = ^BOOL(NSNumber *pruneValue) { + return [pruneValue boolValue]; +}; + +static BOOL (^kFKeepPredicate)(id) = ^BOOL(NSNumber *pruneValue) { + return ![pruneValue boolValue]; +}; + ++ (FImmutableTree *)pruneTree { + static dispatch_once_t onceToken; + static FImmutableTree *pruneTree; + dispatch_once(&onceToken, ^{ + pruneTree = [[FImmutableTree alloc] initWithValue:@YES]; + }); + return pruneTree; +} + ++ (FImmutableTree *)keepTree { + static dispatch_once_t onceToken; + static FImmutableTree *keepTree; + dispatch_once(&onceToken, ^{ + keepTree = [[FImmutableTree alloc] initWithValue:@NO]; + }); + return keepTree; +} + +- (id)initWithForest:(FImmutableTree *)tree { + self = [super init]; + if (self != nil) { + self->_pruneForest = tree; + } + return self; +} + ++ (FPruneForest *)empty { + static dispatch_once_t onceToken; + static FPruneForest *forest; + dispatch_once(&onceToken, ^{ + forest = [[FPruneForest alloc] initWithForest:[FImmutableTree empty]]; + }); + return forest; +} + +- (BOOL)prunesAnything { + return [self.pruneForest containsValueMatching:kFPrunePredicate]; +} + +- (BOOL)shouldPruneUnkeptDescendantsAtPath:(FPath *)path { + NSNumber *shouldPrune = [self.pruneForest leafMostValueOnPath:path]; + return shouldPrune != nil && [shouldPrune boolValue]; +} + +- (BOOL)shouldKeepPath:(FPath *)path { + NSNumber *shouldPrune = [self.pruneForest leafMostValueOnPath:path]; + return shouldPrune != nil && ![shouldPrune boolValue]; +} + +- (BOOL)affectsPath:(FPath *)path { + return [self.pruneForest rootMostValueOnPath:path] != nil || + ![[self.pruneForest subtreeAtPath:path] isEmpty]; +} + +- (FPruneForest *)child:(NSString *)childKey { + FImmutableTree *childPruneForest = [self.pruneForest.children get:childKey]; + if (childPruneForest == nil) { + if (self.pruneForest.value != nil) { + childPruneForest = [self.pruneForest.value boolValue] + ? [FPruneForest pruneTree] + : [FPruneForest keepTree]; + } else { + childPruneForest = [FImmutableTree empty]; + } + } else { + if (childPruneForest.value == nil && self.pruneForest.value != nil) { + childPruneForest = [childPruneForest setValue:self.pruneForest.value + atPath:[FPath empty]]; + } + } + return [[FPruneForest alloc] initWithForest:childPruneForest]; +} + +- (FPruneForest *)childAtPath:(FPath *)path { + if (path.isEmpty) { + return self; + } else { + return [[self child:path.getFront] childAtPath:[path popFront]]; + } +} + +- (FPruneForest *)prunePath:(FPath *)path { + if ([self.pruneForest rootMostValueOnPath:path matching:kFKeepPredicate]) { + [NSException raise:NSInvalidArgumentException + format:@"Can't prune path that was kept previously!"]; + } + if ([self.pruneForest rootMostValueOnPath:path matching:kFPrunePredicate]) { + // This path will already be pruned + return self; + } else { + FImmutableTree *newPruneForest = + [self.pruneForest setTree:[FPruneForest pruneTree] atPath:path]; + return [[FPruneForest alloc] initWithForest:newPruneForest]; + } +} + +- (FPruneForest *)keepPath:(FPath *)path { + if ([self.pruneForest rootMostValueOnPath:path matching:kFKeepPredicate]) { + // This path will already be kept + return self; + } else { + FImmutableTree *newPruneForest = + [self.pruneForest setTree:[FPruneForest keepTree] atPath:path]; + return [[FPruneForest alloc] initWithForest:newPruneForest]; + } +} + +- (FPruneForest *)keepAll:(NSSet *)children atPath:(FPath *)path { + if ([self.pruneForest rootMostValueOnPath:path matching:kFKeepPredicate]) { + // This path will already be kept + return self; + } else { + return [self setPruneValue:[FPruneForest keepTree] + forAll:children + atPath:path]; + } +} + +- (FPruneForest *)pruneAll:(NSSet *)children atPath:(FPath *)path { + if ([self.pruneForest rootMostValueOnPath:path matching:kFKeepPredicate]) { + [NSException raise:NSInvalidArgumentException + format:@"Can't prune path that was kept previously!"]; + } + if ([self.pruneForest rootMostValueOnPath:path matching:kFPrunePredicate]) { + // This path will already be pruned + return self; + } else { + return [self setPruneValue:[FPruneForest pruneTree] + forAll:children + atPath:path]; + } +} + +- (FPruneForest *)setPruneValue:(FImmutableTree *)pruneValue + forAll:(NSSet *)children + atPath:(FPath *)path { + FImmutableTree *subtree = [self.pruneForest subtreeAtPath:path]; + __block FImmutableSortedDictionary *childrenDictionary = subtree.children; + [children enumerateObjectsUsingBlock:^(NSString *childKey, BOOL *stop) { + childrenDictionary = [childrenDictionary insertKey:childKey + withValue:pruneValue]; + }]; + FImmutableTree *newSubtree = + [[FImmutableTree alloc] initWithValue:subtree.value + children:childrenDictionary]; + return [[FPruneForest alloc] + initWithForest:[self.pruneForest setTree:newSubtree atPath:path]]; +} + +- (void)enumarateKeptNodesUsingBlock:(void (^)(FPath *))block { + [self.pruneForest forEach:^(FPath *path, id value) { + if (value != nil && ![value boolValue]) { + block(path); + } + }]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FStorageEngine.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FStorageEngine.h new file mode 100644 index 0000000..5f418b8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FStorageEngine.h @@ -0,0 +1,60 @@ +/* + * 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 + +@protocol FNode; +@class FPruneForest; +@class FPath; +@class FCompoundWrite; +@class FQuerySpec; +@class FTrackedQuery; + +@protocol FStorageEngine + +- (void)close; + +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId; +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId; +- (void)removeUserWrite:(NSUInteger)writeId; +- (void)removeAllUserWrites; +- (NSArray *)userWrites; + +- (id)serverCacheAtPath:(FPath *)path; +- (id)serverCacheForKeys:(NSSet *)keys atPath:(FPath *)path; +- (void)updateServerCache:(id)node + atPath:(FPath *)path + merge:(BOOL)merge; +- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge atPath:(FPath *)path; +- (NSUInteger)serverCacheEstimatedSizeInBytes; + +- (void)pruneCache:(FPruneForest *)pruneForest atPath:(FPath *)path; + +- (NSArray *)loadTrackedQueries; +- (void)removeTrackedQuery:(NSUInteger)queryId; +- (void)saveTrackedQuery:(FTrackedQuery *)query; + +- (void)setTrackedQueryKeys:(NSSet *)keys forQueryId:(NSUInteger)queryId; +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQueryId:(NSUInteger)queryId; +- (NSSet *)trackedQueryKeysForQuery:(NSUInteger)queryId; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.h new file mode 100644 index 0000000..7413816 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.h @@ -0,0 +1,43 @@ +/* + * 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 + +@class FQuerySpec; + +@interface FTrackedQuery : NSObject + +@property(nonatomic, readonly) NSUInteger queryId; +@property(nonatomic, strong, readonly) FQuerySpec *query; +@property(nonatomic, readonly) NSTimeInterval lastUse; +@property(nonatomic, readonly) BOOL isComplete; +@property(nonatomic, readonly) BOOL isActive; + +- (id)initWithId:(NSUInteger)queryId + query:(FQuerySpec *)query + lastUse:(NSTimeInterval)lastUse + isActive:(BOOL)isActive; +- (id)initWithId:(NSUInteger)queryId + query:(FQuerySpec *)query + lastUse:(NSTimeInterval)lastUse + isActive:(BOOL)isActive + isComplete:(BOOL)isComplete; + +- (FTrackedQuery *)updateLastUse:(NSTimeInterval)lastUse; +- (FTrackedQuery *)setComplete; +- (FTrackedQuery *)setActiveState:(BOOL)isActive; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.m new file mode 100644 index 0000000..2f67dd3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.m @@ -0,0 +1,113 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FTrackedQuery.h" + +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" + +@interface FTrackedQuery () + +@property(nonatomic, readwrite) NSUInteger queryId; +@property(nonatomic, strong, readwrite) FQuerySpec *query; +@property(nonatomic, readwrite) NSTimeInterval lastUse; +@property(nonatomic, readwrite) BOOL isComplete; +@property(nonatomic, readwrite) BOOL isActive; + +@end + +@implementation FTrackedQuery + +- (id)initWithId:(NSUInteger)queryId + query:(FQuerySpec *)query + lastUse:(NSTimeInterval)lastUse + isActive:(BOOL)isActive + isComplete:(BOOL)isComplete { + self = [super init]; + if (self != nil) { + self->_queryId = queryId; + self->_query = query; + self->_lastUse = lastUse; + self->_isComplete = isComplete; + self->_isActive = isActive; + } + return self; +} + +- (id)initWithId:(NSUInteger)queryId + query:(FQuerySpec *)query + lastUse:(NSTimeInterval)lastUse + isActive:(BOOL)isActive { + return [self initWithId:queryId + query:query + lastUse:lastUse + isActive:isActive + isComplete:NO]; +} + +- (FTrackedQuery *)updateLastUse:(NSTimeInterval)lastUse { + return [[FTrackedQuery alloc] initWithId:self.queryId + query:self.query + lastUse:lastUse + isActive:self.isActive + isComplete:self.isComplete]; +} + +- (FTrackedQuery *)setComplete { + return [[FTrackedQuery alloc] initWithId:self.queryId + query:self.query + lastUse:self.lastUse + isActive:self.isActive + isComplete:YES]; +} + +- (FTrackedQuery *)setActiveState:(BOOL)isActive { + return [[FTrackedQuery alloc] initWithId:self.queryId + query:self.query + lastUse:self.lastUse + isActive:isActive + isComplete:self.isComplete]; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[FTrackedQuery class]]) { + return NO; + } + FTrackedQuery *other = (FTrackedQuery *)object; + if (self.queryId != other.queryId) + return NO; + if (self.query != other.query && ![self.query isEqual:other.query]) + return NO; + if (self.lastUse != other.lastUse) + return NO; + if (self.isComplete != other.isComplete) + return NO; + if (self.isActive != other.isActive) + return NO; + + return YES; +} + +- (NSUInteger)hash { + NSUInteger hash = self.queryId; + hash = hash * 31 + self.query.hash; + hash = hash * 31 + (self.isActive ? 1 : 0); + hash = hash * 31 + (NSUInteger)self.lastUse; + hash = hash * 31 + (self.isComplete ? 1 : 0); + hash = hash * 31 + (self.isActive ? 1 : 0); + return hash; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h new file mode 100644 index 0000000..cd7d5a1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h @@ -0,0 +1,52 @@ +/* + * 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 + +@protocol FStorageEngine; +@protocol FClock; +@protocol FCachePolicy; +@class FQuerySpec; +@class FPath; +@class FTrackedQuery; +@class FPruneForest; + +@interface FTrackedQueryManager : NSObject + +- (id)initWithStorageEngine:(id)storageEngine + clock:(id)clock; + +- (FTrackedQuery *)findTrackedQuery:(FQuerySpec *)query; + +- (BOOL)isQueryComplete:(FQuerySpec *)query; + +- (void)removeTrackedQuery:(FQuerySpec *)query; +- (void)setQueryComplete:(FQuerySpec *)query; +- (void)setQueriesCompleteAtPath:(FPath *)path; +- (void)setQueryActive:(FQuerySpec *)query; +- (void)setQueryInactive:(FQuerySpec *)query; + +- (BOOL)hasActiveDefaultQueryAtPath:(FPath *)path; +- (void)ensureCompleteTrackedQueryAtPath:(FPath *)path; + +- (FPruneForest *)pruneOldQueries:(id)cachePolicy; +- (NSUInteger)numberOfPrunableQueries; +- (NSSet *)knownCompleteChildrenAtPath:(FPath *)path; + +// For testing +- (void)verifyCache; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.m new file mode 100644 index 0000000..c3af1e1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.m @@ -0,0 +1,375 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/FClock.h" +#import "FirebaseDatabase/Sources/Persistence/FCachePolicy.h" +#import "FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h" +#import "FirebaseDatabase/Sources/Persistence/FPruneForest.h" +#import "FirebaseDatabase/Sources/Persistence/FTrackedQuery.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FTrackedQueryManager () + +@property(nonatomic, strong) FImmutableTree *trackedQueryTree; +@property(nonatomic, strong) id storageEngine; +@property(nonatomic, strong) id clock; +@property(nonatomic) NSUInteger currentQueryId; + +@end + +@implementation FTrackedQueryManager + +- (id)initWithStorageEngine:(id)storageEngine + clock:(id)clock { + self = [super init]; + if (self != nil) { + self->_storageEngine = storageEngine; + self->_clock = clock; + self->_trackedQueryTree = [FImmutableTree empty]; + + NSTimeInterval lastUse = [clock currentTime]; + + NSArray *trackedQueries = [self.storageEngine loadTrackedQueries]; + [trackedQueries enumerateObjectsUsingBlock:^( + FTrackedQuery *trackedQuery, NSUInteger idx, + BOOL *stop) { + self.currentQueryId = + MAX(trackedQuery.queryId + 1, self.currentQueryId); + if (trackedQuery.isActive) { + trackedQuery = + [[trackedQuery setActiveState:NO] updateLastUse:lastUse]; + FFDebug( + @"I-RDB081001", + @"Setting active query %lu from previous app start inactive", + (unsigned long)trackedQuery.queryId); + [self.storageEngine saveTrackedQuery:trackedQuery]; + } + [self cacheTrackedQuery:trackedQuery]; + }]; + } + return self; +} + ++ (void)assertValidTrackedQuery:(FQuerySpec *)query { + NSAssert(!query.loadsAllData || query.isDefault, + @"Can't have tracked non-default query that loads all data"); +} + ++ (FQuerySpec *)normalizeQuery:(FQuerySpec *)query { + return query.loadsAllData ? [FQuerySpec defaultQueryAtPath:query.path] + : query; +} + +- (FTrackedQuery *)findTrackedQuery:(FQuerySpec *)query { + query = [FTrackedQueryManager normalizeQuery:query]; + NSDictionary *set = [self.trackedQueryTree valueAtPath:query.path]; + return set[query.params]; +} + +- (void)removeTrackedQuery:(FQuerySpec *)query { + query = [FTrackedQueryManager normalizeQuery:query]; + FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; + NSAssert(trackedQuery, @"Tracked query must exist to be removed!"); + + [self.storageEngine removeTrackedQuery:trackedQuery.queryId]; + NSMutableDictionary *trackedQueries = + [self.trackedQueryTree valueAtPath:query.path]; + [trackedQueries removeObjectForKey:query.params]; +} + +- (void)setQueryActive:(FQuerySpec *)query { + [self setQueryActive:YES forQuery:query]; +} + +- (void)setQueryInactive:(FQuerySpec *)query { + [self setQueryActive:NO forQuery:query]; +} + +- (void)setQueryActive:(BOOL)isActive forQuery:(FQuerySpec *)query { + query = [FTrackedQueryManager normalizeQuery:query]; + FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; + + // Regardless of whether it's now active or no langer active, we update the + // lastUse time + NSTimeInterval lastUse = [self.clock currentTime]; + if (trackedQuery != nil) { + trackedQuery = + [[trackedQuery updateLastUse:lastUse] setActiveState:isActive]; + [self.storageEngine saveTrackedQuery:trackedQuery]; + } else { + NSAssert(isActive, @"If we're setting the query to inactive, we should " + @"already be tracking it!"); + trackedQuery = [[FTrackedQuery alloc] initWithId:self.currentQueryId++ + query:query + lastUse:lastUse + isActive:isActive]; + [self.storageEngine saveTrackedQuery:trackedQuery]; + } + + [self cacheTrackedQuery:trackedQuery]; +} + +- (void)setQueryComplete:(FQuerySpec *)query { + query = [FTrackedQueryManager normalizeQuery:query]; + FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; + if (!trackedQuery) { + // We might have removed a query and pruned it before we got the + // complete message from the server... + FFWarn(@"I-RDB081002", + @"Trying to set a query complete that is not tracked!"); + } else if (!trackedQuery.isComplete) { + trackedQuery = [trackedQuery setComplete]; + [self.storageEngine saveTrackedQuery:trackedQuery]; + [self cacheTrackedQuery:trackedQuery]; + } else { + // Nothing to do, already marked complete + } +} + +- (void)setQueriesCompleteAtPath:(FPath *)path { + [[self.trackedQueryTree subtreeAtPath:path] + forEach:^(FPath *childPath, NSDictionary *trackedQueries) { + [trackedQueries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *parms, FTrackedQuery *trackedQuery, + BOOL *stop) { + if (!trackedQuery.isComplete) { + FTrackedQuery *newTrackedQuery = [trackedQuery setComplete]; + [self.storageEngine saveTrackedQuery:newTrackedQuery]; + [self cacheTrackedQuery:newTrackedQuery]; + } + }]; + }]; +} + +- (BOOL)isQueryComplete:(FQuerySpec *)query { + if ([self isIncludedInDefaultCompleteQuery:query]) { + return YES; + } else if (query.loadsAllData) { + // We didn't find a default complete query, so must not be complete. + return NO; + } else { + NSDictionary *trackedQueries = + [self.trackedQueryTree valueAtPath:query.path]; + return [trackedQueries[query.params] isComplete]; + } +} + +- (BOOL)hasActiveDefaultQueryAtPath:(FPath *)path { + return [self.trackedQueryTree + rootMostValueOnPath:path + matching:^BOOL(NSDictionary *trackedQueries) { + return + [trackedQueries[[FQueryParams defaultInstance]] + isActive]; + }] != nil; +} + +- (void)ensureCompleteTrackedQueryAtPath:(FPath *)path { + FQuerySpec *query = [FQuerySpec defaultQueryAtPath:path]; + if (![self isIncludedInDefaultCompleteQuery:query]) { + FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; + if (trackedQuery == nil) { + trackedQuery = + [[FTrackedQuery alloc] initWithId:self.currentQueryId++ + query:query + lastUse:[self.clock currentTime] + isActive:NO + isComplete:YES]; + } else { + NSAssert(!trackedQuery.isComplete, + @"This should have been handled above!"); + trackedQuery = [trackedQuery setComplete]; + } + [self.storageEngine saveTrackedQuery:trackedQuery]; + [self cacheTrackedQuery:trackedQuery]; + } +} + +- (BOOL)isIncludedInDefaultCompleteQuery:(FQuerySpec *)query { + return + [self.trackedQueryTree + findRootMostMatchingPath:query.path + predicate:^BOOL(NSDictionary *trackedQueries) { + return + [trackedQueries[[FQueryParams defaultInstance]] + isComplete]; + }] != nil; +} + +- (void)cacheTrackedQuery:(FTrackedQuery *)query { + [FTrackedQueryManager assertValidTrackedQuery:query.query]; + NSMutableDictionary *trackedDict = + [self.trackedQueryTree valueAtPath:query.query.path]; + if (trackedDict == nil) { + trackedDict = [NSMutableDictionary dictionary]; + self.trackedQueryTree = + [self.trackedQueryTree setValue:trackedDict + atPath:query.query.path]; + } + trackedDict[query.query.params] = query; +} + +- (NSUInteger)numberOfQueriesToPrune:(id)cachePolicy + prunableCount:(NSUInteger)numPrunable { + NSUInteger numPercent = (NSUInteger)ceilf( + numPrunable * [cachePolicy percentOfQueriesToPruneAtOnce]); + NSUInteger maxToKeep = [cachePolicy maxNumberOfQueriesToKeep]; + NSUInteger numMax = (numPrunable > maxToKeep) ? numPrunable - maxToKeep : 0; + // Make sure we get below number of max queries to prune + return MAX(numMax, numPercent); +} + +- (FPruneForest *)pruneOldQueries:(id)cachePolicy { + NSMutableArray *pruneableQueries = [NSMutableArray array]; + NSMutableArray *unpruneableQueries = [NSMutableArray array]; + [self.trackedQueryTree + forEach:^(FPath *path, NSDictionary *trackedQueries) { + [trackedQueries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *params, FTrackedQuery *trackedQuery, + BOOL *stop) { + if (!trackedQuery.isActive) { + [pruneableQueries addObject:trackedQuery]; + } else { + [unpruneableQueries addObject:trackedQuery]; + } + }]; + }]; + [pruneableQueries sortUsingComparator:^NSComparisonResult( + FTrackedQuery *q1, FTrackedQuery *q2) { + if (q1.lastUse < q2.lastUse) { + return NSOrderedAscending; + } else if (q1.lastUse > q2.lastUse) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]; + + __block FPruneForest *pruneForest = [FPruneForest empty]; + NSUInteger numToPrune = + [self numberOfQueriesToPrune:cachePolicy + prunableCount:pruneableQueries.count]; + + // TODO: do in transaction + for (NSUInteger i = 0; i < numToPrune; i++) { + FTrackedQuery *toPrune = pruneableQueries[i]; + pruneForest = [pruneForest prunePath:toPrune.query.path]; + [self removeTrackedQuery:toPrune.query]; + } + + // Keep the rest of the prunable queries + for (NSUInteger i = numToPrune; i < pruneableQueries.count; i++) { + FTrackedQuery *toKeep = pruneableQueries[i]; + pruneForest = [pruneForest keepPath:toKeep.query.path]; + } + + // Also keep unprunable queries + [unpruneableQueries enumerateObjectsUsingBlock:^( + FTrackedQuery *toKeep, NSUInteger idx, BOOL *stop) { + pruneForest = [pruneForest keepPath:toKeep.query.path]; + }]; + + return pruneForest; +} + +- (NSUInteger)numberOfPrunableQueries { + __block NSUInteger count = 0; + [self.trackedQueryTree + forEach:^(FPath *path, NSDictionary *trackedQueries) { + [trackedQueries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *params, FTrackedQuery *trackedQuery, + BOOL *stop) { + if (!trackedQuery.isActive) { + count++; + } + }]; + }]; + return count; +} + +- (NSSet *)filteredQueryIdsAtPath:(FPath *)path { + NSDictionary *queries = [self.trackedQueryTree valueAtPath:path]; + if (queries) { + NSMutableSet *ids = [NSMutableSet set]; + [queries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *params, FTrackedQuery *query, BOOL *stop) { + if (!query.query.loadsAllData) { + [ids addObject:@(query.queryId)]; + } + }]; + return ids; + } else { + return [NSSet set]; + } +} + +- (NSSet *)knownCompleteChildrenAtPath:(FPath *)path { + NSAssert(![self isQueryComplete:[FQuerySpec defaultQueryAtPath:path]], + @"Path is fully complete"); + + NSMutableSet *completeChildren = [NSMutableSet set]; + // First, get complete children from any queries at this location. + NSSet *queryIds = [self filteredQueryIdsAtPath:path]; + [queryIds enumerateObjectsUsingBlock:^(NSNumber *queryId, BOOL *stop) { + NSSet *keys = [self.storageEngine + trackedQueryKeysForQuery:[queryId unsignedIntegerValue]]; + [completeChildren unionSet:keys]; + }]; + + // Second, get any complete default queries immediately below us. + [[[self.trackedQueryTree subtreeAtPath:path] children] + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if ([childTree.value[[FQueryParams defaultInstance]] isComplete]) { + [completeChildren addObject:childKey]; + } + }]; + + return completeChildren; +} + +- (void)verifyCache { + NSArray *storedTrackedQueries = [self.storageEngine loadTrackedQueries]; + NSMutableArray *trackedQueries = [NSMutableArray array]; + + [self.trackedQueryTree forEach:^(FPath *path, NSDictionary *queryDict) { + [trackedQueries addObjectsFromArray:queryDict.allValues]; + }]; + NSComparator comparator = + ^NSComparisonResult(FTrackedQuery *q1, FTrackedQuery *q2) { + if (q1.queryId < q2.queryId) { + return NSOrderedAscending; + } else if (q1.queryId > q2.queryId) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }; + [trackedQueries sortUsingComparator:comparator]; + storedTrackedQueries = + [storedTrackedQueries sortedArrayUsingComparator:comparator]; + + if (![trackedQueries isEqualToArray:storedTrackedQueries]) { + [NSException + raise:NSInternalInconsistencyException + format:@"Tracked queries and queries stored on disk don't match"]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h new file mode 100644 index 0000000..3aecd81 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.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. + */ + +#ifndef Firebase_FIRDataEventType_h +#define Firebase_FIRDataEventType_h + +#import + +/** + * This enum is the set of events that you can observe at a Firebase Database + * location. + */ +typedef NS_ENUM(NSInteger, FIRDataEventType) { + /// A new child node is added to a location. + FIRDataEventTypeChildAdded, + /// A child node is removed from a location. + FIRDataEventTypeChildRemoved, + /// A child node at a location changes. + FIRDataEventTypeChildChanged, + /// A child node moves relative to the other child nodes at a location. + FIRDataEventTypeChildMoved, + /// Any data changes at a location or, recursively, at any child node. + FIRDataEventTypeValue +} NS_SWIFT_NAME(DataEventType); + +#endif diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h new file mode 100644 index 0000000..e88febb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h @@ -0,0 +1,142 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@class FIRDatabaseReference; + +/** + * A FIRDataSnapshot contains data from a Firebase Database location. Any time + * you read Firebase data, you receive the data as a FIRDataSnapshot. + * + * FIRDataSnapshots are passed to the blocks you attach with + * observeEventType:withBlock: or observeSingleEvent:withBlock:. They are + * efficiently-generated immutable copies of the data at a Firebase Database + * location. They can't be modified and will never change. To modify data at a + * location, use a FIRDatabaseReference (e.g. with setValue:). + */ +NS_SWIFT_NAME(DataSnapshot) +@interface FIRDataSnapshot : NSObject + +#pragma mark - Navigating and inspecting a snapshot + +/** + * Gets a FIRDataSnapshot for the location at the specified relative path. + * The relative path can either be a simple child key (e.g. 'fred') + * or a deeper slash-separated path (e.g. 'fred/name/first'). If the child + * location has no data, an empty FIRDataSnapshot is returned. + * + * @param childPathString A relative path to the location of child data. + * @return The FIRDataSnapshot for the child location. + */ +- (FIRDataSnapshot *)childSnapshotForPath:(NSString *)childPathString; + +/** + * Return YES if the specified child exists. + * + * @param childPathString A relative path to the location of a potential child. + * @return YES if data exists at the specified childPathString, else NO. + */ +- (BOOL)hasChild:(NSString *)childPathString; + +/** + * Return YES if the DataSnapshot has any children. + * + * @return YES if this snapshot has any children, else NO. + */ +- (BOOL)hasChildren; + +/** + * Return YES if the DataSnapshot contains a non-null value. + * + * @return YES if this snapshot contains a non-null value, else NO. + */ +- (BOOL)exists; + +#pragma mark - Data export + +/** + * Returns the raw value at this location, coupled with any metadata, such as + * priority. + * + * Priorities, where they exist, are accessible under the ".priority" key in + * instances of NSDictionary. For leaf locations with priorities, the value will + * be under the ".value" key. + */ +- (id __nullable)valueInExportFormat; + +#pragma mark - Properties + +/** + * Returns the contents of this data snapshot as native types. + * + * Data types returned: + * + NSDictionary + * + NSArray + * + NSNumber (also includes booleans) + * + NSString + * + * @return The data as a native object. + */ +@property(strong, readonly, nonatomic, nullable) id value; + +/** + * Gets the number of children for this DataSnapshot. + * + * @return An integer indicating the number of children. + */ +@property(readonly, nonatomic) NSUInteger childrenCount; + +/** + * Gets a FIRDatabaseReference for the location that this data came from. + * + * @return A FIRDatabaseReference instance for the location of this data. + */ +@property(nonatomic, readonly, strong) FIRDatabaseReference *ref; + +/** + * The key of the location that generated this FIRDataSnapshot. + * + * @return An NSString containing the key for the location of this + * FIRDataSnapshot. + */ +@property(strong, readonly, nonatomic) NSString *key; + +/** + * An iterator for snapshots of the child nodes in this snapshot. + * You can use the native for..in syntax: + * + * for (FIRDataSnapshot* child in snapshot.children) { + * ... + * } + * + * @return An NSEnumerator of the children. + */ +@property(strong, readonly, nonatomic) + NSEnumerator *children; + +/** + * The priority of the data in this FIRDataSnapshot. + * + * @return The priority as a string, or nil if no priority was set. + */ +@property(strong, readonly, nonatomic, nullable) id priority; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h new file mode 100644 index 0000000..d5733f7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h @@ -0,0 +1,186 @@ +/* + * 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 "FIRDatabaseReference.h" +#import + +@class FIRApp; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The entry point for accessing a Firebase Database. You can get an instance + * by calling [FIRDatabase database]. To access a location in the database and + * read or write data, use [FIRDatabase reference]. + */ +NS_SWIFT_NAME(Database) +@interface FIRDatabase : NSObject + +/** + * The NSObject initializer that has been marked as unavailable. Use the + * `database` class method instead. + */ +- (instancetype)init + __attribute__((unavailable("use the database method instead"))); + +/** + * Gets the instance of FIRDatabase for the default FIRApp. + * + * @return A FIRDatabase instance. + */ ++ (FIRDatabase *)database NS_SWIFT_NAME(database()); + +/** + * Gets a FirebaseDatabase instance for the specified URL. + * + * @param url The URL to the Firebase Database instance you want to access. + * @return A FIRDatabase instance. + */ ++ (FIRDatabase *)databaseWithURL:(NSString *)url NS_SWIFT_NAME(database(url:)); + +/** + * Gets a FirebaseDatabase instance for the specified URL, using the specified + * FirebaseApp. + * + * @param app The FIRApp to get a FIRDatabase for. + * @param url The URL to the Firebase Database instance you want to access. + * @return A FIRDatabase instance. + */ +// clang-format off ++ (FIRDatabase *)databaseForApp:(FIRApp *)app + URL:(NSString *)url NS_SWIFT_NAME(database(app:url:)); +// clang-format on + +/** + * Gets an instance of FIRDatabase for a specific FIRApp. + * + * @param app The FIRApp to get a FIRDatabase for. + * @return A FIRDatabase instance. + */ ++ (FIRDatabase *)databaseForApp:(FIRApp *)app NS_SWIFT_NAME(database(app:)); + +/** The FIRApp instance to which this FIRDatabase belongs. */ +@property(weak, readonly, nonatomic) FIRApp *app; + +/** + * Gets a FIRDatabaseReference for the root of your Firebase Database. + */ +- (FIRDatabaseReference *)reference; + +/** + * Gets a FIRDatabaseReference for the provided path. + * + * @param path Path to a location in your Firebase Database. + * @return A FIRDatabaseReference pointing to the specified path. + */ +- (FIRDatabaseReference *)referenceWithPath:(NSString *)path; + +/** + * Gets a FIRDatabaseReference for the provided URL. The URL must be a URL to a + * path within this Firebase Database. To create a FIRDatabaseReference to a + * different database, create a FIRApp with a FIROptions object configured with + * the appropriate database URL. + * + * @param databaseUrl A URL to a path within your database. + * @return A FIRDatabaseReference for the provided URL. + */ +- (FIRDatabaseReference *)referenceFromURL:(NSString *)databaseUrl; + +/** + * The Firebase Database client automatically queues writes and sends them to + * the server at the earliest opportunity, depending on network connectivity. In + * some cases (e.g. offline usage) there may be a large number of writes waiting + * to be sent. Calling this method will purge all outstanding writes so they are + * abandoned. + * + * All writes will be purged, including transactions and onDisconnect writes. + * The writes will be rolled back locally, perhaps triggering events for + * affected event listeners, and the client will not (re-)send them to the + * Firebase Database backend. + */ +- (void)purgeOutstandingWrites; + +/** + * Shuts down our connection to the Firebase Database backend until goOnline is + * called. + */ +- (void)goOffline; + +/** + * Resumes our connection to the Firebase Database backend after a previous + * goOffline call. + */ +- (void)goOnline; + +/** + * The Firebase Database client will cache synchronized data and keep track of + * all writes you've initiated while your application is running. It seamlessly + * handles intermittent network connections and re-sends write operations when + * the network connection is restored. + * + * However by default your write operations and cached data are only stored + * in-memory and will be lost when your app restarts. By setting this value to + * `YES`, the data will be persisted to on-device (disk) storage and will thus + * be available again when the app is restarted (even when there is no network + * connectivity at that time). Note that this property must be set before + * creating your first Database reference and only needs to be called once per + * application. + * + */ +@property(nonatomic) BOOL persistenceEnabled NS_SWIFT_NAME(isPersistenceEnabled) + ; + +/** + * By default the Firebase Database client will use up to 10MB of disk space to + * cache data. If the cache grows beyond this size, the client will start + * removing data that hasn't been recently used. If you find that your + * application caches too little or too much data, call this method to change + * the cache size. This property must be set before creating your first + * FIRDatabaseReference and only needs to be called once per application. + * + * Note that the specified cache size is only an approximation and the size on + * disk may temporarily exceed it at times. Cache sizes smaller than 1 MB or + * greater than 100 MB are not supported. + */ +@property(nonatomic) NSUInteger persistenceCacheSizeBytes; + +/** + * Sets the dispatch queue on which all events are raised. The default queue is + * the main queue. + * + * Note that this must be set before creating your first Database reference. + */ +@property(nonatomic, strong) dispatch_queue_t callbackQueue; + +/** + * Enables verbose diagnostic logging. + * + * @param enabled YES to enable logging, NO to disable. + */ ++ (void)setLoggingEnabled:(BOOL)enabled; + +/** Retrieve the Firebase Database SDK version. */ ++ (NSString *)sdkVersion; + +/** + * Configures the database to use an emulated backend instead of the default + * remote backend. + */ +- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h new file mode 100644 index 0000000..54ce8bc --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h @@ -0,0 +1,467 @@ +/* + * 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 "FIRDataEventType.h" +#import "FIRDataSnapshot.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A FIRDatabaseHandle is used to identify listeners of Firebase Database + * events. These handles are returned by observeEventType: and can later be + * passed to removeObserverWithHandle: to stop receiving updates. + */ +typedef NSUInteger FIRDatabaseHandle NS_SWIFT_NAME(DatabaseHandle); + +/** + * A FIRDatabaseQuery instance represents a query over the data at a particular + * location. + * + * You create one by calling one of the query methods (queryOrderedByChild:, + * queryStartingAtValue:, etc.) on a FIRDatabaseReference. The query methods can + * be chained to further specify the data you are interested in observing + */ +NS_SWIFT_NAME(DatabaseQuery) +@interface FIRDatabaseQuery : NSObject + +#pragma mark - Attach observers to read data + +/** + * observeEventType:withBlock: is used to listen for data changes at a + * particular location. This is the primary way to read data from the Firebase + * Database. Your block will be triggered for the initial data and again + * whenever the data changes. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot. + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock: + (void (^)(FIRDataSnapshot *snapshot))block; + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data + * changes at a particular location. This is the primary way to read data from + * the Firebase Database. Your block will be triggered for the initial data and + * again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, + * FIRDataEventTypeChildMoved, and FIRDataEventTypeChildChanged events, your + * block will be passed the key of the previous node by priority order. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot and the previous child's key. + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; + +/** + * observeEventType:withBlock: is used to listen for data changes at a + * particular location. This is the primary way to read data from the Firebase + * Database. Your block will be triggered for the initial data and again + * whenever the data changes. + * + * The cancelBlock will be called if you will no longer receive new events due + * to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data + * changes at a particular location. This is the primary way to read data from + * the Firebase Database. Your block will be triggered for the initial data and + * again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, + * FIRDataEventTypeChildMoved, and FIRDataEventTypeChildChanged events, your + * block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you will no longer receive new events due + * to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +/** + * getDataWithCompletionBlock: is used to get the most up-to-date value for + * this query. This method updates the cache and raises events if successful. If + * not connected, falls back to a locally-cached value. + * + * @param block The block that should be called with the most up-to-date value + * of this query, or an error if no such value could be retrieved. + */ +- (void)getDataWithCompletionBlock: + (void (^_Nonnull)(NSError *__nullable error, + FIRDataSnapshot *snapshot))block + NS_SWIFT_NAME(getData(completion:)); + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. In addition, for + * FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the + * previous node by priority order. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot and the previous child's key. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. + * + * The cancelBlock will be called if you do not have permission to read data at + * this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock:(nullable void (^)(NSError *error))cancelBlock; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. In addition, for + * FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the + * previous node by priority order. + * + * The cancelBlock will be called if you do not have permission to read data at + * this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +#pragma mark - Detaching observers + +/** + * Detach a block previously attached with observeEventType:withBlock:. + * + * @param handle The handle returned by the call to observeEventType:withBlock: + * which we are trying to remove. + */ +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle; + +/** + * Detach all blocks previously attached to this Firebase Database location with + * observeEventType:withBlock: + */ +- (void)removeAllObservers; + +/** + * By calling `keepSynced:YES` on a location, the data for that location will + * automatically be downloaded and kept in sync, even when no listeners are + * attached for that location. Additionally, while a location is kept synced, it + * will not be evicted from the persistent disk cache. + * + * @param keepSynced Pass YES to keep this location synchronized, pass NO to + * stop synchronization. + */ +- (void)keepSynced:(BOOL)keepSynced; + +#pragma mark - Querying and limiting + +/** + * queryLimitedToFirst: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryLimitedToFirst: will respond to at most the first limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit; + +/** + * queryLimitedToLast: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryLimitedToLast: will respond to at most the last limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit; + +/** + * queryOrderBy: is used to generate a reference to a view of the data that's + * been sorted by the values of a particular child key. This method is intended + * to be used in combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @param key The child key to use in ordering data visible to the returned + * FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, ordered by the values of the specified + * child key. + */ +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key; + +/** + * queryOrderedByKey: is used to generate a reference to a view of the data + * that's been sorted by child key. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child keys. + */ +- (FIRDatabaseQuery *)queryOrderedByKey; + +/** + * queryOrderedByValue: is used to generate a reference to a view of the data + * that's been sorted by child value. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child value. + */ +- (FIRDatabaseQuery *)queryOrderedByValue; + +/** + * queryOrderedByPriority: is used to generate a reference to a view of the data + * that's been sorted by child priority. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child priorities. + */ +- (FIRDatabaseQuery *)queryOrderedByPriority; + +/** + * queryStartingAtValue: is used to generate a reference to a limited view of + * the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAtValue: will respond to events at nodes with a value greater + * than or equal to startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue; + +/** + * queryStartingAtValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAtValue:childKey will respond to events at nodes with a value + * greater than startValue, or equal to startValue and with a key greater than + * or equal to childKey. This is most useful when implementing pagination in a + * case where multiple nodes can match the startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned FIRDatabaseQuery + * @param childKey The lower bound, inclusive, for the key of nodes with value + * equal to startValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue + childKey:(nullable NSString *)childKey; + +/** + * queryStartingAfterValue: is used to generate a reference to a + * limited view of the data at this location. The FIRDatabaseQuery instance + * returned by queryStartingAfterValue: will respond to events at nodes + * with a value greater than startAfterValue. + * + * @param startAfterValue The lower bound, exclusive, for the value of data + * visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater + * startAfterValue + */ +- (FIRDatabaseQuery *)queryStartingAfterValue:(nullable id)startAfterValue; + +/** + * queryStartingAfterValue:childKey: is used to generate a reference to a + * limited view of the data at this location. The FIRDatabaseQuery instance + * returned by queryStartingAfterValue:childKey will respond to events at nodes + * with a value greater than startAfterValue, or equal to startAfterValue and + * with a key greater than childKey. This is most useful when implementing + * pagination in a case where multiple nodes can match the startAfterValue. + * + * @param startAfterValue The lower bound, inclusive, for the value of data + * visible to the returned FIRDatabaseQuery + * @param childKey The lower bound, exclusive, for the key of nodes with value + * equal to startAfterValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * startAfterValue, or equal to startAfterValue with a key greater than childKey + */ +- (FIRDatabaseQuery *)queryStartingAfterValue:(nullable id)startAfterValue + childKey:(nullable NSString *)childKey; +/** + * queryEndingAtValue: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryEndingAtValue: will respond to events at nodes with a value less than or + * equal to endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue; + +/** + * queryEndingAtValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryEndingAtValue:childKey will respond to events at nodes with a value less + * than endValue, or equal to endValue and with a key less than or equal to + * childKey. This is most useful when implementing pagination in a case where + * multiple nodes can match the endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @param childKey The upper bound, inclusive, for the key of nodes with value + * equal to endValue + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue + childKey:(nullable NSString *)childKey; + +/** + * queryEndingBeforeValue: is used to generate a reference to a limited view of + * the data at this location. The FIRDatabaseQuery instance returned by + * queryEndingBeforeValue: will respond to events at nodes with a value less + * than endValue. + * + * @param endValue The upper bound, exclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value less than + * endValue + */ +- (FIRDatabaseQuery *)queryEndingBeforeValue:(nullable id)endValue; + +/** + * queryEndingBeforeValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryEndingBeforeValue:childKey will respond to events at nodes with a value + * less than endValue, or equal to endValue and with a key less than childKey. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @param childKey The upper bound, exclusive, for the key of nodes with value + * equal to endValue + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingBeforeValue:(nullable id)endValue + childKey:(nullable NSString *)childKey; + +/** + * queryEqualToValue: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryEqualToValue: will respond to events at nodes with a value equal to the + * supplied argument. + * + * @param value The value that the data returned by this FIRDatabaseQuery will + * have + * @return A FIRDatabaseQuery instance, limited to data with the supplied value. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value; + +/** + * queryEqualToValue:childKey: is used to generate a reference to a limited view + * of the data at this location. The FIRDatabaseQuery instance returned by + * queryEqualToValue:childKey will respond to events at nodes with a value equal + * to the supplied argument and with their key equal to childKey. There will be + * at most one node that matches because child keys are unique. + * + * @param value The value that the data returned by this FIRDatabaseQuery will + * have + * @param childKey The name of nodes with the right value + * @return A FIRDatabaseQuery instance, limited to data with the supplied value + * and the key. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value + childKey:(nullable NSString *)childKey; + +#pragma mark - Properties + +/** + * Gets a FIRDatabaseReference for the location of this query. + * + * @return A FIRDatabaseReference for the location of this query. + */ +@property(nonatomic, readonly, strong) FIRDatabaseReference *ref; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h new file mode 100644 index 0000000..06bbd76 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h @@ -0,0 +1,906 @@ +/* + * 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 "FIRDataSnapshot.h" +#import "FIRDatabase.h" +#import "FIRDatabaseQuery.h" +#import "FIRMutableData.h" +#import "FIRServerValue.h" +#import "FIRTransactionResult.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@class FIRDatabase; + +/** + * A FIRDatabaseReference represents a particular location in your Firebase + * Database and can be used for reading or writing data to that Firebase + * Database location. + * + * This class is the starting point for all Firebase Database operations. After + * you've obtained your first FIRDatabaseReference via [FIRDatabase reference], + * you can use it to read data (ie. observeEventType:withBlock:), write data + * (ie. setValue:), and to create new FIRDatabaseReferences (ie. child:). + */ +NS_SWIFT_NAME(DatabaseReference) +@interface FIRDatabaseReference : FIRDatabaseQuery + +#pragma mark - Getting references to children locations + +/** + * Gets a FIRDatabaseReference for the location at the specified relative path. + * The relative path can either be a simple child key (e.g. 'fred') or a + * deeper slash-separated path (e.g. 'fred/name/first'). + * + * @param pathString A relative path from this location to the desired child + * location. + * @return A FIRDatabaseReference for the specified relative path. + */ +- (FIRDatabaseReference *)child:(NSString *)pathString; + +/** + * childByAutoId generates a new child location using a unique key and returns a + * FIRDatabaseReference to it. This is useful when the children of a Firebase + * Database location represent a list of items. + * + * The unique key generated by childByAutoId: is prefixed with a + * client-generated timestamp so that the resulting list will be + * chronologically-sorted. + * + * @return A FIRDatabaseReference for the generated location. + */ +- (FIRDatabaseReference *)childByAutoId; + +#pragma mark - Writing data + +/** Write data to this Firebase Database location. + +This will overwrite any data at this location and all child locations. + +Data types that can be set are: + +- NSString -- @"Hello World" +- NSNumber (also includes boolean) -- @YES, @43, @4.333 +- NSDictionary -- @{@"key": @"value", @"nested": @{@"another": @"value"} } +- NSArray + +The effect of the write will be visible immediately and the corresponding +events will be triggered. Synchronization of the data to the Firebase Database +servers will also be started. + +Passing null for the new value is equivalent to calling remove:; +all data at this location or any child location will be deleted. + +Note that setValue: will remove any priority stored at this location, so if +priority is meant to be preserved, you should use setValue:andPriority: instead. + +@param value The value to be written. + */ +- (void)setValue:(nullable id)value; + +/** + * The same as setValue: with a block that gets triggered after the write + * operation has been committed to the Firebase Database servers. + * + * @param value The value to be written. + * @param block The block to be called after the write has been committed to the + * Firebase Database servers. + */ +- (void)setValue:(nullable id)value + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +/** + * The same as setValue: with an additional priority to be attached to the data + * being written. Priorities are used to order items. + * + * @param value The value to be written. + * @param priority The priority to be attached to that data. + */ +- (void)setValue:(nullable id)value andPriority:(nullable id)priority; + +/** + * The same as setValue:andPriority: with a block that gets triggered after the + * write operation has been committed to the Firebase Database servers. + * + * @param value The value to be written. + * @param priority The priority to be attached to that data. + * @param block The block to be called after the write has been committed to the + * Firebase Database servers. + */ +- (void)setValue:(nullable id)value + andPriority:(nullable id)priority + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +/** + * Remove the data at this Firebase Database location. Any data at child + * locations will also be deleted. + * + * The effect of the delete will be visible immediately and the corresponding + * events will be triggered. Synchronization of the delete to the Firebase + * Database servers will also be started. + * + * remove: is equivalent to calling setValue:nil + */ +- (void)removeValue; + +/** + * The same as remove: with a block that gets triggered after the remove + * operation has been committed to the Firebase Database servers. + * + * @param block The block to be called after the remove has been committed to + * the Firebase Database servers. + */ +- (void)removeValueWithCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +/** + * Sets a priority for the data at this Firebase Database location. + * Priorities can be used to provide a custom ordering for the children at a + * location (if no priorities are specified, the children are ordered by key). + * + * You cannot set a priority on an empty location. For this reason + * setValue:andPriority: should be used when setting initial data with a + * specific priority and setPriority: should be used when updating the priority + * of existing data. + * + * Children are sorted based on this priority using the following rules: + * + * Children with no priority come first. + * Children with a number as their priority come next. They are sorted + * numerically by priority (small to large). Children with a string as their + * priority come last. They are sorted lexicographically by priority. Whenever + * two children have the same priority (including no priority), they are sorted + * by key. Numeric keys come first (sorted numerically), followed by the + * remaining keys (sorted lexicographically). + * + * Note that priorities are parsed and ordered as IEEE 754 double-precision + * floating-point numbers. Keys are always stored as strings and are treated as + * numbers only when they can be parsed as a 32-bit integer + * + * @param priority The priority to set at the specified location. + */ +- (void)setPriority:(nullable id)priority; + +/** + * The same as setPriority: with a block that is called once the priority has + * been committed to the Firebase Database servers. + * + * @param priority The priority to set at the specified location. + * @param block The block that is triggered after the priority has been written + * on the servers. + */ +- (void)setPriority:(nullable id)priority + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +/** + * Updates the values at the specified paths in the dictionary without + * overwriting other keys at this location. + * + * @param values A dictionary of the keys to change and their new values + */ +- (void)updateChildValues:(NSDictionary *)values; + +/** + * The same as update: with a block that is called once the update has been + * committed to the Firebase Database servers + * + * @param values A dictionary of the keys to change and their new values + * @param block The block that is triggered after the update has been written on + * the Firebase Database servers + */ +- (void)updateChildValues:(NSDictionary *)values + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +#pragma mark - Attaching observers to read data + +/** + * observeEventType:withBlock: is used to listen for data changes at a + * particular location. This is the primary way to read data from the Firebase + * Database. Your block will be triggered for the initial data and again + * whenever the data changes. + * + * Use removeObserverWithHandle: to stop receiving updates. + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot. + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock: + (void (^)(FIRDataSnapshot *snapshot))block; + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data + * changes at a particular location. This is the primary way to read data from + * the Firebase Database. Your block will be triggered for the initial data and + * again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, + * FIRDataEventTypeChildMoved, and FIRDataEventTypeChildChanged events, your + * block will be passed the key of the previous node by priority order. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot and the previous child's key. + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; + +/** + * observeEventType:withBlock: is used to listen for data changes at a + * particular location. This is the primary way to read data from the Firebase + * Database. Your block will be triggered for the initial data and again + * whenever the data changes. + * + * The cancelBlock will be called if you will no longer receive new events due + * to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data + * changes at a particular location. This is the primary way to read data from + * the Firebase Database. Your block will be triggered for the initial data and + * again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, + * FIRDataEventTypeChildMoved, and FIRDataEventTypeChildChanged events, your + * block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you will no longer receive new events due + * to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. In addition, for + * FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the + * previous node by priority order. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot and the previous child's key. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. + * + * The cancelBlock will be called if you do not have permission to read data at + * this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock:(nullable void (^)(NSError *error))cancelBlock; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. In addition, for + * FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the + * previous node by priority order. + * + * The cancelBlock will be called if you do not have permission to read data at + * this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +/** + * getDataWithCompletionBlock: is used to get the most up-to-date value for + * this query. This method updates the cache and raises events if successful. If + * not connected, falls back to a locally-cached value. + * + * @param block The block that should be called with the most up-to-date value + * of this query, or an error if no such value could be retrieved. + */ +- (void)getDataWithCompletionBlock: + (void (^_Nonnull)(NSError *__nullable error, + FIRDataSnapshot *snapshot))block + NS_SWIFT_NAME(getData(completion:)); + +#pragma mark - Detaching observers + +/** + * Detach a block previously attached with observeEventType:withBlock:. + * + * @param handle The handle returned by the call to observeEventType:withBlock: + * which we are trying to remove. + */ +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle; + +/** + * By calling `keepSynced:YES` on a location, the data for that location will + * automatically be downloaded and kept in sync, even when no listeners are + * attached for that location. Additionally, while a location is kept synced, it + * will not be evicted from the persistent disk cache. + * + * @param keepSynced Pass YES to keep this location synchronized, pass NO to + * stop synchronization. + */ +- (void)keepSynced:(BOOL)keepSynced; + +/** + * Removes all observers at the current reference, but does not remove any + * observers at child references. removeAllObservers must be called again for + * each child reference where a listener was established to remove the + * observers. + */ +- (void)removeAllObservers; + +#pragma mark - Querying and limiting + +/** + * queryLimitedToFirst: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryLimitedToFirst: will respond to at most the first limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit; + +/** + * queryLimitedToLast: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryLimitedToLast: will respond to at most the last limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit; + +/** + * queryOrderBy: is used to generate a reference to a view of the data that's + * been sorted by the values of a particular child key. This method is intended + * to be used in combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @param key The child key to use in ordering data visible to the returned + * FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, ordered by the values of the specified + * child key. + */ +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key; + +/** + * queryOrderedByKey: is used to generate a reference to a view of the data + * that's been sorted by child key. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child keys. + */ +- (FIRDatabaseQuery *)queryOrderedByKey; + +/** + * queryOrderedByPriority: is used to generate a reference to a view of the data + * that's been sorted by child priority. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child priorities. + */ +- (FIRDatabaseQuery *)queryOrderedByPriority; + +/** + * queryStartingAtValue: is used to generate a reference to a limited view of + * the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAtValue: will respond to events at nodes with a value greater + * than or equal to startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue; + +/** + * queryStartingAtValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAtValue:childKey will respond to events at nodes with a value + * greater than startValue, or equal to startValue and with a key greater than + * or equal to childKey. + * + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned FIRDatabaseQuery + * @param childKey The lower bound, inclusive, for the key of nodes with value + * equal to startValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue + childKey:(nullable NSString *)childKey; + +/** + * queryStartingAfterValue: is used to generate a reference to a limited view of + * the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAfterValue: will respond to events at nodes with a value greater + * than startAfterValue. + * + * @param startAfterValue The lower bound, exclusive, for the value of data + * visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * startAfterValue + */ +- (FIRDatabaseQuery *)queryStartingAfterValue:(nullable id)startAfterValue; + +/** + * queryStartingAfterValue:childKey: is used to generate a reference to a + * limited view of the data at this location. The FIRDatabaseQuery instance + * returned by queryStartingAfterValue:childKey will respond to events at nodes + * with a value greater than startAfterValue, or equal to startAfterValue and + * with a key greater than childKey. This is most useful when implementing + * pagination in a case where multiple nodes can match the startAfterValue. + * + * @param startAfterValue The lower bound, inclusive, for the value of data + * visible to the returned FIRDatabaseQuery + * @param childKey The lower bound, exclusive, for the key of nodes with value + * equal to startAfterValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startAfterValue, or equal to startAfterValue and with a key + * greater than childKey. + */ +- (FIRDatabaseQuery *)queryStartingAfterValue:(nullable id)startAfterValue + childKey:(nullable NSString *)childKey; + +/** + * queryEndingAtValue: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryEndingAtValue: will respond to events at nodes with a value less than or + * equal to endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue; + +/** + * queryEndingAtValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryEndingAtValue:childKey will respond to events at nodes with a value less + * than endValue, or equal to endValue and with a key less than or equal to + * childKey. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @param childKey The upper bound, inclusive, for the key of nodes with value + * equal to endValue + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue + childKey:(nullable NSString *)childKey; + +/** + * queryEqualToValue: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryEqualToValue: will respond to events at nodes with a value equal to the + * supplied argument. + * + * @param value The value that the data returned by this FIRDatabaseQuery will + * have + * @return A FIRDatabaseQuery instance, limited to data with the supplied value. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value; + +/** + * queryEqualToValue:childKey: is used to generate a reference to a limited view + * of the data at this location. The FIRDatabaseQuery instance returned by + * queryEqualToValue:childKey will respond to events at nodes with a value equal + * to the supplied argument with a key equal to childKey. There will be at most + * one node that matches because child keys are unique. + * + * @param value The value that the data returned by this FIRDatabaseQuery will + * have + * @param childKey The key of nodes with the right value + * @return A FIRDatabaseQuery instance, limited to data with the supplied value + * and the key. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value + childKey:(nullable NSString *)childKey; + +#pragma mark - Managing presence + +/** + * Ensure the data at this location is set to the specified value when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * onDisconnectSetValue: is especially useful for implementing "presence" + * systems, where a value should be changed or cleared when a user disconnects + * so that he appears "offline" to other users. + * + * @param value The value to be set after the connection is lost. + */ +- (void)onDisconnectSetValue:(nullable id)value; + +/** + * Ensure the data at this location is set to the specified value when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * The completion block will be triggered when the operation has been + * successfully queued up on the Firebase Database servers + * + * @param value The value to be set after the connection is lost. + * @param block Block to be triggered when the operation has been queued up on + * the Firebase Database servers + */ +- (void)onDisconnectSetValue:(nullable id)value + withCompletionBlock:(void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; + +/** + * Ensure the data at this location is set to the specified value and priority + * when the client is disconnected (due to closing the browser, navigating to a + * new page, or network issues). + * + * @param value The value to be set after the connection is lost. + * @param priority The priority to be set after the connection is lost. + */ +- (void)onDisconnectSetValue:(nullable id)value andPriority:(id)priority; + +/** + * Ensure the data at this location is set to the specified value and priority + * when the client is disconnected (due to closing the browser, navigating to a + * new page, or network issues). + * + * The completion block will be triggered when the operation has been + * successfully queued up on the Firebase Database servers + * + * @param value The value to be set after the connection is lost. + * @param priority The priority to be set after the connection is lost. + * @param block Block to be triggered when the operation has been queued up on + * the Firebase Database servers + */ +- (void)onDisconnectSetValue:(nullable id)value + andPriority:(nullable id)priority + withCompletionBlock:(void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; + +/** + * Ensure the data at this location is removed when + * the client is disconnected (due to closing the app, navigating + * to a new page, or network issues). + * + * onDisconnectRemoveValue is especially useful for implementing "presence" + * systems. + */ +- (void)onDisconnectRemoveValue; + +/** + * Ensure the data at this location is removed when + * the client is disconnected (due to closing the app, navigating + * to a new page, or network issues). + * + * onDisconnectRemoveValueWithCompletionBlock: is especially useful for + * implementing "presence" systems. + * + * @param block Block to be triggered when the operation has been queued up on + * the Firebase Database servers + */ +- (void)onDisconnectRemoveValueWithCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +/** + * Ensure the data has the specified child values updated when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * + * @param values A dictionary of child node keys and the values to set them to + * after the connection is lost. + */ +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values; + +/** + * Ensure the data has the specified child values updated when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * + * @param values A dictionary of child node keys and the values to set them to + * after the connection is lost. + * @param block A block that will be called once the operation has been queued + * up on the Firebase Database servers + */ +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values + withCompletionBlock: + (void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; + +/** + * Cancel any operations that are set to run on disconnect. If you previously + * called onDisconnectSetValue:, onDisconnectRemoveValue:, or + * onDisconnectUpdateChildValues:, and no longer want the values updated when + * the connection is lost, call cancelDisconnectOperations: + */ +- (void)cancelDisconnectOperations; + +/** + * Cancel any operations that are set to run on disconnect. If you previously + * called onDisconnectSetValue:, onDisconnectRemoveValue:, or + * onDisconnectUpdateChildValues:, and no longer want the values updated when + * the connection is lost, call cancelDisconnectOperations: + * + * @param block A block that will be triggered once the Firebase Database + * servers have acknowledged the cancel request. + */ +- (void)cancelDisconnectOperationsWithCompletionBlock: + (nullable void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; + +#pragma mark - Manual Connection Management + +/** + * Manually disconnect the Firebase Database client from the server and disable + * automatic reconnection. + * + * The Firebase Database client automatically maintains a persistent connection + * to the Firebase Database server, which will remain active indefinitely and + * reconnect when disconnected. However, the goOffline( ) and goOnline( ) + * methods may be used to manually control the client connection in cases where + * a persistent connection is undesirable. + * + * While offline, the Firebase Database client will no longer receive data + * updates from the server. However, all database operations performed locally + * will continue to immediately fire events, allowing your application to + * continue behaving normally. Additionally, each operation performed locally + * will automatically be queued and retried upon reconnection to the Firebase + * Database server. + * + * To reconnect to the Firebase Database server and begin receiving remote + * events, see goOnline( ). Once the connection is reestablished, the Firebase + * Database client will transmit the appropriate data and fire the appropriate + * events so that your client "catches up" automatically. + * + * Note: Invoking this method will impact all Firebase Database connections. + */ ++ (void)goOffline; + +/** + * Manually reestablish a connection to the Firebase Database server and enable + * automatic reconnection. + * + * The Firebase Database client automatically maintains a persistent connection + * to the Firebase Database server, which will remain active indefinitely and + * reconnect when disconnected. However, the goOffline( ) and goOnline( ) + * methods may be used to manually control the client connection in cases where + * a persistent connection is undesirable. + * + * This method should be used after invoking goOffline( ) to disable the active + * connection. Once reconnected, the Firebase Database client will automatically + * transmit the proper data and fire the appropriate events so that your client + * "catches up" automatically. + * + * To disconnect from the Firebase Database server, see goOffline( ). + * + * Note: Invoking this method will impact all Firebase Database connections. + */ ++ (void)goOnline; + +#pragma mark - Transactions + +/** + * Performs an optimistic-concurrency transactional update to the data at this + * location. Your block will be called with a FIRMutableData instance that + * contains the current data at this location. Your block should update this + * data to the value you wish to write to this location, and then return an + * instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had + * stale data, your block will be run again with the latest data from the + * server. + * + * When your block is run, you may decide to abort the transaction by returning + * [FIRTransactionResult abort]. + * + * @param block This block receives the current data at this location and must + * return an instance of FIRTransactionResult + */ +- (void)runTransactionBlock: + (FIRTransactionResult * (^)(FIRMutableData *currentData))block; + +/** + * Performs an optimistic-concurrency transactional update to the data at this + * location. Your block will be called with a FIRMutableData instance that + * contains the current data at this location. Your block should update this + * data to the value you wish to write to this location, and then return an + * instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had + * stale data, your block will be run again with the latest data from the + * server. + * + * When your block is run, you may decide to abort the transaction by returning + * [FIRTransactionResult abort]. + * + * @param block This block receives the current data at this location and must + * return an instance of FIRTransactionResult + * @param completionBlock This block will be triggered once the transaction is + * complete, whether it was successful or not. It will indicate if there was an + * error, whether or not the data was committed, and what the current value of + * the data at this location is. + */ +- (void)runTransactionBlock: + (FIRTransactionResult * (^)(FIRMutableData *currentData))block + andCompletionBlock: + (void (^)(NSError *__nullable error, BOOL committed, + FIRDataSnapshot *__nullable snapshot))completionBlock; + +/** + * Performs an optimistic-concurrency transactional update to the data at this + * location. Your block will be called with a FIRMutableData instance that + * contains the current data at this location. Your block should update this + * data to the value you wish to write to this location, and then return an + * instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had + * stale data, your block will be run again with the latest data from the + * server. + * + * When your block is run, you may decide to abort the transaction by return + * [FIRTransactionResult abort]. + * + * Since your block may be run multiple times, this client could see several + * immediate states that don't exist on the server. You can suppress those + * immediate states until the server confirms the final state of the + * transaction. + * + * @param block This block receives the current data at this location and must + * return an instance of FIRTransactionResult + * @param completionBlock This block will be triggered once the transaction is + * complete, whether it was successful or not. It will indicate if there was an + * error, whether or not the data was committed, and what the current value of + * the data at this location is. + * @param localEvents Set this to NO to suppress events raised for intermediate + * states, and only get events based on the final state of the transaction. + */ +- (void)runTransactionBlock: + (FIRTransactionResult * (^)(FIRMutableData *currentData))block + andCompletionBlock: + (nullable void (^)(NSError *__nullable error, BOOL committed, + FIRDataSnapshot *__nullable snapshot)) + completionBlock + withLocalEvents:(BOOL)localEvents; + +#pragma mark - Retrieving String Representation + +/** + * Gets the absolute URL of this Firebase Database location. + * + * @return The absolute URL of the referenced Firebase Database location. + */ +- (NSString *)description; + +#pragma mark - Properties + +/** + * Gets a FIRDatabaseReference for the parent location. + * If this instance refers to the root of your Firebase Database, it has no + * parent, and therefore parent( ) will return null. + * + * @return A FIRDatabaseReference for the parent location. + */ +@property(strong, readonly, nonatomic, nullable) FIRDatabaseReference *parent; + +/** + * Gets a FIRDatabaseReference for the root location + * + * @return A new FIRDatabaseReference to root location. + */ +@property(strong, readonly, nonatomic) FIRDatabaseReference *root; + +/** + * Gets the last token in a Firebase Database location (e.g. 'fred' in + * https://SampleChat.firebaseIO-demo.com/users/fred) + * + * @return The key of the location this reference points to. + */ +@property(strong, readonly, nonatomic, nullable) NSString *key; + +/** + * Gets the URL for the Firebase Database location referenced by this + * FIRDatabaseReference. + * + * @return The url of the location this reference points to. + */ +@property(strong, readonly, nonatomic) NSString *URL; + +/** + * Gets the FIRDatabase instance associated with this reference. + * + * @return The FIRDatabase object for this reference. + */ +@property(strong, readonly, nonatomic) FIRDatabase *database; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h new file mode 100644 index 0000000..9797a67 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h @@ -0,0 +1,128 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * A FIRMutableData instance is populated with data from a Firebase Database + * location. When you are using runTransactionBlock:, you will be given an + * instance containing the current data at that location. Your block will be + * responsible for updating that instance to the data you wish to save at that + * location, and then returning using [FIRTransactionResult successWithValue:]. + * + * To modify the data, set its value property to any of the native types support + * by Firebase Database: + * + * + NSNumber (includes BOOL) + * + NSDictionary + * + NSArray + * + NSString + * + nil / NSNull to remove the data + * + * Note that changes made to a child FIRMutableData instance will be visible to + * the parent. + */ +NS_SWIFT_NAME(MutableData) +@interface FIRMutableData : NSObject + +#pragma mark - Inspecting and navigating the data + +/** + * Returns boolean indicating whether this mutable data has children. + * + * @return YES if this data contains child nodes. + */ +- (BOOL)hasChildren; + +/** + * Indicates whether this mutable data has a child at the given path. + * + * @param path A path string, consisting either of a single segment, like + * 'child', or multiple segments, 'a/deeper/child' + * @return YES if this data contains a child at the specified relative path + */ +- (BOOL)hasChildAtPath:(NSString *)path; + +/** + * Used to obtain a FIRMutableData instance that encapsulates the data at the + * given relative path. Note that changes made to the child will be visible to + * the parent. + * + * @param path A path string, consisting either of a single segment, like + * 'child', or multiple segments, 'a/deeper/child' + * @return A FIRMutableData instance containing the data at the given path + */ +- (FIRMutableData *)childDataByAppendingPath:(NSString *)path; + +#pragma mark - Properties + +/** + * To modify the data contained by this instance of FIRMutableData, set this to + * any of the native types supported by Firebase Database: + * + * + NSNumber (includes BOOL) + * + NSDictionary + * + NSArray + * + NSString + * + nil / NSNull to remove the data + * + * Note that setting this value will override the priority at this location. + * + * @return The current data at this location as a native object + */ +@property(strong, nonatomic, nullable) id value; + +/** + * Set this property to update the priority of the data at this location. Can be + * set to the following types: + * + * + NSNumber + * + NSString + * + nil / NSNull to remove the priority + * + * @return The priority of the data at this location + */ +@property(strong, nonatomic, nullable) id priority; + +/** + * @return The number of child nodes at this location + */ +@property(readonly, nonatomic) NSUInteger childrenCount; + +/** + * Used to iterate over the children at this location. You can use the native + * for .. in syntax: + * + * for (FIRMutableData* child in data.children) { + * ... + * } + * + * Note that this enumerator operates on an immutable copy of the child list. + * So, you can modify the instance during iteration, but the new additions will + * not be visible until you get a new enumerator. + */ +@property(readonly, nonatomic, strong) NSEnumerator *children; + +/** + * @return The key name of this node, or nil if it is the top-most location + */ +@property(readonly, nonatomic, strong, nullable) NSString *key; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h new file mode 100644 index 0000000..5f57094 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h @@ -0,0 +1,53 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * Placeholder values you may write into Firebase Database as a value or + * priority that will automatically be populated by the Firebase Database + * server. + */ +NS_SWIFT_NAME(ServerValue) +@interface FIRServerValue : NSObject + +/** + * Placeholder value for the number of milliseconds since the Unix epoch + */ ++ (NSDictionary *)timestamp; + +/** + * Returns a placeholder value that can be used to atomically increment the + * current database value by the provided delta. + * + * The delta must be a long or double value. If the current value is not an + * integer or double, or if the data does not yet exist, the transformation will + * set the data to the delta value. If either of the delta value or the existing + * data are doubles, both values will be interpreted as doubles. Double + * arithmetic and representation of double values follow IEEE 754 semantics. If + * there is positive/negative integer overflow, the sum is calculated as a + * double. + * + * @param delta the amount to modify the current value atomically. + * @return a placeholder value for modifying data atomically server-side. + */ ++ (NSDictionary *)increment:(NSNumber *)delta NS_SWIFT_NAME(increment(_:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h new file mode 100644 index 0000000..7f5ccc1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h @@ -0,0 +1,50 @@ +/* + * 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 "FIRMutableData.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Used for runTransactionBlock:. An FIRTransactionResult instance is a + * container for the results of the transaction. + */ +NS_SWIFT_NAME(TransactionResult) +@interface FIRTransactionResult : NSObject + +/** + * Used for runTransactionBlock:. Indicates that the new value should be saved + * at this location + * + * @param value A FIRMutableData instance containing the new value to be set + * @return An FIRTransactionResult instance that can be used as a return value + * from the block given to runTransactionBlock: + */ ++ (FIRTransactionResult *)successWithValue:(FIRMutableData *)value; + +/** + * Used for runTransactionBlock:. Indicates that the current transaction should + * no longer proceed. + * + * @return An FIRTransactionResult instance that can be used as a return value + * from the block given to runTransactionBlock: + */ ++ (FIRTransactionResult *)abort; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FirebaseDatabase.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FirebaseDatabase.h new file mode 100644 index 0000000..ae6b933 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FirebaseDatabase.h @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FirebaseDatabase_h +#define FirebaseDatabase_h + +#import "FIRDataEventType.h" +#import "FIRDataSnapshot.h" +#import "FIRDatabase.h" +#import "FIRDatabaseQuery.h" +#import "FIRDatabaseReference.h" +#import "FIRMutableData.h" +#import "FIRServerValue.h" +#import "FIRTransactionResult.h" + +#endif /* FirebaseDatabase_h */ diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.h new file mode 100644 index 0000000..84bb8df --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.h @@ -0,0 +1,61 @@ +/* + * 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 "FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@protocol FConnectionDelegate; + +@interface FConnection : NSObject + +@property(nonatomic, weak) id delegate; + +- (instancetype)initWith:(FRepoInfo *)aRepoInfo + andDispatchQueue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID + lastSessionID:(NSString *)lastSessionID + appCheckToken:(NSString *)appCheckToken; + +- (void)open; +- (void)close; +- (void)sendRequest:(NSDictionary *)dataMsg sensitive:(BOOL)sensitive; + +// FWebSocketDelegate delegate methods +- (void)onMessage:(FWebSocketConnection *)fwebSocket + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FWebSocketConnection *)fwebSocket + wasEverConnected:(BOOL)everConnected; + +@end + +typedef enum { + DISCONNECT_REASON_SERVER_RESET = 0, + DISCONNECT_REASON_OTHER = 1 +} FDisconnectReason; + +@protocol FConnectionDelegate + +- (void)onReady:(FConnection *)fconnection + atTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID; +- (void)onDataMessage:(FConnection *)fconnection + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FConnection *)fconnection + withReason:(FDisconnectReason)reason; +- (void)onKill:(FConnection *)fconnection withReason:(NSString *)reason; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.m new file mode 100644 index 0000000..f520888 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.m @@ -0,0 +1,238 @@ +/* + * 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 "FirebaseDatabase/Sources/Realtime/FConnection.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" + +typedef enum { + REALTIME_STATE_CONNECTING = 0, + REALTIME_STATE_CONNECTED = 1, + REALTIME_STATE_DISCONNECTED = 2, +} FConnectionState; + +@interface FConnection () { + FConnectionState state; +} + +@property(nonatomic, strong) FWebSocketConnection *conn; +@property(nonatomic, strong) FRepoInfo *repoInfo; + +@end + +#pragma mark - +#pragma mark FConnection implementation + +@implementation FConnection + +@synthesize delegate; +@synthesize conn; +@synthesize repoInfo; + +#pragma mark - +#pragma mark Initializers + +- (instancetype)initWith:(FRepoInfo *)aRepoInfo + andDispatchQueue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID + lastSessionID:(NSString *)lastSessionID + appCheckToken:(NSString *)appCheckToken { + self = [super init]; + if (self) { + state = REALTIME_STATE_CONNECTING; + self.repoInfo = aRepoInfo; + self.conn = [[FWebSocketConnection alloc] initWith:self.repoInfo + andQueue:queue + googleAppID:googleAppID + lastSessionID:lastSessionID + appCheckToken:appCheckToken]; + self.conn.delegate = self; + } + return self; +} + +#pragma mark - +#pragma mark Public method implementation + +- (void)open { + FFLog(@"I-RDB082001", @"Calling open in FConnection"); + [self.conn open]; +} + +- (void)closeWithReason:(FDisconnectReason)reason { + if (state != REALTIME_STATE_DISCONNECTED) { + FFLog(@"I-RDB082002", @"Closing realtime connection."); + state = REALTIME_STATE_DISCONNECTED; + + if (self.conn) { + FFLog(@"I-RDB082003", @"Calling close again."); + [self.conn close]; + self.conn = nil; + } + + [self.delegate onDisconnect:self withReason:reason]; + } +} + +- (void)close { + [self closeWithReason:DISCONNECT_REASON_OTHER]; +} + +- (void)sendRequest:(NSDictionary *)dataMsg sensitive:(BOOL)sensitive { + // since this came from the persistent connection, wrap it in a data message + // envelope + NSDictionary *msg = @{ + kFWPRequestType : kFWPRequestTypeData, + kFWPRequestDataPayload : dataMsg + }; + [self sendData:msg sensitive:sensitive]; +} + +#pragma mark - +#pragma mark Helpers + +- (void)sendData:(NSDictionary *)data sensitive:(BOOL)sensitive { + if (state != REALTIME_STATE_CONNECTED) { + @throw [[NSException alloc] + initWithName:@"InvalidConnectionState" + reason:@"Tried to send data on an unconnected FConnection" + userInfo:nil]; + } else { + if (sensitive) { + FFLog(@"I-RDB082004", @"Sending data (contents hidden)"); + } else { + FFLog(@"I-RDB082005", @"Sending: %@", data); + } + [self.conn send:data]; + } +} + +#pragma mark - +#pragma mark FWebSocketConnectinDelegate implementation + +// Corresponds to onConnectionLost in JS +- (void)onDisconnect:(FWebSocketConnection *)fwebSocket + wasEverConnected:(BOOL)everConnected { + + self.conn = nil; + if (!everConnected && state == REALTIME_STATE_CONNECTING) { + FFLog(@"I-RDB082006", @"Realtime connection failed."); + + // Since we failed to connect at all, clear any cached entry for this + // namespace in case the machine went away + [self.repoInfo clearInternalHostCache]; + } else if (state == REALTIME_STATE_CONNECTED) { + FFLog(@"I-RDB082007", @"Realtime connection lost."); + } + + [self close]; +} + +// Corresponds to onMessageReceived in JS +- (void)onMessage:(FWebSocketConnection *)fwebSocket + withMessage:(NSDictionary *)message { + NSString *rawMessageType = + [message objectForKey:kFWPAsyncServerEnvelopeType]; + if (rawMessageType != nil) { + if ([rawMessageType isEqualToString:kFWPAsyncServerDataMessage]) { + [self onDataMessage:[message + objectForKey:kFWPAsyncServerEnvelopeData]]; + } else if ([rawMessageType + isEqualToString:kFWPAsyncServerControlMessage]) { + [self onControl:[message objectForKey:kFWPAsyncServerEnvelopeData]]; + } else { + FFLog(@"I-RDB082008", @"Unrecognized server packet type: %@", + rawMessageType); + } + } else { + FFLog(@"I-RDB082009", @"Unrecognized raw server packet received: %@", + message); + } +} + +- (void)onDataMessage:(NSDictionary *)message { + // we don't do anything with data messages, just kick them up a level + FFLog(@"I-RDB082010", @"Got data message: %@", message); + [self.delegate onDataMessage:self withMessage:message]; +} + +- (void)onControl:(NSDictionary *)message { + FFLog(@"I-RDB082011", @"Got control message: %@", message); + NSString *type = [message objectForKey:kFWPAsyncServerControlMessageType]; + if ([type isEqualToString:kFWPAsyncServerControlMessageShutdown]) { + NSString *reason = + [message objectForKey:kFWPAsyncServerControlMessageData]; + [self onConnectionShutdownWithReason:reason]; + } else if ([type isEqualToString:kFWPAsyncServerControlMessageReset]) { + NSString *host = + [message objectForKey:kFWPAsyncServerControlMessageData]; + [self onReset:host]; + } else if ([type isEqualToString:kFWPAsyncServerHello]) { + NSDictionary *handshakeData = + [message objectForKey:kFWPAsyncServerControlMessageData]; + [self onHandshake:handshakeData]; + } else { + FFLog(@"I-RDB082012", + @"Unknown control message returned from server: %@", message); + } +} + +- (void)onConnectionShutdownWithReason:(NSString *)reason { + FFLog(@"I-RDB082013", + @"Connection shutdown command received. Shutting down..."); + + [self.delegate onKill:self withReason:reason]; + [self close]; +} + +- (void)onHandshake:(NSDictionary *)handshake { + NSNumber *timestamp = + [handshake objectForKey:kFWPAsyncServerHelloTimestamp]; + // NSString* version = [handshake + // objectForKey:kFWPAsyncServerHelloVersion]; + NSString *host = [handshake objectForKey:kFWPAsyncServerHelloConnectedHost]; + NSString *sessionID = [handshake objectForKey:kFWPAsyncServerHelloSession]; + + self.repoInfo.internalHost = host; + + if (state == REALTIME_STATE_CONNECTING) { + [self.conn start]; + [self onConnection:self.conn readyAtTime:timestamp sessionID:sessionID]; + } +} + +- (void)onConnection:(FWebSocketConnection *)conn + readyAtTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID { + FFLog(@"I-RDB082014", @"Realtime connection established"); + state = REALTIME_STATE_CONNECTED; + + [self.delegate onReady:self atTime:timestamp sessionID:sessionID]; +} + +- (void)onReset:(NSString *)host { + FFLog( + @"I-RDB082015", + @"Got a reset; killing connection to: %@; Updating internalHost to: %@", + repoInfo.internalHost, host); + self.repoInfo.internalHost = host; + + // Explicitly close the connection with SERVER_RESET so calling code knows + // to reconnect immediately. + [self closeWithReason:DISCONNECT_REASON_SERVER_RESET]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h new file mode 100644 index 0000000..6769718 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h @@ -0,0 +1,67 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#if !TARGET_OS_WATCH +#import "FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h" +#endif // !TARGET_OS_WATCH +#import + +@protocol FWebSocketDelegate; + +#if !TARGET_OS_WATCH +@interface FWebSocketConnection : NSObject +#else +@interface FWebSocketConnection : NSObject +#endif // else !TARGET_OS_WATCH + +@property(nonatomic, weak) id delegate; + +- (instancetype)initWith:(FRepoInfo *)repoInfo + andQueue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID + lastSessionID:(NSString *)lastSessionID + appCheckToken:(NSString *)appCheckToken; + +- (void)open; +- (void)close; +- (void)start; +- (void)send:(NSDictionary *)dictionary; + +// Ignore FSRWebSocketDelegate calls on watchOS. +#if !TARGET_OS_WATCH +- (void)webSocket:(FSRWebSocket *)webSocket didReceiveMessage:(id)message; + +// Exclude the `webSocket` argument since it isn't used in this codebase and it +// allows for better code sharing with watchOS. +- (void)webSocketDidOpen; +- (void)webSocket:(FSRWebSocket *)webSocket didFailWithError:(NSError *)error; +- (void)webSocket:(FSRWebSocket *)webSocket + didCloseWithCode:(NSInteger)code + reason:(NSString *)reason + wasClean:(BOOL)wasClean; +#endif // !TARGET_OS_WATCH + +@end + +@protocol FWebSocketDelegate + +- (void)onMessage:(FWebSocketConnection *)fwebSocket + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FWebSocketConnection *)fwebSocket + wasEverConnected:(BOOL)everConnected; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.m new file mode 100644 index 0000000..3b873c2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.m @@ -0,0 +1,504 @@ +/* + * 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. + */ + +// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual +// release build. + +#import + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_WATCH +#import +#import +#endif // TARGET_OS_WATCH + +static NSString *const kAppCheckTokenHeader = @"X-Firebase-AppCheck"; +static NSString *const kUserAgentHeader = @"User-Agent"; +static NSString *const kGoogleAppIDHeader = @"X-Firebase-GMPID"; + +@interface FWebSocketConnection () { + NSMutableString *frame; + BOOL everConnected; + BOOL isClosed; + NSTimer *keepAlive; +} + +- (void)shutdown; +- (void)onClosed; +- (void)closeIfNeverConnected; + +#if TARGET_OS_WATCH +@property(nonatomic, strong) NSURLSessionWebSocketTask *webSocketTask; +#else +@property(nonatomic, strong) FSRWebSocket *webSocket; +#endif // TARGET_OS_WATCH +@property(nonatomic, strong) NSNumber *connectionId; +@property(nonatomic, readwrite) int totalFrames; +@property(nonatomic, readonly) BOOL buffering; +@property(nonatomic, readonly) NSString *userAgent; +@property(nonatomic) dispatch_queue_t dispatchQueue; + +- (void)nop:(NSTimer *)timer; + +@end + +@implementation FWebSocketConnection + +@synthesize delegate; +#if !TARGET_OS_WATCH +@synthesize webSocket; +#endif // !TARGET_OS_WATCH +@synthesize connectionId; + +- (instancetype)initWith:(FRepoInfo *)repoInfo + andQueue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID + lastSessionID:(NSString *)lastSessionID + appCheckToken:(nullable NSString *)appCheckToken { + self = [super init]; + if (self) { + everConnected = NO; + isClosed = NO; + self.connectionId = [FUtilities LUIDGenerator]; + self.totalFrames = 0; + self.dispatchQueue = queue; + frame = nil; + + NSString *userAgent = [self userAgent]; + NSString *connectionURL = + [repoInfo connectionURLWithLastSessionID:lastSessionID]; + + FFLog(@"I-RDB083001", @"(wsc:%@) Connecting to: %@ as %@", + self.connectionId, connectionURL, userAgent); + + NSURLRequest *req = [[self class] createRequestWithURL:connectionURL + userAgent:userAgent + googleAppID:googleAppID + appCheckToken:appCheckToken]; +#if TARGET_OS_WATCH + // Regular NSURLSession websocket. + NSOperationQueue *opQueue = [[NSOperationQueue alloc] init]; + opQueue.underlyingQueue = queue; + NSURLSession *session = [NSURLSession + sessionWithConfiguration:[NSURLSessionConfiguration + defaultSessionConfiguration] + delegate:self + delegateQueue:opQueue]; + NSURLSessionWebSocketTask *task = + [session webSocketTaskWithRequest:req]; + self.webSocketTask = task; + + if (@available(watchOS 7.0, *)) { + [[NSNotificationCenter defaultCenter] + addObserverForName:WKApplicationWillResignActiveNotification + object:nil + queue:opQueue + usingBlock:^(NSNotification *_Nonnull note) { + FFLog(@"I-RDB083015", + @"Received watchOS background notification, " + @"closing web socket."); + [self onClosed]; + }]; + } +#else + // TODO(mmaksym): Remove googleAppID and userAgent from FSRWebSocket as + // they are passed via NSURLRequest. + self.webSocket = [[FSRWebSocket alloc] initWithURLRequest:req + queue:queue + googleAppID:googleAppID + andUserAgent:userAgent]; + [self.webSocket setDelegateDispatchQueue:queue]; + self.webSocket.delegate = self; +#endif // TARGET_OS_WATCH + } + return self; +} + +- (NSString *)userAgent { + NSString *systemVersion; + NSString *deviceName; + BOOL hasUiDeviceClass = NO; + +// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual +// release build. +#if TARGET_OS_IOS || TARGET_OS_TV + Class uiDeviceClass = NSClassFromString(@"UIDevice"); + if (uiDeviceClass) { + systemVersion = [uiDeviceClass currentDevice].systemVersion; + deviceName = [uiDeviceClass currentDevice].model; + hasUiDeviceClass = YES; + } +#endif // TARGET_OS_IOS || TARGET_OS_TV + + if (!hasUiDeviceClass) { + NSDictionary *systemVersionDictionary = [NSDictionary + dictionaryWithContentsOfFile: + @"/System/Library/CoreServices/SystemVersion.plist"]; + systemVersion = + [systemVersionDictionary objectForKey:@"ProductVersion"]; + deviceName = [systemVersionDictionary objectForKey:@"ProductName"]; + } + + NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + + // Sanitize '/'s in deviceName and bundleIdentifier for stats + deviceName = [FStringUtilities sanitizedForUserAgent:deviceName]; + bundleIdentifier = + [FStringUtilities sanitizedForUserAgent:bundleIdentifier]; + + // Firebase/5/__//{device model / + // os (Mac OS X, iPhone, etc.}_ + NSString *ua = [NSString + stringWithFormat:@"Firebase/%@/%@/%@/%@_%@", kWebsocketProtocolVersion, + [FIRDatabase buildVersion], systemVersion, deviceName, + bundleIdentifier]; + return ua; +} + +- (BOOL)buffering { + return frame != nil; +} + +#pragma mark - +#pragma mark Public FWebSocketConnection methods + +- (void)open { + FFLog(@"I-RDB083002", @"(wsc:%@) FWebSocketConnection open.", + self.connectionId); + assert(delegate); + everConnected = NO; + // TODO Assert url +#if TARGET_OS_WATCH + [self.webSocketTask resume]; + // We need to request data from the web socket in order for it to start + // sending data. + [self receiveWebSocketData]; +#else + [self.webSocket open]; +#endif // TARGET_OS_WATCH + dispatch_time_t when = dispatch_time( + DISPATCH_TIME_NOW, kWebsocketConnectTimeout * NSEC_PER_SEC); + dispatch_after(when, self.dispatchQueue, ^{ + [self closeIfNeverConnected]; + }); +} + +- (void)close { + FFLog(@"I-RDB083003", @"(wsc:%@) FWebSocketConnection is being closed.", + self.connectionId); + isClosed = YES; +#if TARGET_OS_WATCH + [self.webSocketTask + cancelWithCloseCode:NSURLSessionWebSocketCloseCodeNormalClosure + reason:nil]; +#else + [self.webSocket close]; +#endif // TARGET_OS_WATCH +} + +- (void)start { + // Start is a no-op for websockets. +} + +- (void)send:(NSDictionary *)dictionary { + + [self resetKeepAlive]; + + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary + options:kNilOptions + error:nil]; + + NSString *data = [[NSString alloc] initWithData:jsonData + encoding:NSUTF8StringEncoding]; + + NSArray *dataSegs = [FUtilities splitString:data + intoMaxSize:kWebsocketMaxFrameSize]; + + // First send the header so the server knows how many segments are + // forthcoming + if (dataSegs.count > 1) { + NSString *formattedData = + [NSString stringWithFormat:@"%u", (unsigned int)dataSegs.count]; + [self sendStringToWebSocket:formattedData]; + } + + // Then, actually send the segments. + for (NSString *segment in dataSegs) { + [self sendStringToWebSocket:segment]; + } +} + +- (void)nop:(NSTimer *)timer { + if (!isClosed) { + FFLog(@"I-RDB083004", @"(wsc:%@) nop", self.connectionId); + // Note: the backend is expecting a string "0" here, not any special + // ping/pong from build in websocket APIs. + [self sendStringToWebSocket:@"0"]; + } else { + FFLog(@"I-RDB083005", + @"(wsc:%@) No more websocket; invalidating nop timer.", + self.connectionId); + [timer invalidate]; + } +} + +- (void)handleNewFrameCount:(int)numFrames { + self.totalFrames = numFrames; + frame = [[NSMutableString alloc] initWithString:@""]; + FFLog(@"I-RDB083006", @"(wsc:%@) handleNewFrameCount: %d", + self.connectionId, self.totalFrames); +} + +- (NSString *)extractFrameCount:(NSString *)message { + if ([message length] <= 4) { + int frameCount = [message intValue]; + if (frameCount > 0) { + [self handleNewFrameCount:frameCount]; + return nil; + } + } + [self handleNewFrameCount:1]; + return message; +} + +- (void)appendFrame:(NSString *)message { + [frame appendString:message]; + self.totalFrames = self.totalFrames - 1; + + if (self.totalFrames == 0) { + // Call delegate and pass an immutable version of the frame + NSDictionary *json = [NSJSONSerialization + JSONObjectWithData:[frame dataUsingEncoding:NSUTF8StringEncoding] + options:kNilOptions + error:nil]; + frame = nil; + FFLog(@"I-RDB083007", + @"(wsc:%@) handleIncomingFrame sending complete frame: %d", + self.connectionId, self.totalFrames); + + @autoreleasepool { + [self.delegate onMessage:self withMessage:json]; + } + } +} + +- (void)handleIncomingFrame:(NSString *)message { + [self resetKeepAlive]; + if (self.buffering) { + [self appendFrame:message]; + } else { + NSString *remaining = [self extractFrameCount:message]; + if (remaining) { + [self appendFrame:remaining]; + } + } +} + +#pragma mark - +#pragma mark URLSessionWebSocketDelegate watchOS implementation +#if TARGET_OS_WATCH + +- (void)URLSession:(NSURLSession *)session + webSocketTask:(NSURLSessionWebSocketTask *)webSocketTask + didOpenWithProtocol:(NSString *)protocol { + [self webSocketDidOpen]; +} + +- (void)URLSession:(NSURLSession *)session + webSocketTask:(NSURLSessionWebSocketTask *)webSocketTask + didCloseWithCode:(NSURLSessionWebSocketCloseCode)closeCode + reason:(NSData *)reason { + FFLog(@"I-RDB083011", @"(wsc:%@) didCloseWithCode: %ld %@", + self.connectionId, (long)closeCode, reason); + [self onClosed]; +} + +- (void)receiveWebSocketData { + __weak __auto_type weakSelf = self; + [self.webSocketTask receiveMessageWithCompletionHandler:^( + NSURLSessionWebSocketMessage *_Nullable message, + NSError *_Nullable error) { + __auto_type strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + if (message) { + [strongSelf handleIncomingFrame:message.string]; + } else if (error && !strongSelf->isClosed) { + FFWarn(@"I-RDB083020", + @"Error received from web socket, closing the connection. %@", + error); + [strongSelf shutdown]; + return; + } + + [strongSelf receiveWebSocketData]; + }]; +} + +#else + +#pragma mark SRWebSocketDelegate implementation + +- (void)webSocket:(FSRWebSocket *)webSocket didReceiveMessage:(id)message { + [self handleIncomingFrame:message]; +} + +- (void)webSocket:(FSRWebSocket *)webSocket didFailWithError:(NSError *)error { + FFLog(@"I-RDB083010", @"(wsc:%@) didFailWithError didFailWithError: %@", + self.connectionId, [error description]); + [self onClosed]; +} + +- (void)webSocket:(FSRWebSocket *)webSocket + didCloseWithCode:(NSInteger)code + reason:(NSString *)reason + wasClean:(BOOL)wasClean { + FFLog(@"I-RDB083011", @"(wsc:%@) didCloseWithCode: %ld %@", + self.connectionId, (long)code, reason); + [self onClosed]; +} + +#endif // TARGET_OS_WATCH + +// Common to both SRWebSocketDelegate and URLSessionWebSocketDelegate. + +- (void)webSocketDidOpen { + FFLog(@"I-RDB083008", @"(wsc:%@) webSocketDidOpen", self.connectionId); + + everConnected = YES; + + dispatch_async(dispatch_get_main_queue(), ^{ + self->keepAlive = + [NSTimer scheduledTimerWithTimeInterval:kWebsocketKeepaliveInterval + target:self + selector:@selector(nop:) + userInfo:nil + repeats:YES]; + FFLog(@"I-RDB083009", @"(wsc:%@) nop timer kicked off", + self.connectionId); + }); +} + +#pragma mark - +#pragma mark Private methods + +/** Sends a string through the open web socket. */ +- (void)sendStringToWebSocket:(NSString *)string { +#if TARGET_OS_WATCH + // Use built-in URLSessionWebSocket functionality. + [self.webSocketTask sendMessage:[[NSURLSessionWebSocketMessage alloc] + initWithString:string] + completionHandler:^(NSError *_Nullable error) { + if (error) { + FFWarn(@"I-RDB083016", + @"Error sending web socket data: %@.", error); + return; + } + }]; +#else + // Use existing SocketRocket implementation. + [self.webSocket send:string]; +#endif // TARGET_OS_WATCH +} + +/** + * Note that the close / onClosed / shutdown cycle here is a little different + * from the javascript client. In order to properly handle deallocation, no + * close-related action is taken at a higher level until we have received + * notification from the websocket itself that it is closed. Otherwise, we end + * up deallocating this class and the FConnection class before the websocket has + * a change to call some of its delegate methods. So, since close is the + * external close handler, we just set a flag saying not to call our own + * delegate method and close the websocket. That will trigger a callback into + * this class that can then do things like clean up the keepalive timer. + */ + +- (void)closeIfNeverConnected { + if (!everConnected) { + FFLog(@"I-RDB083012", @"(wsc:%@) Websocket timed out on connect", + self.connectionId); +#if TARGET_OS_WATCH + [self.webSocketTask + cancelWithCloseCode:NSURLSessionWebSocketCloseCodeNoStatusReceived + reason:nil]; +#else + [self.webSocket close]; +#endif // TARGET_OS_WATCH + } +} + +- (void)shutdown { + isClosed = YES; + + // Call delegate methods + [self.delegate onDisconnect:self wasEverConnected:everConnected]; +} + +- (void)onClosed { + if (!isClosed) { + FFLog(@"I-RDB083013", @"Websocket is closing itself"); + [self shutdown]; + } +#if TARGET_OS_WATCH + self.webSocketTask = nil; +#else + self.webSocket = nil; +#endif // TARGET_OS_WATCH + if (keepAlive.isValid) { + [keepAlive invalidate]; + } +} + +- (void)resetKeepAlive { + NSDate *newTime = + [NSDate dateWithTimeIntervalSinceNow:kWebsocketKeepaliveInterval]; + // Calling setFireDate is actually kinda' expensive, so wait at least 5 + // seconds before updating it. + if ([newTime timeIntervalSinceDate:keepAlive.fireDate] > 5) { + FFLog(@"I-RDB083014", @"(wsc:%@) resetting keepalive, to %@ ; old: %@", + self.connectionId, newTime, [keepAlive fireDate]); + [keepAlive setFireDate:newTime]; + } +} + ++ (NSURLRequest *)createRequestWithURL:(NSString *)connectionURL + userAgent:(NSString *)userAgent + googleAppID:(NSString *)googleAppID + appCheckToken:(nullable NSString *)appCheckToken { + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] + initWithURL:[[NSURL alloc] initWithString:connectionURL]]; + + [request setValue:appCheckToken forHTTPHeaderField:kAppCheckTokenHeader]; + [request setValue:userAgent forHTTPHeaderField:kUserAgentHeader]; + [request setValue:googleAppID forHTTPHeaderField:kGoogleAppIDHeader]; + + return [request copy]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.h new file mode 100644 index 0000000..e597dcc --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.h @@ -0,0 +1,42 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" +#import + +@class FNamedNode; + +@interface FChildrenNode : NSObject + +- (id)initWithChildren:(FImmutableSortedDictionary *)someChildren; +- (id)initWithPriority:(id)aPriority + children:(FImmutableSortedDictionary *)someChildren; + +// FChildrenNode specific methods + +- (void)enumerateChildrenAndPriorityUsingBlock:(void (^)(NSString *, id, + BOOL *))block; + +- (FNamedNode *)firstChild; +- (FNamedNode *)lastChild; + +@property(nonatomic, strong) FImmutableSortedDictionary *children; +@property(nonatomic, strong) id priorityNode; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.m new file mode 100644 index 0000000..faa2e06 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.m @@ -0,0 +1,418 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/FPriorityIndex.h" +#import "FirebaseDatabase/Sources/FTransformedEnumerator.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FChildrenNode () +@property(nonatomic, strong) NSString *lazyHash; +@end + +@implementation FChildrenNode + +// Note: The only reason we allow nil priority is to for EmptyNode, since we +// can't use EmptyNode as the priority of EmptyNode. We might want to consider +// making EmptyNode its own class instead of an empty ChildrenNode. + +- (id)init { + return [self + initWithPriority:nil + children:[FImmutableSortedDictionary + dictionaryWithComparator:[FUtilities + keyComparator]]]; +} + +- (id)initWithChildren:(FImmutableSortedDictionary *)someChildren { + return [self initWithPriority:nil children:someChildren]; +} + +- (id)initWithPriority:(id)aPriority + children:(FImmutableSortedDictionary *)someChildren { + if (someChildren.isEmpty && aPriority != nil && ![aPriority isEmpty]) { + [NSException raise:NSInvalidArgumentException + format:@"Can't create empty node with priority!"]; + } + self = [super init]; + if (self) { + self.children = someChildren; + self.priorityNode = aPriority; + } + return self; +} + +- (NSString *)description { + return [[self valForExport:YES] description]; +} + +#pragma mark - +#pragma mark FNode methods + +- (BOOL)isLeafNode { + return NO; +} + +- (id)getPriority { + if (self.priorityNode) { + return self.priorityNode; + } else { + return [FEmptyNode emptyNode]; + } +} + +- (id)updatePriority:(id)aPriority { + if ([self.children isEmpty]) { + return [FEmptyNode emptyNode]; + } else { + return [[FChildrenNode alloc] initWithPriority:aPriority + children:self.children]; + } +} + +- (id)getImmediateChild:(NSString *)childName { + if ([childName isEqualToString:@".priority"]) { + return [self getPriority]; + } else { + id child = [self.children objectForKey:childName]; + return (child == nil) ? [FEmptyNode emptyNode] : child; + } +} + +- (id)getChild:(FPath *)path { + NSString *front = [path getFront]; + if (front == nil) { + return self; + } else { + return [[self getImmediateChild:front] getChild:[path popFront]]; + } +} + +- (BOOL)hasChild:(NSString *)childName { + return ![self getImmediateChild:childName].isEmpty; +} + +- (id)updateImmediateChild:(NSString *)childName + withNewChild:(id)newChildNode { + NSAssert(newChildNode != nil, @"Should always be passing nodes."); + + if ([childName isEqualToString:@".priority"]) { + return [self updatePriority:newChildNode]; + } else { + FImmutableSortedDictionary *newChildren; + if (newChildNode.isEmpty) { + newChildren = [self.children removeObjectForKey:childName]; + } else { + newChildren = [self.children setObject:newChildNode + forKey:childName]; + } + if (newChildren.isEmpty) { + return [FEmptyNode emptyNode]; + } else { + return [[FChildrenNode alloc] initWithPriority:self.getPriority + children:newChildren]; + } + } +} + +- (id)updateChild:(FPath *)path withNewChild:(id)newChildNode { + NSString *front = [path getFront]; + if (front == nil) { + return newChildNode; + } else { + NSAssert(![front isEqualToString:@".priority"] || path.length == 1, + @".priority must be the last token in a path."); + id newImmediateChild = + [[self getImmediateChild:front] updateChild:[path popFront] + withNewChild:newChildNode]; + return [self updateImmediateChild:front withNewChild:newImmediateChild]; + } +} + +- (BOOL)isEmpty { + return [self.children isEmpty]; +} + +- (int)numChildren { + return [self.children count]; +} + +- (id)val { + return [self valForExport:NO]; +} + +- (id)valForExport:(BOOL)exp { + if ([self isEmpty]) { + return [NSNull null]; + } + + __block int numKeys = 0; + __block NSInteger maxKey = 0; + __block BOOL allIntegerKeys = YES; + + NSMutableDictionary *obj = + [[NSMutableDictionary alloc] initWithCapacity:[self.children count]]; + [self enumerateChildrenUsingBlock:^(NSString *key, id childNode, + BOOL *stop) { + [obj setObject:[childNode valForExport:exp] forKey:key]; + + numKeys++; + + // If we already found a string key, don't bother with any of this + if (!allIntegerKeys) { + return; + } + + // Treat leading zeroes that are not exactly "0" as strings + NSString *firstChar = [key substringWithRange:NSMakeRange(0, 1)]; + if ([firstChar isEqualToString:@"0"] && [key length] > 1) { + allIntegerKeys = NO; + } else { + NSNumber *keyAsNum = [FUtilities intForString:key]; + if (keyAsNum != nil) { + NSInteger keyAsInt = [keyAsNum integerValue]; + if (keyAsInt > maxKey) { + maxKey = keyAsInt; + } + } else { + allIntegerKeys = NO; + } + } + }]; + + if (!exp && allIntegerKeys && maxKey < 2 * numKeys) { + // convert to an array + NSMutableArray *array = + [[NSMutableArray alloc] initWithCapacity:maxKey + 1]; + for (int i = 0; i <= maxKey; ++i) { + NSString *keyString = [NSString stringWithFormat:@"%i", i]; + id child = obj[keyString]; + if (child != nil) { + [array addObject:child]; + } else { + [array addObject:[NSNull null]]; + } + } + return array; + } else { + + if (exp && [self getPriority] != nil && !self.getPriority.isEmpty) { + obj[kPayloadPriority] = [self.getPriority val]; + } + + return obj; + } +} + +- (NSString *)dataHash { + if (self.lazyHash == nil) { + NSMutableString *toHash = [[NSMutableString alloc] init]; + + if (!self.getPriority.isEmpty) { + [toHash appendString:@"priority:"]; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:(FLeafNode *) + self.getPriority + toString:toHash + hashVersion:FDataHashVersionV1]; + [toHash appendString:@":"]; + } + + __block BOOL sawPriority = NO; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + sawPriority = sawPriority || [[node getPriority] isEmpty]; + *stop = sawPriority; + }]; + if (sawPriority) { + NSMutableArray *array = [NSMutableArray array]; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + FNamedNode *namedNode = [[FNamedNode alloc] initWithName:key + andNode:node]; + [array addObject:namedNode]; + }]; + [array sortUsingComparator:^NSComparisonResult( + FNamedNode *namedNode1, FNamedNode *namedNode2) { + return + [[FPriorityIndex priorityIndex] compareNamedNode:namedNode1 + toNamedNode:namedNode2]; + }]; + [array enumerateObjectsUsingBlock:^(FNamedNode *namedNode, + NSUInteger idx, BOOL *stop) { + NSString *childHash = [namedNode.node dataHash]; + if (![childHash isEqualToString:@""]) { + [toHash appendFormat:@":%@:%@", namedNode.name, childHash]; + } + }]; + } else { + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + NSString *childHash = [node dataHash]; + if (![childHash isEqualToString:@""]) { + [toHash appendFormat:@":%@:%@", key, childHash]; + } + }]; + } + self.lazyHash = [toHash isEqualToString:@""] + ? @"" + : [FStringUtilities base64EncodedSha1:toHash]; + } + return self.lazyHash; +} + +- (NSComparisonResult)compare:(id)other { + // children nodes come last, unless this is actually an empty node, then we + // come first. + if (self.isEmpty) { + if (other.isEmpty) { + return NSOrderedSame; + } else { + return NSOrderedAscending; + } + } else if (other.isLeafNode || other.isEmpty) { + return NSOrderedDescending; + } else if (other == [FMaxNode maxNode]) { + return NSOrderedAscending; + } else { + // Must be another node with children. + return NSOrderedSame; + } +} + +- (BOOL)isEqual:(id)other { + if (other == self) { + return YES; + } else if (other == nil) { + return NO; + } else if (other.isLeafNode) { + return NO; + } else if (self.isEmpty && [other isEmpty]) { + // Empty nodes do not have priority + return YES; + } else { + FChildrenNode *otherChildrenNode = other; + if (![self.getPriority isEqual:other.getPriority]) { + return NO; + } else if (self.children.count == otherChildrenNode.children.count) { + __block BOOL equal = YES; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + id child = [otherChildrenNode getImmediateChild:key]; + if (![child isEqual:node]) { + equal = NO; + *stop = YES; + } + }]; + return equal; + } else { + return NO; + } + } +} + +- (NSUInteger)hash { + __block NSUInteger hashCode = 0; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + hashCode = 31 * hashCode + key.hash; + hashCode = 17 * hashCode + node.hash; + }]; + return 17 * hashCode + self.priorityNode.hash; +} + +- (void)enumerateChildrenAndPriorityUsingBlock:(void (^)(NSString *, id, + BOOL *))block { + if ([self.getPriority isEmpty]) { + [self enumerateChildrenUsingBlock:block]; + } else { + __block BOOL passedPriorityKey = NO; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + if (!passedPriorityKey && + [FUtilities compareKey:key + toKey:@".priority"] == NSOrderedDescending) { + passedPriorityKey = YES; + BOOL stopAfterPriority = NO; + block(@".priority", [self getPriority], &stopAfterPriority); + if (stopAfterPriority) + return; + } + block(key, node, stop); + }]; + } +} + +- (void)enumerateChildrenUsingBlock:(void (^)(NSString *, id, + BOOL *))block { + [self.children enumerateKeysAndObjectsUsingBlock:block]; +} + +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock: + (void (^)(NSString *, id, BOOL *))block { + [self.children enumerateKeysAndObjectsReverse:reverse usingBlock:block]; +} + +- (NSEnumerator *)childEnumerator { + return [[FTransformedEnumerator alloc] + initWithEnumerator:self.children.keyEnumerator + andTransform:^id(NSString *key) { + return [FNamedNode nodeWithName:key + node:[self getImmediateChild:key]]; + }]; +} + +- (NSString *)predecessorChildKey:(NSString *)childKey { + return [self.children getPredecessorKey:childKey]; +} + +#pragma mark - +#pragma mark FChildrenNode specific methods + +- (id)childrenGetter:(id)key { + return [self.children objectForKey:key]; +} + +- (FNamedNode *)firstChild { + NSString *childKey = self.children.minKey; + if (childKey) { + return + [[FNamedNode alloc] initWithName:childKey + andNode:[self getImmediateChild:childKey]]; + } else { + return nil; + } +} + +- (FNamedNode *)lastChild { + NSString *childKey = self.children.maxKey; + if (childKey) { + return + [[FNamedNode alloc] initWithName:childKey + andNode:[self getImmediateChild:childKey]]; + } else { + return nil; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h new file mode 100644 index 0000000..47de66f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h @@ -0,0 +1,64 @@ +/* + * 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 + +@class FImmutableTree; +@protocol FNode; +@class FPath; + +/** + * This class holds a collection of writes that can be applied to nodes in + * unison. It abstracts away the logic with dealing with priority writes and + * multiple nested writes. At any given path, there is only allowed to be one + * write modifying that path. Any write to an existing path or shadowing an + * existing path will modify that existing write to reflect the write added. + */ +@interface FCompoundWrite : NSObject + +- (id)initWithWriteTree:(FImmutableTree *)tree; + +/** + * Creates a compound write with NSDictionary from path string to object + */ ++ (FCompoundWrite *)compoundWriteWithValueDictionary:(NSDictionary *)dictionary; +/** + * Creates a compound write with NSDictionary from path string to node + */ ++ (FCompoundWrite *)compoundWriteWithNodeDictionary:(NSDictionary *)dictionary; + ++ (FCompoundWrite *)emptyWrite; + +- (FCompoundWrite *)addWrite:(id)node atPath:(FPath *)path; +- (FCompoundWrite *)addWrite:(id)node atKey:(NSString *)key; +- (FCompoundWrite *)addCompoundWrite:(FCompoundWrite *)node + atPath:(FPath *)path; +- (FCompoundWrite *)removeWriteAtPath:(FPath *)path; +- (id)rootWrite; +- (BOOL)hasCompleteWriteAtPath:(FPath *)path; +- (id)completeNodeAtPath:(FPath *)path; +- (NSArray *)completeChildren; +- (NSDictionary *)childCompoundWrites; +- (FCompoundWrite *)childCompoundWriteAtPath:(FPath *)path; +- (id)applyToNode:(id)node; +- (void)enumerateWrites:(void (^)(FPath *path, id node, + BOOL *stop))block; + +- (NSDictionary *)valForExport:(BOOL)exportFormat; + +- (BOOL)isEmpty; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.m new file mode 100644 index 0000000..a7c1b2a --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.m @@ -0,0 +1,304 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" + +@interface FCompoundWrite () +@property(nonatomic, strong) FImmutableTree *writeTree; +@end + +@implementation FCompoundWrite + +- (id)initWithWriteTree:(FImmutableTree *)tree { + self = [super init]; + if (self) { + self.writeTree = tree; + } + return self; +} + ++ (FCompoundWrite *)compoundWriteWithValueDictionary: + (NSDictionary *)dictionary { + __block FImmutableTree *writeTree = [FImmutableTree empty]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *pathString, + id value, BOOL *stop) { + id node = [FSnapshotUtilities nodeFrom:value]; + FImmutableTree *tree = [[FImmutableTree alloc] initWithValue:node]; + writeTree = [writeTree setTree:tree + atPath:[[FPath alloc] initWith:pathString]]; + }]; + return [[FCompoundWrite alloc] initWithWriteTree:writeTree]; +} + ++ (FCompoundWrite *)compoundWriteWithNodeDictionary:(NSDictionary *)dictionary { + __block FImmutableTree *writeTree = [FImmutableTree empty]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *pathString, + id node, BOOL *stop) { + FImmutableTree *tree = [[FImmutableTree alloc] initWithValue:node]; + writeTree = [writeTree setTree:tree + atPath:[[FPath alloc] initWith:pathString]]; + }]; + return [[FCompoundWrite alloc] initWithWriteTree:writeTree]; +} + ++ (FCompoundWrite *)emptyWrite { + static dispatch_once_t pred = 0; + static FCompoundWrite *empty = nil; + dispatch_once(&pred, ^{ + empty = [[FCompoundWrite alloc] + initWithWriteTree:[[FImmutableTree alloc] initWithValue:nil]]; + }); + return empty; +} + +- (FCompoundWrite *)addWrite:(id)node atPath:(FPath *)path { + if (path.isEmpty) { + return [[FCompoundWrite alloc] + initWithWriteTree:[[FImmutableTree alloc] initWithValue:node]]; + } else { + FTuplePathValue *rootMost = + [self.writeTree findRootMostValueAndPath:path]; + if (rootMost != nil) { + FPath *relativePath = [FPath relativePathFrom:rootMost.path + to:path]; + id value = [rootMost.value updateChild:relativePath + withNewChild:node]; + return [[FCompoundWrite alloc] + initWithWriteTree:[self.writeTree setValue:value + atPath:rootMost.path]]; + } else { + FImmutableTree *subtree = + [[FImmutableTree alloc] initWithValue:node]; + FImmutableTree *newWriteTree = [self.writeTree setTree:subtree + atPath:path]; + return [[FCompoundWrite alloc] initWithWriteTree:newWriteTree]; + } + } +} + +- (FCompoundWrite *)addWrite:(id)node atKey:(NSString *)key { + return [self addWrite:node atPath:[[FPath alloc] initWith:key]]; +} + +- (FCompoundWrite *)addCompoundWrite:(FCompoundWrite *)compoundWrite + atPath:(FPath *)path { + __block FCompoundWrite *newWrite = self; + [compoundWrite.writeTree forEach:^(FPath *childPath, id value) { + newWrite = [newWrite addWrite:value atPath:[path child:childPath]]; + }]; + return newWrite; +} + +/** + * Will remove a write at the given path and deeper paths. This will + * not modify a write at a higher location, which must be removed by + * calling this method with that path. + * @param path The path at which a write and all deeper writes should be + * removed. + * @return The new FWriteCompound with the removed path. + */ +- (FCompoundWrite *)removeWriteAtPath:(FPath *)path { + if (path.isEmpty) { + return [FCompoundWrite emptyWrite]; + } else { + FImmutableTree *newWriteTree = + [self.writeTree setTree:[FImmutableTree empty] atPath:path]; + return [[FCompoundWrite alloc] initWithWriteTree:newWriteTree]; + } +} + +/** + * Returns whether this FCompoundWrite will fully overwrite a node at a given + * location and can therefore be considered "complete". + * @param path The path to check for + * @return Whether there is a complete write at that path. + */ +- (BOOL)hasCompleteWriteAtPath:(FPath *)path { + return [self completeNodeAtPath:path] != nil; +} + +/** + * Returns a node for a path if and only if the node is a "complete" overwrite + * at that path. This will not aggregate writes from depeer paths, but will + * return child nodes from a more shallow path. + * @param path The path to get a complete write + * @return The node if complete at that path, or nil otherwise. + */ +- (id)completeNodeAtPath:(FPath *)path { + FTuplePathValue *rootMost = [self.writeTree findRootMostValueAndPath:path]; + if (rootMost != nil) { + FPath *relativePath = [FPath relativePathFrom:rootMost.path to:path]; + return [rootMost.value getChild:relativePath]; + } else { + return nil; + } +} + +// TODO: change into traversal method... +- (NSArray *)completeChildren { + NSMutableArray *children = [[NSMutableArray alloc] init]; + if (self.writeTree.value != nil) { + id node = self.writeTree.value; + [node enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + [children addObject:[[FNamedNode alloc] initWithName:key + andNode:node]]; + }]; + } else { + [self.writeTree.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if (childTree.value != nil) { + [children addObject:[[FNamedNode alloc] + initWithName:childKey + andNode:childTree.value]]; + } + }]; + } + return children; +} + +// TODO: change into enumarate method +- (NSDictionary *)childCompoundWrites { + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + [self.writeTree.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *key, FImmutableTree *childWrite, BOOL *stop) { + dict[key] = [[FCompoundWrite alloc] initWithWriteTree:childWrite]; + }]; + return dict; +} + +- (FCompoundWrite *)childCompoundWriteAtPath:(FPath *)path { + if (path.isEmpty) { + return self; + } else { + id shadowingNode = [self completeNodeAtPath:path]; + if (shadowingNode != nil) { + return [[FCompoundWrite alloc] + initWithWriteTree:[[FImmutableTree alloc] + initWithValue:shadowingNode]]; + } else { + return [[FCompoundWrite alloc] + initWithWriteTree:[self.writeTree subtreeAtPath:path]]; + } + } +} + +- (id)applySubtreeWrite:(FImmutableTree *)subtreeWrite + atPath:(FPath *)relativePath + toNode:(id)node { + if (subtreeWrite.value != nil) { + // Since a write there is always a leaf, we're done here. + return [node updateChild:relativePath withNewChild:subtreeWrite.value]; + } else { + __block id priorityWrite = nil; + __block id blockNode = node; + [subtreeWrite.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if ([childKey isEqualToString:@".priority"]) { + // Apply priorities at the end so we don't update priorities + // for either empty nodes or forget to apply priorities to + // empty nodes that are later filled. + NSAssert(childTree.value != nil, + @"Priority writes must always be leaf nodes"); + priorityWrite = childTree.value; + } else { + blockNode = [self + applySubtreeWrite:childTree + atPath:[relativePath childFromString:childKey] + toNode:blockNode]; + } + }]; + // If there was a priority write, we only apply it if the node is not + // empty + if (![blockNode getChild:relativePath].isEmpty && + priorityWrite != nil) { + blockNode = [blockNode + updateChild:[relativePath childFromString:@".priority"] + withNewChild:priorityWrite]; + } + return blockNode; + } +} + +- (void)enumerateWrites:(void (^)(FPath *, id, BOOL *))block { + __block BOOL stop = NO; + // TODO: add stop to tree iterator... + [self.writeTree forEach:^(FPath *path, id value) { + if (!stop) { + block(path, value, &stop); + } + }]; +} + +/** + * Applies this FCompoundWrite to a node. The node is returned with all writes + * from this FCompoundWrite applied to the node. + * @param node The node to apply this FCompoundWrite to + * @return The node with all writes applied + */ +- (id)applyToNode:(id)node { + return [self applySubtreeWrite:self.writeTree + atPath:[FPath empty] + toNode:node]; +} + +/** + * Return true if this CompoundWrite is empty and therefore does not modify any + * nodes. + * @return Whether this CompoundWrite is empty + */ +- (BOOL)isEmpty { + return self.writeTree.isEmpty; +} + +- (id)rootWrite { + return self.writeTree.value; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[FCompoundWrite class]]) { + return NO; + } + FCompoundWrite *other = (FCompoundWrite *)object; + return + [[self valForExport:YES] isEqualToDictionary:[other valForExport:YES]]; +} + +- (NSUInteger)hash { + return [[self valForExport:YES] hash]; +} + +- (NSDictionary *)valForExport:(BOOL)exportFormat { + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + [self.writeTree forEach:^(FPath *path, id value) { + dictionary[path.wireFormat] = [value valForExport:exportFormat]; + }]; + return dictionary; +} + +- (NSString *)description { + return [[self valForExport:YES] description]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.h new file mode 100644 index 0000000..aa67983 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FEmptyNode : NSObject + ++ (id)emptyNode; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.m new file mode 100644 index 0000000..2f9283e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.m @@ -0,0 +1,30 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" + +@implementation FEmptyNode + ++ (id)emptyNode { + static FChildrenNode *empty = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + empty = [[FChildrenNode alloc] init]; + }); + return empty; +} +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.h new file mode 100644 index 0000000..4434855 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.h @@ -0,0 +1,55 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +/** + * Represents a node together with an index. The index and node are updated in + * unison. In the case where the index does not affect the ordering (i.e. the + * ordering is identical to the key ordering) this class uses a fallback index + * to save memory. Everything operating on the index must special case the + * fallback index. + */ +@interface FIndexedNode : NSObject + +@property(nonatomic, strong, readonly) id node; + ++ (FIndexedNode *)indexedNodeWithNode:(id)node; ++ (FIndexedNode *)indexedNodeWithNode:(id)node index:(id)index; + +- (BOOL)hasIndex:(id)index; +- (FIndexedNode *)updateChild:(NSString *)key + withNewChild:(id)newChildNode; +- (FIndexedNode *)updatePriority:(id)priority; + +- (FNamedNode *)firstChild; +- (FNamedNode *)lastChild; + +- (NSString *)predecessorForChildKey:(NSString *)childKey + childNode:(id)childNode + index:(id)index; + +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock:(void (^)(NSString *key, id node, + BOOL *stop))block; + +- (NSEnumerator *)childEnumerator; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.m new file mode 100644 index 0000000..4f36e67 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.m @@ -0,0 +1,218 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" + +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/FPriorityIndex.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h" + +static FImmutableSortedSet *FALLBACK_INDEX; + +@interface FIndexedNode () + +@property(nonatomic, strong) id node; +/** + * The indexed set is initialized lazily to prevent creation when it is not + * needed + */ +@property(nonatomic, strong) FImmutableSortedSet *indexed; +@property(nonatomic, strong) id index; + +@end + +@implementation FIndexedNode + ++ (FImmutableSortedSet *)fallbackIndex { + static FImmutableSortedSet *fallbackIndex; + static dispatch_once_t once; + dispatch_once(&once, ^{ + fallbackIndex = [[FImmutableSortedSet alloc] init]; + }); + return fallbackIndex; +} + ++ (FIndexedNode *)indexedNodeWithNode:(id)node { + return [[FIndexedNode alloc] initWithNode:node + index:[FPriorityIndex priorityIndex]]; +} + ++ (FIndexedNode *)indexedNodeWithNode:(id)node index:(id)index { + return [[FIndexedNode alloc] initWithNode:node index:index]; +} + +- (id)initWithNode:(id)node index:(id)index { + // Initialize indexed lazily + return [self initWithNode:node index:index indexed:nil]; +} + +- (id)initWithNode:(id)node + index:(id)index + indexed:(FImmutableSortedSet *)indexed { + self = [super init]; + if (self != nil) { + self->_node = node; + self->_index = index; + self->_indexed = indexed; + } + return self; +} + +- (void)ensureIndexed { + if (!self.indexed) { + if ([self.index isEqual:[FKeyIndex keyIndex]]) { + self.indexed = [FIndexedNode fallbackIndex]; + } else { + __block BOOL sawChild = NO; + [self.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + sawChild = sawChild || [self.index isDefinedOn:node]; + *stop = sawChild; + }]; + if (sawChild) { + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + [self.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + FNamedNode *namedNode = + [[FNamedNode alloc] initWithName:key andNode:node]; + dict[namedNode] = [NSNull null]; + }]; + // Make sure to assign index here, because the comparator will + // be retained and using self will cause a cycle + id index = self.index; + self.indexed = [FImmutableSortedSet + setWithKeysFromDictionary:dict + comparator:^NSComparisonResult( + FNamedNode *namedNode1, + FNamedNode *namedNode2) { + return [index compareNamedNode:namedNode1 + toNamedNode:namedNode2]; + }]; + } else { + self.indexed = [FIndexedNode fallbackIndex]; + } + } + } +} + +- (BOOL)hasIndex:(id)index { + return [self.index isEqual:index]; +} + +- (FIndexedNode *)updateChild:(NSString *)key + withNewChild:(id)newChildNode { + id newNode = [self.node updateImmediateChild:key + withNewChild:newChildNode]; + if (self.indexed == [FIndexedNode fallbackIndex] && + ![self.index isDefinedOn:newChildNode]) { + // doesn't affect the index, no need to create an index + return [[FIndexedNode alloc] initWithNode:newNode + index:self.index + indexed:[FIndexedNode fallbackIndex]]; + } else if (!self.indexed || self.indexed == [FIndexedNode fallbackIndex]) { + // No need to index yet, index lazily + return [[FIndexedNode alloc] initWithNode:newNode index:self.index]; + } else { + id oldChild = [self.node getImmediateChild:key]; + FImmutableSortedSet *newIndexed = [self.indexed + removeObject:[FNamedNode nodeWithName:key node:oldChild]]; + if (![newChildNode isEmpty]) { + newIndexed = [newIndexed + addObject:[FNamedNode nodeWithName:key node:newChildNode]]; + } + return [[FIndexedNode alloc] initWithNode:newNode + index:self.index + indexed:newIndexed]; + } +} + +- (FIndexedNode *)updatePriority:(id)priority { + return + [[FIndexedNode alloc] initWithNode:[self.node updatePriority:priority] + index:self.index + indexed:self.indexed]; +} + +- (FNamedNode *)firstChild { + if (![self.node isKindOfClass:[FChildrenNode class]]) { + return nil; + } else { + [self ensureIndexed]; + if (self.indexed == [FIndexedNode fallbackIndex]) { + return [((FChildrenNode *)self.node) firstChild]; + } else { + return self.indexed.firstObject; + } + } +} + +- (FNamedNode *)lastChild { + if (![self.node isKindOfClass:[FChildrenNode class]]) { + return nil; + } else { + [self ensureIndexed]; + if (self.indexed == [FIndexedNode fallbackIndex]) { + return [((FChildrenNode *)self.node) lastChild]; + } else { + return self.indexed.lastObject; + } + } +} + +- (NSString *)predecessorForChildKey:(NSString *)childKey + childNode:(id)childNode + index:(id)index { + if (![self.index isEqual:index]) { + [NSException raise:NSInvalidArgumentException + format:@"Index not available in IndexedNode!"]; + } + [self ensureIndexed]; + if (self.indexed == [FIndexedNode fallbackIndex]) { + return [self.node predecessorChildKey:childKey]; + } else { + FNamedNode *node = [self.indexed + predecessorEntry:[FNamedNode nodeWithName:childKey node:childNode]]; + return node.name; + } +} + +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock: + (void (^)(NSString *, id, BOOL *))block { + [self ensureIndexed]; + if (self.indexed == [FIndexedNode fallbackIndex]) { + [self.node enumerateChildrenReverse:reverse usingBlock:block]; + } else { + [self.indexed + enumerateObjectsReverse:reverse + usingBlock:^(FNamedNode *namedNode, BOOL *stop) { + block(namedNode.name, namedNode.node, stop); + }]; + } +} + +- (NSEnumerator *)childEnumerator { + [self ensureIndexed]; + if (self.indexed == [FIndexedNode fallbackIndex]) { + return [self.node childEnumerator]; + } else { + return [self.indexed objectEnumerator]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.h new file mode 100644 index 0000000..07277ba --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FLeafNode : NSObject + +- (id)initWithValue:(id)aValue; +- (id)initWithValue:(id)aValue withPriority:(id)aPriority; + +@property(nonatomic, strong) id value; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.m new file mode 100644 index 0000000..189cb31 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.m @@ -0,0 +1,266 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" + +@interface FLeafNode () +@property(nonatomic, strong) id priorityNode; +@property(nonatomic, strong) NSString *lazyHash; + +@end + +@implementation FLeafNode + +@synthesize value; +@synthesize priorityNode; + +- (id)initWithValue:(id)aValue { + self = [super init]; + if (self) { + self.value = aValue; + self.priorityNode = [FEmptyNode emptyNode]; + } + return self; +} + +- (id)initWithValue:(id)aValue withPriority:(id)aPriority { + self = [super init]; + if (self) { + self.value = aValue; + [FSnapshotUtilities validatePriorityNode:aPriority]; + self.priorityNode = aPriority; + } + return self; +} + +#pragma mark - +#pragma mark FNode methods + +- (BOOL)isLeafNode { + return YES; +} + +- (id)getPriority { + return self.priorityNode; +} + +- (id)updatePriority:(id)aPriority { + return [[FLeafNode alloc] initWithValue:self.value withPriority:aPriority]; +} + +- (id)getImmediateChild:(NSString *)childName { + if ([childName isEqualToString:@".priority"]) { + return self.priorityNode; + } else { + return [FEmptyNode emptyNode]; + } +} + +- (id)getChild:(FPath *)path { + if (path.getFront == nil) { + return self; + } else if ([[path getFront] isEqualToString:@".priority"]) { + return [self getPriority]; + } else { + return [FEmptyNode emptyNode]; + } +} + +- (BOOL)hasChild:(NSString *)childName { + return + [childName isEqualToString:@".priority"] && ![self getPriority].isEmpty; +} + +- (NSString *)predecessorChildKey:(NSString *)childKey { + return nil; +} + +- (id)updateImmediateChild:(NSString *)childName + withNewChild:(id)newChildNode { + if ([childName isEqualToString:@".priority"]) { + return [self updatePriority:newChildNode]; + } else if (newChildNode.isEmpty) { + return self; + } else { + FChildrenNode *childrenNode = [[FChildrenNode alloc] init]; + childrenNode = [childrenNode updateImmediateChild:childName + withNewChild:newChildNode]; + childrenNode = [childrenNode updatePriority:self.priorityNode]; + return childrenNode; + } +} + +- (id)updateChild:(FPath *)path withNewChild:(id)newChildNode { + NSString *front = [path getFront]; + if (front == nil) { + return newChildNode; + } else if (newChildNode.isEmpty && ![front isEqualToString:@".priority"]) { + return self; + } else { + NSAssert(![front isEqualToString:@".priority"] || path.length == 1, + @".priority must be the last token in a path."); + return [self updateImmediateChild:front + withNewChild:[[FEmptyNode emptyNode] + updateChild:[path popFront] + withNewChild:newChildNode]]; + } +} + +- (id)val { + return [self valForExport:NO]; +} + +- (id)valForExport:(BOOL)exp { + if (exp && !self.getPriority.isEmpty) { + return @{ + kPayloadValue : self.value, + kPayloadPriority : [[self getPriority] val] + }; + } else { + return self.value; + } +} + +- (BOOL)isEqual:(id)other { + if (other == self) { + return YES; + } else if (other.isLeafNode) { + FLeafNode *otherLeaf = other; + if ([FUtilities getJavascriptType:self.value] != + [FUtilities getJavascriptType:otherLeaf.value]) { + return NO; + } + return [otherLeaf.value isEqual:self.value] && + [otherLeaf.priorityNode isEqual:self.priorityNode]; + } else { + return NO; + } +} + +- (NSUInteger)hash { + return [self.value hash] * 17 + self.priorityNode.hash; +} + +- (id)withIndex:(id)index { + return self; +} + +- (BOOL)isIndexed:(id)index { + return YES; +} + +- (BOOL)isEmpty { + return NO; +} + +- (int)numChildren { + return 0; +} + +- (void)enumerateChildrenUsingBlock:(void (^)(NSString *, id, + BOOL *))block { + // Nothing to iterate over +} + +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock: + (void (^)(NSString *, id, BOOL *))block { + // Nothing to iterate over +} + +- (NSEnumerator *)childEnumerator { + // Nothing to iterate over + return [@[] objectEnumerator]; +} + +- (NSString *)dataHash { + if (self.lazyHash == nil) { + NSMutableString *toHash = [[NSMutableString alloc] init]; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:self + toString:toHash + hashVersion:FDataHashVersionV1]; + + self.lazyHash = [FStringUtilities base64EncodedSha1:toHash]; + } + return self.lazyHash; +} + +- (NSComparisonResult)compare:(id)other { + if (other == [FEmptyNode emptyNode]) { + return NSOrderedDescending; + } else if ([other isKindOfClass:[FChildrenNode class]]) { + return NSOrderedAscending; + } else { + NSAssert(other.isLeafNode, @"Compared against unknown type of node."); + return [self compareToLeafNode:(FLeafNode *)other]; + } +} + ++ (NSArray *)valueTypeOrder { + static NSArray *valueOrder = nil; + static dispatch_once_t once; + dispatch_once(&once, ^{ + valueOrder = @[ + kJavaScriptObject, kJavaScriptBoolean, kJavaScriptNumber, + kJavaScriptString + ]; + }); + return valueOrder; +} + +- (NSComparisonResult)compareToLeafNode:(FLeafNode *)other { + NSString *thisLeafType = [FUtilities getJavascriptType:self.value]; + NSString *otherLeafType = [FUtilities getJavascriptType:other.value]; + NSUInteger thisIndex = + [[FLeafNode valueTypeOrder] indexOfObject:thisLeafType]; + NSUInteger otherIndex = + [[FLeafNode valueTypeOrder] indexOfObject:otherLeafType]; + assert(thisIndex >= 0 && otherIndex >= 0); + if (otherIndex == thisIndex) { + // Same type. Compare values. + if (thisLeafType == kJavaScriptObject) { + // Deferred value nodes are all equal, but we should also never get + // to this point... + return NSOrderedSame; + } else if (thisLeafType == kJavaScriptString) { + return [self.value compare:other.value options:NSLiteralSearch]; + } else { + return [self.value compare:other.value]; + } + } else { + return thisIndex > otherIndex ? NSOrderedDescending + : NSOrderedAscending; + } +} + +- (NSString *)description { + return [[self valForExport:YES] description]; +} + +- (void)forEachChildDo:(fbt_bool_nsstring_node)action { + // There are no children, so there is nothing to do. + return; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FNode.h new file mode 100644 index 0000000..eff1986 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FNode.h @@ -0,0 +1,50 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import + +@protocol FIndex; + +@protocol FNode + +- (BOOL)isLeafNode; +- (id)getPriority; +- (id)updatePriority:(id)priority; +- (id)getImmediateChild:(NSString *)childKey; +- (id)getChild:(FPath *)path; +- (NSString *)predecessorChildKey:(NSString *)childKey; +- (id)updateImmediateChild:(NSString *)childKey + withNewChild:(id)newChildNode; +- (id)updateChild:(FPath *)path withNewChild:(id)newChildNode; +- (BOOL)hasChild:(NSString *)childKey; +- (BOOL)isEmpty; +- (int)numChildren; +- (id)val; +- (id)valForExport:(BOOL)exp; +- (NSString *)dataHash; +- (NSComparisonResult)compare:(id)other; +- (BOOL)isEqual:(id)other; +- (void)enumerateChildrenUsingBlock:(void (^)(NSString *key, id node, + BOOL *stop))block; +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock:(void (^)(NSString *key, id node, + BOOL *stop))block; + +- (NSEnumerator *)childEnumerator; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h new file mode 100644 index 0000000..92c25e6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h @@ -0,0 +1,49 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@class FImmutableSortedDictionary; +@class FCompoundWrite; +@class FLeafNode; +@protocol FNode; + +typedef NS_ENUM(NSInteger, FDataHashVersion) { + FDataHashVersionV1, + FDataHashVersionV2, +}; + +@interface FSnapshotUtilities : NSObject + ++ (id)nodeFrom:(id)val; ++ (id)nodeFrom:(id)val priority:(id)priority; ++ (id)nodeFrom:(id)val withValidationFrom:(NSString *)fn; ++ (id)nodeFrom:(id)val + priority:(id)priority + withValidationFrom:(NSString *)fn; ++ (FCompoundWrite *)compoundWriteFromDictionary:(NSDictionary *)values + withValidationFrom:(NSString *)fn; ++ (void)validatePriorityNode:(id)priorityNode; ++ (void)appendHashRepresentationForLeafNode:(FLeafNode *)val + toString:(NSMutableString *)string + hashVersion:(FDataHashVersion)hashVersion; ++ (void)appendHashV2RepresentationForString:(NSString *)string + toString:(NSMutableString *)mutableString; + ++ (NSUInteger)estimateSerializedNodeSize:(id)node; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.m new file mode 100644 index 0000000..68754c8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.m @@ -0,0 +1,394 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h" + +@implementation FSnapshotUtilities + ++ (id)nodeFrom:(id)val { + return [FSnapshotUtilities nodeFrom:val priority:nil]; +} + ++ (id)nodeFrom:(id)val priority:(id)priority { + return [FSnapshotUtilities nodeFrom:val + priority:priority + withValidationFrom:@"nodeFrom:priority:"]; +} + ++ (id)nodeFrom:(id)val withValidationFrom:(NSString *)fn { + return [FSnapshotUtilities nodeFrom:val priority:nil withValidationFrom:fn]; +} + ++ (id)nodeFrom:(id)val + priority:(id)priority + withValidationFrom:(NSString *)fn { + return [FSnapshotUtilities nodeFrom:val + priority:priority + withValidationFrom:fn + atDepth:0 + path:[[NSMutableArray alloc] init]]; +} + ++ (id)nodeFrom:(id)val + priority:(id)aPriority + withValidationFrom:(NSString *)fn + atDepth:(int)depth + path:(NSMutableArray *)path { + @autoreleasepool { + return [FSnapshotUtilities internalNodeFrom:val + priority:aPriority + withValidationFrom:fn + atDepth:depth + path:path]; + } +} + ++ (id)internalNodeFrom:(id)val + priority:(id)aPriority + withValidationFrom:(NSString *)fn + atDepth:(int)depth + path:(NSMutableArray *)path { + + if (depth > kFirebaseMaxObjectDepth) { + NSRange range; + range.location = 0; + range.length = 100; + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Max object depth exceeded: %@...", + fn, pathString] + userInfo:nil]; + } + + if (val == nil || val == [NSNull null]) { + // Null is a valid type to store + return [FEmptyNode emptyNode]; + } + + [FValidation validateFrom:fn isValidPriorityValue:aPriority withPath:path]; + id priority = [FSnapshotUtilities nodeFrom:aPriority]; + + id value = val; + BOOL isLeafNode = NO; + + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dict = val; + if (dict[kPayloadPriority] != nil) { + id rawPriority = [dict objectForKey:kPayloadPriority]; + [FValidation validateFrom:fn + isValidPriorityValue:rawPriority + withPath:path]; + priority = [FSnapshotUtilities nodeFrom:rawPriority]; + } + + if (dict[kPayloadValue] != nil) { + value = [dict objectForKey:kPayloadValue]; + if ([FValidation validateFrom:fn + isValidLeafValue:value + withPath:path]) { + isLeafNode = YES; + } else { + @throw [[NSException alloc] + initWithName:@"InvalidLeafValueType" + reason:[NSString stringWithFormat: + @"(%@) Invalid data type used " + @"with .value. Can only use " + "NSString and NSNumber or be " + "null. Found %@ instead.", + fn, [[value class] description]] + userInfo:nil]; + } + } + } + + if ([FValidation validateFrom:fn isValidLeafValue:value withPath:path]) { + isLeafNode = YES; + } + + if (isLeafNode) { + return [[FLeafNode alloc] initWithValue:value withPriority:priority]; + } + + // Unlike with JS, we have to handle the dictionary and array cases + // separately. + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dval = (NSDictionary *)value; + NSMutableDictionary *children = + [NSMutableDictionary dictionaryWithCapacity:dval.count]; + + // Avoid creating a million newPaths by appending to old one + for (id keyId in dval) { + [FValidation validateFrom:fn + validDictionaryKey:keyId + withPath:path]; + NSString *key = (NSString *)keyId; + + if (![key hasPrefix:kPayloadMetadataPrefix]) { + [path addObject:key]; + id childNode = [FSnapshotUtilities nodeFrom:dval[key] + priority:nil + withValidationFrom:fn + atDepth:depth + 1 + path:path]; + [path removeLastObject]; + + if (![childNode isEmpty]) { + children[key] = childNode; + } + } + } + + if ([children count] == 0) { + return [FEmptyNode emptyNode]; + } else { + FImmutableSortedDictionary *childrenDict = + [FImmutableSortedDictionary + fromDictionary:children + withComparator:[FUtilities keyComparator]]; + return [[FChildrenNode alloc] initWithPriority:priority + children:childrenDict]; + } + } else if ([value isKindOfClass:[NSArray class]]) { + NSArray *aval = (NSArray *)value; + NSMutableDictionary *children = + [NSMutableDictionary dictionaryWithCapacity:aval.count]; + + for (int i = 0; i < [aval count]; i++) { + NSString *key = [NSString stringWithFormat:@"%i", i]; + [path addObject:key]; + id childNode = + [FSnapshotUtilities nodeFrom:[aval objectAtIndex:i] + priority:nil + withValidationFrom:fn + atDepth:depth + 1 + path:path]; + [path removeLastObject]; + + if (![childNode isEmpty]) { + children[key] = childNode; + } + } + + if ([children count] == 0) { + return [FEmptyNode emptyNode]; + } else { + FImmutableSortedDictionary *childrenDict = + [FImmutableSortedDictionary + fromDictionary:children + withComparator:[FUtilities keyComparator]]; + return [[FChildrenNode alloc] initWithPriority:priority + children:childrenDict]; + } + } else { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store object of type %@ at %@. " + "Can only store objects of type NSNumber, " + "NSString, NSDictionary, and NSArray.", + fn, [[value class] description], pathString] + userInfo:nil]; + } +} + ++ (FCompoundWrite *)compoundWriteFromDictionary:(NSDictionary *)values + withValidationFrom:(NSString *)fn { + FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite]; + + NSMutableArray *updatePaths = + [NSMutableArray arrayWithCapacity:values.count]; + for (NSString *keyId in values) { + id value = values[keyId]; + [FValidation validateFrom:fn + validUpdateDictionaryKey:keyId + withValue:value]; + + FPath *path = [FPath pathWithString:keyId]; + id node = [FSnapshotUtilities nodeFrom:value + withValidationFrom:fn]; + + [updatePaths addObject:path]; + compoundWrite = [compoundWrite addWrite:node atPath:path]; + } + + // Check that the update paths are not descendants of each other. + [updatePaths + sortUsingComparator:^NSComparisonResult(FPath *left, FPath *right) { + return [left compare:right]; + }]; + FPath *prevPath = nil; + for (FPath *path in updatePaths) { + if (prevPath != nil && [prevPath contains:path]) { + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Invalid path in object. Path " + @"(%@) is an ancestor of (%@).", + fn, prevPath, path] + userInfo:nil]; + } + prevPath = path; + } + + return compoundWrite; +} + ++ (void)validatePriorityNode:(id)priorityNode { + assert(priorityNode != nil); + if (priorityNode.isLeafNode) { + id val = priorityNode.val; + if ([val isKindOfClass:[NSDictionary class]]) { + NSDictionary *valDict __unused = (NSDictionary *)val; + NSAssert(valDict[kServerValueSubKey] != nil, + @"Priority can't be object unless it's a deferred value"); + } else { + NSString *jsType __unused = [FUtilities getJavascriptType:val]; + NSAssert(jsType == kJavaScriptString || jsType == kJavaScriptNumber, + @"Priority of unexpected type."); + } + } else { + NSAssert(priorityNode == [FMaxNode maxNode] || priorityNode.isEmpty, + @"Priority of unexpected type."); + } + // Don't call getPriority() on MAX_NODE to avoid hitting assertion. + NSAssert(priorityNode == [FMaxNode maxNode] || + priorityNode.getPriority.isEmpty, + @"Priority nodes can't have a priority of their own."); +} + ++ (void)appendHashRepresentationForLeafNode:(FLeafNode *)leafNode + toString:(NSMutableString *)string + hashVersion:(FDataHashVersion)hashVersion { + NSAssert(hashVersion == FDataHashVersionV1 || + hashVersion == FDataHashVersionV2, + @"Unknown hash version: %lu", (unsigned long)hashVersion); + if (!leafNode.getPriority.isEmpty) { + [string appendString:@"priority:"]; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:leafNode.getPriority + toString:string + hashVersion:hashVersion]; + [string appendString:@":"]; + } + + NSString *jsType = [FUtilities getJavascriptType:leafNode.val]; + [string appendString:jsType]; + [string appendString:@":"]; + + if (jsType == kJavaScriptBoolean) { + NSString *boolString = + [leafNode.val boolValue] ? kJavaScriptTrue : kJavaScriptFalse; + [string appendString:boolString]; + } else if (jsType == kJavaScriptNumber) { + NSString *numberString = + [FUtilities ieee754StringForNumber:leafNode.val]; + [string appendString:numberString]; + } else if (jsType == kJavaScriptString) { + if (hashVersion == FDataHashVersionV1) { + [string appendString:leafNode.val]; + } else { + NSAssert(hashVersion == FDataHashVersionV2, + @"Invalid hash version found"); + [FSnapshotUtilities appendHashV2RepresentationForString:leafNode.val + toString:string]; + } + } else { + [NSException raise:NSInvalidArgumentException + format:@"Unknown value for hashing: %@", leafNode]; + } +} + ++ (void)appendHashV2RepresentationForString:(NSString *)string + toString:(NSMutableString *)mutableString { + string = [string stringByReplacingOccurrencesOfString:@"\\" + withString:@"\\\\"]; + string = [string stringByReplacingOccurrencesOfString:@"\"" + withString:@"\\\""]; + [mutableString appendString:@"\""]; + [mutableString appendString:string]; + [mutableString appendString:@"\""]; +} + ++ (NSUInteger)estimateLeafNodeSize:(FLeafNode *)leafNode { + NSString *jsType = [FUtilities getJavascriptType:leafNode.val]; + // These values are somewhat arbitrary, but we don't need an exact value so + // prefer performance over exact value + NSUInteger valueSize; + if (jsType == kJavaScriptNumber) { + valueSize = 8; // estimate each float with 8 bytes + } else if (jsType == kJavaScriptBoolean) { + valueSize = 4; // true or false need roughly 4 bytes + } else if (jsType == kJavaScriptString) { + valueSize = 2 + [leafNode.val length]; // add 2 for quotes + } else { + [NSException raise:NSInvalidArgumentException + format:@"Unknown leaf type: %@", leafNode]; + return 0; + } + + if (leafNode.getPriority.isEmpty) { + return valueSize; + } else { + // Account for extra overhead due to the extra JSON object and the + // ".value" and ".priority" keys, colons, comma + NSUInteger leafPriorityOverhead = 2 + 8 + 11 + 2 + 1; + return leafPriorityOverhead + valueSize + + [FSnapshotUtilities estimateLeafNodeSize:leafNode.getPriority]; + } +} + ++ (NSUInteger)estimateSerializedNodeSize:(id)node { + if ([node isEmpty]) { + return 4; // null keyword + } else if ([node isLeafNode]) { + return [FSnapshotUtilities estimateLeafNodeSize:node]; + } else { + NSAssert([node isKindOfClass:[FChildrenNode class]], + @"Unexpected node type: %@", [node class]); + __block NSUInteger sum = 1; // opening brackets + [((FChildrenNode *)node) enumerateChildrenAndPriorityUsingBlock:^( + NSString *key, id child, + BOOL *stop) { + sum += key.length; + sum += + 4; // quotes around key and colon and (comma or closing bracket) + sum += [FSnapshotUtilities estimateSerializedNodeSize:child]; + }]; + return sum; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.h new file mode 100644 index 0000000..b8668d2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.h @@ -0,0 +1,23 @@ +/* + * 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 + +@interface FAtomicNumber : NSObject + +- (NSNumber *)getAndIncrement; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.m new file mode 100644 index 0000000..2cf54ce --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.m @@ -0,0 +1,55 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" + +@interface FAtomicNumber () { + unsigned long number; +} + +@property(nonatomic, strong) NSLock *lock; + +@end + +@implementation FAtomicNumber + +@synthesize lock; + +- (id)init { + self = [super init]; + if (self) { + number = 1; + self.lock = [[NSLock alloc] init]; + } + return self; +} + +- (NSNumber *)getAndIncrement { + NSNumber *result; + + // See: + // http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW14 + // to improve, etc. + + [self.lock lock]; + result = [NSNumber numberWithUnsignedLong:number]; + number = number + 1; + [self.lock unlock]; + + return result; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.h new file mode 100644 index 0000000..b4f69b9 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.h @@ -0,0 +1,36 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" + +@interface FEventEmitter : NSObject + +- (id)initWithAllowedEvents:(NSArray *)theAllowedEvents + queue:(dispatch_queue_t)queue; + +- (id)getInitialEventForType:(NSString *)eventType; +- (void)triggerEventType:(NSString *)eventType data:(id)data; + +- (FIRDatabaseHandle)observeEventType:(NSString *)eventType + withBlock:(fbt_void_id)block; +- (void)removeObserverForEventType:(NSString *)eventType + withHandle:(FIRDatabaseHandle)handle; + +- (void)validateEventType:(NSString *)eventType; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.m new file mode 100644 index 0000000..977c06c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.m @@ -0,0 +1,161 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FEventEmitter.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FEventListener : NSObject + +@property(nonatomic, copy) fbt_void_id userCallback; +@property(nonatomic) FIRDatabaseHandle handle; + +@end + +@implementation FEventListener + +@synthesize userCallback; +@synthesize handle; + +@end + +@interface FEventEmitter () + +@property(nonatomic, strong) NSArray *allowedEvents; +@property(nonatomic, strong) NSMutableDictionary *listeners; +@property(nonatomic, strong) dispatch_queue_t queue; + +@end + +@implementation FEventEmitter + +@synthesize allowedEvents; +@synthesize listeners; + +- (id)initWithAllowedEvents:(NSArray *)theAllowedEvents + queue:(dispatch_queue_t)queue { + if (theAllowedEvents == nil || [theAllowedEvents count] == 0) { + @throw [NSException + exceptionWithName:@"AllowedEventsValidation" + reason:@"FEventEmitters must be initialized with at " + @"least one valid event." + userInfo:nil]; + } + + self = [super init]; + + if (self) { + self.allowedEvents = [theAllowedEvents copy]; + self.listeners = [[NSMutableDictionary alloc] init]; + self.queue = queue; + } + + return self; +} + +- (id)getInitialEventForType:(NSString *)eventType { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"You must override getInitialEvent: " + @"when subclassing FEventEmitter" + userInfo:nil]; +} + +- (void)triggerEventType:(NSString *)eventType data:(id)data { + [self validateEventType:eventType]; + NSMutableDictionary *eventTypeListeners = + [self.listeners objectForKey:eventType]; + for (FEventListener *listener in eventTypeListeners) { + [self triggerListener:listener withData:data]; + } +} + +- (void)triggerListener:(FEventListener *)listener withData:(id)data { + // TODO, should probably get this from FRepo or something although it ends + // up being the same. (Except maybe for testing) + if (listener.userCallback) { + dispatch_async(self.queue, ^{ + listener.userCallback(data); + }); + } +} + +- (FIRDatabaseHandle)observeEventType:(NSString *)eventType + withBlock:(fbt_void_id)block { + [self validateEventType:eventType]; + + // Create listener + FEventListener *listener = [[FEventListener alloc] init]; + listener.handle = [[FUtilities LUIDGenerator] integerValue]; + listener.userCallback = block; // copies block automatically + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self addEventListener:listener forEventType:eventType]; + }); + + return listener.handle; +} + +- (void)addEventListener:(FEventListener *)listener + forEventType:(NSString *)eventType { + // Get or initializer listeners map [FIRDatabaseHandle -> callback block] + // for eventType + NSMutableArray *eventTypeListeners = + [self.listeners objectForKey:eventType]; + if (eventTypeListeners == nil) { + eventTypeListeners = [[NSMutableArray alloc] init]; + [self.listeners setObject:eventTypeListeners forKey:eventType]; + } + + // Add listener and fire the current event for this listener + [eventTypeListeners addObject:listener]; + id initialData = [self getInitialEventForType:eventType]; + [self triggerListener:listener withData:initialData]; +} + +- (void)removeObserverForEventType:(NSString *)eventType + withHandle:(FIRDatabaseHandle)handle { + [self validateEventType:eventType]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self removeEventListenerWithHandle:handle forEventType:eventType]; + }); +} + +- (void)removeEventListenerWithHandle:(FIRDatabaseHandle)handle + forEventType:(NSString *)eventType { + NSMutableArray *eventTypeListeners = + [self.listeners objectForKey:eventType]; + for (FEventListener *listener in [eventTypeListeners copy]) { + if (handle == NSNotFound || handle == listener.handle) { + [eventTypeListeners removeObject:listener]; + } + } +} + +- (void)validateEventType:(NSString *)eventType { + if ([self.allowedEvents indexOfObject:eventType] == NSNotFound) { + @throw [NSException + exceptionWithName:@"InvalidEventType" + reason:[NSString stringWithFormat: + @"%@ is not a valid event type. %@ " + @"is the list of valid events.", + eventType, self.allowedEvents] + userInfo:nil]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.h new file mode 100644 index 0000000..90213a8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.h @@ -0,0 +1,27 @@ +/* + * 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 + +@interface FNextPushId : NSObject + ++ (NSString *)get:(NSTimeInterval)now; + ++ (NSString *)successor:(NSString *)key; + ++ (NSString *)predecessor:(NSString *)key; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.m new file mode 100644 index 0000000..2d92ffb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.m @@ -0,0 +1,144 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FNextPushId.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +static NSString *const PUSH_CHARS = + @"-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; + +static NSString *const MIN_PUSH_CHAR = @"-"; + +static NSString *const MAX_PUSH_CHAR = @"z"; + +static NSInteger const MAX_KEY_LEN = 786; + +@implementation FNextPushId + ++ (NSString *)get:(NSTimeInterval)currentTime { + static long long lastPushTime = 0; + static int lastRandChars[12]; + + long long now = (long long)(currentTime * 1000); + + BOOL duplicateTime = now == lastPushTime; + lastPushTime = now; + + unichar timeStampChars[8]; + for (int i = 7; i >= 0; i--) { + timeStampChars[i] = [PUSH_CHARS characterAtIndex:(now % 64)]; + now = (long long)floor(now / 64); + } + + NSMutableString *id = [[NSMutableString alloc] init]; + [id appendString:[NSString stringWithCharacters:timeStampChars length:8]]; + + if (!duplicateTime) { + for (int i = 0; i < 12; i++) { + lastRandChars[i] = (int)floor(arc4random() % 64); + } + } else { + int i = 0; + for (i = 11; i >= 0 && lastRandChars[i] == 63; i--) { + lastRandChars[i] = 0; + } + lastRandChars[i]++; + } + + for (int i = 0; i < 12; i++) { + [id appendFormat:@"%C", [PUSH_CHARS characterAtIndex:lastRandChars[i]]]; + } + + return [NSString stringWithString:id]; +} + ++ (NSString *)successor:(NSString *_Nonnull)key { + NSInteger keyAsInt; + if ([FUtilities tryParseString:key asInt:&keyAsInt]) { + if (keyAsInt == [FUtilities int32max]) { + return MIN_PUSH_CHAR; + } + return [NSString stringWithFormat:@"%ld", (long)keyAsInt + 1]; + } + NSMutableString *next = [NSMutableString stringWithString:key]; + if ([next length] < MAX_KEY_LEN) { + [next insertString:MIN_PUSH_CHAR atIndex:[key length]]; + return next; + } + + long i = [next length] - 1; + while (i >= 0) { + if ([next characterAtIndex:i] != [MAX_PUSH_CHAR characterAtIndex:0]) { + break; + } + --i; + } + + // `nextAfter` was called on the largest possible key, so return the + // maxName, which sorts larger than all keys. + if (i == -1) { + return [FUtilities maxName]; + } + + NSString *source = + [NSString stringWithFormat:@"%C", [next characterAtIndex:i]]; + NSInteger sourceIndex = [PUSH_CHARS rangeOfString:source].location; + NSString *sourcePlusOne = [NSString + stringWithFormat:@"%C", [PUSH_CHARS characterAtIndex:sourceIndex + 1]]; + + [next replaceCharactersInRange:NSMakeRange(i, i + 1) + withString:sourcePlusOne]; + return [next substringWithRange:NSMakeRange(0, i + 1)]; +} + +// `key` is assumed to be non-empty. ++ (NSString *)predecessor:(NSString *_Nonnull)key { + NSInteger keyAsInt; + if ([FUtilities tryParseString:key asInt:&keyAsInt]) { + if (keyAsInt == [FUtilities int32min]) { + return [FUtilities minName]; + } + return [NSString stringWithFormat:@"%ld", (long)keyAsInt - 1]; + } + NSMutableString *next = [NSMutableString stringWithString:key]; + if ([next characterAtIndex:(next.length - 1)] == + [MIN_PUSH_CHAR characterAtIndex:0]) { + if ([next length] == 1) { + return + [NSString stringWithFormat:@"%ld", (long)[FUtilities int32max]]; + } + // If the last character is the smallest possible character, then the + // next smallest string is the prefix of `key` without it. + [next replaceCharactersInRange:NSMakeRange([next length] - 1, 1) + withString:@""]; + return next; + } + // Replace the last character with its immedate predecessor, and fill the + // suffix of the key with MAX_PUSH_CHAR. This is the lexicographically + // largest possible key smaller than `key`. + unichar curr = [next characterAtIndex:next.length - 1]; + NSRange dstRange = NSMakeRange([next length] - 1, 1); + NSRange srcRange = + [PUSH_CHARS rangeOfString:[NSString stringWithFormat:@"%C", curr]]; + srcRange.location -= 1; + [next replaceCharactersInRange:dstRange + withString:[PUSH_CHARS substringWithRange:srcRange]]; + return [next stringByPaddingToLength:MAX_KEY_LEN + withString:MAX_PUSH_CHAR + startingAtIndex:0]; +}; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.h new file mode 100644 index 0000000..413e5df --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.h @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +@interface FParsedUrl : NSObject + +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FPath *path; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.m new file mode 100644 index 0000000..81fa02e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.m @@ -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 "FirebaseDatabase/Sources/Utilities/FParsedUrl.h" + +@implementation FParsedUrl + +@synthesize repoInfo; +@synthesize path; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.h new file mode 100644 index 0000000..f7d19b6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.h @@ -0,0 +1,26 @@ +/* + * 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 + +@interface FStringUtilities : NSObject + ++ (NSString *)base64EncodedSha1:(NSString *)str; ++ (NSString *)urlDecoded:(NSString *)url; ++ (NSString *)urlEncoded:(NSString *)url; ++ (NSString *)sanitizedForUserAgent:(NSString *)str; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.m new file mode 100644 index 0000000..f4370f2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.m @@ -0,0 +1,72 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" +#import "FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h" +#import + +@implementation FStringUtilities + +// http://stackoverflow.com/questions/3468268/objective-c-sha1 +// http://stackoverflow.com/questions/7310457/ios-objective-c-sha-1-and-base64-problem ++ (NSString *)base64EncodedSha1:(NSString *)str { + const char *cstr = [str cStringUsingEncoding:NSUTF8StringEncoding]; + // NSString reports length in characters, but we want it in bytes, which + // strlen will give us. + unsigned long dataLen = strlen(cstr); + NSData *data = [NSData dataWithBytes:cstr length:dataLen]; + uint8_t digest[CC_SHA1_DIGEST_LENGTH]; + CC_SHA1(data.bytes, (unsigned int)data.length, digest); + NSData *output = [[NSData alloc] initWithBytes:digest + length:CC_SHA1_DIGEST_LENGTH]; + return [FSRUtilities base64EncodedStringFromData:output]; +} + ++ (NSString *)urlDecoded:(NSString *)url { + NSString *replaced = [url stringByReplacingOccurrencesOfString:@"+" + withString:@" "]; + NSString *decoded = [replaced stringByRemovingPercentEncoding]; + // This is kind of a hack, but is generally how the js client works. We + // could run into trouble if some piece is a correctly escaped %-sequence, + // and another isn't. But, that's bad input anyways... + if (decoded) { + return decoded; + } else { + return replaced; + } +} + ++ (NSString *)urlEncoded:(NSString *)url { + // Didn't seem like there was an Apple NSCharacterSet that had our version + // of the encoding So I made my own, following RFC 2396 + // https://www.ietf.org/rfc/rfc2396.txt allowedCharacters = alphanum | "-" | + // "_" | "~" + NSCharacterSet *allowedCharacters = [NSCharacterSet + characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGH" + @"IJKLMNOPQRSTUVWXYZ0123456789-_~"]; + return [url + stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters]; +} + ++ (NSString *)sanitizedForUserAgent:(NSString *)str { + return + [str stringByReplacingOccurrencesOfString:@"/|_" + withString:@"|" + options:NSRegularExpressionSearch + range:NSMakeRange(0, [str length])]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FTypedefs.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FTypedefs.h new file mode 100644 index 0000000..56d97ff --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FTypedefs.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#ifndef Firebase_FTypedefs_h +#define Firebase_FTypedefs_h + +/** + * Stub... + */ +@class FIRDataSnapshot; +@class FIRDatabaseReference; +@class FAuthData; +@protocol FNode; + +// fbt = Firebase Block Typedef + +typedef void (^fbt_void_void)(void); +typedef void (^fbt_void_datasnapshot_nsstring)(FIRDataSnapshot *snapshot, + NSString *prevName); +typedef void (^fbt_void_datasnapshot)(FIRDataSnapshot *snapshot); +typedef void (^fbt_void_user)(FAuthData *user); +typedef void (^fbt_void_nsstring_id)(NSString *status, id data); +typedef void (^fbt_void_nserror_id)(NSError *error, id data); +typedef void (^fbt_void_nserror)(NSError *error); +typedef void (^fbt_void_nserror_ref)(NSError *error, FIRDatabaseReference *ref); +typedef void (^fbt_void_nserror_user)(NSError *error, FAuthData *user); +typedef void (^fbt_void_nserror_json)(NSError *error, NSDictionary *json); +typedef void (^fbt_void_nsdictionary)(NSDictionary *data); +typedef id (^fbt_id_node_nsstring)(id node, NSString *childName); + +#endif diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.h new file mode 100644 index 0000000..f166c3d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.h @@ -0,0 +1,88 @@ +/* + * 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 "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import + +#import "FirebaseDatabase/Sources/Utilities/FParsedUrl.h" + +@interface FUtilities : NSObject + ++ (NSArray *)splitString:(NSString *)str intoMaxSize:(const unsigned int)size; ++ (NSNumber *)LUIDGenerator; ++ (FParsedUrl *)parseUrl:(NSString *)url; ++ (NSString *)getJavascriptType:(id)obj; ++ (NSError *)errorForStatus:(NSString *)status andReason:(NSString *)reason; ++ (NSNumber *)intForString:(NSString *)string; ++ (NSInteger)int32min; ++ (NSInteger)int32max; ++ (NSString *)ieee754StringForNumber:(NSNumber *)val; ++ (BOOL)tryParseString:(NSString *)string asInt:(NSInteger *)integer; ++ (void)setLoggingEnabled:(BOOL)enabled; ++ (BOOL)getLoggingEnabled; + ++ (NSString *)minName; ++ (NSString *)maxName; ++ (NSComparisonResult)compareKey:(NSString *)a toKey:(NSString *)b; ++ (NSComparator)stringComparator; ++ (NSComparator)keyComparator; + ++ (double)randomDouble; + +@end + +typedef enum { + FLogLevelDebug = 1, + FLogLevelInfo = 2, + FLogLevelWarn = 3, + FLogLevelError = 4, + FLogLevelNone = 5 +} FLogLevel; + +// Log tags +FOUNDATION_EXPORT NSString *const kFPersistenceLogTag; + +#define FFLog(code, format, ...) FFDebug((code), (format), ##__VA_ARGS__) + +#define FFDebug(code, format, ...) \ + do { \ + if (FFIsLoggingEnabled(FLogLevelDebug)) { \ + FIRLogDebug(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ + } \ + } while (0) + +#define FFInfo(code, format, ...) \ + do { \ + if (FFIsLoggingEnabled(FLogLevelInfo)) { \ + FIRLogError(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ + } \ + } while (0) + +#define FFWarn(code, format, ...) \ + do { \ + if (FFIsLoggingEnabled(FLogLevelWarn)) { \ + FIRLogWarning(kFIRLoggerDatabase, (code), (format), \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#define INTEGER_32_MIN (-2147483648) +#define INTEGER_32_MAX 2147483647 + +extern FIRLoggerService kFIRLoggerDatabase; +BOOL FFIsLoggingEnabled(FLogLevel logLevel); +void firebaseUncaughtExceptionHandler(NSException *exception); +void firebaseJobsTroll(void); diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.m new file mode 100644 index 0000000..69dfd69 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.m @@ -0,0 +1,443 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" + +#define ARC4RANDOM_MAX 0x100000000 + +#pragma mark - +#pragma mark C functions + +FIRLoggerService kFIRLoggerDatabase = @"[Firebase/Database]"; +static FLogLevel logLevel = FLogLevelInfo; // Default log level is info +static NSMutableDictionary *options = nil; + +BOOL FFIsLoggingEnabled(FLogLevel level) { return level >= logLevel; } + +void firebaseJobsTroll(void) { + FFLog(@"I-RDB095001", + @"password super secret; JFK conspiracy; Hello there! Having fun " + @"digging through Firebase? We're always hiring! jobs@firebase.com"); +} + +#pragma mark - +#pragma mark Private property and singleton specification + +@interface FUtilities () { +} + +@property(nonatomic, strong) FAtomicNumber *localUid; + ++ (FUtilities *)singleton; + +@end + +@implementation FUtilities + +@synthesize localUid; + +- (id)init { + self = [super init]; + if (self) { + self.localUid = [[FAtomicNumber alloc] init]; + } + return self; +} + +// TODO: We really want to be able to set the log level ++ (void)setLoggingEnabled:(BOOL)enabled { + logLevel = enabled ? FLogLevelDebug : FLogLevelInfo; +} + ++ (BOOL)getLoggingEnabled { + return logLevel == FLogLevelDebug; +} + ++ (FUtilities *)singleton { + static dispatch_once_t pred = 0; + __strong static id _sharedObject = nil; + dispatch_once(&pred, ^{ + _sharedObject = [[self alloc] init]; // or some other init method + }); + return _sharedObject; +} + +// Refactor as a category of NSString ++ (NSArray *)splitString:(NSString *)str intoMaxSize:(const unsigned int)size { + if (str.length <= size) { + return [NSArray arrayWithObject:str]; + } + + NSMutableArray *dataSegs = [[NSMutableArray alloc] init]; + for (int c = 0; c < str.length; c += size) { + if (c + size > str.length) { + int rangeStart = c; + unsigned long rangeLength = size - ((c + size) - str.length); + [dataSegs + addObject:[str substringWithRange:NSMakeRange(rangeStart, + rangeLength)]]; + } else { + int rangeStart = c; + int rangeLength = size; + [dataSegs + addObject:[str substringWithRange:NSMakeRange(rangeStart, + rangeLength)]]; + } + } + return dataSegs; +} + ++ (NSNumber *)LUIDGenerator { + FUtilities *f = [FUtilities singleton]; + return [f.localUid getAndIncrement]; +} + ++ (NSString *)decodePath:(NSString *)pathString { + NSMutableArray *decodedPieces = [[NSMutableArray alloc] init]; + NSArray *pieces = [pathString componentsSeparatedByString:@"/"]; + for (NSString *piece in pieces) { + if (piece.length > 0) { + [decodedPieces addObject:[FStringUtilities urlDecoded:piece]]; + } + } + return [NSString + stringWithFormat:@"/%@", [decodedPieces componentsJoinedByString:@"/"]]; +} + ++ (NSString *)extractPathFromUrlString:(NSString *)url { + NSString *path = url; + + NSRange schemeIndex = [path rangeOfString:@"//"]; + if (schemeIndex.location != NSNotFound) { + path = [path substringFromIndex:schemeIndex.location + 2]; + } + + NSUInteger pathIndex = [path rangeOfString:@"/"].location; + if (pathIndex != NSNotFound) { + path = [path substringFromIndex:pathIndex + 1]; + } else { + path = @""; + } + + NSUInteger queryParamIndex = [path rangeOfString:@"?"].location; + if (queryParamIndex != NSNotFound) { + path = [path substringToIndex:queryParamIndex]; + } + + return path; +} + ++ (FParsedUrl *)parseUrl:(NSString *)url { + // For backwards compatibility, support URLs without schemes on iOS. + if (![url containsString:@"://"]) { + url = [@"http://" stringByAppendingString:url]; + } + + NSString *originalPathString = [self extractPathFromUrlString:url]; + + // Sanitize the database URL by removing the path component, which may + // contain invalid URL characters. + NSString *sanitizedUrlWithoutPath = + [url stringByReplacingOccurrencesOfString:originalPathString + withString:@""]; + NSURLComponents *urlComponents = + [NSURLComponents componentsWithString:sanitizedUrlWithoutPath]; + if (!urlComponents) { + [NSException raise:@"Failed to parse database URL" + format:@"Failed to parse database URL: %@", url]; + } + + NSString *host = [urlComponents.host lowercaseString]; + NSString *namespace; + bool secure; + + if (urlComponents.port != nil) { + secure = [urlComponents.scheme isEqualToString:@"https"] || + [urlComponents.scheme isEqualToString:@"wss"]; + host = [host stringByAppendingFormat:@":%@", urlComponents.port]; + } else { + secure = YES; + }; + + NSArray *parts = [urlComponents.host componentsSeparatedByString:@"."]; + if ([parts count] == 3) { + namespace = [parts[0] lowercaseString]; + } else { + // Attempt to extract namespace from "ns" query param. + NSArray *queryItems = urlComponents.queryItems; + for (NSURLQueryItem *item in queryItems) { + if ([item.name isEqualToString:@"ns"]) { + namespace = item.value; + break; + } + } + + if (!namespace) { + namespace = [parts[0] lowercaseString]; + } + } + + NSString *pathString = [self + decodePath:[NSString stringWithFormat:@"/%@", originalPathString]]; + FPath *path = [[FPath alloc] initWith:pathString]; + FRepoInfo *repoInfo = [[FRepoInfo alloc] initWithHost:host + isSecure:secure + withNamespace:namespace]; + + FFLog(@"I-RDB095002", @"---> Parsed (%@) to: (%@,%@); ns=(%@); path=(%@)", + url, [repoInfo description], [repoInfo connectionURL], + repoInfo.namespace, [path description]); + + FParsedUrl *parsedUrl = [[FParsedUrl alloc] init]; + parsedUrl.repoInfo = repoInfo; + parsedUrl.path = path; + + return parsedUrl; +} + +/* + case str: JString => priString + "string:" + str.s; + case bool: JBool => priString + "boolean:" + bool.value; + case double: JDouble => priString + "number:" + double.num; + case int: JInt => priString + "number:" + int.num; + case _ => { + error("Leaf node has value '" + data.value + "' of invalid type '" + + data.value.getClass.toString + "'"); + ""; + } + */ + ++ (NSString *)getJavascriptType:(id)obj { + if ([obj isKindOfClass:[NSDictionary class]]) { + return kJavaScriptObject; + } else if ([obj isKindOfClass:[NSString class]]) { + return kJavaScriptString; + } else if ([obj isKindOfClass:[NSNumber class]]) { + // We used to just compare to @encode(BOOL) as suggested at + // http://stackoverflow.com/questions/2518761/get-type-of-nsnumber, but + // on arm64, @encode(BOOL) returns "B" instead of "c" even though + // objCType still returns 'c' (signed char). So check both. + if (strcmp([obj objCType], @encode(BOOL)) == 0 || + strcmp([obj objCType], @encode(signed char)) == 0) { + return kJavaScriptBoolean; + } else { + return kJavaScriptNumber; + } + } else { + return kJavaScriptNull; + } +} + ++ (NSError *)errorForStatus:(NSString *)status andReason:(NSString *)reason { + static dispatch_once_t pred = 0; + __strong static NSDictionary *errorMap = nil; + __strong static NSDictionary *errorCodes = nil; + dispatch_once(&pred, ^{ + errorMap = @{ + @"permission_denied" : @"Permission Denied", + @"unavailable" : @"Service is unavailable", + kFErrorWriteCanceled : @"Write cancelled by user" + }; + errorCodes = @{ + @"permission_denied" : @1, + @"unavailable" : @2, + kFErrorWriteCanceled : @3 + }; + }); + + if ([status isEqualToString:kFWPResponseForActionStatusOk]) { + return nil; + } else { + NSInteger code; + NSString *desc = nil; + if (reason) { + desc = reason; + } else if ([errorMap objectForKey:status] != nil) { + desc = [errorMap objectForKey:status]; + } else { + desc = status; + } + + if ([errorCodes objectForKey:status] != nil) { + NSNumber *num = [errorCodes objectForKey:status]; + code = [num integerValue]; + } else { + // XXX what to do here? + code = 9999; + } + + return [[NSError alloc] + initWithDomain:kFErrorDomain + code:code + userInfo:@{NSLocalizedDescriptionKey : desc}]; + } +} + ++ (NSNumber *)intForString:(NSString *)string { + static NSCharacterSet *notDigits = nil; + if (!notDigits) { + notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet]; + } + if ([string rangeOfCharacterFromSet:notDigits].length == 0) { + NSInteger num; + NSScanner *scanner = [NSScanner scannerWithString:string]; + if ([scanner scanInteger:&num]) { + return [NSNumber numberWithInteger:num]; + } + } + return nil; +} + ++ (NSInteger)int32min { + return INTEGER_32_MIN; +} + ++ (NSInteger)int32max { + return INTEGER_32_MAX; +} + ++ (NSString *)ieee754StringForNumber:(NSNumber *)val { + double d = [val doubleValue]; + NSData *data = [NSData dataWithBytes:&d length:sizeof(double)]; + NSMutableString *str = [[NSMutableString alloc] init]; + const unsigned char *buffer = (const unsigned char *)[data bytes]; + for (int i = 0; i < data.length; i++) { + unsigned char byte = buffer[7 - i]; + [str appendFormat:@"%02x", byte]; + } + return str; +} + ++ (BOOL)tryParseString:(NSString *)string asInt:(NSInteger *)integer { + return tryParseStringToInt(string, integer); +} + +static inline BOOL tryParseStringToInt(__unsafe_unretained NSString *str, + NSInteger *integer) { + // First do some cheap checks (NOTE: The below checks are significantly + // faster than an equivalent regex :-( ). + NSUInteger length = str.length; + if (length > 11 || length == 0) { + return NO; + } + long long value = 0; + BOOL negative = NO; + NSUInteger i = 0; + if ([str characterAtIndex:0] == '-') { + if (length == 1) { + return NO; + } + negative = YES; + i = 1; + } + for (; i < length; i++) { + unichar c = [str characterAtIndex:i]; + // Must be a digit, or '-' if it's the first char. + if (c < '0' || c > '9') { + return NO; + } else { + int charValue = c - '0'; + value = value * 10 + charValue; + } + } + + value = (negative) ? -value : value; + + if (value < INTEGER_32_MIN || value > INTEGER_32_MAX) { + return NO; + } else { + *integer = (NSInteger)value; + return YES; + } +} + ++ (NSString *)maxName { + static dispatch_once_t once; + static NSString *maxName; + dispatch_once(&once, ^{ + maxName = [[NSString alloc] initWithFormat:@"[MAX_NAME]"]; + }); + return maxName; +} + ++ (NSString *)minName { + static dispatch_once_t once; + static NSString *minName; + dispatch_once(&once, ^{ + minName = [[NSString alloc] initWithFormat:@"[MIN_NAME]"]; + }); + return minName; +} + ++ (NSComparisonResult)compareKey:(NSString *)a toKey:(NSString *)b { + if (a == b) { + return NSOrderedSame; + } else if (a == [FUtilities minName] || b == [FUtilities maxName]) { + return NSOrderedAscending; + } else if (b == [FUtilities minName] || a == [FUtilities maxName]) { + return NSOrderedDescending; + } else { + NSInteger aAsInt, bAsInt; + if (tryParseStringToInt(a, &aAsInt)) { + if (tryParseStringToInt(b, &bAsInt)) { + if (aAsInt > bAsInt) { + return NSOrderedDescending; + } else if (aAsInt < bAsInt) { + return NSOrderedAscending; + } else if (a.length > b.length) { + return NSOrderedDescending; + } else if (a.length < b.length) { + return NSOrderedAscending; + } else { + return NSOrderedSame; + } + } else { + return (NSComparisonResult)NSOrderedAscending; + } + } else if (tryParseStringToInt(b, &bAsInt)) { + return (NSComparisonResult)NSOrderedDescending; + } else { + // Perform literal character by character search to prevent a > b && + // b > a issues. Note that calling -(NSString + // *)decomposedStringWithCanonicalMapping also works. + return [a compare:b options:NSLiteralSearch]; + } + } +} + ++ (NSComparator)keyComparator { + return ^NSComparisonResult(__unsafe_unretained NSString *a, + __unsafe_unretained NSString *b) { + return [FUtilities compareKey:a toKey:b]; + }; +} + ++ (NSComparator)stringComparator { + return ^NSComparisonResult(__unsafe_unretained NSString *a, + __unsafe_unretained NSString *b) { + return [a compare:b]; + }; +} + ++ (double)randomDouble { + return ((double)arc4random() / ARC4RANDOM_MAX); +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.h new file mode 100644 index 0000000..02c98a2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.h @@ -0,0 +1,55 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import "FirebaseDatabase/Sources/Utilities/FParsedUrl.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@interface FValidation : NSObject + ++ (void)validateFrom:(NSString *)fn writablePath:(FPath *)path; ++ (void)validateFrom:(NSString *)fn knownEventType:(FIRDataEventType)event; ++ (void)validateFrom:(NSString *)fn validPathString:(NSString *)pathString; ++ (void)validateFrom:(NSString *)fn validRootPathString:(NSString *)pathString; ++ (void)validateFrom:(NSString *)fn validKey:(NSString *)key; ++ (void)validateFrom:(NSString *)fn validURL:(FParsedUrl *)parsedUrl; + ++ (void)validateToken:(NSString *)token; + +// Functions for handling passing errors back ++ (void)handleError:(NSError *)error + withUserCallback:(fbt_void_nserror_id)userCallback; ++ (void)handleError:(NSError *)error + withSuccessCallback:(fbt_void_nserror)userCallback; + +// Functions used for validating while creating snapshots in FSnapshotUtilities ++ (BOOL)validateFrom:(NSString *)fn + isValidLeafValue:(id)value + withPath:(NSArray *)path; ++ (void)validateFrom:(NSString *)fn + validDictionaryKey:(id)keyId + withPath:(NSArray *)path; ++ (void)validateFrom:(NSString *)fn + validUpdateDictionaryKey:(id)keyId + withValue:(id)value; ++ (void)validateFrom:(NSString *)fn + isValidPriorityValue:(id)value + withPath:(NSArray *)path; ++ (BOOL)validatePriorityValue:value; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.m new file mode 100644 index 0000000..6e083ce --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.m @@ -0,0 +1,461 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FValidation.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Utilities/FParsedUrl.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" + +// Have to escape: * ? + [ ( ) { } ^ $ | \ . / +// See: +// https://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html + +NSString *const kInvalidPathCharacters = @"[].#$"; +NSString *const kInvalidKeyCharacters = @"[].#$/"; + +@implementation FValidation + ++ (void)validateFrom:(NSString *)fn writablePath:(FPath *)path { + if ([[path getFront] isEqualToString:kDotInfoPrefix]) { + @throw [[NSException alloc] + initWithName:@"WritablePathValidation" + reason:[NSString + stringWithFormat:@"(%@) failed to path %@: Can't " + @"modify data under %@", + fn, [path description], + kDotInfoPrefix] + userInfo:nil]; + } +} + ++ (void)validateFrom:(NSString *)fn knownEventType:(FIRDataEventType)event { + switch (event) { + case FIRDataEventTypeValue: + case FIRDataEventTypeChildAdded: + case FIRDataEventTypeChildChanged: + case FIRDataEventTypeChildMoved: + case FIRDataEventTypeChildRemoved: + return; + break; + default: + @throw [[NSException alloc] + initWithName:@"KnownEventTypeValidation" + reason:[NSString + stringWithFormat:@"(%@) Unknown event type: %d", + fn, (int)event] + userInfo:nil]; + break; + } +} + ++ (BOOL)isValidPathString:(NSString *)pathString { + static dispatch_once_t token; + static NSCharacterSet *badPathChars = nil; + dispatch_once(&token, ^{ + badPathChars = [NSCharacterSet + characterSetWithCharactersInString:kInvalidPathCharacters]; + }); + return pathString != nil && [pathString length] != 0 && + [pathString rangeOfCharacterFromSet:badPathChars].location == + NSNotFound; +} + ++ (void)validateFrom:(NSString *)fn validPathString:(NSString *)pathString { + if (![self isValidPathString:pathString]) { + @throw [[NSException alloc] + initWithName:@"InvalidPathValidation" + reason:[NSString stringWithFormat: + @"(%@) Must be a non-empty string and " + @"not contain '.' '#' '$' '[' or ']'", + fn] + userInfo:nil]; + } +} + ++ (void)validateFrom:(NSString *)fn validRootPathString:(NSString *)pathString { + static dispatch_once_t token; + static NSRegularExpression *dotInfoRegex = nil; + dispatch_once(&token, ^{ + dotInfoRegex = [NSRegularExpression + regularExpressionWithPattern:@"^\\/*\\.info(\\/|$)" + options:0 + error:nil]; + }); + + NSString *tempPath = pathString; + // HACK: Obj-C regex are kinda' slow. Do a plain string search first before + // bothering with the regex. + if ([pathString rangeOfString:@".info"].location != NSNotFound) { + tempPath = [dotInfoRegex + stringByReplacingMatchesInString:pathString + options:0 + range:NSMakeRange(0, pathString.length) + withTemplate:@"/"]; + } + [self validateFrom:fn validPathString:tempPath]; +} + ++ (BOOL)isValidKey:(NSString *)key { + static dispatch_once_t token; + static NSCharacterSet *badKeyChars = nil; + dispatch_once(&token, ^{ + badKeyChars = [NSCharacterSet + characterSetWithCharactersInString:kInvalidKeyCharacters]; + }); + return key != nil && key.length > 0 && + [key rangeOfCharacterFromSet:badKeyChars].location == NSNotFound; +} + ++ (void)validateFrom:(NSString *)fn validKey:(NSString *)key { + if (![self isValidKey:key]) { + @throw [[NSException alloc] + initWithName:@"InvalidKeyValidation" + reason:[NSString + stringWithFormat: + @"(%@) Must be a non-empty string and not " + @"contain '/' '.' '#' '$' '[' or ']'", + fn] + userInfo:nil]; + } +} + ++ (void)validateFrom:(NSString *)fn validURL:(FParsedUrl *)parsedUrl { + NSString *pathString = [parsedUrl.path description]; + [self validateFrom:fn validRootPathString:pathString]; +} + +#pragma mark - +#pragma mark Authentication validation + ++ (BOOL)stringNonempty:(NSString *)str { + return str != nil && ![str isKindOfClass:[NSNull class]] && str.length > 0; +} + ++ (void)validateToken:(NSString *)token { + if (![FValidation stringNonempty:token]) { + [NSException raise:NSInvalidArgumentException + format:@"Can't have empty string or nil for custom token"]; + } +} + +#pragma mark - +#pragma mark Handling authentication errors + +/** + * This function immediately calls the callback. + * It assumes that it is not on FirebaseWorker thread. + * It assumes it's on a user-controlled thread. + */ ++ (void)handleError:(NSError *)error + withUserCallback:(fbt_void_nserror_id)userCallback { + if (userCallback) { + userCallback(error, nil); + } +} + +/** + * This function immediately calls the callback. + * It assumes that it is not on FirebaseWorker thread. + * It assumes it's on a user-controlled thread. + */ ++ (void)handleError:(NSError *)error + withSuccessCallback:(fbt_void_nserror)userCallback { + if (userCallback) { + userCallback(error); + } +} + +#pragma mark - +#pragma mark Snapshot validation + ++ (BOOL)validateFrom:(NSString *)fn + isValidLeafValue:(id)value + withPath:(NSArray *)path { + if ([value isKindOfClass:[NSString class]]) { + // Try to avoid conversion to bytes if possible + NSString *theString = value; + if ([theString maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] > + kFirebaseMaxLeafSize && + [theString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > + kFirebaseMaxLeafSize) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat:@"(%@) String exceeds max " + @"size of %u utf8 bytes: %@", + fn, (int)kFirebaseMaxLeafSize, + pathString] + userInfo:nil]; + } + return YES; + } + + else if ([value isKindOfClass:[NSNumber class]]) { + // Cannot store NaN, but otherwise can store NSNumbers. + if ([[NSDecimalNumber notANumber] isEqualToNumber:value]) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store NaN at path: %@.", fn, + pathString] + userInfo:nil]; + } + return YES; + } + + else if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dval = value; + if (dval[kServerValueSubKey] != nil) { + if ([dval count] > 1) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store other keys " + @"with server value keys.%@.", + fn, pathString] + userInfo:nil]; + } + return YES; + } + return NO; + } + + else if (value == [NSNull null] || value == nil) { + // Null is valid type to store at leaf + return YES; + } + + return NO; +} + ++ (NSString *)parseAndValidateKey:(id)keyId + fromFunction:(NSString *)fn + path:(NSArray *)path { + if (![keyId isKindOfClass:[NSString class]]) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat:@"(%@) Non-string keys are not " + @"allowed in object at path: %@", + fn, pathString] + userInfo:nil]; + } + return (NSString *)keyId; +} + ++ (void)validateFrom:(NSString *)fn + validDictionaryKey:(id)keyId + withPath:(NSArray *)path { + NSString *key = [self parseAndValidateKey:keyId fromFunction:fn path:path]; + if (![key isEqualToString:kPayloadPriority] && + ![key isEqualToString:kPayloadValue] && + ![key isEqualToString:kServerValueSubKey] && + ![FValidation isValidKey:key]) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Invalid key in object at path: " + @"%@. Keys must be non-empty and cannot " + @"contain '/' '.' '#' '$' '[' or ']'", + fn, pathString] + userInfo:nil]; + } +} + ++ (void)validateFrom:(NSString *)fn + validUpdateDictionaryKey:(id)keyId + withValue:(id)value { + FPath *path = [FPath pathWithString:[self parseAndValidateKey:keyId + fromFunction:fn + path:@[]]]; + __block NSInteger keyNum = 0; + [path enumerateComponentsUsingBlock:^void(NSString *key, BOOL *stop) { + if ([key isEqualToString:kPayloadPriority] && + keyNum == [path length] - 1) { + [self validateFrom:fn isValidPriorityValue:value withPath:@[]]; + } else { + keyNum++; + + if (![FValidation isValidKey:key]) { + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Invalid key in object. Keys must " + @"be non-empty and cannot contain '.' " + @"'#' '$' '[' or ']'", + fn] + userInfo:nil]; + } + } + }]; +} + ++ (void)validateFrom:(NSString *)fn + isValidPriorityValue:(id)value + withPath:(NSArray *)path { + [self validateFrom:fn + isValidPriorityValue:value + withPath:path + throwError:YES]; +} + +/** + * Returns YES if priority is valid. + */ ++ (BOOL)validatePriorityValue:value { + return [self validateFrom:nil + isValidPriorityValue:value + withPath:nil + throwError:NO]; +} + +/** + * Helper for validating priorities. If passed YES for throwError, it'll throw + * descriptive errors on validation problems. Else, it'll just return YES/NO. + */ ++ (BOOL)validateFrom:(NSString *)fn + isValidPriorityValue:(id)value + withPath:(NSArray *)path + throwError:(BOOL)throwError { + if ([value isKindOfClass:[NSNumber class]]) { + if ([[NSDecimalNumber notANumber] isEqualToNumber:value]) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store NaN as " + @"priority at path: %@.", + fn, pathString] + userInfo:nil]; + } else { + return NO; + } + } else if (value == (id)kCFBooleanFalse || + value == (id)kCFBooleanTrue) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store true/false " + @"as priority at path: %@.", + fn, pathString] + userInfo:nil]; + } else { + return NO; + } + } + } else if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dval = value; + if (dval[kServerValueSubKey] != nil) { + if ([dval count] > 1) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store other keys " + @"with server value keys as " + @"priority at path: %@.", + fn, pathString] + userInfo:nil]; + } else { + return NO; + } + } + } else { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store an NSDictionary " + @"as priority at path: %@.", + fn, pathString] + userInfo:nil]; + } else { + return NO; + } + } + } else if ([value isKindOfClass:[NSArray class]]) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store an NSArray as " + @"priority at path: %@.", + fn, pathString] + userInfo:nil]; + } else { + return NO; + } + } + + // It's valid! + return YES; +} +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h new file mode 100644 index 0000000..12714c7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@interface FTupleBoolBlock : NSObject + +@property(nonatomic, readwrite) BOOL boolean; +@property(nonatomic, copy) fbt_void_void block; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.m new file mode 100644 index 0000000..0e6e9a1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.m @@ -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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h" + +@implementation FTupleBoolBlock + +@synthesize boolean; +@synthesize block; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h new file mode 100644 index 0000000..7c4cc6c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import + +@interface FTupleCallbackStatus : NSObject +@property(nonatomic, copy) fbt_void_nsstring_nsstring block; +@property(nonatomic) NSString *status; +@property(nonatomic) NSString *errorReason; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.m new file mode 100644 index 0000000..fee5871 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.m @@ -0,0 +1,22 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h" + +@implementation FTupleCallbackStatus +@synthesize block; +@synthesize status; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h new file mode 100644 index 0000000..1fad277 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h @@ -0,0 +1,26 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import + +@interface FTupleFirebase : NSObject + +@property(nonatomic, strong) FIRDatabaseReference *one; +@property(nonatomic, strong) FIRDatabaseReference *two; +@property(nonatomic, strong) FIRDatabaseReference *three; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.m new file mode 100644 index 0000000..8060eb3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.m @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h" + +@implementation FTupleFirebase + +@synthesize one; +@synthesize two; +@synthesize three; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h new file mode 100644 index 0000000..f0a6fb7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h @@ -0,0 +1,28 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FTupleNodePath : NSObject + +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) id node; + +- (id)initWithNode:(id)aNode andPath:(FPath *)aPath; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.m new file mode 100644 index 0000000..d4e812b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h" + +@implementation FTupleNodePath + +@synthesize path; +@synthesize node; + +- (id)initWithNode:(id)aNode andPath:(FPath *)aPath { + self = [super init]; + if (self) { + self.path = aPath; + self.node = aNode; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h new file mode 100644 index 0000000..79d769b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FTupleObjectNode : NSObject + +- (id)initWithObject:(id)aObj andNode:(id)aNode; + +@property(nonatomic, strong) id node; +@property(nonatomic, strong) id obj; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.m new file mode 100644 index 0000000..0cb7226 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.m @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h" + +@implementation FTupleObjectNode + +@synthesize obj; +@synthesize node; + +- (id)initWithObject:(id)aObj andNode:(id)aNode { + self = [super init]; + if (self) { + self.obj = aObj; + self.node = aNode; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.h new file mode 100644 index 0000000..05b3141 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.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 + +@interface FTupleObjects : NSObject + +@property(nonatomic, strong) id objA; +@property(nonatomic, strong) id objB; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.m new file mode 100644 index 0000000..bb98eb2 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.m @@ -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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.h" + +@implementation FTupleObjects + +@synthesize objA; +@synthesize objB; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h new file mode 100644 index 0000000..4f4ee05 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import + +@interface FTupleOnDisconnect : NSObject + +@property(strong, nonatomic) NSString *pathString; +@property(strong, nonatomic) NSString *action; +@property(strong, nonatomic) id data; +@property(strong, nonatomic) fbt_void_nsstring_nsstring onComplete; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.m new file mode 100644 index 0000000..bb36fd4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.m @@ -0,0 +1,26 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h" + +@implementation FTupleOnDisconnect + +@synthesize pathString; +@synthesize action; +@synthesize data; +@synthesize onComplete; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h new file mode 100644 index 0000000..b0a515c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h @@ -0,0 +1,25 @@ +/* + * 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 + +@class FPath; + +@interface FTuplePathValue : NSObject +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) id value; +- (id)initWithPath:(FPath *)aPath value:(id)aValue; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.m new file mode 100644 index 0000000..fbe18c1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.m @@ -0,0 +1,38 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +@interface FTuplePathValue () +@property(nonatomic, strong, readwrite) id value; +@property(nonatomic, strong, readwrite) FPath *path; +@end + +@implementation FTuplePathValue +@synthesize path; +@synthesize value; + +- (id)initWithPath:(FPath *)aPath value:(id)aValue { + self = [super init]; + if (self) { + self.value = aValue; + self.path = aPath; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h new file mode 100644 index 0000000..7269c2f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h @@ -0,0 +1,30 @@ +/* + * 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 + +@interface FTupleRemovedQueriesEvents : NSObject +/** + * `FIRDatabaseQuery`s removed with [SyncPoint removeEventRegistration:] + */ +@property(nonatomic, strong, readonly) NSArray *removedQueries; +/** + * cancel events as FEvent + */ +@property(nonatomic, strong, readonly) NSArray *cancelEvents; + +- (id)initWithRemovedQueries:(NSArray *)removed cancelEvents:(NSArray *)events; +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.m new file mode 100644 index 0000000..786f0cb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.m @@ -0,0 +1,37 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h" + +@interface FTupleRemovedQueriesEvents () +@property(nonatomic, strong, readwrite) NSArray *removedQueries; +@property(nonatomic, strong, readwrite) NSArray *cancelEvents; +@end + +@implementation FTupleRemovedQueriesEvents +@synthesize removedQueries; +@synthesize cancelEvents; + +- (id)initWithRemovedQueries:(NSArray *)removed cancelEvents:(NSArray *)events { + self = [super init]; + if (self) { + self.removedQueries = removed; + self.cancelEvents = events; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h new file mode 100644 index 0000000..d80730b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import + +@interface FTupleSetIdPath : NSObject + +- (id)initWithSetId:(NSNumber *)aSetId andPath:(FPath *)aPath; + +@property(strong, nonatomic) NSNumber *setId; +@property(strong, nonatomic) FPath *path; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.m new file mode 100644 index 0000000..1213aaf --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h" + +@implementation FTupleSetIdPath + +@synthesize path; +@synthesize setId; + +- (id)initWithSetId:(NSNumber *)aSetId andPath:(FPath *)aPath { + self = [super init]; + if (self) { + self.setId = aSetId; + self.path = aPath; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h new file mode 100644 index 0000000..0873982 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FTupleStringNode : NSObject + +- (id)initWithString:(NSString *)aString andNode:(id)aNode; + +@property(nonatomic, strong) id node; +@property(nonatomic, strong) NSString *string; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.m new file mode 100644 index 0000000..baf1629 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h" + +@implementation FTupleStringNode + +@synthesize string; +@synthesize node; + +- (id)initWithString:(NSString *)aString andNode:(id)aNode { + self = [super init]; + if (self) { + self.string = aString; + self.node = aNode; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h new file mode 100644 index 0000000..e3cc372 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h" +#import + +@interface FTupleTSN : NSObject + +@property(nonatomic, strong) FTupleStringNode *from; +@property(nonatomic, strong) FTupleStringNode *to; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.m new file mode 100644 index 0000000..fd4fb32 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.m @@ -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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h" + +@implementation FTupleTSN + +@synthesize from; +@synthesize to; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h new file mode 100644 index 0000000..16ae42e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h @@ -0,0 +1,75 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@interface FTupleTransaction : NSObject + +@property(nonatomic, strong) FPath *path; +@property(nonatomic, copy) fbt_transactionresult_mutabledata update; +@property(nonatomic, copy) fbt_void_nserror_bool_datasnapshot onComplete; +@property(nonatomic) FTransactionStatus status; + +/** + * Used when combining transaction at different locations to figure out which + * one goes first. + */ +@property(nonatomic, strong) NSNumber *order; +/** + * Whether to raise local events for this transaction + */ +@property(nonatomic) BOOL applyLocally; + +/** + * Count how many times we've retried the transaction + */ +@property(nonatomic) int retryCount; + +/** + * Function to call to clean up our listener + */ +@property(nonatomic, copy) fbt_void_void unwatcher; + +/** + * Stores why a transaction was aborted + */ +@property(nonatomic, strong, readonly) NSString *abortStatus; +@property(nonatomic, strong, readonly) NSString *abortReason; + +- (void)setAbortStatus:(NSString *)abortStatus reason:(NSString *)reason; +- (NSError *)abortError; + +@property(nonatomic, strong) NSNumber *currentWriteId; + +/** + * Stores the input snapshot, before the update + */ +@property(nonatomic, strong) id currentInputSnapshot; + +/** + * Stores the unresolved (for server values) output snapshot, after the update + */ +@property(nonatomic, strong) id currentOutputSnapshotRaw; + +/** + * Stores the resolved (for server values) output snapshot, after the update + */ +@property(nonatomic, strong) id currentOutputSnapshotResolved; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.m new file mode 100644 index 0000000..829912b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.m @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FTupleTransaction () + +@property(nonatomic, strong) NSString *abortStatus; +@property(nonatomic, strong) NSString *abortReason; + +@end + +@implementation FTupleTransaction + +- (void)setAbortStatus:(NSString *)abortStatus reason:(NSString *)reason { + self.abortStatus = abortStatus; + self.abortReason = reason; +} + +- (NSError *)abortError { + return (self.abortStatus != nil) + ? [FUtilities errorForStatus:self.abortStatus + andReason:self.abortReason] + : nil; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h new file mode 100644 index 0000000..a14ab33 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@interface FTupleUserCallback : NSObject + +- (id)initWithHandle:(NSUInteger)handle; + +@property(nonatomic, copy) + fbt_void_datasnapshot_nsstring datasnapshotPrevnameCallback; +@property(nonatomic, copy) fbt_void_datasnapshot datasnapshotCallback; +@property(nonatomic, copy) fbt_void_nserror cancelCallback; +@property(nonatomic, copy) FQueryParams *queryParams; +@property(nonatomic) NSUInteger handle; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.m new file mode 100644 index 0000000..43e2fdf --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h" + +@implementation FTupleUserCallback + +@synthesize datasnapshotCallback; +@synthesize datasnapshotPrevnameCallback; +@synthesize cancelCallback; +@synthesize queryParams; +@synthesize handle; + +- (id)initWithHandle:(NSUInteger)theHandle { + self = [super init]; + if (self) { + self.handle = theHandle; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h new file mode 100644 index 0000000..6354caf --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h @@ -0,0 +1,21 @@ +#import +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" + +/** + * This is an array backed implementation of FImmutableSortedDictionary. It uses arrays and linear lookups to achieve + * good memory efficiency while maintaining good performance for small collections. It also uses less allocations than + * a comparable red black tree. To avoid degrading performance with increasing collection size it will automatically + * convert to a FTreeSortedDictionary after an insert call above a certain threshold. + */ +@interface FArraySortedDictionary : FImmutableSortedDictionary + ++ (FArraySortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator; + +- (id)initWithComparator:(NSComparator)comparator; + +#pragma mark - +#pragma mark Properties + +@property (nonatomic, copy, readonly) NSComparator comparator; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.m new file mode 100644 index 0000000..fead532 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.m @@ -0,0 +1,266 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h" + +@interface FArraySortedDictionaryEnumerator : NSEnumerator + +- (id)initWithKeys:(NSArray *)keys startPos:(NSInteger)pos isReverse:(BOOL)reverse; +- (id)nextObject; + +@property (nonatomic) NSInteger pos; +@property (nonatomic) BOOL reverse; +@property (nonatomic, strong) NSArray *keys; + +@end + +@implementation FArraySortedDictionaryEnumerator + +- (id)initWithKeys:(NSArray *)keys startPos:(NSInteger)pos isReverse:(BOOL)reverse +{ + self = [super init]; + if (self != nil) { + self->_pos = pos; + self->_reverse = reverse; + self->_keys = keys; + } + return self; +} + +- (id)nextObject +{ + NSInteger pos = self->_pos; + if (pos >= 0 && pos < self.keys.count) { + if (self.reverse) { + self->_pos--; + } else { + self->_pos++; + } + return self.keys[pos]; + } else { + return nil; + } +} + +@end + +@interface FArraySortedDictionary () + +- (id)initWithComparator:(NSComparator)comparator; + +@property (nonatomic, copy, readwrite) NSComparator comparator; +@property (nonatomic, strong) NSArray *keys; +@property (nonatomic, strong) NSArray *values; + +@end + +@implementation FArraySortedDictionary + ++ (FArraySortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator +{ + NSMutableArray *keys = [NSMutableArray arrayWithCapacity:dictionary.count]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [keys addObject:key]; + }]; + [keys sortUsingComparator:comparator]; + + [keys enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if (idx > 0) { + if (comparator(keys[idx - 1], obj) != NSOrderedAscending) { + [NSException raise:NSInvalidArgumentException format:@"Can't create FImmutableSortedDictionary with keys with same ordering!"]; + } + } + }]; + + NSMutableArray *values = [NSMutableArray arrayWithCapacity:keys.count]; + NSInteger pos = 0; + for (id key in keys) { + values[pos++] = dictionary[key]; + } + NSAssert(values.count == keys.count, @"We added as many keys as values"); + return [[FArraySortedDictionary alloc] initWithComparator:comparator keys:keys values:values]; +} + +- (id)initWithComparator:(NSComparator)comparator +{ + self = [super init]; + if (self != nil) { + self->_comparator = comparator; + self->_keys = [NSArray array]; + self->_values = [NSArray array]; + } + return self; +} + +- (id)initWithComparator:(NSComparator)comparator keys:(NSArray *)keys values:(NSArray *)values +{ + self = [super init]; + if (self != nil) { + self->_comparator = comparator; + self->_keys = keys; + self->_values = values; + } + return self; +} + +- (NSInteger) findInsertPositionForKey:(id)key +{ + NSInteger newPos = 0; + while (newPos < self.keys.count && self.comparator(self.keys[newPos], key) < NSOrderedSame) { + newPos++; + } + return newPos; +} + +- (NSInteger) findKey:(id)key +{ + if (key == nil) { + return NSNotFound; + } + for (NSInteger pos = 0; pos < self.keys.count; pos++) { + NSComparisonResult result = self.comparator(key, self.keys[pos]); + if (result == NSOrderedSame) { + return pos; + } else if (result == NSOrderedAscending) { + return NSNotFound; + } + } + return NSNotFound; +} + +- (FImmutableSortedDictionary *) insertKey:(id)key withValue:(id)value +{ + NSInteger pos = [self findKey:key]; + + if (pos == NSNotFound) { + /* + * If we're above the threshold we want to convert it to a tree backed implementation to not have + * degrading performance + */ + if (self.count >= SORTED_DICTIONARY_ARRAY_TO_RB_TREE_SIZE_THRESHOLD) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:self.count]; + for (NSInteger i = 0; i < self.keys.count; i++) { + dict[self.keys[i]] = self.values[i]; + } + dict[key] = value; + return [FTreeSortedDictionary fromDictionary:dict withComparator:self.comparator]; + } else { + NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys]; + NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values]; + NSInteger newPos = [self findInsertPositionForKey:key]; + [newKeys insertObject:key atIndex:newPos]; + [newValues insertObject:value atIndex:newPos]; + return [[FArraySortedDictionary alloc] initWithComparator:self.comparator keys:newKeys values:newValues]; + } + } else { + NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys]; + NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values]; + newKeys[pos] = key; + newValues[pos] = value; + return [[FArraySortedDictionary alloc] initWithComparator:self.comparator keys:newKeys values:newValues]; + } +} + +- (FImmutableSortedDictionary *) removeKey:(id)key +{ + NSInteger pos = [self findKey:key]; + if (pos == NSNotFound) { + return self; + } else { + NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys]; + NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values]; + [newKeys removeObjectAtIndex:pos]; + [newValues removeObjectAtIndex:pos]; + return [[FArraySortedDictionary alloc] initWithComparator:self.comparator keys:newKeys values:newValues]; + } +} + +- (id) get:(id)key +{ + NSInteger pos = [self findKey:key]; + if (pos == NSNotFound) { + return nil; + } else { + return self.values[pos]; + } +} + +- (id) getPredecessorKey:(id) key { + NSInteger pos = [self findKey:key]; + if (pos == NSNotFound) { + [NSException raise:NSInternalInconsistencyException format:@"Can't get predecessor key for non-existent key"]; + return nil; + } else if (pos == 0) { + return nil; + } else { + return self.keys[pos - 1]; + } +} + +- (BOOL) isEmpty { + return self.keys.count == 0; +} + +- (int) count +{ + return (int)self.keys.count; +} + +- (id) minKey +{ + return [self.keys firstObject]; +} + +- (id) maxKey +{ + return [self.keys lastObject]; +} + +- (void) enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block +{ + [self enumerateKeysAndObjectsReverse:NO usingBlock:block]; +} + +- (void) enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block +{ + if (reverse) { + BOOL stop = NO; + for (NSInteger i = self.keys.count - 1; i >= 0; i--) { + block(self.keys[i], self.values[i], &stop); + if (stop) return; + } + } else { + BOOL stop = NO; + for (NSInteger i = 0; i < self.keys.count; i++) { + block(self.keys[i], self.values[i], &stop); + if (stop) return; + } + } +} + +- (BOOL) contains:(id)key { + return [self findKey:key] != NSNotFound; +} + +- (NSEnumerator *) keyEnumerator { + return [self.keys objectEnumerator]; +} + +- (NSEnumerator *) keyEnumeratorFrom:(id)startKey { + NSInteger startPos = [self findInsertPositionForKey:startKey]; + return [[FArraySortedDictionaryEnumerator alloc] initWithKeys:self.keys startPos:startPos isReverse:NO]; +} + +- (NSEnumerator *) reverseKeyEnumerator { + return [self.keys reverseObjectEnumerator]; +} + +- (NSEnumerator *) reverseKeyEnumeratorFrom:(id)startKey { + NSInteger startPos = [self findInsertPositionForKey:startKey]; + // if there's no exact match, findKeyOrInsertPosition will return the index *after* the closest match, but + // since this is a reverse iterator, we want to start just *before* the closest match. + if (startPos >= self.keys.count || self.comparator(self.keys[startPos], startKey) != NSOrderedSame) { + startPos -= 1; + } + return [[FArraySortedDictionaryEnumerator alloc] initWithKeys:self.keys startPos:startPos isReverse:YES]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h new file mode 100644 index 0000000..d6687d8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h @@ -0,0 +1,54 @@ +/** + * @fileoverview Implementation of an immutable SortedMap using a Left-leaning + * Red-Black Tree, adapted from the implementation in Mugs + * (http://mads379.github.com/mugs/) by Mads Hartmann Jensen + * (mads379@gmail.com). + * + * Original paper on Left-leaning Red-Black Trees: + * http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf + * + * Invariant 1: No red node has a red child + * Invariant 2: Every leaf path has the same number of black nodes + * Invariant 3: Only the left child can be red (left leaning) + */ + +#import + +/** + * The size threshold where we use a tree backed sorted map instead of an array backed sorted map. + * This is a more or less arbitrary chosen value, that was chosen to be large enough to fit most of object kind + * of Firebase data, but small enough to not notice degradation in performance for inserting and lookups. + * Feel free to empirically determine this constant, but don't expect much gain in real world performance. + */ +#define SORTED_DICTIONARY_ARRAY_TO_RB_TREE_SIZE_THRESHOLD 25 + +@interface FImmutableSortedDictionary : NSObject + ++ (FImmutableSortedDictionary *)dictionaryWithComparator:(NSComparator)comparator; ++ (FImmutableSortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator; + +- (FImmutableSortedDictionary *) insertKey:(id)aKey withValue:(id)aValue; +- (FImmutableSortedDictionary *) removeKey:(id)aKey; +- (id) get:(id) key; +- (id) getPredecessorKey:(id) key; +- (BOOL) isEmpty; +- (int) count; +- (id) minKey; +- (id) maxKey; +- (void) enumerateKeysAndObjectsUsingBlock:(void(^)(id key, id value, BOOL *stop))block; +- (void) enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void(^)(id key, id value, BOOL *stop))block; +- (BOOL) contains:(id)key; +- (NSEnumerator *) keyEnumerator; +- (NSEnumerator *) keyEnumeratorFrom:(id)startKey; +- (NSEnumerator *) reverseKeyEnumerator; +- (NSEnumerator *) reverseKeyEnumeratorFrom:(id)startKey; + +#pragma mark - +#pragma mark Methods similar to NSMutableDictionary + +- (FImmutableSortedDictionary *) setObject:(id)anObject forKey:(id)aKey; +- (id) objectForKey:(id)key; +- (FImmutableSortedDictionary *) removeObjectForKey:(id)aKey; + +@end + diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.m new file mode 100644 index 0000000..eb4fa8f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.m @@ -0,0 +1,142 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h" + +#define THROW_ABSTRACT_METHOD_EXCEPTION(sel) do { \ + @throw [NSException exceptionWithName:NSInternalInconsistencyException \ + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(sel)] \ + userInfo:nil]; \ +} while(0) + +@implementation FImmutableSortedDictionary + ++ (FImmutableSortedDictionary *)dictionaryWithComparator:(NSComparator)comparator +{ + return [[FArraySortedDictionary alloc] initWithComparator:comparator]; +} + ++ (FImmutableSortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator +{ + if (dictionary.count <= SORTED_DICTIONARY_ARRAY_TO_RB_TREE_SIZE_THRESHOLD) { + return [FArraySortedDictionary fromDictionary:dictionary withComparator:comparator]; + } else { + return [FTreeSortedDictionary fromDictionary:dictionary withComparator:comparator]; + } +} + +- (FImmutableSortedDictionary *) insertKey:(id)aKey withValue:(id)aValue { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(insertKey:withValue:)); +} + +- (FImmutableSortedDictionary *) removeKey:(id)aKey { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(removeKey:)); +} + +- (id) get:(id) key { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(get:)); +} + +- (id) getPredecessorKey:(id) key { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(getPredecessorKey:)); +} + +- (BOOL) isEmpty { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(isEmpty)); +} + +- (int) count { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector((count))); +} + +- (id) minKey { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(minKey)); +} + +- (id) maxKey { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(maxKey)); +} + +- (void) enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(enumerateKeysAndObjectsUsingBlock:)); +} + +- (void) enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(enumerateKeysAndObjectsReverse:usingBlock:)); +} + +- (BOOL) contains:(id)key { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(contains:)); +} + +- (NSEnumerator *) keyEnumerator { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(keyEnumerator)); +} + +- (NSEnumerator *) keyEnumeratorFrom:(id)startKey { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(keyEnumeratorFrom:)); +} + +- (NSEnumerator *) reverseKeyEnumerator { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(reverseKeyEnumerator)); +} + +- (NSEnumerator *) reverseKeyEnumeratorFrom:(id)startKey { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(reverseKeyEnumeratorFrom:)); +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[FImmutableSortedDictionary class]]) { + return NO; + } + FImmutableSortedDictionary *other = (FImmutableSortedDictionary *)object; + if (self.count != other.count) { + return NO; + } + __block BOOL isEqual = YES; + [self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + id otherValue = [other objectForKey:key]; + isEqual = isEqual && (value == otherValue || [value isEqual:otherValue]); + *stop = !isEqual; + }]; + return isEqual; +} + +- (NSUInteger)hash { + __block NSUInteger hash = 0; + [self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + hash = (hash * 31 + [key hash]) * 17 + [value hash]; + }]; + return hash; +} + +- (NSString *)description { + NSMutableString *str = [[NSMutableString alloc] init]; + __block BOOL first = YES; + [str appendString:@"{ "]; + [self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + if (!first) { + [str appendString:@", "]; + } + first = NO; + [str appendString:[NSString stringWithFormat:@"%@: %@", key, value]]; + }]; + [str appendString:@" }"]; + return str; +} + +#pragma mark - +#pragma mark Methods similar to NSMutableDictionary + +- (FImmutableSortedDictionary *) setObject:(__unsafe_unretained id)anObject forKey:(__unsafe_unretained id)aKey { + return [self insertKey:aKey withValue:anObject]; +} + +- (FImmutableSortedDictionary *) removeObjectForKey:(__unsafe_unretained id)aKey { + return [self removeKey:aKey]; +} + +- (id) objectForKey:(__unsafe_unretained id)key { + return [self get:key]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h new file mode 100644 index 0000000..ac15c2f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h @@ -0,0 +1,22 @@ +#import + +@interface FImmutableSortedSet : NSObject + ++ (FImmutableSortedSet *)setWithKeysFromDictionary:(NSDictionary *)array comparator:(NSComparator)comparator; + +- (BOOL)containsObject:(id)object; +- (FImmutableSortedSet *)addObject:(id)object; +- (FImmutableSortedSet *)removeObject:(id)object; +- (id)firstObject; +- (id)lastObject; +- (NSUInteger)count; +- (BOOL)isEmpty; + +- (id)predecessorEntry:(id)entry; + +- (void)enumerateObjectsUsingBlock:(void (^)(id obj, BOOL *stop))block; +- (void)enumerateObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id obj, BOOL *stop))block; + +- (NSEnumerator *)objectEnumerator; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.m new file mode 100644 index 0000000..f284637 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.m @@ -0,0 +1,115 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" + +@interface FImmutableSortedSet () + +@property (nonatomic, strong) FImmutableSortedDictionary *dictionary; + +@end + +@implementation FImmutableSortedSet + ++ (FImmutableSortedSet *)setWithKeysFromDictionary:(NSDictionary *)dictionary comparator:(NSComparator)comparator +{ + FImmutableSortedDictionary *setDict = [FImmutableSortedDictionary fromDictionary:dictionary withComparator:comparator]; + return [[FImmutableSortedSet alloc] initWithDictionary:setDict]; +} + +- (id)initWithDictionary:(FImmutableSortedDictionary *)dictionary +{ + self = [super init]; + if (self != nil) { + self->_dictionary = dictionary; + } + return self; +} + +- (BOOL)contains:(id)object +{ + return [self.dictionary contains:object]; +} + +- (FImmutableSortedSet *)addObject:(id)object +{ + FImmutableSortedDictionary *newDictionary = [self.dictionary insertKey:object withValue:[NSNull null]]; + if (newDictionary != self.dictionary) { + return [[FImmutableSortedSet alloc] initWithDictionary:newDictionary]; + } else { + return self; + } +} + +- (FImmutableSortedSet *)removeObject:(id)object +{ + FImmutableSortedDictionary *newDictionary = [self.dictionary removeObjectForKey:object]; + if (newDictionary != self.dictionary) { + return [[FImmutableSortedSet alloc] initWithDictionary:newDictionary]; + } else { + return self; + } +} + +- (BOOL)containsObject:(id)object +{ + return [self.dictionary contains:object]; +} + +- (id)firstObject +{ + return [self.dictionary minKey]; +} + +- (id)lastObject +{ + return [self.dictionary maxKey]; +} + +- (id)predecessorEntry:(id)entry +{ + return [self.dictionary getPredecessorKey:entry]; +} + +- (NSUInteger)count +{ + return [self.dictionary count]; +} + +- (BOOL)isEmpty +{ + return [self.dictionary isEmpty]; +} + +- (void)enumerateObjectsUsingBlock:(void (^)(id, BOOL *))block +{ + [self enumerateObjectsReverse:NO usingBlock:block]; +} + +- (void)enumerateObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, BOOL *))block +{ + [self.dictionary enumerateKeysAndObjectsReverse:reverse usingBlock:^(id key, id value, BOOL *stop) { + block(key, stop); + }]; +} + +- (NSEnumerator *)objectEnumerator +{ + return [self.dictionary keyEnumerator]; +} + +- (NSString *)description +{ + NSMutableString *str = [[NSMutableString alloc] init]; + __block BOOL first = YES; + [str appendString:@"FImmutableSortedSet ( "]; + [self enumerateObjectsUsingBlock:^(id obj, BOOL *stop) { + if (!first) { + [str appendString:@", "]; + } + first = NO; + [str appendString:[NSString stringWithFormat:@"%@", obj]]; + }]; + [str appendString:@" )"]; + return str; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h new file mode 100644 index 0000000..4cad969 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h @@ -0,0 +1,27 @@ +#import +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h" + +@interface FLLRBEmptyNode : NSObject + ++ (id)emptyNode; + +- (id)copyWith:(id) aKey withValue:(id) aValue withColor:(FLLRBColor*) aColor withLeft:(id)aLeft withRight:(id)aRight; +- (id) insertKey:(id) aKey forValue:(id)aValue withComparator:(NSComparator)aComparator; +- (id) remove:(id) aKey withComparator:(NSComparator)aComparator; +- (int) count; +- (BOOL) isEmpty; +- (BOOL) inorderTraversal:(BOOL (^)(id key, id value))action; +- (BOOL) reverseTraversal:(BOOL (^)(id key, id value))action; +- (id) min; +- (id) minKey; +- (id) maxKey; +- (BOOL) isRed; +- (int) check; + +@property (nonatomic, strong) id key; +@property (nonatomic, strong) id value; +@property (nonatomic, strong) FLLRBColor* color; +@property (nonatomic, strong) id left; +@property (nonatomic, strong) id right; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.m new file mode 100644 index 0000000..0de01e6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.m @@ -0,0 +1,72 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h" + +@implementation FLLRBEmptyNode + +@synthesize key, value, color, left, right; + +- (NSString *) description { + return [NSString stringWithFormat:@"[key=%@ val=%@ color=%@]", key, value, + (color != nil ? @"true" : @"false")]; +} + ++ (id)emptyNode +{ + static dispatch_once_t pred = 0; + __strong static id _sharedObject = nil; + dispatch_once(&pred, ^{ + _sharedObject = [[self alloc] init]; // or some other init method + }); + return _sharedObject; +} + +- (id)copyWith:(id) aKey withValue:(id) aValue withColor:(FLLRBColor*) aColor withLeft:(id)aLeft withRight:(id)aRight { + return self; +} + +- (id) insertKey:(id) aKey forValue:(id)aValue withComparator:(NSComparator)aComparator { + FLLRBValueNode* result = [[FLLRBValueNode alloc] initWithKey:aKey withValue:aValue withColor:nil withLeft:nil withRight:nil]; + return result; +} + +- (id) remove:(id) key withComparator:(NSComparator)aComparator { + return self; +} + +- (int) count { + return 0; +} + +- (BOOL) isEmpty { + return YES; +} + +- (BOOL) inorderTraversal:(BOOL (^)(id key, id value))action { + return NO; +} + +- (BOOL) reverseTraversal:(BOOL (^)(id key, id value))action { + return NO; +} + +- (id) min { + return self; +} + +- (id) minKey { + return nil; +} + +- (id) maxKey { + return nil; +} + +- (BOOL) isRed { + return NO; +} + +- (int) check { + return 0; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h new file mode 100644 index 0000000..09b234c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h @@ -0,0 +1,29 @@ +#import + +#define RED @true +#define BLACK @false + +typedef NSNumber FLLRBColor; + +@protocol FLLRBNode + +- (id)copyWith:(id) aKey withValue:(id) aValue withColor:(FLLRBColor*) aColor withLeft:(id)aLeft withRight:(id)aRight; +- (id) insertKey:(id) aKey forValue:(id)aValue withComparator:(NSComparator)aComparator; +- (id) remove:(id) key withComparator:(NSComparator)aComparator; +- (int) count; +- (BOOL) isEmpty; +- (BOOL) inorderTraversal:(BOOL (^)(id key, id value))action; +- (BOOL) reverseTraversal:(BOOL (^)(id key, id value))action; +- (id) min; +- (id) minKey; +- (id) maxKey; +- (BOOL) isRed; +- (int) check; + +@property (nonatomic, strong) id key; +@property (nonatomic, strong) id value; +@property (nonatomic, strong) FLLRBColor* color; +@property (nonatomic, strong) id left; +@property (nonatomic, strong) id right; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h new file mode 100644 index 0000000..04eef4f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h @@ -0,0 +1,29 @@ +#import +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h" + +@interface FLLRBValueNode : NSObject + + +- (id)initWithKey:(id) key withValue:(id) value withColor:(FLLRBColor*) color withLeft:(id)left withRight:(id)right; +- (id)copyWith:(id) aKey withValue:(id) aValue withColor:(FLLRBColor*) aColor withLeft:(id)aLeft withRight:(id)aRight; +- (id) insertKey:(id) aKey forValue:(id)aValue withComparator:(NSComparator)aComparator; +- (id) remove:(id) aKey withComparator:(NSComparator)aComparator; +- (int) count; +- (BOOL) isEmpty; +- (BOOL) inorderTraversal:(BOOL (^)(id key, id value))action; +- (BOOL) reverseTraversal:(BOOL (^)(id key, id value))action; +- (id) min; +- (id) minKey; +- (id) maxKey; +- (BOOL) isRed; +- (int) check; + +- (BOOL) checkMaxDepth; + +@property (nonatomic, strong) id key; +@property (nonatomic, strong) id value; +@property (nonatomic, strong) FLLRBColor* color; +@property (nonatomic, strong) id left; +@property (nonatomic, strong) id right; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.m new file mode 100644 index 0000000..da2c871 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.m @@ -0,0 +1,230 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h" + +@implementation FLLRBValueNode + +@synthesize key, value, color, left, right; + +- (NSString *) description { + return [NSString stringWithFormat:@"[key=%@ val=%@ color=%@]", key, value, + (color != nil ? @"true" : @"false")]; +} + +- (id)initWithKey:(__unsafe_unretained id) aKey withValue:(__unsafe_unretained id) aValue withColor:(__unsafe_unretained FLLRBColor*) aColor withLeft:(__unsafe_unretained id)aLeft withRight:(__unsafe_unretained id)aRight +{ + self = [super init]; + if (self) { + self.key = aKey; + self.value = aValue; + self.color = aColor != nil ? aColor : RED; + self.left = aLeft != nil ? aLeft : [FLLRBEmptyNode emptyNode]; + self.right = aRight != nil ? aRight : [FLLRBEmptyNode emptyNode]; + } + return self; +} + +- (id)copyWith:(__unsafe_unretained id) aKey withValue:(__unsafe_unretained id) aValue withColor:(__unsafe_unretained FLLRBColor*) aColor withLeft:(__unsafe_unretained id)aLeft withRight:(__unsafe_unretained id)aRight { + return [[FLLRBValueNode alloc] initWithKey:(aKey != nil) ? aKey : self.key + withValue:(aValue != nil) ? aValue : self.value + withColor:(aColor != nil) ? aColor : self.color + withLeft:(aLeft != nil) ? aLeft : self.left + withRight:(aRight != nil) ? aRight : self.right]; +} + +- (int) count { + return [self.left count] + 1 + [self.right count]; +} + +- (BOOL) isEmpty { + return NO; +} + +/** +* Early terminates if aciton returns YES. +* @return The first truthy value returned by action, or the last falsey value returned by action. +*/ +- (BOOL) inorderTraversal:(BOOL (^)(id key, id value))action { + return [self.left inorderTraversal:action] || + action(self.key, self.value) || + [self.right inorderTraversal:action]; +} + +- (BOOL) reverseTraversal:(BOOL (^)(id key, id value))action { + return [self.right reverseTraversal:action] || + action(self.key, self.value) || + [self.left reverseTraversal:action]; +} + +- (id) min { + if([self.left isEmpty]) { + return self; + } + else { + return [self.left min]; + } +} + +- (id) minKey { + return [[self min] key]; +} + +- (id) maxKey { + if([self.right isEmpty]) { + return self.key; + } + else { + return [self.right maxKey]; + } +} + +- (id) insertKey:(__unsafe_unretained id) aKey forValue:(__unsafe_unretained id)aValue withComparator:(NSComparator)aComparator { + NSComparisonResult cmp = aComparator(aKey, self.key); + FLLRBValueNode* n = self; + + if(cmp == NSOrderedAscending) { + n = [n copyWith:nil withValue:nil withColor:nil withLeft:[n.left insertKey:aKey forValue:aValue withComparator:aComparator] withRight:nil]; + } + else if(cmp == NSOrderedSame) { + n = [n copyWith:nil withValue:aValue withColor:nil withLeft:nil withRight:nil]; + } + else { + n = [n copyWith:nil withValue:nil withColor:nil withLeft:nil withRight:[n.right insertKey:aKey forValue:aValue withComparator:aComparator]]; + } + + return [n fixUp]; +} + +- (id) removeMin { + + if([self.left isEmpty]) { + return [FLLRBEmptyNode emptyNode]; + } + + FLLRBValueNode* n = self; + if(! [n.left isRed] && ! [n.left.left isRed]) { + n = [n moveRedLeft]; + } + + n = [n copyWith:nil withValue:nil withColor:nil withLeft:[(FLLRBValueNode*)n.left removeMin] withRight:nil]; + return [n fixUp]; +} + + +- (id) fixUp { + FLLRBValueNode* n = self; + if([n.right isRed] && ! [n.left isRed]) n = [n rotateLeft]; + if([n.left isRed] && [n.left.left isRed]) n = [n rotateRight]; + if([n.left isRed] && [n.right isRed]) n = [n colorFlip]; + return n; +} + +- (FLLRBValueNode*) moveRedLeft { + FLLRBValueNode* n = [self colorFlip]; + if([n.right.left isRed]) { + n = [n copyWith:nil withValue:nil withColor:nil withLeft:nil withRight:[(FLLRBValueNode*)n.right rotateRight]]; + n = [n rotateLeft]; + n = [n colorFlip]; + } + return n; +} + +- (FLLRBValueNode*) moveRedRight { + FLLRBValueNode* n = [self colorFlip]; + if([n.left.left isRed]) { + n = [n rotateRight]; + n = [n colorFlip]; + } + return n; +} + +- (id) rotateLeft { + id nl = [self copyWith:nil withValue:nil withColor:RED withLeft:nil withRight:self.right.left]; + return [self.right copyWith:nil withValue:nil withColor:self.color withLeft:nl withRight:nil];; +} + +- (id) rotateRight { + id nr = [self copyWith:nil withValue:nil withColor:RED withLeft:self.left.right withRight:nil]; + return [self.left copyWith:nil withValue:nil withColor:self.color withLeft:nil withRight:nr]; +} + +- (id) colorFlip { + id nleft = [self.left copyWith:nil withValue:nil withColor:[NSNumber numberWithBool:![self.left.color boolValue]] withLeft:nil withRight:nil]; + id nright = [self.right copyWith:nil withValue:nil withColor:[NSNumber numberWithBool:![self.right.color boolValue]] withLeft:nil withRight:nil]; + + return [self copyWith:nil withValue:nil withColor:[NSNumber numberWithBool:![self.color boolValue]] withLeft:nleft withRight:nright]; +} + +- (id) remove:(__unsafe_unretained id) aKey withComparator:(NSComparator)comparator { + id smallest; + FLLRBValueNode* n = self; + + if(comparator(aKey, n.key) == NSOrderedAscending) { + if(![n.left isEmpty] && ![n.left isRed] && ![n.left.left isRed]) { + n = [n moveRedLeft]; + } + n = [n copyWith:nil withValue:nil withColor:nil withLeft:[n.left remove:aKey withComparator:comparator] withRight:nil]; + } + else { + if([n.left isRed]) { + n = [n rotateRight]; + } + + if(![n.right isEmpty] && ![n.right isRed] && ![n.right.left isRed]) { + n = [n moveRedRight]; + } + + if(comparator(aKey, n.key) == NSOrderedSame) { + if([n.right isEmpty]) { + return [FLLRBEmptyNode emptyNode]; + } + else { + smallest = [n.right min]; + n = [n copyWith:smallest.key withValue:smallest.value withColor:nil withLeft:nil withRight:[(FLLRBValueNode*)n.right removeMin]]; + } + } + n = [n copyWith:nil withValue:nil withColor:nil withLeft:nil withRight:[n.right remove:aKey withComparator:comparator]]; + } + return [n fixUp]; +} + +- (BOOL) isRed { + return [self.color boolValue]; +} + +- (BOOL) checkMaxDepth { + int blackDepth = [self check]; + if(pow(2.0, blackDepth) <= ([self count] + 1)) { + return YES; + } + else { + return NO; + } +} + +- (int) check { + int blackDepth = 0; + + if([self isRed] && [self.left isRed]) { + @throw [[NSException alloc] initWithName:@"check" reason:@"Red node has a red child" userInfo:nil]; + } + + if([self.right isRed]) { + @throw [[NSException alloc] initWithName:@"check" reason:@"Right child is red" userInfo:nil]; + } + + blackDepth = [self.left check]; +// NSLog(err); + if(blackDepth != [self.right check]) { + NSString* err = [NSString stringWithFormat:@"(%@ -> %@)blackDepth: %d ; self.right check: %d", self.value, [self.color boolValue] ? @"red" : @"black", blackDepth, [self.right check]]; +// return 10; + @throw [[NSException alloc] initWithName:@"check" reason:err userInfo:nil]; + } + else { + int ret = blackDepth + ([self isRed] ? 0 : 1); +// NSLog(@"black depth is: %d; other is: %d, ret is: %d", blackDepth, ([self isRed] ? 0 : 1), ret); + return ret; + } +} + + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h new file mode 100644 index 0000000..395fad6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h @@ -0,0 +1,30 @@ +/** + * @fileoverview Implementation of an immutable SortedMap using a Left-leaning + * Red-Black Tree, adapted from the implementation in Mugs + * (http://mads379.github.com/mugs/) by Mads Hartmann Jensen + * (mads379@gmail.com). + * + * Original paper on Left-leaning Red-Black Trees: + * http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf + * + * Invariant 1: No red node has a red child + * Invariant 2: Every leaf path has the same number of black nodes + * Invariant 3: Only the left child can be red (left leaning) + */ + +#import +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h" + +@interface FTreeSortedDictionary : FImmutableSortedDictionary + +@property (nonatomic, copy, readonly) NSComparator comparator; +@property (nonatomic, strong, readonly) id root; + +- (id)initWithComparator:(NSComparator)aComparator; + +// Override methods to return subtype +- (FTreeSortedDictionary *) insertKey:(id)aKey withValue:(id)aValue; +- (FTreeSortedDictionary *) removeKey:(id)aKey; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.m new file mode 100644 index 0000000..d80b5cb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.m @@ -0,0 +1,326 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h" + +typedef void (^fbt_void_nsnumber_int)(NSNumber* color, NSUInteger chunkSize); + +@interface FTreeSortedDictionary () + +@property (nonatomic, strong) id root; +@property (nonatomic, copy, readwrite) NSComparator comparator; + +@end + +@implementation FTreeSortedDictionary + +- (id)initWithComparator:(NSComparator)aComparator { + self = [super init]; + if (self) { + self.root = [FLLRBEmptyNode emptyNode]; + self.comparator = aComparator; + } + return self; +} + +- (id)initWithComparator:(NSComparator)aComparator withRoot:(__unsafe_unretained id)aRoot { + self = [super init]; + if (self) { + self.root = aRoot; + self.comparator = aComparator; + } + return self; +} + +/** + * Returns a copy of the map, with the specified key/value added or replaced. + */ +- (FTreeSortedDictionary *) insertKey:(__unsafe_unretained id)aKey withValue:(__unsafe_unretained id)aValue { + return [[FTreeSortedDictionary alloc] initWithComparator:self.comparator + withRoot:[[self.root insertKey:aKey forValue:aValue withComparator:self.comparator] + copyWith:nil + withValue:nil + withColor:BLACK + withLeft:nil + withRight:nil]]; +} + + +- (FTreeSortedDictionary *) removeKey:(__unsafe_unretained id)aKey { + // Remove is somewhat expensive even if the key doesn't exist (the tree does rebalancing and stuff). So avoid it. + if (![self contains:aKey]) { + return self; + } else { + return [[FTreeSortedDictionary alloc] + initWithComparator:self.comparator + withRoot:[[self.root remove:aKey withComparator:self.comparator] + copyWith:nil + withValue:nil + withColor:BLACK + withLeft:nil + withRight:nil]]; + } +} + +- (id) get:(__unsafe_unretained id) key { + if (key == nil) { + return nil; + } + NSComparisonResult cmp; + id node = self.root; + while(![node isEmpty]) { + cmp = self.comparator(key, node.key); + if(cmp == NSOrderedSame) { + return node.value; + } + else if (cmp == NSOrderedAscending) { + node = node.left; + } + else { + node = node.right; + } + } + return nil; +} + +- (id) getPredecessorKey:(__unsafe_unretained id) key { + NSComparisonResult cmp; + id node = self.root; + id rightParent = nil; + while(![node isEmpty]) { + cmp = self.comparator(key, node.key); + if(cmp == NSOrderedSame) { + if(![node.left isEmpty]) { + node = node.left; + while(! [node.right isEmpty]) { + node = node.right; + } + return node.key; + } + else if (rightParent != nil) { + return rightParent.key; + } + else { + return nil; + } + } + else if (cmp == NSOrderedAscending) { + node = node.left; + } + else if (cmp == NSOrderedDescending) { + rightParent = node; + node = node.right; + } + } + @throw [NSException exceptionWithName:@"NonexistentKey" reason:@"getPredecessorKey called with nonexistent key." userInfo:@{@"key": [key description] }]; +} + +- (BOOL) isEmpty { + return [self.root isEmpty]; +} + +- (int) count { + return [self.root count]; +} + +- (id) minKey { + return [self.root minKey]; +} + +- (id) maxKey { + return [self.root maxKey]; +} + +- (void) enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block +{ + [self enumerateKeysAndObjectsReverse:NO usingBlock:block]; +} + +- (void) enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block +{ + if (reverse) { + __block BOOL stop = NO; + [self.root reverseTraversal:^BOOL(id key, id value) { + block(key, value, &stop); + return stop; + }]; + } else { + __block BOOL stop = NO; + [self.root inorderTraversal:^BOOL(id key, id value) { + block(key, value, &stop); + return stop; + }]; + } +} + +- (BOOL) contains:(__unsafe_unretained id)key { + return ([self objectForKey:key] != nil); +} + +- (NSEnumerator *) keyEnumerator { + return [[FTreeSortedDictionaryEnumerator alloc] + initWithImmutableSortedDictionary:self startKey:nil isReverse:NO]; +} + +- (NSEnumerator *) keyEnumeratorFrom:(id)startKey { + return [[FTreeSortedDictionaryEnumerator alloc] + initWithImmutableSortedDictionary:self startKey:startKey isReverse:NO]; +} + +- (NSEnumerator *) reverseKeyEnumerator { + return [[FTreeSortedDictionaryEnumerator alloc] + initWithImmutableSortedDictionary:self startKey:nil isReverse:YES]; +} + +- (NSEnumerator *) reverseKeyEnumeratorFrom:(id)startKey { + return [[FTreeSortedDictionaryEnumerator alloc] + initWithImmutableSortedDictionary:self startKey:startKey isReverse:YES]; +} + + +#pragma mark - +#pragma mark Tree Builder + +// Code to efficiently build a RB Tree +typedef struct _base1_2list { + unsigned int bits; + unsigned short count; + unsigned short current; +} Base1_2List; + +Base1_2List *base1_2List_new(unsigned int length); +void base1_2List_free(Base1_2List* list); +unsigned int log_base2(unsigned int num); +BOOL base1_2List_next(Base1_2List* list); + +unsigned int log_base2(unsigned int num) { + return (unsigned int)(log(num) / log(2)); +} + +/** + * Works like an iterator, so it moves to the next bit. Do not call more than list->count times. + * @return whether or not the next bit is a 1 in base {1,2}. + */ +BOOL base1_2List_next(Base1_2List* list) { + BOOL result = !(list->bits & (0x1 << list->current)); + list->current--; + return result; +} + +static inline unsigned bit_mask(int x) { + return (x >= sizeof(unsigned) * CHAR_BIT) ? (unsigned) -1 : (1U << x) - 1; +} + +/** + * We represent the base{1,2} number as the combination of a binary number and a number of bits that we care about + * We iterate backwards, from most significant bit to least, to build up the llrb nodes. 0 base 2 => 1 base {1,2}, 1 base 2 => 2 base {1,2} + */ +Base1_2List *base1_2List_new(unsigned int length) { + size_t sz = sizeof(Base1_2List); + Base1_2List* list = calloc(1, sz); + // Calculate the number of bits that we care about + list->count = (unsigned short)log_base2(length + 1); + unsigned int mask = bit_mask(list->count); + list->bits = (length + 1) & mask; + list->current = list->count - 1; + return list; +} + + +void base1_2List_free(Base1_2List* list) { + free(list); +} + ++ (id) buildBalancedTree:(NSArray *)keys dictionary:(NSDictionary *)dictionary subArrayStartIndex:(NSUInteger)startIndex length:(NSUInteger)length { + length = MIN(keys.count - startIndex, length); // Bound length by the actual length of the array + if (length == 0) { + return nil; + } else if (length == 1) { + id key = keys[startIndex]; + return [[FLLRBValueNode alloc] initWithKey:key withValue:dictionary[key] withColor:BLACK withLeft:nil withRight:nil]; + } else { + NSUInteger middle = length / 2; + id left = [FTreeSortedDictionary buildBalancedTree:keys dictionary:dictionary subArrayStartIndex:startIndex length:middle]; + id right = [FTreeSortedDictionary buildBalancedTree:keys dictionary:dictionary subArrayStartIndex:(startIndex+middle+1) length:middle]; + id key = keys[startIndex + middle]; + return [[FLLRBValueNode alloc] initWithKey:key withValue:dictionary[key] withColor:BLACK withLeft:left withRight:right]; + } +} + ++ (id) rootFrom12List:(Base1_2List *)base1_2List keyList:(NSArray *)keyList dictionary:(NSDictionary *)dictionary { + __block id root = nil; + __block id node = nil; + __block NSUInteger index = keyList.count; + + fbt_void_nsnumber_int buildPennant = ^(NSNumber* color, NSUInteger chunkSize) { + NSUInteger startIndex = index - chunkSize + 1; + index -= chunkSize; + id key = keyList[index]; + id childTree = [self buildBalancedTree:keyList dictionary:dictionary subArrayStartIndex:startIndex length:(chunkSize - 1)]; + id pennant = [[FLLRBValueNode alloc] initWithKey:key withValue:dictionary[key] withColor:color withLeft:nil withRight:childTree]; + //attachPennant(pennant); + if (node) { + node.left = pennant; + node = pennant; + } else { + root = pennant; + node = pennant; + } + }; + + for (int i = 0; i < base1_2List->count; ++i) { + BOOL isOne = base1_2List_next(base1_2List); + NSUInteger chunkSize = (NSUInteger)pow(2.0, base1_2List->count - (i + 1)); + if (isOne) { + buildPennant(BLACK, chunkSize); + } else { + buildPennant(BLACK, chunkSize); + buildPennant(RED, chunkSize); + } + } + return root; +} + +/** + * Uses the algorithm linked here: + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.46.1458 + */ + ++ (FImmutableSortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator +{ + // Steps: + // 0. Sort the array + // 1. Calculate the 1-2 number + // 2. Build From 1-2 number + // 0. for each digit in 1-2 number + // 0. calculate chunk size + // 1. build 1 or 2 pennants of that size + // 2. attach pennants and update node pointer + // 1. return root + NSMutableArray *sortedKeyList = [NSMutableArray arrayWithCapacity:dictionary.count]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [sortedKeyList addObject:key]; + }]; + [sortedKeyList sortUsingComparator:comparator]; + + [sortedKeyList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if (idx > 0) { + if (comparator(sortedKeyList[idx - 1], obj) != NSOrderedAscending) { + [NSException raise:NSInvalidArgumentException format:@"Can't create FImmutableSortedDictionary with keys with same ordering!"]; + } + } + }]; + + Base1_2List* list = base1_2List_new((unsigned int)sortedKeyList.count); + id root = [self rootFrom12List:list keyList:sortedKeyList dictionary:dictionary]; + base1_2List_free(list); + + if (root != nil) { + return [[FTreeSortedDictionary alloc] initWithComparator:comparator withRoot:root]; + } else { + return [[FTreeSortedDictionary alloc] initWithComparator:comparator]; + } +} + +@end + diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h new file mode 100644 index 0000000..a582e14 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h @@ -0,0 +1,9 @@ +#import +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h" + +@interface FTreeSortedDictionaryEnumerator : NSEnumerator + +- (id)initWithImmutableSortedDictionary:(FTreeSortedDictionary *)aDict startKey:(id)startKey isReverse:(BOOL)reverse; +- (id)nextObject; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.m new file mode 100644 index 0000000..473abac --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.m @@ -0,0 +1,83 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h" + +@interface FTreeSortedDictionaryEnumerator() +@property (nonatomic, strong) FTreeSortedDictionary* immutableSortedDictionary; +@property (nonatomic, strong) NSMutableArray* stack; +@property (nonatomic) BOOL isReverse; + +@end + +@implementation FTreeSortedDictionaryEnumerator + +- (id)initWithImmutableSortedDictionary:(FTreeSortedDictionary *)aDict + startKey:(id)startKey isReverse:(BOOL)reverse { + self = [super init]; + if (self) { + self.immutableSortedDictionary = aDict; + self.stack = [[NSMutableArray alloc] init]; + self.isReverse = reverse; + + NSComparator comparator = aDict.comparator; + id node = self.immutableSortedDictionary.root; + + NSInteger cmp; + while(![node isEmpty]) { + cmp = startKey ? comparator(node.key, startKey) : 1; + // flip the comparison if we're going in reverse + if (self.isReverse) cmp *= -1; + + if (cmp < 0) { + // This node is less than our start key. Ignore it. + if (self.isReverse) { + node = node.left; + } else { + node = node.right; + } + } else if (cmp == 0) { + // This node is exactly equal to our start key. Push it on the stack, but stop iterating: + [self.stack addObject:node]; + break; + } else { + // This node is greater than our start key, add it to the stack and move on to the next one. + [self.stack addObject:node]; + if (self.isReverse) { + node = node.right; + } else { + node = node.left; + } + } + } + } + return self; +} + +- (id)nextObject { + if([self.stack count] == 0) { + return nil; + } + + id node = nil; + @synchronized(self.stack) { + node = [self.stack lastObject]; + [self.stack removeLastObject]; + } + id result = node.key; + + if (self.isReverse) { + node = node.left; + while (![node isEmpty]) { + [self.stack addObject:node]; + node = node.right; + } + } else { + node = node.right; + while (![node isEmpty]) { + [self.stack addObject:node]; + node = node.left; + } + } + + return result; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h new file mode 100644 index 0000000..876677d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h @@ -0,0 +1,112 @@ +// +// Copyright 2012 Square Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if !TARGET_OS_WATCH +#import +#import + +typedef enum { + SR_CONNECTING = 0, + SR_OPEN = 1, + SR_CLOSING = 2, + SR_CLOSED = 3, + +} FSRReadyState; + +@class FSRWebSocket; + +extern NSString *const FSRWebSocketErrorDomain; + +@protocol FSRWebSocketDelegate; + +@interface FSRWebSocket : NSObject + +@property (nonatomic, weak) id delegate; + +@property (nonatomic, readonly) FSRReadyState readyState; +@property (nonatomic, readonly, retain) NSURL *url; + +// This returns the negotiated protocol. +// It will be niluntil after the handshake completes. +@property (nonatomic, readonly, copy) NSString *protocol; + +// Protocols should be an array of strings that turn into Sec-WebSocket-Protocol +- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols queue:(dispatch_queue_t)queue googleAppID:(NSString*)googleAppID andUserAgent:(NSString *)userAgent; +- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols; +- (id)initWithURLRequest:(NSURLRequest *)request queue:(dispatch_queue_t)queue googleAppID:(NSString*)googleAppID andUserAgent:(NSString *)userAgent; +- (id)initWithURLRequest:(NSURLRequest *)request; + +// Some helper constructors +- (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols; +- (id)initWithURL:(NSURL *)url; + +// Delegate queue will be dispatch_main_queue by default. +// You cannot set both OperationQueue and dispatch_queue. +- (void)setDelegateOperationQueue:(NSOperationQueue*) queue; +- (void)setDelegateDispatchQueue:(dispatch_queue_t)queue; + +// By default, it will schedule itself on +[NSRunLoop SR_networkRunLoop] using defaultModes. +- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; +- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; + +// SRWebSockets are intended one-time-use only. Open should be called once and only once +- (void)open; + +- (void)close; +- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason; + +// Send a UTF8 String or Data +- (void)send:(id)data; + +@end + +@protocol FSRWebSocketDelegate + +// message will either be an NSString if the server is using text +// or NSData if the server is using binary +- (void)webSocket:(FSRWebSocket *)webSocket didReceiveMessage:(id)message; + +@optional + +// Exclude the `webSocket` argument since it isn't used in this codebase and it allows for better +// code sharing with watchOS. +- (void)webSocketDidOpen; +- (void)webSocket:(FSRWebSocket *)webSocket didFailWithError:(NSError *)error; +- (void)webSocket:(FSRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean; + +@end + + +@interface NSURLRequest (FCertificateAdditions) + +@property (nonatomic, retain, readonly) NSArray *FSR_SSLPinnedCertificates; + +@end + + +@interface NSMutableURLRequest (FCertificateAdditions) + +@property (nonatomic, retain) NSArray *FSR_SSLPinnedCertificates; + +@end + +@interface NSRunLoop (FSRWebSocket) + ++ (NSRunLoop *)FSR_networkRunLoop; + +@end + +#endif // TARGET_OS_WATCH diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m new file mode 100644 index 0000000..d789f33 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m @@ -0,0 +1,1874 @@ +// +// Copyright 2012 Square Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +#import "FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h" + +#if __has_include() +#define HAS_ICU +#endif + +#import + +#ifdef HAS_ICU +#import +#endif + +#if __has_include() +#import +#else +#import +#endif + +#import +#import +#import "FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h" +#import "FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h" + +#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE +#define sr_dispatch_retain(x) +#define sr_dispatch_release(x) +#define maybe_bridge(x) ((__bridge void *) x) +#else +#define sr_dispatch_retain(x) dispatch_retain(x) +#define sr_dispatch_release(x) dispatch_release(x) +#define maybe_bridge(x) (x) +#endif + +#if !TARGET_OS_WATCH +typedef enum { + SROpCodeTextFrame = 0x1, + SROpCodeBinaryFrame = 0x2, + //3-7Reserved + SROpCodeConnectionClose = 0x8, + SROpCodePing = 0x9, + SROpCodePong = 0xA, + //B-F reserved +} FSROpCode; + +typedef enum { + SRStatusCodeNormal = 1000, + SRStatusCodeGoingAway = 1001, + SRStatusCodeProtocolError = 1002, + SRStatusCodeUnhandledType = 1003, + // 1004 reserved + SRStatusNoStatusReceived = 1005, + // 1004-1006 reserved + SRStatusCodeInvalidUTF8 = 1007, + SRStatusCodePolicyViolated = 1008, + SRStatusCodeMessageTooBig = 1009, +} FSRStatusCode; + +typedef struct { + BOOL fin; +// BOOL rsv1; +// BOOL rsv2; +// BOOL rsv3; + uint8_t opcode; + BOOL masked; + uint64_t payload_length; +} frame_header; + +static NSString *const SRWebSocketAppendToSecKeyString = @"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + +static inline int32_t validate_dispatch_data_partial_string(NSData *data); +static inline void SRFastLog(NSString *format, ...); + +@interface NSData (FSRWebSocket) + +- (NSString *)stringBySHA1ThenBase64Encoding; + +@end + + +@interface NSString (FSRWebSocket) + +- (NSString *)stringBySHA1ThenBase64Encoding; + +@end + + +@interface NSURL (FSRWebSocket) + +// The origin isn't really applicable for a native application +// So instead, just map ws -> http and wss -> https +- (NSString *)SR_origin; + +@end + +@interface _FSRRunLoopThread : NSThread + +@property (nonatomic, readonly) NSRunLoop *runLoop; + +@end + +static NSString *newSHA1String(const char *bytes, size_t length) { + uint8_t md[CC_SHA1_DIGEST_LENGTH]; + + CC_SHA1(bytes, (int)length, md); + + size_t buffer_size = ((sizeof(md) * 3 + 2) / 2); + + char *buffer = (char *)malloc(buffer_size); + + int len = f_b64_ntop(md, CC_SHA1_DIGEST_LENGTH, buffer, buffer_size); + if (len == -1) { + free(buffer); + return nil; + } else{ + return [[NSString alloc] initWithBytesNoCopy:buffer length:len encoding:NSASCIIStringEncoding freeWhenDone:YES]; + } +} + +@implementation NSData (FSRWebSocket) + +- (NSString *)stringBySHA1ThenBase64Encoding; +{ + return newSHA1String(self.bytes, self.length); +} + +@end + + +@implementation NSString (FSRWebSocket) + +- (NSString *)stringBySHA1ThenBase64Encoding; +{ + return newSHA1String(self.UTF8String, self.length); +} + +@end + +NSString *const FSRWebSocketErrorDomain = @"FSRWebSocketErrorDomain"; + +// Returns number of bytes consumed. returning 0 means you didn't match. +// Sends bytes to callback handler; +typedef size_t (^stream_scanner)(NSData *collected_data); + +typedef void (^data_callback)(FSRWebSocket *webSocket, NSData *data); + +@interface FSRIOConsumer : NSObject { + stream_scanner _scanner; + data_callback _handler; + size_t _bytesNeeded; + BOOL _readToCurrentFrame; + BOOL _unmaskBytes; +} +@property (nonatomic, copy, readonly) stream_scanner consumer; +@property (nonatomic, copy, readonly) data_callback handler; +@property (nonatomic, assign) size_t bytesNeeded; +@property (nonatomic, assign, readonly) BOOL readToCurrentFrame; +@property (nonatomic, assign, readonly) BOOL unmaskBytes; + +@end + +// This class is not thread-safe, and is expected to always be run on the same queue. +@interface FSRIOConsumerPool : NSObject + +- (id)initWithBufferCapacity:(NSUInteger)poolSize; + +- (FSRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +- (void)returnConsumer:(FSRIOConsumer *)consumer; + +@end + +@interface FSRWebSocket () + +- (void)_writeData:(NSData *)data; +- (void)_closeWithProtocolError:(NSString *)message; +- (void)_failWithError:(NSError *)error; + +- (void)_disconnect; + +- (void)_readFrameNew; +- (void)_readFrameContinue; + +- (void)_pumpScanner; + +- (void)_pumpWriting; + +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback; +- (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)callback readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength; +- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler; +- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler; + +- (void)_sendFrameWithOpcode:(FSROpCode)opcode data:(id)data; + +- (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage; +- (void)_SR_commonInit; + +- (void)_initializeStreams; +- (void)_connect; + +@property (nonatomic) FSRReadyState readyState; + +@property (nonatomic) NSOperationQueue *delegateOperationQueue; +@property (nonatomic) dispatch_queue_t delegateDispatchQueue; + +@end + + +@implementation FSRWebSocket { + NSInteger _webSocketVersion; + + NSOperationQueue *_delegateOperationQueue; + dispatch_queue_t _delegateDispatchQueue; + dispatch_queue_t _workQueue; + NSMutableArray *_consumers; + + NSInputStream *_inputStream; + NSOutputStream *_outputStream; + + NSMutableData *_readBuffer; + NSInteger _readBufferOffset; + + NSMutableData *_outputBuffer; + NSInteger _outputBufferOffset; + + uint8_t _currentFrameOpcode; + size_t _currentFrameCount; + size_t _readOpCount; + uint32_t _currentStringScanPosition; + NSMutableData *_currentFrameData; + + NSString *_closeReason; + + NSString *_secKey; + + BOOL _pinnedCertFound; + + uint8_t _currentReadMaskKey[4]; + size_t _currentReadMaskOffset; + + BOOL _consumerStopped; + + BOOL _closeWhenFinishedWriting; + BOOL _failed; + + BOOL _secure; + NSURLRequest *_urlRequest; + NSString *_userAgent; + NSString *_googleAppID; + + CFHTTPMessageRef _receivedHTTPHeaders; + + BOOL _sentClose; + BOOL _didFail; + BOOL _cleanupScheduled; + int _closeCode; + + BOOL _isPumping; + + NSMutableSet *_scheduledRunloops; + + // We use this to retain ourselves. + __strong FSRWebSocket *_selfRetain; + + NSArray *_requestedProtocols; + FSRIOConsumerPool *_consumerPool; +} + +@synthesize delegate = _delegate; +@synthesize url = _url; +@synthesize readyState = _readyState; +@synthesize protocol = _protocol; + +static __strong NSData *CRLFCRLF; + ++ (void)initialize; +{ + CRLFCRLF = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4]; +} + +- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols queue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID andUserAgent:(NSString *)userAgent; +{ + self = [super init]; + if (self) { + assert(request.URL); + _url = request.URL; + NSString *scheme = [_url scheme]; + + _requestedProtocols = [protocols copy]; + _googleAppID = googleAppID; + _userAgent = userAgent; + + assert([scheme isEqualToString:@"ws"] || [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]); + _urlRequest = request; + + if ([scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]) { + _secure = YES; + } + + if (!queue) { + _delegateDispatchQueue = dispatch_get_main_queue(); + } else { + _delegateDispatchQueue = queue; + } + + [self _SR_commonInit]; + } + + return self; +} + +- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols; +{ + return [self initWithURLRequest:request protocols:nil queue:nil googleAppID:nil andUserAgent:nil]; +} + +- (id)initWithURLRequest:(NSURLRequest *)request queue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID andUserAgent:(NSString *)userAgent; +{ + return [self initWithURLRequest:request protocols:nil queue:queue googleAppID:googleAppID + andUserAgent:userAgent]; +} + +- (id)initWithURLRequest:(NSURLRequest *)request; +{ + return [self initWithURLRequest:request protocols:nil]; +} + +- (id)initWithURL:(NSURL *)url; +{ + return [self initWithURL:url protocols:nil]; +} + +- (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols; +{ + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; + return [self initWithURLRequest:request protocols:protocols]; +} + +- (void)_SR_commonInit; +{ + _readyState = SR_CONNECTING; + + _consumerStopped = YES; + + _webSocketVersion = 13; + + _workQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + + // Going to set a specific on the queue so we can validate we're on the work queue + dispatch_queue_set_specific(_workQueue, (__bridge void *)self, maybe_bridge(_workQueue), NULL); + + sr_dispatch_retain(_delegateDispatchQueue); + + _readBuffer = [[NSMutableData alloc] init]; + _outputBuffer = [[NSMutableData alloc] init]; + + _currentFrameData = [[NSMutableData alloc] init]; + + _consumers = [[NSMutableArray alloc] init]; + + _consumerPool = [[FSRIOConsumerPool alloc] init]; + + _scheduledRunloops = [[NSMutableSet alloc] init]; + + [self _initializeStreams]; + + // default handlers +} + +- (void)assertOnWorkQueue; +{ + assert(dispatch_get_specific((__bridge void *)self) == maybe_bridge(_workQueue)); +} + +- (void)dealloc +{ + _inputStream.delegate = nil; + _outputStream.delegate = nil; + + [_inputStream close]; + [_outputStream close]; + + sr_dispatch_release(_workQueue); + _workQueue = NULL; + + if (_receivedHTTPHeaders) { + CFRelease(_receivedHTTPHeaders); + _receivedHTTPHeaders = NULL; + } + + if (_delegateDispatchQueue) { + sr_dispatch_release(_delegateDispatchQueue); + _delegateDispatchQueue = NULL; + } +} + +#ifndef NDEBUG + +- (void)setReadyState:(FSRReadyState)aReadyState; +{ + [self willChangeValueForKey:@"readyState"]; + assert(aReadyState > _readyState); + _readyState = aReadyState; + [self didChangeValueForKey:@"readyState"]; +} + +#endif + +- (void)open; +{ + assert(_url); + NSAssert(_readyState == SR_CONNECTING, @"Cannot call -(void)open on SRWebSocket more than once"); + + _selfRetain = self; + + [self _connect]; +} + +// Calls block on delegate queue +- (void)_performDelegateBlock:(dispatch_block_t)block; +{ + if (_delegateOperationQueue) { + [_delegateOperationQueue addOperationWithBlock:block]; + } else { + assert(_delegateDispatchQueue); + dispatch_async(_delegateDispatchQueue, block); + } +} + +- (void)setDelegateDispatchQueue:(dispatch_queue_t)queue; +{ + if (queue) { + sr_dispatch_retain(queue); + } + + if (_delegateDispatchQueue) { + sr_dispatch_release(_delegateDispatchQueue); + } + + _delegateDispatchQueue = queue; +} + +- (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage; +{ + NSString *acceptHeader = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(httpMessage, CFSTR("Sec-WebSocket-Accept"))); + + if (acceptHeader == nil) { + return NO; + } + + NSString *concattedString = [_secKey stringByAppendingString:SRWebSocketAppendToSecKeyString]; + NSString *expectedAccept = [concattedString stringBySHA1ThenBase64Encoding]; + + return [acceptHeader isEqualToString:expectedAccept]; +} + +- (void)_HTTPHeadersDidFinish; +{ + NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders); + + if (responseCode >= 400) { + SRFastLog(@"Request failed with response code %d", responseCode); + [self _failWithError:[NSError errorWithDomain:@"org.lolrus.SocketRocket" code:2132 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"received bad response code from server %u", (int)responseCode] forKey:NSLocalizedDescriptionKey]]]; + return; + + } + + if(![self _checkHandshake:_receivedHTTPHeaders]) { + [self _failWithError:[NSError errorWithDomain:FSRWebSocketErrorDomain code:2133 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Invalid Sec-WebSocket-Accept response"] forKey:NSLocalizedDescriptionKey]]]; + return; + } + + NSString *negotiatedProtocol = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(_receivedHTTPHeaders, CFSTR("Sec-WebSocket-Protocol"))); + if (negotiatedProtocol) { + // Make sure we requested the protocol + if ([_requestedProtocols indexOfObject:negotiatedProtocol] == NSNotFound) { + [self _failWithError:[NSError errorWithDomain:FSRWebSocketErrorDomain code:2133 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Server specified Sec-WebSocket-Protocol that wasn't requested"] forKey:NSLocalizedDescriptionKey]]]; + return; + } + + _protocol = negotiatedProtocol; + } + + self.readyState = SR_OPEN; + + if (!_didFail) { + [self _readFrameNew]; + } + + [self _performDelegateBlock:^{ + if ([self.delegate respondsToSelector:@selector(webSocketDidOpen)]) { + [self.delegate webSocketDidOpen]; + }; + }]; +} + + +- (void)_readHTTPHeader; +{ + if (_receivedHTTPHeaders == NULL) { + _receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO); + } + + [self _readUntilHeaderCompleteWithCallback:^(FSRWebSocket *self, NSData *data) { + CFHTTPMessageAppendBytes(self->_receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length); + + if (CFHTTPMessageIsHeaderComplete(self->_receivedHTTPHeaders)) { + SRFastLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(self->_receivedHTTPHeaders))); + [self _HTTPHeadersDidFinish]; + } else { + [self _readHTTPHeader]; + } + }]; +} + +- (void)didConnect +{ + SRFastLog(@"Connected"); + CFHTTPMessageRef request = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), (__bridge CFURLRef)_url, kCFHTTPVersion1_1); + + // Set host first so it defaults + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Host"), (__bridge CFStringRef) + (_url.port != nil ? [NSString stringWithFormat:@"%@:%@", + _url.host, _url.port] : _url.host)); + + NSMutableData *keyBytes = [[NSMutableData alloc] initWithLength:16]; + int result = SecRandomCopyBytes(kSecRandomDefault, keyBytes.length, keyBytes.mutableBytes); + assert(result == 0); + _secKey = [FSRUtilities base64EncodedStringFromData:keyBytes]; + assert([_secKey length] == 24); + + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Upgrade"), CFSTR("websocket")); + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Connection"), CFSTR("Upgrade")); + if (_userAgent) { + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("User-Agent"), (__bridge CFStringRef)_userAgent); + } + + if (_googleAppID) { + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("X-Firebase-GMPID"), (__bridge CFStringRef)_googleAppID); + } + + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)_secKey); + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)[NSString stringWithFormat:@"%u", (int)_webSocketVersion]); + + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)_url.SR_origin); + + if (_requestedProtocols) { + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Protocol"), (__bridge CFStringRef)[_requestedProtocols componentsJoinedByString:@", "]); + } + + [_urlRequest.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)key, (__bridge CFStringRef)obj); + }]; + + NSData *message = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(request)); + + CFRelease(request); + + [self _writeData:message]; + [self _readHTTPHeader]; +} + +//- (void)_connectToHost:(NSString *)host port:(NSInteger)port; +- (void)_initializeStreams; +{ + NSInteger port = _url.port.integerValue; + if (port == 0) { + if (!_secure) { + port = 80; + } else { + port = 443; + } + } + NSString *host = _url.host; + + CFReadStreamRef readStream = NULL; + CFWriteStreamRef writeStream = NULL; + + CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, (int)port, &readStream, &writeStream); + + // XXX + CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeBackground); + CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeBackground); + + _outputStream = CFBridgingRelease(writeStream); + _inputStream = CFBridgingRelease(readStream); + + + if (_secure) { + NSMutableDictionary *SSLOptions = [[NSMutableDictionary alloc] init]; + + [_outputStream setProperty:(__bridge id)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel]; + + // If we're using pinned certs, don't validate the certificate chain + if ([_urlRequest FSR_SSLPinnedCertificates].count) { + [SSLOptions setValue:[NSNumber numberWithBool:NO] forKey:(__bridge id)kCFStreamSSLValidatesCertificateChain]; + } + + [_outputStream setProperty:SSLOptions + forKey:(__bridge id)kCFStreamPropertySSLSettings]; + } + + _inputStream.delegate = self; + _outputStream.delegate = self; + + [_outputStream open]; + [_inputStream open]; +} + +- (void)_connect; +{ + if (!_scheduledRunloops.count) { + [self scheduleInRunLoop:[NSRunLoop FSR_networkRunLoop] forMode:NSDefaultRunLoopMode]; + } + + + [_outputStream open]; + [_inputStream open]; +} + +- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; +{ + [_outputStream scheduleInRunLoop:aRunLoop forMode:mode]; + [_inputStream scheduleInRunLoop:aRunLoop forMode:mode]; + + [_scheduledRunloops addObject:@[aRunLoop, mode]]; +} + +- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; +{ + [_outputStream removeFromRunLoop:aRunLoop forMode:mode]; + [_inputStream removeFromRunLoop:aRunLoop forMode:mode]; + + [_scheduledRunloops removeObject:@[aRunLoop, mode]]; +} + +- (void)close; +{ + [self closeWithCode:-1 reason:nil]; +} + +- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason; +{ + assert(code); + dispatch_async(_workQueue, ^{ + if (self.readyState == SR_CLOSING || self.readyState == SR_CLOSED) { + return; + } + + BOOL wasConnecting = self.readyState == SR_CONNECTING; + + self.readyState = SR_CLOSING; + + SRFastLog(@"Closing with code %d reason %@", code, reason); + + if (wasConnecting) { + [self _disconnect]; + return; + } + + size_t maxMsgSize = [reason maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + NSMutableData *mutablePayload = [[NSMutableData alloc] initWithLength:sizeof(uint16_t) + maxMsgSize]; + NSData *payload = mutablePayload; + + ((uint16_t *)mutablePayload.mutableBytes)[0] = EndianU16_BtoN(code); + + if (reason) { + NSRange remainingRange = {0}; + + NSUInteger usedLength = 0; + + BOOL success = [reason getBytes:(char *)mutablePayload.mutableBytes + sizeof(uint16_t) maxLength:payload.length - sizeof(uint16_t) usedLength:&usedLength encoding:NSUTF8StringEncoding options:NSStringEncodingConversionExternalRepresentation range:NSMakeRange(0, reason.length) remainingRange:&remainingRange]; + + assert(success); + assert(remainingRange.length == 0); + + if (usedLength != maxMsgSize) { + payload = [payload subdataWithRange:NSMakeRange(0, usedLength + sizeof(uint16_t))]; + } + } + + + [self _sendFrameWithOpcode:SROpCodeConnectionClose data:payload]; + }); +} + +- (void)_closeWithProtocolError:(NSString *)message; +{ + // Need to shunt this on the _callbackQueue first to see if they received any messages + [self _performDelegateBlock:^{ + [self closeWithCode:SRStatusCodeProtocolError reason:message]; + dispatch_async(self->_workQueue, ^{ + [self _disconnect]; + }); + }]; +} + +- (void)_failWithError:(NSError *)error; +{ + dispatch_async(_workQueue, ^{ + if (self.readyState != SR_CLOSED) { + self->_failed = YES; + [self _performDelegateBlock:^{ + if ([self.delegate respondsToSelector:@selector(webSocket:didFailWithError:)]) { + [self.delegate webSocket:self didFailWithError:error]; + } + }]; + + self.readyState = SR_CLOSED; + + SRFastLog(@"Failing with error %@", error.localizedDescription); + + [self _disconnect]; + [self _scheduleCleanup]; + } + }); +} + +- (void)_writeData:(NSData *)data; +{ + [self assertOnWorkQueue]; + + if (_closeWhenFinishedWriting) { + return; + } + [_outputBuffer appendData:data]; + [self _pumpWriting]; +} +- (void)send:(id)data; +{ + SRFastLog(@"Sending data %@", data); + NSAssert(self.readyState != SR_CONNECTING, @"Invalid State: Cannot call send: until connection is open"); + // TODO: maybe not copy this for performance + data = [data copy]; + dispatch_async(_workQueue, ^{ + if ([data isKindOfClass:[NSString class]]) { + [self _sendFrameWithOpcode:SROpCodeTextFrame data:[(NSString *)data dataUsingEncoding:NSUTF8StringEncoding]]; + } else if ([data isKindOfClass:[NSData class]]) { + [self _sendFrameWithOpcode:SROpCodeBinaryFrame data:data]; + } else if (data == nil) { + [self _sendFrameWithOpcode:SROpCodeTextFrame data:data]; + } else { + assert(NO); + } + }); +} + +- (void)handlePing:(NSData *)pingData; +{ + // Need to pingpong this off _callbackQueue first to make sure messages happen in order + [self _performDelegateBlock:^{ + dispatch_async(self->_workQueue, ^{ + [self _sendFrameWithOpcode:SROpCodePong data:pingData]; + }); + }]; +} + +- (void)handlePong; +{ + // NOOP +} + +- (void)_handleMessage:(id)message +{ + SRFastLog(@"Received message"); + [self _performDelegateBlock:^{ + if ([self.delegate respondsToSelector:@selector(webSocket:didReceiveMessage:)]) { + [self.delegate webSocket:self didReceiveMessage:message]; + } + }]; +} + + +static inline BOOL closeCodeIsValid(int closeCode) { + if (closeCode < 1000) { + return NO; + } + + if (closeCode >= 1000 && closeCode <= 1011) { + if (closeCode == 1004 || + closeCode == 1005 || + closeCode == 1006) { + return NO; + } + return YES; + } + + if (closeCode >= 3000 && closeCode <= 3999) { + return YES; + } + + if (closeCode >= 4000 && closeCode <= 4999) { + return YES; + } + + return NO; +} + +// Note from RFC: +// +// If there is a body, the first two +// bytes of the body MUST be a 2-byte unsigned integer (in network byte +// order) representing a status code with value /code/ defined in +// Section 7.4. Following the 2-byte integer the body MAY contain UTF-8 +// encoded data with value /reason/, the interpretation of which is not +// defined by this specification. + +- (void)handleCloseWithData:(NSData *)data; +{ + size_t dataSize = data.length; + __block uint16_t closeCode = 0; + + SRFastLog(@"Received close frame"); + + if (dataSize == 1) { + // TODO handle error + [self _closeWithProtocolError:@"Payload for close must be larger than 2 bytes"]; + return; + } else if (dataSize >= 2) { + [data getBytes:&closeCode length:sizeof(closeCode)]; + _closeCode = EndianU16_BtoN(closeCode); + if (!closeCodeIsValid(_closeCode)) { + [self _closeWithProtocolError:[NSString stringWithFormat:@"Cannot have close code of %d", _closeCode]]; + return; + } + if (dataSize > 2) { + _closeReason = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(2, dataSize - 2)] encoding:NSUTF8StringEncoding]; + if (!_closeReason) { + [self _closeWithProtocolError:@"Close reason MUST be valid UTF-8"]; + return; + } + } + } else { + _closeCode = SRStatusNoStatusReceived; + } + + [self assertOnWorkQueue]; + + if (self.readyState == SR_OPEN) { + [self closeWithCode:1000 reason:nil]; + } + dispatch_async(_workQueue, ^{ + [self _disconnect]; + }); +} + +- (void)_disconnect; +{ + [self assertOnWorkQueue]; + SRFastLog(@"Trying to disconnect"); + _closeWhenFinishedWriting = YES; + [self _pumpWriting]; +} + +- (void)_handleFrameWithData:(NSData *)frameData opCode:(NSInteger)opcode; +{ + // Check that the current data is valid UTF8 + + BOOL isControlFrame = (opcode == SROpCodePing || opcode == SROpCodePong || opcode == SROpCodeConnectionClose); + if (!isControlFrame) { + [self _readFrameNew]; + } else { + dispatch_async(_workQueue, ^{ + [self _readFrameContinue]; + }); + } + + switch (opcode) { + case SROpCodeTextFrame: { + NSString *str = [[NSString alloc] initWithData:frameData encoding:NSUTF8StringEncoding]; + if (str == nil && frameData) { + [self closeWithCode:SRStatusCodeInvalidUTF8 reason:@"Text frames must be valid UTF-8"]; + dispatch_async(_workQueue, ^{ + [self _disconnect]; + }); + + return; + } + [self _handleMessage:str]; + break; + } + case SROpCodeBinaryFrame: + [self _handleMessage:[frameData copy]]; + break; + case SROpCodeConnectionClose: + [self handleCloseWithData:frameData]; + break; + case SROpCodePing: + [self handlePing:frameData]; + break; + case SROpCodePong: + [self handlePong]; + break; + default: + [self _closeWithProtocolError:[NSString stringWithFormat:@"Unknown opcode %u", (int)opcode]]; + // TODO: Handle invalid opcode + break; + } +} + +- (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData; +{ + assert(frame_header.opcode != 0); + + if (self.readyState != SR_OPEN) { + return; + } + + + BOOL isControlFrame = (frame_header.opcode == SROpCodePing || frame_header.opcode == SROpCodePong || frame_header.opcode == SROpCodeConnectionClose); + + if (isControlFrame && !frame_header.fin) { + [self _closeWithProtocolError:@"Fragmented control frames not allowed"]; + return; + } + + if (isControlFrame && frame_header.payload_length >= 126) { + [self _closeWithProtocolError:@"Control frames cannot have payloads larger than 126 bytes"]; + return; + } + + if (!isControlFrame) { + _currentFrameOpcode = frame_header.opcode; + _currentFrameCount += 1; + } + + if (frame_header.payload_length == 0) { + if (isControlFrame) { + [self _handleFrameWithData:curData opCode:frame_header.opcode]; + } else { + if (frame_header.fin) { + [self _handleFrameWithData:_currentFrameData opCode:frame_header.opcode]; + } else { + // TODO add assert that opcode is not a control; + [self _readFrameContinue]; + } + } + } else { + [self _addConsumerWithDataLength:(size_t)frame_header.payload_length callback:^(FSRWebSocket *self, NSData *newData) { + if (isControlFrame) { + [self _handleFrameWithData:newData opCode:frame_header.opcode]; + } else { + if (frame_header.fin) { + [self _handleFrameWithData:self->_currentFrameData opCode:frame_header.opcode]; + } else { + // TODO add assert that opcode is not a control; + [self _readFrameContinue]; + } + + } + } readToCurrentFrame:!isControlFrame unmaskBytes:frame_header.masked]; + } +} + +/* From RFC: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-------+-+-------------+-------------------------------+ + |F|R|R|R| opcode|M| Payload len | Extended payload length | + |I|S|S|S| (4) |A| (7) | (16/64) | + |N|V|V|V| |S| | (if payload len==126/127) | + | |1|2|3| |K| | | + +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + | Extended payload length continued, if payload len == 127 | + + - - - - - - - - - - - - - - - +-------------------------------+ + | |Masking-key, if MASK set to 1 | + +-------------------------------+-------------------------------+ + | Masking-key (continued) | Payload Data | + +-------------------------------- - - - - - - - - - - - - - - - + + : Payload Data continued ... : + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | Payload Data continued ... | + +---------------------------------------------------------------+ + */ + +static const uint8_t SRFinMask = 0x80; +static const uint8_t SROpCodeMask = 0x0F; +static const uint8_t SRRsvMask = 0x70; +static const uint8_t SRMaskMask = 0x80; +static const uint8_t SRPayloadLenMask = 0x7F; + + +- (void)_readFrameContinue; +{ + assert((_currentFrameCount == 0 && _currentFrameOpcode == 0) || (_currentFrameCount > 0 && _currentFrameOpcode > 0)); + + [self _addConsumerWithDataLength:2 callback:^(FSRWebSocket *self, NSData *data) { + __block frame_header header = {0}; + + const uint8_t *headerBuffer = data.bytes; + assert(data.length >= 2); + + if (headerBuffer[0] & SRRsvMask) { + [self _closeWithProtocolError:@"Server used RSV bits"]; + return; + } + + uint8_t receivedOpcode = (SROpCodeMask & headerBuffer[0]); + + BOOL isControlFrame = (receivedOpcode == SROpCodePing || receivedOpcode == SROpCodePong || receivedOpcode == SROpCodeConnectionClose); + + if (!isControlFrame && receivedOpcode != 0 && self->_currentFrameCount > 0) { + [self _closeWithProtocolError:@"all data frames after the initial data frame must have opcode 0"]; + return; + } + + if (receivedOpcode == 0 && self->_currentFrameCount == 0) { + [self _closeWithProtocolError:@"cannot continue a message"]; + return; + } + + header.opcode = receivedOpcode == 0 ? self->_currentFrameOpcode : receivedOpcode; + + header.fin = !!(SRFinMask & headerBuffer[0]); + + + header.masked = !!(SRMaskMask & headerBuffer[1]); + header.payload_length = SRPayloadLenMask & headerBuffer[1]; + + headerBuffer = NULL; + + if (header.masked) { + [self _closeWithProtocolError:@"Client must receive unmasked data"]; + } + + size_t extra_bytes_needed = header.masked ? sizeof(self->_currentReadMaskKey) : 0; + + if (header.payload_length == 126) { + extra_bytes_needed += sizeof(uint16_t); + } else if (header.payload_length == 127) { + extra_bytes_needed += sizeof(uint64_t); + } + + if (extra_bytes_needed == 0) { + [self _handleFrameHeader:header curData:self->_currentFrameData]; + } else { + [self _addConsumerWithDataLength:extra_bytes_needed callback:^(FSRWebSocket *self, NSData *data) { + size_t mapped_size = data.length; + const void *mapped_buffer = data.bytes; + size_t offset = 0; + + if (header.payload_length == 126) { + assert(mapped_size >= sizeof(uint16_t)); + uint16_t newLen = EndianU16_BtoN(*(uint16_t *)(mapped_buffer)); + header.payload_length = newLen; + offset += sizeof(uint16_t); + } else if (header.payload_length == 127) { + assert(mapped_size >= sizeof(uint64_t)); + header.payload_length = EndianU64_BtoN(*(uint64_t *)(mapped_buffer)); + offset += sizeof(uint64_t); + } else { + assert(header.payload_length < 126 && header.payload_length >= 0); + } + + + if (header.masked) { + assert(mapped_size >= sizeof(self->_currentReadMaskOffset) + offset); + memcpy(self->_currentReadMaskKey, ((uint8_t *)mapped_buffer) + offset, sizeof(self->_currentReadMaskKey)); + } + + [self _handleFrameHeader:header curData:self->_currentFrameData]; + } readToCurrentFrame:NO unmaskBytes:NO]; + } + } readToCurrentFrame:NO unmaskBytes:NO]; +} + +- (void)_readFrameNew; +{ + dispatch_async(_workQueue, ^{ + [self->_currentFrameData setLength:0]; + + self->_currentFrameOpcode = 0; + self->_currentFrameCount = 0; + self->_readOpCount = 0; + self->_currentStringScanPosition = 0; + + [self _readFrameContinue]; + }); +} + +- (void)_pumpWriting; +{ + [self assertOnWorkQueue]; + + NSUInteger dataLength = _outputBuffer.length; + if (dataLength - _outputBufferOffset > 0 && _outputStream.hasSpaceAvailable) { + NSUInteger bytesWritten = [_outputStream write:_outputBuffer.bytes + _outputBufferOffset maxLength:dataLength - _outputBufferOffset]; + if (bytesWritten == -1) { + [self _failWithError:[NSError errorWithDomain:@"org.lolrus.SocketRocket" code:2145 userInfo:[NSDictionary dictionaryWithObject:@"Error writing to stream" forKey:NSLocalizedDescriptionKey]]]; + return; + } + + _outputBufferOffset += bytesWritten; + + if (_outputBufferOffset > 4096 && _outputBufferOffset > (_outputBuffer.length >> 1)) { + _outputBuffer = [[NSMutableData alloc] initWithBytes:(char *)_outputBuffer.bytes + _outputBufferOffset length:_outputBuffer.length - _outputBufferOffset]; + _outputBufferOffset = 0; + } + } + + if (_closeWhenFinishedWriting && + _outputBuffer.length - _outputBufferOffset == 0 && + (_inputStream.streamStatus != NSStreamStatusNotOpen && + _inputStream.streamStatus != NSStreamStatusClosed) && + !_sentClose) { + _sentClose = YES; + + @synchronized (self) { + [_outputStream close]; + [_inputStream close]; + + // TODO: Why are we missing the SocketRocket code to call unscheduleFromRunLoop??? + } + + if (!_failed) { + [self _performDelegateBlock:^{ + if ([self.delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)]) { + [self.delegate webSocket:self didCloseWithCode:self->_closeCode reason:self->_closeReason wasClean:YES]; + } + }]; + } + [self _scheduleCleanup]; + } +} + +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback; +{ + [self assertOnWorkQueue]; + [self _addConsumerWithScanner:consumer callback:callback dataLength:0]; +} + +- (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)callback readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +{ + [self assertOnWorkQueue]; + assert(dataLength); + + [_consumers addObject:[_consumerPool consumerWithScanner:nil handler:callback bytesNeeded:dataLength readToCurrentFrame:readToCurrentFrame unmaskBytes:unmaskBytes]]; + [self _pumpScanner]; +} + +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength; +{ + [self assertOnWorkQueue]; + [_consumers addObject:[_consumerPool consumerWithScanner:consumer handler:callback bytesNeeded:dataLength readToCurrentFrame:NO unmaskBytes:NO]]; + [self _pumpScanner]; +} + + +- (void)_scheduleCleanup +{ + @synchronized(self) { + if (_cleanupScheduled) { + return; + } + + _cleanupScheduled = YES; + + // Cleanup NSStream delegate's in the same RunLoop used by the streams themselves: + // This way we'll prevent race conditions between handleEvent and SRWebsocket's dealloc + NSTimer *timer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(_cleanupSelfReference:) userInfo:nil repeats:NO]; + [[NSRunLoop FSR_networkRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; + } +} + +- (void)_cleanupSelfReference:(NSTimer *)timer +{ + @synchronized(self) { + // Nuke NSStream delegate's + _inputStream.delegate = nil; + _outputStream.delegate = nil; + + // Remove the streams, right now, from the networkRunLoop + [_inputStream close]; + [_outputStream close]; + } + + // Cleanup selfRetain in the same GCD queue as usual + dispatch_async(_workQueue, ^{ + self->_selfRetain = nil; + }); +} + + +static const char CRLFCRLFBytes[] = {'\r', '\n', '\r', '\n'}; + +- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler; +{ + [self _readUntilBytes:CRLFCRLFBytes length:sizeof(CRLFCRLFBytes) callback:dataHandler]; +} + +- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler; +{ + // TODO optimize so this can continue from where we last searched + stream_scanner consumer = ^size_t(NSData *data) { + __block size_t found_size = 0; + __block size_t match_count = 0; + + size_t size = data.length; + const unsigned char *buffer = data.bytes; + for (int i = 0; i < size; i++ ) { + if (((const unsigned char *)buffer)[i] == ((const unsigned char *)bytes)[match_count]) { + match_count += 1; + if (match_count == length) { + found_size = i + 1; + break; + } + } else { + match_count = 0; + } + } + return found_size; + }; + [self _addConsumerWithScanner:consumer callback:dataHandler]; +} + + +// Returns true if did work +- (BOOL)_innerPumpScanner { + + BOOL didWork = NO; + + if (self.readyState >= SR_CLOSING) { + return didWork; + } + + if (!_consumers.count) { + return didWork; + } + + size_t curSize = _readBuffer.length - _readBufferOffset; + if (!curSize) { + return didWork; + } + + FSRIOConsumer *consumer = [_consumers objectAtIndex:0]; + + size_t bytesNeeded = consumer.bytesNeeded; + + size_t foundSize = 0; + if (consumer.consumer) { + NSData *tempView = [NSData dataWithBytesNoCopy:(char *)_readBuffer.bytes + _readBufferOffset length:_readBuffer.length - _readBufferOffset freeWhenDone:NO]; + foundSize = consumer.consumer(tempView); + } else { + assert(consumer.bytesNeeded); + if (curSize >= bytesNeeded) { + foundSize = bytesNeeded; + } else if (consumer.readToCurrentFrame) { + foundSize = curSize; + } + } + + NSData *slice = nil; + if (consumer.readToCurrentFrame || foundSize) { + NSRange sliceRange = NSMakeRange(_readBufferOffset, foundSize); + slice = [_readBuffer subdataWithRange:sliceRange]; + + _readBufferOffset += foundSize; + + if (_readBufferOffset > 4096 && _readBufferOffset > (_readBuffer.length >> 1)) { + _readBuffer = [[NSMutableData alloc] initWithBytes:(char *)_readBuffer.bytes + _readBufferOffset length:_readBuffer.length - _readBufferOffset]; _readBufferOffset = 0; + } + + if (consumer.unmaskBytes) { + NSMutableData *mutableSlice = [slice mutableCopy]; + + NSUInteger len = mutableSlice.length; + uint8_t *bytes = mutableSlice.mutableBytes; + + for (int i = 0; i < len; i++) { + bytes[i] = bytes[i] ^ _currentReadMaskKey[_currentReadMaskOffset % sizeof(_currentReadMaskKey)]; + _currentReadMaskOffset += 1; + } + + slice = mutableSlice; + } + + if (consumer.readToCurrentFrame) { + [_currentFrameData appendData:slice]; + + _readOpCount += 1; + + if (_currentFrameOpcode == SROpCodeTextFrame) { + // Validate UTF8 stuff. + size_t currentDataSize = _currentFrameData.length; + if (_currentFrameOpcode == SROpCodeTextFrame && currentDataSize > 0) { + // TODO: Optimize the crap out of this. Don't really have to copy all the data each time + + size_t scanSize = currentDataSize - _currentStringScanPosition; + + NSData *scan_data = [_currentFrameData subdataWithRange:NSMakeRange(_currentStringScanPosition, scanSize)]; + int32_t valid_utf8_size = validate_dispatch_data_partial_string(scan_data); + + if (valid_utf8_size == -1) { + [self closeWithCode:SRStatusCodeInvalidUTF8 reason:@"Text frames must be valid UTF-8"]; + dispatch_async(_workQueue, ^{ + [self _disconnect]; + }); + return didWork; + } else { + _currentStringScanPosition += valid_utf8_size; + } + } + + } + + consumer.bytesNeeded -= foundSize; + + if (consumer.bytesNeeded == 0) { + [_consumers removeObjectAtIndex:0]; + consumer.handler(self, nil); + didWork = YES; + } + } else if (foundSize) { + [_consumers removeObjectAtIndex:0]; + consumer.handler(self, slice); + didWork = YES; + } + } + return didWork; +} + +-(void)_pumpScanner; +{ + [self assertOnWorkQueue]; + + if (!_isPumping) { + _isPumping = YES; + } else { + return; + } + + while ([self _innerPumpScanner]) { + + } + + _isPumping = NO; +} + +//#define NOMASK + +static const size_t SRFrameHeaderOverhead = 32; + +- (void)_sendFrameWithOpcode:(FSROpCode)opcode data:(id)data; +{ + [self assertOnWorkQueue]; + + if (data == nil) { + return; + } + + NSAssert([data isKindOfClass:[NSData class]] || [data isKindOfClass:[NSString class]], @"Function expects nil, NSString or NSData"); + + size_t payloadLength = [data isKindOfClass:[NSString class]] ? [(NSString *)data lengthOfBytesUsingEncoding:NSUTF8StringEncoding] : [data length]; + + NSMutableData *frame = [[NSMutableData alloc] initWithLength:payloadLength + SRFrameHeaderOverhead]; + if (!frame) { + [self closeWithCode:SRStatusCodeMessageTooBig reason:@"Message too big"]; + return; + } + uint8_t *frame_buffer = (uint8_t *)[frame mutableBytes]; + + // set fin + frame_buffer[0] = SRFinMask | opcode; + + BOOL useMask = YES; + +#endif // !TARGET_OS_WATCH +#ifdef NOMASK + useMask = NO; +#endif +#if !TARGET_OS_WATCH + + if (useMask) { + // set the mask and header + frame_buffer[1] |= SRMaskMask; + } + + size_t frame_buffer_size = 2; + + const uint8_t *unmasked_payload = NULL; + if ([data isKindOfClass:[NSData class]]) { + unmasked_payload = (uint8_t *)[data bytes]; + } else if ([data isKindOfClass:[NSString class]]) { + unmasked_payload = (const uint8_t *)[data UTF8String]; + } else { + assert(NO); + } + + if (payloadLength < 126) { + frame_buffer[1] |= payloadLength; + } else if (payloadLength <= UINT16_MAX) { + frame_buffer[1] |= 126; + *((uint16_t *)(frame_buffer + frame_buffer_size)) = EndianU16_BtoN((uint16_t)payloadLength); + frame_buffer_size += sizeof(uint16_t); + } else { + frame_buffer[1] |= 127; + *((uint64_t *)(frame_buffer + frame_buffer_size)) = EndianU64_BtoN((uint64_t)payloadLength); + frame_buffer_size += sizeof(uint64_t); + } + + if (!useMask) { + for (int i = 0; i < payloadLength; i++) { + frame_buffer[frame_buffer_size] = unmasked_payload[i]; + frame_buffer_size += 1; + } + } else { + uint8_t *mask_key = frame_buffer + frame_buffer_size; + int result = SecRandomCopyBytes(kSecRandomDefault, sizeof(uint32_t), (uint8_t *)mask_key); + assert(result == 0); + frame_buffer_size += sizeof(uint32_t); + + // TODO: could probably optimize this with SIMD + for (int i = 0; i < payloadLength; i++) { + frame_buffer[frame_buffer_size] = unmasked_payload[i] ^ mask_key[i % sizeof(uint32_t)]; + frame_buffer_size += 1; + } + } + + assert(frame_buffer_size <= [frame length]); + frame.length = frame_buffer_size; + + [self _writeData:frame]; +} + +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode; +{ + __weak __typeof__(self) weakSelf = self; + + // turn on keep-alive for the output stream. + if (eventCode == NSStreamEventOpenCompleted && aStream == _outputStream) { + CFDataRef socketData = CFWriteStreamCopyProperty((CFWriteStreamRef)_outputStream, kCFStreamPropertySocketNativeHandle); + // In rare cases socketData might be nil (there are crash reports out there), in which case we'll have to just + // live without keep-alive :( + if (socketData != nil) { + CFSocketNativeHandle socket; + CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&socket); + CFRelease(socketData); + + int keepAliveOn = 1; + if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &keepAliveOn, sizeof(keepAliveOn)) == -1) { + SRFastLog(@"Failed to turn on TCP keepalive for websocket"); + } + } + } + + if (_secure && !_pinnedCertFound && (eventCode == NSStreamEventHasBytesAvailable || eventCode == NSStreamEventHasSpaceAvailable)) { + + NSArray *sslCerts = [_urlRequest FSR_SSLPinnedCertificates]; + if (sslCerts) { + SecTrustRef secTrust = (__bridge SecTrustRef)[aStream propertyForKey:(__bridge id)kCFStreamPropertySSLPeerTrust]; + if (secTrust) { + NSInteger numCerts = SecTrustGetCertificateCount(secTrust); + for (NSInteger i = 0; i < numCerts && !_pinnedCertFound; i++) { + SecCertificateRef cert = SecTrustGetCertificateAtIndex(secTrust, i); + NSData *certData = CFBridgingRelease(SecCertificateCopyData(cert)); + + for (id ref in sslCerts) { + SecCertificateRef trustedCert = (__bridge SecCertificateRef)ref; + NSData *trustedCertData = CFBridgingRelease(SecCertificateCopyData(trustedCert)); + + if ([trustedCertData isEqualToData:certData]) { + _pinnedCertFound = YES; + break; + } + } + } + } + + if (!_pinnedCertFound) { + dispatch_async(_workQueue, ^{ + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : @"Invalid server cert" }; + [weakSelf _failWithError:[NSError errorWithDomain:@"org.lolrus.SocketRocket" code:23556 userInfo:userInfo]]; + }); + return; + } + } + } + + // SRFastLog(@"%@ Got stream event %d", aStream, eventCode); + dispatch_async(_workQueue, ^{ + [weakSelf safeHandleEvent:eventCode stream:aStream]; + }); +} + +- (void)safeHandleEvent:(NSStreamEvent)eventCode stream:(NSStream *)aStream +{ + switch (eventCode) { + case NSStreamEventOpenCompleted: { + SRFastLog(@"NSStreamEventOpenCompleted %@", aStream); + if (self.readyState >= SR_CLOSING) { + return; + } + + + assert(_readBuffer); + + if (self.readyState == SR_CONNECTING && aStream == _inputStream) { + [self didConnect]; + } + [self _pumpWriting]; + [self _pumpScanner]; + break; + } + + case NSStreamEventErrorOccurred: { + // Note: The upstream code for SocketRocket logs the error message, but this causes + // crashes on iOS 13 (https://github.com/firebase/firebase-ios-sdk/issues/3950) + SRFastLog(@"NSStreamEventErrorOccurred %@", aStream); + /// TODO specify error better! + [self _failWithError:aStream.streamError]; + _readBufferOffset = 0; + [_readBuffer setLength:0]; + break; + + } + + case NSStreamEventEndEncountered: { + [self _pumpScanner]; + SRFastLog(@"NSStreamEventEndEncountered %@", aStream); + if (aStream.streamError) { + [self _failWithError:aStream.streamError]; + } else { + dispatch_async(_workQueue, ^{ + if (self.readyState != SR_CLOSED) { + self.readyState = SR_CLOSED; + [self _scheduleCleanup]; + } + + if (!self->_sentClose && !self->_failed) { + self->_sentClose = YES; + // If we get closed in this state it's probably not clean because we should be sending this when we send messages + [self _performDelegateBlock:^{ + if ([self.delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)]) { + [self.delegate webSocket:self didCloseWithCode:0 reason:@"Stream end encountered" wasClean:NO]; + } + }]; + } + }); + } + + break; + } + + case NSStreamEventHasBytesAvailable: { + SRFastLog(@"NSStreamEventHasBytesAvailable %@", aStream); + + #define FSRWEB_SOCKET_BUFFER_SIZE 2048 + uint8_t buffer[FSRWEB_SOCKET_BUFFER_SIZE]; + + + while (_inputStream.hasBytesAvailable) { + NSInteger bytes_read = [_inputStream read:buffer maxLength:FSRWEB_SOCKET_BUFFER_SIZE]; + + if (bytes_read > 0) { + [_readBuffer appendBytes:buffer length:bytes_read]; + } else if (bytes_read < 0) { + [self _failWithError:_inputStream.streamError]; + } + + if (bytes_read != FSRWEB_SOCKET_BUFFER_SIZE) { + break; + } + }; + [self _pumpScanner]; + break; + } + + case NSStreamEventHasSpaceAvailable: { + SRFastLog(@"NSStreamEventHasSpaceAvailable %@", aStream); + [self _pumpWriting]; + break; + } + + default: + SRFastLog(@"(default) %@", aStream); + break; + } +} + +@end + + +@implementation FSRIOConsumer + +@synthesize bytesNeeded = _bytesNeeded; +@synthesize consumer = _scanner; +@synthesize handler = _handler; +@synthesize readToCurrentFrame = _readToCurrentFrame; +@synthesize unmaskBytes = _unmaskBytes; + +- (void)setupWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +{ + _scanner = [scanner copy]; + _handler = [handler copy]; + _bytesNeeded = bytesNeeded; + _readToCurrentFrame = readToCurrentFrame; + _unmaskBytes = unmaskBytes; + assert(_scanner || _bytesNeeded); +} + +@end + +@implementation FSRIOConsumerPool { + NSUInteger _poolSize; + NSMutableArray *_bufferedConsumers; +} + +- (id)initWithBufferCapacity:(NSUInteger)poolSize; +{ + self = [super init]; + if (self) { + _poolSize = poolSize; + _bufferedConsumers = [[NSMutableArray alloc] initWithCapacity:poolSize]; + } + return self; +} + +- (id)init +{ + return [self initWithBufferCapacity:8]; +} + +- (FSRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +{ + FSRIOConsumer *consumer = nil; + if (_bufferedConsumers.count) { + consumer = [_bufferedConsumers lastObject]; + [_bufferedConsumers removeLastObject]; + } else { + consumer = [[FSRIOConsumer alloc] init]; + } + + [consumer setupWithScanner:scanner handler:handler bytesNeeded:bytesNeeded readToCurrentFrame:readToCurrentFrame unmaskBytes:unmaskBytes]; + + return consumer; +} + +- (void)returnConsumer:(FSRIOConsumer *)consumer; +{ + if (_bufferedConsumers.count < _poolSize) { + [_bufferedConsumers addObject:consumer]; + } +} + +@end + +@implementation NSURLRequest (FCertificateAdditions) + +- (NSArray *)FSR_SSLPinnedCertificates; +{ + return [NSURLProtocol propertyForKey:@"FSR_SSLPinnedCertificates" inRequest:self]; +} + +@end + +@implementation NSMutableURLRequest (FCertificateAdditions) + +- (NSArray *)FSR_SSLPinnedCertificates; +{ + return [NSURLProtocol propertyForKey:@"FSR_SSLPinnedCertificates" inRequest:self]; +} + +- (void)setFSR_SSLPinnedCertificates:(NSArray *)FSR_SSLPinnedCertificates; +{ + [NSURLProtocol setProperty:FSR_SSLPinnedCertificates forKey:@"FSR_SSLPinnedCertificates" inRequest:self]; +} + +@end + +@implementation NSURL (FSRWebSocket) + +- (NSString *)SR_origin; +{ + NSString *scheme = [self.scheme lowercaseString]; + + if ([scheme isEqualToString:@"wss"]) { + scheme = @"https"; + } else if ([scheme isEqualToString:@"ws"]) { + scheme = @"http"; + } + + if (self.port != nil) { + return [NSString stringWithFormat:@"%@://%@:%@/", scheme, self.host, self.port]; + } else { + return [NSString stringWithFormat:@"%@://%@/", scheme, self.host]; + } +} + +@end + +// #define SR_ENABLE_LOG + +static inline void SRFastLog(NSString *format, ...) { +#ifdef SR_ENABLE_LOG + __block va_list arg_list; + va_start (arg_list, format); + + NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list]; + + va_end(arg_list); + + NSLog(@"[SR] %@", formattedString); +#endif +} + + +#ifdef HAS_ICU + +static inline int32_t validate_dispatch_data_partial_string(NSData *data) { + + const void * contents = [data bytes]; + long size = [data length]; + + const uint8_t *str = (const uint8_t *)contents; + + + UChar32 codepoint = 1; + int32_t offset = 0; + int32_t lastOffset = 0; + while(offset < size && codepoint > 0) { + lastOffset = offset; + U8_NEXT(str, offset, size, codepoint); + } + + if (codepoint == -1) { + // Check to see if the last byte is valid or whether it was just continuing + if (!U8_IS_LEAD(str[lastOffset]) || U8_COUNT_TRAIL_BYTES(str[lastOffset]) + lastOffset < (int32_t)size) { + + size = -1; + } else { + uint8_t leadByte = str[lastOffset]; + U8_MASK_LEAD_BYTE(leadByte, U8_COUNT_TRAIL_BYTES(leadByte)); + + for (int i = lastOffset + 1; i < offset; i++) { + + if (U8_IS_SINGLE(str[i]) || U8_IS_LEAD(str[i]) || !U8_IS_TRAIL(str[i])) { + size = -1; + } + } + + if (size != -1) { + size = lastOffset; + } + } + } + + if (size != -1 && ![[NSString alloc] initWithBytesNoCopy:(char *)[data bytes] length:size encoding:NSUTF8StringEncoding freeWhenDone:NO]) { + size = -1; + } + + return (int32_t)size; +} + +#else + +// This is a hack, and probably not optimal +static inline int32_t validate_dispatch_data_partial_string(NSData *data) { + static const int maxCodepointSize = 3; + + for (int i = 0; i < maxCodepointSize; i++) { + NSString *str = [[NSString alloc] initWithBytesNoCopy:(char *)data.bytes length:data.length - i encoding:NSUTF8StringEncoding freeWhenDone:NO]; + if (str) { + return (int)(data.length - i); + } + } + + return -1; +} + +#endif + +static _FSRRunLoopThread *networkThread = nil; +static NSRunLoop *networkRunLoop = nil; + +@implementation NSRunLoop (FSRWebSocket) + ++ (NSRunLoop *)FSR_networkRunLoop { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + networkThread = [[_FSRRunLoopThread alloc] init]; + networkThread.name = @"com.squareup.SocketRocket.NetworkThread"; + [networkThread start]; + networkRunLoop = networkThread.runLoop; + }); + + return networkRunLoop; +} + +@end + + +@implementation _FSRRunLoopThread { + dispatch_group_t _waitGroup; +} + +@synthesize runLoop = _runLoop; + +- (void)dealloc +{ + sr_dispatch_release(_waitGroup); +} + +- (id)init +{ + self = [super init]; + if (self) { + _waitGroup = dispatch_group_create(); + dispatch_group_enter(_waitGroup); + } + return self; +} + + +/** + * This is the main method of the thread on which the socket events are scheduled in a run loop. + */ +- (void)main; +{ + @autoreleasepool { + _runLoop = [NSRunLoop currentRunLoop]; + dispatch_group_leave(_waitGroup); + + // Add an empty run loop source to prevent runloop from spinning. + CFRunLoopSourceContext sourceCtx = { + .version = 0, + .info = NULL, + .retain = NULL, + .release = NULL, + .copyDescription = NULL, + .equal = NULL, + .hash = NULL, + .schedule = NULL, + .cancel = NULL, + .perform = NULL + }; + CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &sourceCtx); + CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); + CFRelease(source); + + while ([_runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) { + + } + assert(NO); + } +} + +- (NSRunLoop *)runLoop; +{ + dispatch_group_wait(_waitGroup, DISPATCH_TIME_FOREVER); + return _runLoop; +} + +@end +#endif // TARGET_OS_WATCH diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h new file mode 100644 index 0000000..bac393b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h @@ -0,0 +1,23 @@ +// +// Copyright 2012 Square Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +@interface FSRUtilities : NSObject + ++ (NSString *)base64EncodedStringFromData:(NSData *)data; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.m b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.m new file mode 100644 index 0000000..7cea4e8 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.m @@ -0,0 +1,37 @@ +// +// Copyright 2012 Square Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h" +#import "FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h" + +@implementation FSRUtilities + ++ (NSString *)base64EncodedStringFromData:(NSData *)data { + size_t buffer_size = ((data.length * 3 + 2) / 2); + + char *buffer = (char *)malloc(buffer_size); + + int len = f_b64_ntop(data.bytes, data.length, buffer, buffer_size); + + if (len == -1) { + free(buffer); + return nil; + } else{ + return [[NSString alloc] initWithBytesNoCopy:buffer length:len encoding:NSUTF8StringEncoding freeWhenDone:YES]; + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.c b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.c new file mode 100644 index 0000000..9f77b53 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.c @@ -0,0 +1,318 @@ +/* $OpenBSD: base64.c,v 1.5 2006/10/21 09:55:03 otto Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* OPENBSD ORIGINAL: lib/libc/net/base64.c */ + + +// +// Distributed with modifications by Firebase ( https://www.firebase.com ) +// + +#if (!defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)) || (!defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON)) + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h" + +static const char Base64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +#if !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) +int +f_b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) +{ + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + u_int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (int)(datalength); +} +#endif /* !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) */ + +#if !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +f_b64_pton(char const *src, u_char *target, size_t targsize) +{ + u_int tarindex, state; + int ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} + +#endif /* !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) */ +#endif diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h new file mode 100644 index 0000000..a9bf142 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h @@ -0,0 +1,33 @@ +// Copyright 2012 Square Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef FSocketRocket_base64_h +#define FSocketRocket_base64_h + +#include + +extern int +f_b64_ntop(u_char const *src, + size_t srclength, + char *target, + size_t targsize); + +extern int +f_b64_pton(char const *src, + u_char *target, + size_t targsize); + + +#endif diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h new file mode 100644 index 0000000..c0baa22 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h @@ -0,0 +1,105 @@ +// +// APLevelDB.h +// +// Created by Adam Preble on 1/23/12. +// Copyright (c) 2012 Adam Preble. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +extern NSString * const APLevelDBErrorDomain; + +@class APLevelDBIterator; +@protocol APLevelDBWriteBatch; + +@interface APLevelDB : NSObject + +@property (nonatomic, readonly, strong) NSString *path; + ++ (APLevelDB *)levelDBWithPath:(NSString *)path error:(NSError *__autoreleasing*)errorOut; +- (void)close; + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key; +- (BOOL)setString:(NSString *)str forKey:(NSString *)key; + +- (NSData *)dataForKey:(NSString *)key; +- (NSString *)stringForKey:(NSString *)key; + +- (BOOL)removeKey:(NSString *)key; + +- (NSArray *)allKeys; + +- (void)enumerateKeys:(void (^)(NSString *key, BOOL *stop))block; +- (void)enumerateKeysWithPrefix:(NSString *)prefix usingBlock:(void (^)(NSString *key, BOOL *stop))block; + +- (void)enumerateKeysAndValuesAsStrings:(void (^)(NSString *key, NSString *value, BOOL *stop))block; +- (void)enumerateKeysWithPrefix:(NSString *)prefix asStrings:(void (^)(NSString *key, NSString *value, BOOL *stop))block; + +- (void)enumerateKeysAndValuesAsData:(void (^)(NSString *key, NSData *value, BOOL *stop))block; +- (void)enumerateKeysWithPrefix:(NSString *)prefix asData:(void (^)(NSString *key, NSData *value, BOOL *stop))block; + +- (NSUInteger)approximateSizeFrom:(NSString *)from to:(NSString *)to; +- (NSUInteger)exactSizeFrom:(NSString *)from to:(NSString *)to; + +// Objective-C Subscripting Support: +// The database object supports subscripting for string-string and string-data key-value access and assignment. +// Examples: +// db[@"key"] = @"value"; +// db[@"key"] = [NSData data]; +// NSString *s = db[@"key"]; +// An NSInvalidArgumentException is raised if the key is not an NSString, or if the assigned object is not an +// instance of NSString or NSData. +- (id)objectForKeyedSubscript:(id)key; +- (void)setObject:(id)object forKeyedSubscript:(id)key; + +// Batch write/atomic update support: +- (id)beginWriteBatch; + +@end + + +@interface APLevelDBIterator : NSObject + ++ (id)iteratorWithLevelDB:(APLevelDB *)db; + +// Designated initializer: +- (id)initWithLevelDB:(APLevelDB *)db; + +- (BOOL)seekToKey:(NSString *)key; +- (NSString *)nextKey; +- (NSString *)key; +- (NSString *)valueAsString; +- (NSData *)valueAsData; + +@end + + +@protocol APLevelDBWriteBatch + +- (void)setData:(NSData *)data forKey:(NSString *)key; +- (void)setString:(NSString *)str forKey:(NSString *)key; + +- (void)removeKey:(NSString *)key; + +// Remove all of the buffered sets and removes: +- (void)clear; +- (BOOL)commit; + +@end diff --git a/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.mm b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.mm new file mode 100644 index 0000000..14b5c93 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.mm @@ -0,0 +1,500 @@ +// +// APLevelDB.m +// +// Created by Adam Preble on 1/23/12. +// Copyright (c) 2012 Adam Preble. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// +// Portions of APLevelDB are based on LevelDB-ObjC: +// https://github.com/hoisie/LevelDB-ObjC +// Specifically the SliceFromString/StringFromSlice macros, and the structure of +// the enumeration methods. License for those potions follows: +// +// Copyright (c) 2011 Pave Labs +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import "FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h" + +#import "leveldb/db.h" +#import "leveldb/options.h" +#import "leveldb/write_batch.h" + +NSString * const APLevelDBErrorDomain = @"APLevelDBErrorDomain"; + +#define SliceFromString(_string_) (leveldb::Slice((char *)[_string_ UTF8String], [_string_ lengthOfBytesUsingEncoding:NSUTF8StringEncoding])) +#define StringFromSlice(_slice_) ([[NSString alloc] initWithBytes:_slice_.data() length:_slice_.size() encoding:NSUTF8StringEncoding]) + + +@interface APLevelDBWriteBatch : NSObject { + @package + leveldb::WriteBatch _batch; +} + +@property (nonatomic, strong) APLevelDB *levelDB; + +- (id)initWithLevelDB:(APLevelDB *)levelDB; +@end + + +#pragma mark - APLevelDB + +@interface APLevelDB () { + leveldb::DB *_db; + leveldb::ReadOptions _readOptions; + leveldb::WriteOptions _writeOptions; +} +- (id)initWithPath:(NSString *)path error:(NSError **)errorOut; ++ (leveldb::Options)defaultCreateOptions; +@property (nonatomic, readonly) leveldb::DB *db; +@end + + +@implementation APLevelDB + +@synthesize path = _path; +@synthesize db = _db; + ++ (APLevelDB *)levelDBWithPath:(NSString *)path error:(NSError *__autoreleasing *)errorOut +{ + return [[APLevelDB alloc] initWithPath:path error:errorOut]; +} + +- (id)initWithPath:(NSString *)path error:(NSError *__autoreleasing *)errorOut +{ + if ((self = [super init])) + { + _path = path; + + leveldb::Options options = [[self class] defaultCreateOptions]; + + leveldb::Status status = leveldb::DB::Open(options, [_path UTF8String], &_db); + + if (!status.ok()) + { + if (errorOut) + { + NSString *statusString = [[NSString alloc] initWithCString:status.ToString().c_str() encoding:NSUTF8StringEncoding]; + *errorOut = [NSError errorWithDomain:APLevelDBErrorDomain + code:0 + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:statusString, NSLocalizedDescriptionKey, nil]]; + } + return nil; + } + + _writeOptions.sync = false; + } + return self; +} + +- (void)close { + if (_db != NULL) { + delete _db; + _db = NULL; + } +} + +- (void)dealloc +{ + if (_db != NULL) { + delete _db; + _db = NULL; + } +} + ++ (leveldb::Options)defaultCreateOptions +{ + leveldb::Options options; + options.create_if_missing = true; + return options; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + leveldb::Slice valueSlice = leveldb::Slice((const char *)[data bytes], (size_t)[data length]); + leveldb::Status status = _db->Put(_writeOptions, keySlice, valueSlice); + return (status.ok() == true); +} + +- (BOOL)setString:(NSString *)str forKey:(NSString *)key +{ + // This could have been based on + leveldb::Slice keySlice = SliceFromString(key); + leveldb::Slice valueSlice = SliceFromString(str); + leveldb::Status status = _db->Put(_writeOptions, keySlice, valueSlice); + return (status.ok() == true); +} + +- (NSData *)dataForKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + std::string valueCPPString; + leveldb::Status status = _db->Get(_readOptions, keySlice, &valueCPPString); + + if (!status.ok()) + return nil; + else + return [NSData dataWithBytes:valueCPPString.data() length:valueCPPString.size()]; +} + +- (NSString *)stringForKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + std::string valueCPPString; + leveldb::Status status = _db->Get(_readOptions, keySlice, &valueCPPString); + + // We assume (dangerously?) UTF-8 string encoding: + if (!status.ok()) + return nil; + else + return [[NSString alloc] initWithBytes:valueCPPString.data() length:valueCPPString.size() encoding:NSUTF8StringEncoding]; +} + +- (BOOL)removeKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + leveldb::Status status = _db->Delete(_writeOptions, keySlice); + return (status.ok() == true); +} + +- (NSArray *)allKeys +{ + NSMutableArray *keys = [NSMutableArray array]; + [self enumerateKeys:^(NSString *key, BOOL *stop) { + [keys addObject:key]; + }]; + return keys; +} + +- (void)enumerateKeysAndValuesAsStrings:(void (^)(NSString *key, NSString *value, BOOL *stop))block +{ + [self enumerateKeysWithPrefix:@"" asStrings:block]; +} + +- (void)enumerateKeysWithPrefix:(NSString *)prefixString asStrings:(void (^)(NSString *, NSString *, BOOL *))block +{ + @autoreleasepool { + BOOL stop = NO; + leveldb::Iterator* iter = _db->NewIterator(leveldb::ReadOptions()); + leveldb::Slice prefix = SliceFromString(prefixString); + for (iter->Seek(prefix); iter->Valid(); iter->Next()) { + leveldb::Slice key = iter->key(), value = iter->value(); + if (key.starts_with(prefix)) { + NSString *k = StringFromSlice(key); + NSString *v = [[NSString alloc] initWithBytes:value.data() length:value.size() encoding:NSUTF8StringEncoding]; + block(k, v, &stop); + if (stop) + break; + } else { + break; + } + } + + delete iter; + } +} + +- (void)enumerateKeys:(void (^)(NSString *key, BOOL *stop))block +{ + [self enumerateKeysWithPrefix:@"" usingBlock:block]; +} + +- (void)enumerateKeysWithPrefix:(NSString *)prefixString usingBlock:(void (^)(NSString *key, BOOL *stop))block; +{ + @autoreleasepool { + BOOL stop = NO; + leveldb::Slice prefix = SliceFromString(prefixString); + leveldb::Iterator* iter = _db->NewIterator(leveldb::ReadOptions()); + for (iter->Seek(prefix); iter->Valid(); iter->Next()) { + leveldb::Slice key = iter->key(); + if (key.starts_with(prefix)) { + NSString *k = StringFromSlice(key); + block(k, &stop); + if (stop) + break; + } else { + break; + } + } + + delete iter; + } +} + +- (void)enumerateKeysAndValuesAsData:(void (^)(NSString *key, NSData *data, BOOL *stop))block +{ + [self enumerateKeysWithPrefix:@"" asData:block]; +} + +- (void)enumerateKeysWithPrefix:(NSString *)prefixString asData:(void (^)(NSString *, NSData *, BOOL *))block +{ + @autoreleasepool { + BOOL stop = NO; + leveldb::Iterator* iter = _db->NewIterator(leveldb::ReadOptions()); + leveldb::Slice prefix = SliceFromString(prefixString); + for (iter->Seek(prefix); iter->Valid(); iter->Next()) { + leveldb::Slice key = iter->key(), value = iter->value(); + if (key.starts_with(prefix)) { + NSString *k = StringFromSlice(key); + NSData *data = [NSData dataWithBytes:value.data() length:value.size()]; + block(k, data, &stop); + if (stop) + break; + } else { + break; + } + } + + delete iter; + } +} + +- (NSUInteger)exactSizeFrom:(NSString *)from to:(NSString *)to { + NSUInteger size = 0; + leveldb::Iterator* iter = _db->NewIterator(leveldb::ReadOptions()); + leveldb::Slice fromSlice = SliceFromString(from); + leveldb::Slice toSlice = SliceFromString(to); + iter->Seek(fromSlice); + while (iter->Valid() && iter->key().compare(toSlice) <= 0) { + size += iter->value().size(); + iter->Next(); + } + delete iter; + return size; +} + + +- (NSUInteger)approximateSizeFrom:(NSString *)from to:(NSString *)to { + leveldb::Range ranges[1]; + leveldb::Slice fromSlice = SliceFromString(from); + leveldb::Slice toSlice = SliceFromString(to); + ranges[0] = leveldb::Range(fromSlice, toSlice); + uint64_t sizes[1]; + _db->GetApproximateSizes(ranges, 1, sizes); + return (NSUInteger)sizes[0]; +} + +#pragma mark - Subscripting Support + +- (id)objectForKeyedSubscript:(id)key +{ + if (![key respondsToSelector: @selector(componentsSeparatedByString:)]) + { + [NSException raise:NSInvalidArgumentException format:@"key must be an NSString"]; + } + return [self stringForKey:key]; +} +- (void)setObject:(id)thing forKeyedSubscript:(id)key +{ + id idKey = (id) key; + if (![idKey respondsToSelector: @selector(componentsSeparatedByString:)]) + { + [NSException raise:NSInvalidArgumentException format:@"key must be NSString or NSData"]; + } + + if ([thing respondsToSelector:@selector(componentsSeparatedByString:)]) + [self setString:thing forKey:(NSString *)key]; + else if ([thing respondsToSelector:@selector(subdataWithRange:)]) + [self setData:thing forKey:(NSString *)key]; + else + [NSException raise:NSInvalidArgumentException format:@"object must be NSString or NSData"]; +} + +#pragma mark - Atomic Updates + +- (id)beginWriteBatch +{ + APLevelDBWriteBatch *batch = [[APLevelDBWriteBatch alloc] initWithLevelDB:self]; + return batch; +} + +- (BOOL)commitWriteBatch:(id)theBatch +{ + if (!theBatch) + return NO; + + APLevelDBWriteBatch *batch = theBatch; + + leveldb::Status status; + status = _db->Write(_writeOptions, &batch->_batch); + return (status.ok() == true); +} + +@end + + +#pragma mark - APLevelDBIterator + +@interface APLevelDBIterator () { + leveldb::Iterator *_iter; +} + +@property (nonatomic, strong) APLevelDB *levelDB; +@end + + + +@implementation APLevelDBIterator + ++ (id)iteratorWithLevelDB:(APLevelDB *)db +{ + APLevelDBIterator *iter = [[[self class] alloc] initWithLevelDB:db]; + return iter; +} + +- (id)initWithLevelDB:(APLevelDB *)db +{ + if ((self = [super init])) + { + // Hold on to the database so it doesn't get deallocated before the iterator is deallocated + self->_levelDB = db; + _iter = db.db->NewIterator(leveldb::ReadOptions()); + _iter->SeekToFirst(); + if (!_iter->Valid()) + return nil; + } + return self; +} + +- (id)init +{ + [NSException raise:@"BadInitializer" format:@"Use the designated initializer, -initWithLevelDB:, instead."]; + return nil; +} + +- (void)dealloc +{ + self->_levelDB = nil; + delete _iter; + _iter = NULL; +} + +- (BOOL)seekToKey:(NSString *)key +{ + leveldb::Slice target = SliceFromString(key); + _iter->Seek(target); + return _iter->Valid() == true; +} + +- (void)seekToFirst +{ + _iter->SeekToFirst(); +} + +- (void)seekToLast +{ + _iter->SeekToLast(); +} + +- (NSString *)nextKey +{ + _iter->Next(); + return [self key]; +} + +- (NSString *)key +{ + if (_iter->Valid() == false) + return nil; + leveldb::Slice value = _iter->key(); + return StringFromSlice(value); +} + +- (NSString *)valueAsString +{ + if (_iter->Valid() == false) + return nil; + leveldb::Slice value = _iter->value(); + return StringFromSlice(value); +} + +- (NSData *)valueAsData +{ + if (_iter->Valid() == false) + return nil; + leveldb::Slice value = _iter->value(); + return [NSData dataWithBytes:value.data() length:value.size()]; +} + +@end + + + +#pragma mark - APLevelDBWriteBatch + +@implementation APLevelDBWriteBatch + +- (id)initWithLevelDB:(APLevelDB *)levelDB { + self = [super init]; + if (self != nil) { + self->_levelDB = levelDB; + } + return self; +} + +- (void)setData:(NSData *)data forKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + leveldb::Slice valueSlice = leveldb::Slice((const char *)[data bytes], (size_t)[data length]); + _batch.Put(keySlice, valueSlice); +} +- (void)setString:(NSString *)str forKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + leveldb::Slice valueSlice = SliceFromString(str); + _batch.Put(keySlice, valueSlice); +} + +- (void)removeKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + _batch.Delete(keySlice); +} + +- (void)clear +{ + _batch.Clear(); +} + +- (BOOL)commit { + return [self.levelDB commitWriteBatch:self]; +} + +@end + diff --git a/saraWhatsUp/Pods/FirebaseDatabase/Interop/Auth/Public/FIRAuthInterop.h b/saraWhatsUp/Pods/FirebaseDatabase/Interop/Auth/Public/FIRAuthInterop.h new file mode 100644 index 0000000..a33da7c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/Interop/Auth/Public/FIRAuthInterop.h @@ -0,0 +1,44 @@ +/* + * 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 FIRAuthInterop_h +#define FIRAuthInterop_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRTokenCallback + @brief The type of block which gets called when a token is ready. + */ +typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable error) + NS_SWIFT_NAME(TokenCallback); + +/// Common methods for Auth interoperability. +NS_SWIFT_NAME(AuthInterop) +@protocol FIRAuthInterop + +/// Retrieves the Firebase authentication token, possibly refreshing it if it has expired. +- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(FIRTokenCallback)callback; + +/// Get the current Auth user's UID. Returns nil if there is no user signed in. +- (nullable NSString *)getUserID; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRAuthInterop_h */ diff --git a/saraWhatsUp/Pods/FirebaseDatabase/LICENSE b/saraWhatsUp/Pods/FirebaseDatabase/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/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/saraWhatsUp/Pods/FirebaseDatabase/README.md b/saraWhatsUp/Pods/FirebaseDatabase/README.md new file mode 100644 index 0000000..7be298d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseDatabase/README.md @@ -0,0 +1,319 @@ +[![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-appcheck-badge]][gh-actions] +[![Actions Status][gh-appdistribution-badge]][gh-actions] +[![Actions Status][gh-auth-badge]][gh-actions] +[![Actions Status][gh-cocoapods-integration-badge]][gh-actions] +[![Actions Status][gh-core-badge]][gh-actions] +[![Actions Status][gh-core-diagnostics-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-google-utilities-badge]][gh-actions] +[![Actions Status][gh-google-utilities-components-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-mlmodeldownloader-badge]][gh-actions] +[![Actions Status][gh-performance-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] + +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics +and FirebaseML. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. +1. [Standard pod install](README.md#standard-pod-install) +1. [Swift Package Manager](SwiftPackageManager.md) +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). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager.md](SwiftPackageManager.md). + +### Installing from GitHub + +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: +```ruby +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: + +```ruby +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). + +### 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 12.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +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 + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### 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/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@13 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. 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. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md). + +## 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 Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### 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. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduces official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on 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 watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are 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-appcheck-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/app_check/badge.svg +[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg +[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg +[gh-cocoapods-integration-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/cocoapods-integration/badge.svg +[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg +[gh-core-diagnostics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core-diagnostics/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-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg +[gh-google-utilities-components-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities-components/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-mlmodeldownloader-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/mlmodeldownloader/badge.svg +[gh-performance-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/performance/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 diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h new file mode 100644 index 0000000..834b740 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#import + +@protocol FIRAppCheckTokenResultInterop; + +NS_ASSUME_NONNULL_BEGIN + +NS_SWIFT_NAME(AppCheckTokenHandlerInterop) +typedef void (^FIRAppCheckTokenHandlerInterop)(id tokenResult); + +@protocol FIRAppCheckInterop + +/// Retrieve a cached or generate a new FAA Token. If forcingRefresh == YES always generates a new +/// token and updates the cache. +- (void)getTokenForcingRefresh:(BOOL)forcingRefresh + completion:(FIRAppCheckTokenHandlerInterop)handler + NS_SWIFT_NAME(getToken(forcingRefresh:completion:)); + +/// A notification with the specified name is sent to the default notification center +/// (`NotificationCenter.default`) each time a Firebase app check token is refreshed. +/// The user info dictionary contains `-[self notificationTokenKey]` and +/// `-[self notificationAppNameKey]` keys. +- (NSString *)tokenDidChangeNotificationName; + +/// `userInfo` key for the FAC token in a notification for `tokenDidChangeNotificationName`. +- (NSString *)notificationTokenKey; +/// `userInfo` key for the `FirebaseApp.name` in a notification for +/// `tokenDidChangeNotificationName`. +- (NSString *)notificationAppNameKey; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h new file mode 100644 index 0000000..cb86a1b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol FIRAppCheckTokenResultInterop + +/// App Check token in the case of success or a dummy token in the case of a failure. +/// In general, the value of the token should always be set to the request header. +@property(nonatomic, readonly) NSString *token; + +/// A token fetch error in the case of a failure or `nil` in the case of success. +@property(nonatomic, readonly, nullable) NSError *error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRAppInternal.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRAppInternal.h new file mode 100644 index 0000000..6c7d723 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRAppInternal.h @@ -0,0 +1,153 @@ +/* + * 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 + +@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; +extern NSString *const kFirebaseCoreErrorDomain; + +/** The NSUserDefaults suite name for FirebaseCore, for those storage locations that use it. */ +extern NSString *const kFirebaseCoreDefaultsSuiteName; + +/** + * 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; + +/** @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; + +/** + * 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 to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * 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/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRComponent.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRComponent.h new file mode 100644 index 0000000..cb51ee7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/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 + +@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 *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 *)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/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRComponentContainer.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRComponentContainer.h new file mode 100644 index 0000000..af18a93 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRComponentContainer.h @@ -0,0 +1,41 @@ +/* + * 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 + +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> 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/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRComponentType.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRComponentType.h new file mode 100644 index 0000000..6f2aca7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/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 + +@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/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h new file mode 100644 index 0000000..76c0c05 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/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 + +@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/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRDependency.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRDependency.h new file mode 100644 index 0000000..46e9b7e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/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 + +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/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h new file mode 100644 index 0000000..9f94256 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/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 + +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 required 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/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRLibrary.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRLibrary.h new file mode 100644 index 0000000..9575e94 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * 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 + +@class FIRApp; +@class FIRComponent; + +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 *)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/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRLogger.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRLogger.h new file mode 100644 index 0000000..b6242ff --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIRLogger.h @@ -0,0 +1,146 @@ +/* + * 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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern FIRLoggerService kFIRLoggerAnalytics; +extern FIRLoggerService kFIRLoggerCrash; +extern FIRLoggerService kFIRLoggerCore; +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/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIROptionsInternal.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIROptionsInternal.h new file mode 100644 index 0000000..8efc5fc --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FIROptionsInternal.h @@ -0,0 +1,115 @@ +/* + * 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 + +/** + * 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 + NS_DESIGNATED_INITIALIZER; + +/** + * 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/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FirebaseCoreInternal.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FirebaseCoreInternal.h new file mode 100644 index 0000000..88d012b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseCore/Sources/Private/FirebaseCoreInternal.h @@ -0,0 +1,28 @@ +// 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. + +#import + +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRComponent.h" +#import "FirebaseCore/Sources/Private/FIRComponentContainer.h" +#import "FirebaseCore/Sources/Private/FIRComponentType.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/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorage.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorage.m new file mode 100644 index 0000000..2a5653b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorage.m @@ -0,0 +1,373 @@ +// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h" +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h" + +#import "FirebaseStorage/Sources/FIRStorageComponent.h" +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" +#import "FirebaseStorage/Sources/FIRStoragePath.h" +#import "FirebaseStorage/Sources/FIRStorageReference_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTokenAuthorizer.h" +#import "FirebaseStorage/Sources/FIRStorageUtils.h" +#import "FirebaseStorage/Sources/FIRStorage_Private.h" + +#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "Interop/Auth/Public/FIRAuthInterop.h" + +#if SWIFT_PACKAGE +@import GTMSessionFetcherCore; +#else +#import +#import +#endif + +static NSMutableDictionary< + NSString * /* app name */, + NSMutableDictionary *> *_fetcherServiceMap; +static GTMSessionFetcherRetryBlock _retryWhenOffline; + +@interface FIRStorage () { + /// Stored Auth reference, if it exists. This needs to be stored for `copyWithZone:`. + id _Nullable _auth; + id _Nullable _appCheck; + BOOL _usesEmulator; + NSTimeInterval _maxUploadRetryTime; + NSTimeInterval _maxDownloadRetryTime; + NSTimeInterval _maxOperationRetryTime; +} +@end + +@implementation FIRStorage + ++ (void)initialize { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _retryWhenOffline = ^(BOOL suggestedWillRetry, NSError *GTM_NULLABLE_TYPE error, + GTMSessionFetcherRetryResponse response) { + bool shouldRetry = suggestedWillRetry; + // GTMSessionFetcher does not consider being offline a retryable error, but we do, so we + // special-case it here. + if (!shouldRetry && error) { + shouldRetry = error.code == NSURLErrorNotConnectedToInternet; + } + response(shouldRetry); + }; + _fetcherServiceMap = [[NSMutableDictionary alloc] init]; + }); +} + ++ (GTMSessionFetcherService *)fetcherServiceForApp:(FIRApp *)app + bucket:(NSString *)bucket + auth:(nullable id)auth + appCheck:(nullable id)appCheck { + @synchronized(_fetcherServiceMap) { + NSMutableDictionary *bucketMap = _fetcherServiceMap[app.name]; + if (!bucketMap) { + bucketMap = [[NSMutableDictionary alloc] init]; + _fetcherServiceMap[app.name] = bucketMap; + } + + GTMSessionFetcherService *fetcherService = bucketMap[bucket]; + if (!fetcherService) { + fetcherService = [[GTMSessionFetcherService alloc] init]; + [fetcherService setRetryEnabled:YES]; + [fetcherService setRetryBlock:_retryWhenOffline]; + [fetcherService setAllowLocalhostRequest:YES]; + FIRStorageTokenAuthorizer *authorizer = + [[FIRStorageTokenAuthorizer alloc] initWithGoogleAppID:app.options.googleAppID + fetcherService:fetcherService + authProvider:auth + appCheck:appCheck]; + [fetcherService setAuthorizer:authorizer]; + bucketMap[bucket] = fetcherService; + } + return fetcherService; + } +} + ++ (void)setGTMSessionFetcherLoggingEnabled:(BOOL)isLoggingEnabled { + [GTMSessionFetcher setLoggingEnabled:isLoggingEnabled]; +} + ++ (instancetype)storage { + return [self storageForApp:[FIRApp defaultApp]]; +} + ++ (instancetype)storageForApp:(FIRApp *)app { + if (app.options.storageBucket) { + NSString *url = [app.options.storageBucket isEqualToString:@""] + ? @"" + : [@"gs://" stringByAppendingString:app.options.storageBucket]; + return [self storageForApp:app URL:url]; + } else { + NSString *const kAppNotConfiguredMessage = + @"No default Storage bucket found. Did you configure Firebase Storage properly?"; + [NSException raise:NSInvalidArgumentException format:kAppNotConfiguredMessage]; + return nil; + } +} + ++ (instancetype)storageWithURL:(NSString *)url { + return [self storageForApp:[FIRApp defaultApp] URL:url]; +} + ++ (instancetype)storageForApp:(FIRApp *)app URL:(NSString *)url { + NSString *bucket; + if ([url isEqualToString:@""]) { + bucket = @""; + } else { + FIRStoragePath *path; + + @try { + path = [FIRStoragePath pathFromGSURI:url]; + } @catch (NSException *e) { + [NSException raise:NSInternalInconsistencyException + format:@"URI must be in the form of gs:///"]; + } + + if (path.object != nil && ![path.object isEqualToString:@""]) { + [NSException raise:NSInternalInconsistencyException + format:@"Storage bucket cannot be initialized with a path"]; + } + + bucket = path.bucket; + } + + // Retrieve the instance provider from the app's container to inject dependencies as needed. + id provider = + FIR_COMPONENT(FIRStorageMultiBucketProvider, app.container); + return [provider storageForBucket:bucket]; +} + +- (instancetype)initWithApp:(FIRApp *)app + bucket:(NSString *)bucket + auth:(nullable id)auth + appCheck:(nullable id)appCheck { + self = [super init]; + if (self) { + _app = app; + _auth = auth; + _appCheck = appCheck; + _storageBucket = bucket; + _host = kFIRStorageHost; + _scheme = kFIRStorageScheme; + _port = @(kFIRStoragePort); + _fetcherServiceForApp = nil; // Configured in `ensureConfigured()` + // Must be a serial queue. + _dispatchQueue = dispatch_queue_create("com.google.firebase.storage", DISPATCH_QUEUE_SERIAL); + _maxDownloadRetryTime = 600.0; + _maxDownloadRetryInterval = + [FIRStorageUtils computeRetryIntervalFromRetryTime:_maxDownloadRetryTime]; + _maxOperationRetryTime = 120.0; + _maxOperationRetryInterval = + [FIRStorageUtils computeRetryIntervalFromRetryTime:_maxOperationRetryTime]; + _maxUploadRetryTime = 600.0; + _maxUploadRetryInterval = + [FIRStorageUtils computeRetryIntervalFromRetryTime:_maxUploadRetryTime]; + } + return self; +} + +- (instancetype)init { + NSAssert(false, @"Storage cannot be directly instantiated, use " + "Storage.storage() or Storage.storage(app:) instead"); + return nil; +} + +#pragma mark - NSObject overrides + +- (instancetype)copyWithZone:(NSZone *)zone { + FIRStorage *storage = [[[self class] allocWithZone:zone] initWithApp:_app + bucket:_storageBucket + auth:_auth + appCheck:_appCheck]; + storage.callbackQueue = self.callbackQueue; + return storage; +} + +// Two FIRStorage objects are equal if they use the same app +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[FIRStorage class]]) { + return NO; + } + + BOOL isEqualObject = [self isEqualToFIRStorage:(FIRStorage *)object]; + return isEqualObject; +} + +- (BOOL)isEqualToFIRStorage:(FIRStorage *)storage { + BOOL isEqual = + [_app isEqual:storage.app] && [_storageBucket isEqualToString:storage.storageBucket]; + return isEqual; +} + +- (NSUInteger)hash { + NSUInteger hash = [_app hash] ^ [self.callbackQueue hash]; + return hash; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@ %p: %@", [self class], self, _app]; +} + +#pragma mark - Retry time intervals + +- (void)setMaxUploadRetryTime:(NSTimeInterval)maxUploadRetryTime { + @synchronized(self) { + _maxUploadRetryTime = maxUploadRetryTime; + _maxUploadRetryInterval = + [FIRStorageUtils computeRetryIntervalFromRetryTime:maxUploadRetryTime]; + } +} + +- (NSTimeInterval)maxDownloadRetryTime { + @synchronized(self) { + return _maxDownloadRetryTime; + } +} + +- (void)setMaxDownloadRetryTime:(NSTimeInterval)maxDownloadRetryTime { + @synchronized(self) { + _maxDownloadRetryTime = maxDownloadRetryTime; + _maxDownloadRetryInterval = + [FIRStorageUtils computeRetryIntervalFromRetryTime:maxDownloadRetryTime]; + } +} + +- (NSTimeInterval)maxUploadRetryTime { + @synchronized(self) { + return _maxUploadRetryTime; + } +} + +- (void)setMaxOperationRetryTime:(NSTimeInterval)maxOperationRetryTime { + @synchronized(self) { + _maxOperationRetryTime = maxOperationRetryTime; + _maxOperationRetryInterval = + [FIRStorageUtils computeRetryIntervalFromRetryTime:maxOperationRetryTime]; + } +} + +- (NSTimeInterval)maxOperationRetryTime { + @synchronized(self) { + return _maxOperationRetryTime; + } +} + +#pragma mark - Public methods + +- (FIRStorageReference *)reference { + [self ensureConfigured]; + + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:_storageBucket object:nil]; + return [[FIRStorageReference alloc] initWithStorage:self path:path]; +} + +- (FIRStorageReference *)referenceForURL:(NSString *)string { + [self ensureConfigured]; + + FIRStoragePath *path = [FIRStoragePath pathFromString:string]; + + // If no default bucket exists (empty string), accept anything. + if ([_storageBucket isEqual:@""]) { + FIRStorageReference *reference = [[FIRStorageReference alloc] initWithStorage:self path:path]; + return reference; + } + + // If there exists a default bucket, throw if provided a different bucket. + if (![path.bucket isEqual:_storageBucket]) { + NSString *const kInvalidBucketFormat = + @"Provided bucket: %@ does not match the Storage bucket of the current instance: %@"; + [NSException raise:NSInvalidArgumentException + format:kInvalidBucketFormat, path.bucket, _storageBucket]; + } + + FIRStorageReference *reference = [[FIRStorageReference alloc] initWithStorage:self path:path]; + return reference; +} + +- (FIRStorageReference *)referenceWithPath:(NSString *)string { + FIRStorageReference *reference = [[self reference] child:string]; + return reference; +} + +- (dispatch_queue_t)callbackQueue { + [self ensureConfigured]; + return _fetcherServiceForApp.callbackQueue; +} + +- (void)setCallbackQueue:(dispatch_queue_t)callbackQueue { + [self ensureConfigured]; + _fetcherServiceForApp.callbackQueue = callbackQueue; +} + +- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port { + if (host.length == 0) { + [NSException raise:NSInvalidArgumentException format:@"Cannot connect to nil or empty host."]; + } + + if (port < 0) { + [NSException raise:NSInvalidArgumentException + format:@"Port must be greater than or equal to zero."]; + } + + if (_fetcherServiceForApp != nil) { + [NSException raise:NSInternalInconsistencyException + format:@"Cannot connect to emulator after Storage SDK initialization. " + @"Call useEmulator(host:port:) before creating a Storage " + @"reference or trying to load data."]; + } + + _usesEmulator = YES; + _scheme = @"http"; + _host = host; + _port = @(port); +} + +#pragma mark - Background tasks + ++ (void)enableBackgroundTasks:(BOOL)isEnabled { + [NSException raise:NSGenericException format:@"enableBackgroundTasks not implemented"]; +} + +- (NSArray *)uploadTasks { + [NSException raise:NSGenericException format:@"getUploadTasks not implemented"]; + return nil; +} + +- (NSArray *)downloadTasks { + [NSException raise:NSGenericException format:@"getDownloadTasks not implemented"]; + return nil; +} + +- (void)ensureConfigured { + if (!_fetcherServiceForApp) { + _fetcherServiceForApp = [FIRStorage fetcherServiceForApp:_app + bucket:_storageBucket + auth:_auth + appCheck:_appCheck]; + if (_usesEmulator) { + _fetcherServiceForApp.allowLocalhostRequest = YES; + _fetcherServiceForApp.allowedInsecureSchemes = @[ @"http" ]; + } + } +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageComponent.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageComponent.h new file mode 100644 index 0000000..ac3637b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageComponent.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 + +@class FIRApp; +@class FIRStorage; + +NS_ASSUME_NONNULL_BEGIN + +/// This protocol is used in the interop registration process to register an instance provider for +/// individual FIRApps. +@protocol FIRStorageMultiBucketProvider + +/// Default method for creating a Storage instance. +- (FIRStorage *)storageForBucket:(NSString *)bucket; + +@end + +/// A concrete implementation for FIRStorageMultiBucketProvider to create Storage instances. +@interface FIRStorageComponent : NSObject + +/// The FIRApp that instances will be set up with. +@property(nonatomic, weak, readonly) FIRApp *app; + +/// Default method for creating a Storage instance. +- (FIRStorage *)storageForBucket:(NSString *)bucket; + +/// Unavailable, use `storageForApp:storageURL:` instead. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageComponent.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageComponent.m new file mode 100644 index 0000000..521ffef --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageComponent.m @@ -0,0 +1,102 @@ +// 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 "FirebaseStorage/Sources/FIRStorageComponent.h" + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h" + +#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h" +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" +#import "Interop/Auth/Public/FIRAuthInterop.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A NSMutableDictionary of FirebaseApp name and bucket names to FIRStorage instance. */ +typedef NSMutableDictionary FIRStorageDictionary; + +@interface FIRStorage () +// Surface the internal initializer to create instances of FIRStorage. +- (instancetype)initWithApp:(FIRApp *)app + bucket:(NSString *)bucket + auth:(nullable id)auth + appCheck:(nullable id)appCheck; +@end + +@interface FIRStorageComponent () +@property(nonatomic) FIRStorageDictionary *instances; +/// Internal initializer. +- (instancetype)initWithApp:(FIRApp *)app; +@end + +@implementation FIRStorageComponent + +#pragma mark - Initialization + +- (instancetype)initWithApp:(FIRApp *)app { + self = [super init]; + if (self) { + _app = app; + _instances = [NSMutableDictionary dictionary]; + } + return self; +} + +#pragma mark - Lifecycle + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self withName:@"fire-str"]; +} + +#pragma mark - FIRComponentRegistrant + ++ (nonnull NSArray *)componentsToRegister { + FIRDependency *authDep = [FIRDependency dependencyWithProtocol:@protocol(FIRAuthInterop) + isRequired:NO]; + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + *isCacheable = YES; + return [[FIRStorageComponent alloc] initWithApp:container.app]; + }; + FIRComponent *storageProvider = + [FIRComponent componentWithProtocol:@protocol(FIRStorageMultiBucketProvider) + instantiationTiming:FIRInstantiationTimingLazy + dependencies:@[ authDep ] + creationBlock:creationBlock]; + + return @[ storageProvider ]; +} + +#pragma mark - FIRStorageInstanceProvider Conformance + +- (FIRStorage *)storageForBucket:(NSString *)bucket { + FIRStorageDictionary *instances = [self instances]; + @synchronized(instances) { + FIRStorage *instance = instances[bucket]; + if (!instance) { + // Create an instance of FIRStorage and return it. + id auth = FIR_COMPONENT(FIRAuthInterop, self.app.container); + id appCheck = FIR_COMPONENT(FIRAppCheckInterop, self.app.container); + instance = [[FIRStorage alloc] initWithApp:self.app + bucket:bucket + auth:auth + appCheck:appCheck]; + instances[bucket] = instance; + } + return instance; + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageConstants.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageConstants.m new file mode 100644 index 0000000..786d17f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageConstants.m @@ -0,0 +1,87 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" + +NSString *const kGCSScheme = @"https"; +NSString *const kGCSHost = @"www.googleapis.com"; +NSString *const kGCSUploadPath = @"upload"; +NSString *const kGCSStorageVersionPath = @"storage/v1"; +NSString *const kGCSBucketPathFormat = @"b/%@"; +NSString *const kGCSObjectPathFormat = @"o/%@"; + +NSString *const kFIRStorageScheme = @"https"; +NSString *const kFIRStorageHost = @"firebasestorage.googleapis.com"; +NSInteger const kFIRStoragePort = 443; +NSString *const kFIRStorageVersionPath = @"v0"; +NSString *const kFIRStorageBucketPathFormat = @"b/%@"; +NSString *const kFIRStorageObjectPathFormat = @"o/%@"; +NSString *const kFIRStorageFullPathFormat = @"/v0/b/%@/o/%@"; + +NSString *const kFIRStorageAuthTokenFormat = @"Firebase %@"; +NSString *const kFIRStorageDefaultBucketFormat = @"gs://%@"; + +NSString *const kFIRStorageResponseErrorDomain = @"ResponseErrorDomain"; +NSString *const kFIRStorageResponseErrorCode = @"ResponseErrorCode"; +NSString *const kFIRStorageResponseBody = @"ResponseBody"; + +NSString *const FIRStorageErrorDomain = @"FIRStorageErrorDomain"; + +NSString *const kFIRStorageInvalidDataFormat = @"Invalid data returned from the server: %@"; +NSString *const kFIRStorageInvalidObserverStatus = + @"Invalid observer status requested, use one " + @"of: FIRStorageTaskStatusPause, Resume, Progress, " + @"Complete, or Failure"; + +/** + * String constants mapping GCS Object#list results to ListResult fields. + */ +NSString *const kFIRStorageListPrefixes = @"prefixes"; +NSString *const kFIRStorageListItems = @"items"; +NSString *const kFIRStorageListItemName = @"name"; +NSString *const kFIRStorageListPageToken = @"nextPageToken"; + +/** + * String constants mapping GCS Object#resource mappings to metadata fields. + */ +NSString *const kFIRStorageMetadataBucket = @"bucket"; +NSString *const kFIRStorageMetadataCacheControl = @"cacheControl"; +NSString *const kFIRStorageMetadataContentDisposition = @"contentDisposition"; +NSString *const kFIRStorageMetadataContentEncoding = @"contentEncoding"; +NSString *const kFIRStorageMetadataContentLanguage = @"contentLanguage"; +NSString *const kFIRStorageMetadataContentType = @"contentType"; +NSString *const kFIRStorageMetadataCustomMetadata = @"metadata"; +NSString *const kFIRStorageMetadataSize = @"size"; +NSString *const kFIRStorageMetadataGeneration = @"generation"; +NSString *const kFIRStorageMetadataMetageneration = @"metageneration"; +NSString *const kFIRStorageMetadataTimeCreated = @"timeCreated"; +NSString *const kFIRStorageMetadataUpdated = @"updated"; +NSString *const kFIRStorageMetadataName = @"name"; +NSString *const kFIRStorageMetadataDownloadTokens = @"downloadTokens"; +NSString *const kFIRStorageMetadataMd5Hash = @"md5Hash"; + +// TODO: add notification support +NSString *const kFIRStorageTaskStatusResumeNotification = + @"kFIRStorageTaskStatusResumeNotification"; +NSString *const kFIRStorageTaskStatusPauseNotification = @"kFIRStorageTaskStatusResumeNotification"; +NSString *const kFIRStorageTaskStatusProgressNotification = + @"kFIRStorageTaskStatusResumeNotification"; +NSString *const kFIRStorageTaskStatusCompleteNotification = + @"kFIRStorageTaskStatusResumeNotification"; +NSString *const kFIRStorageTaskStatusFailureNotification = + @"kFIRStorageTaskStatusResumeNotification"; + +NSString *const kFIRStorageBundleIdentifier = @"com.google.firebase.storage"; diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageConstants_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageConstants_Private.h new file mode 100644 index 0000000..3a46cb1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageConstants_Private.h @@ -0,0 +1,151 @@ +/* + * 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 + +@class FIRStorageMetadata; + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const kGCSScheme; +FOUNDATION_EXPORT NSString *const kGCSHost; +FOUNDATION_EXPORT NSString *const kGCSUploadPath; +FOUNDATION_EXPORT NSString *const kGCSStorageVersionPath; +FOUNDATION_EXPORT NSString *const kGCSBucketPathFormat; +FOUNDATION_EXPORT NSString *const kGCSObjectPathFormat; + +FOUNDATION_EXPORT NSString *const kFIRStorageScheme; +FOUNDATION_EXPORT NSString *const kFIRStorageHost; +FOUNDATION_EXPORT NSInteger const kFIRStoragePort; +FOUNDATION_EXPORT NSString *const kFIRStorageVersionPath; +FOUNDATION_EXPORT NSString *const kFIRStorageBucketPathFormat; +FOUNDATION_EXPORT NSString *const kFIRStorageObjectPathFormat; +FOUNDATION_EXPORT NSString *const kFIRStorageFullPathFormat; + +FOUNDATION_EXPORT NSString *const kFIRStorageAuthTokenFormat; +FOUNDATION_EXPORT NSString *const kFIRStorageDefaultBucketFormat; + +FOUNDATION_EXPORT NSString *const kFIRStorageResponseErrorDomain; +FOUNDATION_EXPORT NSString *const kFIRStorageResponseErrorCode; +FOUNDATION_EXPORT NSString *const kFIRStorageResponseBody; + +FOUNDATION_EXPORT NSString *const kFIRStorageTaskStatusResumeNotification; +FOUNDATION_EXPORT NSString *const kFIRStorageTaskStatusPauseNotification; +FOUNDATION_EXPORT NSString *const kFIRStorageTaskStatusProgressNotification; +FOUNDATION_EXPORT NSString *const kFIRStorageTaskStatusCompleteNotification; +FOUNDATION_EXPORT NSString *const kFIRStorageTaskStatusFailureNotification; + +FOUNDATION_EXPORT NSString *const kFIRStorageListPrefixes; +FOUNDATION_EXPORT NSString *const kFIRStorageListItems; +FOUNDATION_EXPORT NSString *const kFIRStorageListItemName; +FOUNDATION_EXPORT NSString *const kFIRStorageListPageToken; + +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataBucket; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataCacheControl; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataContentDisposition; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataContentEncoding; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataContentLanguage; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataContentType; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataCustomMetadata; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataSize; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataGeneration; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataMetageneration; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataTimeCreated; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataUpdated; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataName; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataDownloadTokens; +FOUNDATION_EXPORT NSString *const kFIRStorageMetadataMd5Hash; + +FOUNDATION_EXPORT NSString *const kFIRStorageInvalidDataFormat; +FOUNDATION_EXPORT NSString *const kFIRStorageInvalidObserverStatus; + +FOUNDATION_EXPORT NSString *const kFIRStorageBundleIdentifier; + +/** + * Enum representing the internal state of an upload or download task. + */ +typedef NS_ENUM(NSInteger, FIRStorageTaskState) { + /** + * Unknown task state + */ + FIRStorageTaskStateUnknown, + + /** + * Task is being queued is ready to run + */ + FIRStorageTaskStateQueueing, + + /** + * Task is resuming from a paused state + */ + FIRStorageTaskStateResuming, + + /** + * Task is currently running + */ + FIRStorageTaskStateRunning, + + /** + * Task reporting a progress event + */ + FIRStorageTaskStateProgress, + + /** + * Task is pausing + */ + FIRStorageTaskStatePausing, + + /** + * Task is completing successfully + */ + FIRStorageTaskStateCompleting, + + /** + * Task is failing unrecoverably + */ + FIRStorageTaskStateFailing, + + /** + * Task paused successfully + */ + FIRStorageTaskStatePaused, + + /** + * Task cancelled successfully + */ + FIRStorageTaskStateCancelled, + + /** + * Task completed successfully + */ + FIRStorageTaskStateSuccess, + + /** + * Task failed unrecoverably + */ + FIRStorageTaskStateFailed +}; + +/** + * Represents the various types of metadata: Files or Folders. + */ +typedef NS_ENUM(NSUInteger, FIRStorageMetadataType) { + FIRStorageMetadataTypeUnknown, + FIRStorageMetadataTypeFile, + FIRStorageMetadataTypeFolder, +}; + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDeleteTask.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDeleteTask.h new file mode 100644 index 0000000..5607714 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDeleteTask.h @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h" + +@class GTMSessionFetcherService; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Task which provides the ability to delete an object in Firebase Storage. + */ +@interface FIRStorageDeleteTask : FIRStorageTask + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + completion:(FIRStorageVoidError)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDeleteTask.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDeleteTask.m new file mode 100644 index 0000000..7fd7651 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDeleteTask.m @@ -0,0 +1,83 @@ +// 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 "FirebaseStorage/Sources/FIRStorageDeleteTask.h" + +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" + +@implementation FIRStorageDeleteTask { + @private + FIRStorageVoidError _completion; +} + +@synthesize fetcher = _fetcher; +@synthesize fetcherCompletion = _fetcherCompletion; + +- (void)dealloc { + [_fetcher stopFetching]; +} + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + completion:(FIRStorageVoidError)completion { + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; + if (self) { + _completion = [completion copy]; + } + return self; +} + +- (void)enqueue { + __weak FIRStorageDeleteTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageDeleteTask *strongSelf = weakSelf; + + if (!strongSelf) { + return; + } + + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + request.HTTPMethod = @"DELETE"; + request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime; + + FIRStorageVoidError callback = strongSelf->_completion; + strongSelf->_completion = nil; + + GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + strongSelf->_fetcher = fetcher; + + fetcher.comment = @"DeleteTask"; + + strongSelf->_fetcherCompletion = ^(NSData *_Nullable data, NSError *_Nullable error) { + if (!self.error) { + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + } + if (callback) { + callback(self.error); + } + self->_fetcherCompletion = nil; + }; + + [fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) { + FIRStorageDeleteTask *strongSelf = weakSelf; + if (strongSelf.fetcherCompletion) { + strongSelf.fetcherCompletion(data, error); + } + }]; + }]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDownloadTask.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDownloadTask.m new file mode 100644 index 0000000..9671495 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDownloadTask.m @@ -0,0 +1,199 @@ +// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageDownloadTask.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" +#import "FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorageObservableTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorage_Private.h" + +@implementation FIRStorageDownloadTask + +@synthesize progress = _progress; +@synthesize fetcher = _fetcher; +@synthesize fetcherCompletion = _fetcherCompletion; + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + file:(nullable NSURL *)fileURL { + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; + if (self) { + _fileURL = [fileURL copy]; + _progress = [NSProgress progressWithTotalUnitCount:0]; + } + return self; +} + +- (void)dealloc { + [_fetcher stopFetching]; +} + +- (void)enqueue { + [self enqueueWithData:nil]; +} + +- (void)enqueueWithData:(nullable NSData *)resumeData { + __weak FIRStorageDownloadTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageDownloadTask *strongSelf = weakSelf; + + if (!strongSelf) { + return; + } + + strongSelf.state = FIRStorageTaskStateQueueing; + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + request.HTTPMethod = @"GET"; + request.timeoutInterval = strongSelf.reference.storage.maxDownloadRetryTime; + NSURLComponents *components = [NSURLComponents componentsWithURL:request.URL + resolvingAgainstBaseURL:NO]; + [components setQuery:@"alt=media"]; + request.URL = components.URL; + + GTMSessionFetcher *fetcher; + if (resumeData) { + fetcher = [GTMSessionFetcher fetcherWithDownloadResumeData:resumeData]; + fetcher.comment = @"Resuming DownloadTask"; + } else { + fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + fetcher.comment = @"Starting DownloadTask"; + } + + [fetcher setResumeDataBlock:^(NSData *data) { + FIRStorageDownloadTask *strong = weakSelf; + if (strong && data) { + strong->_downloadData = data; + } + }]; + + fetcher.maxRetryInterval = strongSelf.reference.storage.maxDownloadRetryInterval; + + if (strongSelf->_fileURL) { + // Handle file downloads + [fetcher setDestinationFileURL:strongSelf->_fileURL]; + [fetcher setDownloadProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite) { + weakSelf.state = FIRStorageTaskStateProgress; + weakSelf.progress.completedUnitCount = totalBytesWritten; + weakSelf.progress.totalUnitCount = totalBytesExpectedToWrite; + FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot]; + weakSelf.state = FIRStorageTaskStateRunning; + }]; + } else { + // Handle data downloads + [fetcher setReceivedProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten) { + weakSelf.state = FIRStorageTaskStateProgress; + weakSelf.progress.completedUnitCount = totalBytesWritten; + int64_t totalLength = [[weakSelf.fetcher response] expectedContentLength]; + weakSelf.progress.totalUnitCount = totalLength; + FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot]; + weakSelf.state = FIRStorageTaskStateRunning; + }]; + } + + strongSelf->_fetcher = fetcher; + strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) { + // Fire last progress updates + [self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot]; + + // Handle potential issues with download + if (error) { + self.state = FIRStorageTaskStateFailed; + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot]; + [self removeAllObservers]; + self->_fetcherCompletion = nil; + return; + } + + // Download completed successfully, fire completion callbacks + self.state = FIRStorageTaskStateSuccess; + + if (data) { + self->_downloadData = data; + } + + [self fireHandlersForStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot]; + [self removeAllObservers]; + self->_fetcherCompletion = nil; + }; + + strongSelf.state = FIRStorageTaskStateRunning; + [strongSelf.fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + FIRStorageDownloadTask *strongSelf = weakSelf; + if (strongSelf.fetcherCompletion) { + strongSelf.fetcherCompletion(data, error); + } + }]; + }]; +} + +#pragma mark - Download Management + +- (void)cancel { + NSError *error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeCancelled]; + [self cancelWithError:error]; +} + +- (void)cancelWithError:(NSError *)error { + __weak FIRStorageDownloadTask *weakSelf = self; + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStateCancelled; + [weakSelf.fetcher stopFetching]; + weakSelf.error = error; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:weakSelf.snapshot]; + }]; +} + +- (void)pause { + __weak FIRStorageDownloadTask *weakSelf = self; + [self dispatchAsync:^() { + __strong FIRStorageDownloadTask *strongSelf = weakSelf; + if (!strongSelf || strongSelf.state == FIRStorageTaskStatePaused || + strongSelf.state == FIRStorageTaskStatePausing) { + return; + } + strongSelf.state = FIRStorageTaskStatePausing; + // Use the resume callback to confirm pause status since it always runs after the last + // NSURLSession update. + [strongSelf.fetcher setResumeDataBlock:^(NSData *data) { + // Silence compiler warning about retain cycles + __strong __typeof(self) strong = weakSelf; + strong->_downloadData = data; + strong.state = FIRStorageTaskStatePaused; + FIRStorageTaskSnapshot *snapshot = strong.snapshot; + [strong fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:snapshot]; + }]; + [strongSelf.fetcher stopFetching]; + }]; +} + +- (void)resume { + __weak FIRStorageDownloadTask *weakSelf = self; + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStateResuming; + FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:snapshot]; + weakSelf.state = FIRStorageTaskStateRunning; + [weakSelf enqueueWithData:weakSelf.downloadData]; + }]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h new file mode 100644 index 0000000..028317f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h @@ -0,0 +1,59 @@ +/* + * 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 + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageDownloadTask.h" + +@class FIRStorageReference; +@class GTMSessionFetcherService; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStorageDownloadTask () + +/** + * Bytes which have been downloaded so far. + */ +@property(readonly, nonatomic) NSData *downloadData; + +/** + * The file on disk to write to. + */ +@property(copy, nonatomic) NSURL *fileURL; + +/** + * Initializes a download task with a base FIRStorageReference and GTMSessionFetcherService. + * @param reference The base FIRStorageReference which fetchers use for configuration. + * @param service The GTMSessionFetcherService which will create fetchers. + * @param queue The shared queue to use for all Storage operations. + * @param fileURL The system URL to download to. If nil, download in memory as bytes. + * @return Returns an instance of FIRStorageDownloadTask + */ +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + file:(nullable NSURL *)fileURL; + +/** + * Cancels the download task and passes an appropriate error to the developer. + * @param error NSError to propegate to the developer. + */ +- (void)cancelWithError:(NSError *)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageErrors.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageErrors.h new file mode 100644 index 0000000..86dca47 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageErrors.h @@ -0,0 +1,70 @@ +/* + * 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRStorageReference; + +/** + * Adds wrappers for common Firebase Storage errors (including creating errors from GCS errors). + * For more information on unwrapping GCS errors, see the GCS errors docs: + * https://cloud.google.com/storage/docs/json_api/v1/status-codes + * This is never publicly exposed to end developers (as they will simply see an NSError). + */ +@interface FIRStorageErrors : NSObject + +/** + * Creates a Firebase Storage error from a specific FIRStorageErrorCode. + */ ++ (NSError *)errorWithCode:(FIRStorageErrorCode)code; + +/** + * Creates a Firebase Storage error from a specific FIRStorageErrorCode while adding + * custom info from an optionally provided info dictionary. + */ ++ (NSError *)errorWithCode:(FIRStorageErrorCode)code + infoDictionary:(nullable NSDictionary *)dictionary; + +/** + * Creates a Firebase Storage error from a specific GCS error and FIRStorageReference. + * @param error Server error to wrap and return as a Firebase Storage error. + * @param reference FIRStorageReference which provides context about the request being made. + * @return Returns a Firebase Storage error, or nil if no error is provided. + */ ++ (nullable NSError *)errorWithServerError:(nullable NSError *)error + reference:(nullable FIRStorageReference *)reference; + +/** + * Creates a Firebase Storage error from an invalid request. + * + * @param request The NSData representation of the invalid user request. + * @return Returns the corresponding Firebase Storage error. + */ ++ (NSError *)errorWithInvalidRequest:(NSData *)request; + +/** + * Creates a Firebase Storage error with a custom error message. + * + * @param errorMessage A custom error message. + * @return Returns the corresponding Firebase Storage error. + */ ++ (NSError *)errorWithCustomMessage:(NSString *)errorMessage; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageErrors.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageErrors.m new file mode 100644 index 0000000..1e5b425 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageErrors.m @@ -0,0 +1,190 @@ +// 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 "FirebaseStorage/Sources/FIRStorageErrors.h" + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" +#import "FirebaseStorage/Sources/FIRStorageReference_Private.h" + +@implementation FIRStorageErrors + ++ (NSError *)errorWithCode:(FIRStorageErrorCode)code { + return [FIRStorageErrors errorWithCode:code infoDictionary:nil]; +} + ++ (NSError *)errorWithCode:(FIRStorageErrorCode)code + infoDictionary:(nullable NSDictionary *)dictionary { + NSMutableDictionary *errorDictionary; + if (dictionary) { + errorDictionary = [dictionary mutableCopy]; + } else { + errorDictionary = [[NSMutableDictionary alloc] init]; + } + + NSString *errorMessage; + switch (code) { + case FIRStorageErrorCodeObjectNotFound: + errorMessage = + [NSString stringWithFormat:@"Object %@ does not exist.", errorDictionary[@"object"]]; + break; + + case FIRStorageErrorCodeBucketNotFound: + errorMessage = + [NSString stringWithFormat:@"Bucket %@ does not exist.", errorDictionary[@"bucket"]]; + break; + + case FIRStorageErrorCodeProjectNotFound: + errorMessage = + [NSString stringWithFormat:@"Project %@ does not exist.", errorDictionary[@"project"]]; + break; + + case FIRStorageErrorCodeQuotaExceeded: { + NSString *const kQuotaExceededFormat = + @"Quota for bucket %@ exceeded, please view quota on firebase.google.com."; + errorMessage = [NSString stringWithFormat:kQuotaExceededFormat, errorDictionary[@"bucket"]]; + break; + } + + case FIRStorageErrorCodeDownloadSizeExceeded: { + int64_t total = [errorDictionary[@"totalSize"] longLongValue]; + int64_t size = [errorDictionary[@"maxAllowedSize"] longLongValue]; + NSString *totalString = total ? @(total).stringValue : @"unknown"; + NSString *sizeString = total ? @(size).stringValue : @"unknown"; + NSString *const kSizeExceededErrorFormat = + @"Attempted to download object with size of %@ bytes, " + @"which exceeds the maximum size of %@ bytes. " + @"Consider raising the maximum download size, or using " + @"[FIRStorageReference writeToFile:]"; + errorMessage = [NSString stringWithFormat:kSizeExceededErrorFormat, totalString, sizeString]; + break; + } + + case FIRStorageErrorCodeUnauthenticated: + errorMessage = @"User is not authenticated, please authenticate using Firebase " + @"Authentication and try again."; + break; + + case FIRStorageErrorCodeUnauthorized: { + NSString *bucket = errorDictionary[@"bucket"]; + NSString *object = errorDictionary[@"object"]; + NSString *const kUnauthorizedFormat = @"User does not have permission to access gs://%@/%@."; + errorMessage = [NSString stringWithFormat:kUnauthorizedFormat, bucket, object]; + break; + } + + case FIRStorageErrorCodeRetryLimitExceeded: + errorMessage = @"Max retry time for operation exceeded, please try again."; + break; + + case FIRStorageErrorCodeNonMatchingChecksum: { + // TODO: replace with actual checksum strings when we choose to implement. + NSString *const kChecksumFailedErrorFormat = + @"Uploaded/downloaded object %@ has checksum: %@ " + @"which does not match server checksum: %@. Please retry the upload/download."; + errorMessage = [NSString stringWithFormat:kChecksumFailedErrorFormat, @"object", + @"client checksum", @"server checksum"]; + break; + } + + case FIRStorageErrorCodeCancelled: + errorMessage = @"User cancelled the upload/download."; + break; + + case FIRStorageErrorCodeUnknown: + /* Fall through to default case for unknown errors */ + + default: + errorMessage = @"An unknown error occurred, please check the server response."; + break; + } + + errorDictionary[NSLocalizedDescriptionKey] = errorMessage; + + NSError *err = [NSError errorWithDomain:FIRStorageErrorDomain code:code userInfo:errorDictionary]; + return err; +} + ++ (nullable NSError *)errorWithServerError:(nullable NSError *)error + reference:(nullable FIRStorageReference *)reference { + if (error == nil) { + return nil; + } + + FIRStorageErrorCode errorCode; + switch (error.code) { + case 400: + errorCode = FIRStorageErrorCodeUnknown; + break; + + case 401: + errorCode = FIRStorageErrorCodeUnauthenticated; + break; + + case 402: + errorCode = FIRStorageErrorCodeQuotaExceeded; + break; + + case 403: + errorCode = FIRStorageErrorCodeUnauthorized; + break; + + case 404: + errorCode = FIRStorageErrorCodeObjectNotFound; + break; + + default: + errorCode = FIRStorageErrorCodeUnknown; + break; + } + + NSMutableDictionary *errorDictionary = + [[[NSDictionary alloc] initWithDictionary:error.userInfo] mutableCopy]; + errorDictionary[kFIRStorageResponseErrorDomain] = error.domain; + errorDictionary[kFIRStorageResponseErrorCode] = @(error.code); + + // Turn raw response into a string + NSData *responseData = errorDictionary[@"data"]; + if (responseData) { + NSString *errorString = [[NSString alloc] initWithData:responseData + encoding:NSUTF8StringEncoding]; + errorDictionary[kFIRStorageResponseBody] = errorString ?: @"No Response from Server."; + } + + errorDictionary[@"bucket"] = reference.path.bucket; + errorDictionary[@"object"] = reference.path.object; + + NSError *clientError = [FIRStorageErrors errorWithCode:errorCode infoDictionary:errorDictionary]; + return clientError; +} + ++ (NSError *)errorWithInvalidRequest:(NSData *)request { + NSString *requestString = [[NSString alloc] initWithData:request encoding:NSUTF8StringEncoding]; + NSString *invalidDataString = + [NSString stringWithFormat:kFIRStorageInvalidDataFormat, requestString]; + NSDictionary *dict; + if (invalidDataString.length > 0) { + dict = @{NSLocalizedFailureReasonErrorKey : invalidDataString}; + } + return [FIRStorageErrors errorWithCode:FIRStorageErrorCodeUnknown infoDictionary:dict]; +} + ++ (NSError *)errorWithCustomMessage:(NSString *)errorMessage { + return [NSError errorWithDomain:FIRStorageErrorDomain + code:FIRStorageErrorCodeUnknown + userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h new file mode 100644 index 0000000..e060d16 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h" + +@class GTMSessionFetcherService; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Task which provides the ability to get a download URL for an object in Firebase Storage. + */ +@interface FIRStorageGetDownloadURLTask : FIRStorageTask + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + completion:(FIRStorageVoidURLError)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.m new file mode 100644 index 0000000..7ebc623 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.m @@ -0,0 +1,126 @@ +// 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 "FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h" + +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorage_Private.h" + +@implementation FIRStorageGetDownloadURLTask { + @private + FIRStorageVoidURLError _completion; +} + +@synthesize fetcher = _fetcher; +@synthesize fetcherCompletion = _fetcherCompletion; + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + completion:(FIRStorageVoidURLError)completion { + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; + if (self) { + _completion = [completion copy]; + } + return self; +} + +- (void)dealloc { + [_fetcher stopFetching]; +} + +- (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary { + NSString *downloadTokens = dictionary[kFIRStorageMetadataDownloadTokens]; + + if (downloadTokens && downloadTokens.length > 0) { + NSArray *downloadTokenArray = [downloadTokens componentsSeparatedByString:@","]; + NSString *bucket = dictionary[kFIRStorageMetadataBucket]; + NSString *path = dictionary[kFIRStorageMetadataName]; + NSString *fullPath = [NSString stringWithFormat:kFIRStorageFullPathFormat, bucket, + [FIRStorageUtils GCSEscapedString:path]]; + + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.scheme = self.reference.storage.scheme; + components.host = self.reference.storage.host; + components.port = self.reference.storage.port; + components.percentEncodedPath = fullPath; + + // The backend can return an arbitrary number of download tokens, but we only expose the first + // token via the download URL. + NSURLQueryItem *altItem = [[NSURLQueryItem alloc] initWithName:@"alt" value:@"media"]; + NSURLQueryItem *tokenItem = [[NSURLQueryItem alloc] initWithName:@"token" + value:downloadTokenArray[0]]; + components.queryItems = @[ altItem, tokenItem ]; + + return [components URL]; + } + + return nil; +} + +- (void)enqueue { + __weak FIRStorageGetDownloadURLTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageGetDownloadURLTask *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + request.HTTPMethod = @"GET"; + request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime; + + FIRStorageVoidURLError callback = strongSelf->_completion; + strongSelf->_completion = nil; + + GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + strongSelf->_fetcher = fetcher; + fetcher.comment = @"GetDownloadURLTask"; + + strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) { + NSURL *downloadURL; + if (error) { + if (!self.error) { + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + } + } else { + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary != nil) { + downloadURL = [strongSelf downloadURLFromMetadataDictionary:responseDictionary]; + if (!downloadURL) { + self.error = + [FIRStorageErrors errorWithCustomMessage:@"Failed to retrieve a download URL."]; + } + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + } + } + + if (callback) { + callback(downloadURL, self.error); + } + + self->_fetcherCompletion = nil; + }; + [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + FIRStorageGetDownloadURLTask *strongSelf = weakSelf; + if (strongSelf.fetcherCompletion) { + strongSelf.fetcherCompletion(data, error); + } + }]; + }]; +}; + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask_Private.h new file mode 100644 index 0000000..e8e9ceb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetDownloadURLTask_Private.h @@ -0,0 +1,31 @@ +/* + * 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 "FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Task which provides the ability to get a download URL for an object in Firebase Storage. + */ +@interface FIRStorageGetDownloadURLTask () + +/** Extracts a download URL from the StorageMetadata dictonary representation. */ +- (nullable NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetMetadataTask.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetMetadataTask.h new file mode 100644 index 0000000..0d2e052 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetMetadataTask.h @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h" + +@class GTMSessionFetcherService; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Task which provides the ability to get metadata on an object in Firebase Storage. + */ +@interface FIRStorageGetMetadataTask : FIRStorageTask + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + completion:(FIRStorageVoidMetadataError)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetMetadataTask.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetMetadataTask.m new file mode 100644 index 0000000..116eaa3 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageGetMetadataTask.m @@ -0,0 +1,98 @@ +// 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 "FirebaseStorage/Sources/FIRStorageGetMetadataTask.h" + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h" + +#import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorageUtils.h" + +@implementation FIRStorageGetMetadataTask { + @private + FIRStorageVoidMetadataError _completion; +} + +@synthesize fetcher = _fetcher; +@synthesize fetcherCompletion = _fetcherCompletion; + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + completion:(FIRStorageVoidMetadataError)completion { + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; + if (self) { + _completion = [completion copy]; + } + return self; +} + +- (void)dealloc { + [_fetcher stopFetching]; +} + +- (void)enqueue { + __weak FIRStorageGetMetadataTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageGetMetadataTask *strongSelf = weakSelf; + + if (!strongSelf) { + return; + } + + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + request.HTTPMethod = @"GET"; + request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime; + + FIRStorageVoidMetadataError callback = strongSelf->_completion; + strongSelf->_completion = nil; + + GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + strongSelf->_fetcher = fetcher; + fetcher.comment = @"GetMetadataTask"; + + strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) { + FIRStorageMetadata *metadata; + if (error) { + if (!self.error) { + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + } + } else { + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary != nil) { + metadata = [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; + [metadata setType:FIRStorageMetadataTypeFile]; + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + } + } + + if (callback) { + callback(metadata, self.error); + } + self->_fetcherCompletion = nil; + }; + + [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + FIRStorageGetMetadataTask *strongSelf = weakSelf; + if (strongSelf.fetcherCompletion) { + strongSelf.fetcherCompletion(data, error); + } + }]; + }]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListResult.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListResult.m new file mode 100644 index 0000000..3cfd70c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListResult.m @@ -0,0 +1,70 @@ +// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h" +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" + +@implementation FIRStorageListResult + ++ (nullable FIRStorageListResult *)fromDictionary:(NSDictionary *)dictionary + atReference:(FIRStorageReference *)reference { + NSMutableArray *prefixes = [NSMutableArray new]; + NSMutableArray *items = [NSMutableArray new]; + + FIRStorageReference *rootReference = reference.root; + + NSArray *prefixEntries = dictionary[kFIRStorageListPrefixes]; + for (NSString *prefixEntry in prefixEntries) { + NSString *pathWithoutTrailingSlash = prefixEntry; + if ([prefixEntry hasSuffix:@"/"]) { + pathWithoutTrailingSlash = [pathWithoutTrailingSlash substringToIndex:prefixEntry.length - 1]; + } + + FIRStorageReference *prefixReference = [rootReference child:pathWithoutTrailingSlash]; + [prefixes addObject:prefixReference]; + } + + NSArray *> *itemEntries = dictionary[kFIRStorageListItems]; + for (NSDictionary *itemEntry in itemEntries) { + FIRStorageReference *itemReference = [rootReference child:itemEntry[kFIRStorageListItemName]]; + [items addObject:itemReference]; + } + + NSString *pageToken = dictionary[kFIRStorageListPageToken]; + return [[FIRStorageListResult alloc] initWithPrefixes:prefixes items:items pageToken:pageToken]; +} + +- (nullable instancetype)initWithPrefixes:(NSArray *)prefixes + items:(NSArray *)items + pageToken:(nullable NSString *)pageToken { + self = [super init]; + if (self) { + _prefixes = [prefixes copy]; + _items = [items copy]; + _pageToken = [pageToken copy]; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + FIRStorageListResult *clone = [[[self class] allocWithZone:zone] initWithPrefixes:_prefixes + items:_items + pageToken:_pageToken]; + + return clone; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListResult_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListResult_Private.h new file mode 100644 index 0000000..0c96467 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListResult_Private.h @@ -0,0 +1,40 @@ +/* + * 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStorageListResult (Private) + +/** + * Creates an instance of FIRStorageListResult with the contents of a dictionary. + * + * @param dictionary A dictionary containing the parsed JSON response from the backend. + * @param reference The FIRStorageReference that `list()` was called on. + * @return An instance of FIRStorageListResult that represents the contents of the dictionary. + */ ++ (nullable FIRStorageListResult *)fromDictionary:(NSDictionary *)dictionary + atReference:(FIRStorageReference *)reference; + +/** Initializes a new FIRStorageListResult with the given data. */ +- (nullable instancetype)initWithPrefixes:(NSArray *)prefixes + items:(NSArray *)items + pageToken:(nullable NSString *)pageToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListTask.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListTask.h new file mode 100644 index 0000000..184fddd --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListTask.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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h" +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h" + +@class GTMSessionFetcherService; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Block typedef typically used in `list()` and `listAll()`. + * @param listResult The FIRStorageListResult returned by the operation, if it exists. + * @param error The error describing failure, if one occurred. + */ +typedef void (^FIRStorageVoidListError)(FIRStorageListResult *_Nullable listResult, + NSError *_Nullable error); + +/** A Task that lists the entries under a {@link StorageReference} */ +@interface FIRStorageListTask : FIRStorageTask + +/** + * Initializes a new List Task. + * + * To schedule the task, invoke `[FIRStorageListTask enqueue]`. + * + * @param reference The location to invoke List on. + * @param service GTMSessionFetcherService to use for the RPC. + * @param queue The queue to schedule the List operation on. + * @param pageSize An optional pageSize, denoting the maximum size of the result set. If + * set to `nil`, the backend will use the default page size. + * @param previousPageToken An optional pageToken, used to resume a previous invocation. + * @param completion The completion handler to be called with the FIRStorageListResult. + */ +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + pageSize:(nullable NSNumber *)pageSize + previousPageToken:(nullable NSString *)previousPageToken + completion:(FIRStorageVoidListError)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListTask.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListTask.m new file mode 100644 index 0000000..69f1294 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageListTask.m @@ -0,0 +1,126 @@ +// 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 "FirebaseStorage/Sources/FIRStorageListTask.h" +#import "FirebaseStorage/Sources/FIRStorageListResult_Private.h" +#import "FirebaseStorage/Sources/FIRStorageReference_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" + +@implementation FIRStorageListTask { + @private + FIRStorageVoidListError _completion; + NSNumber *_pageSize; + NSString *_previousPageToken; +} + +@synthesize fetcher = _fetcher; +@synthesize fetcherCompletion = _fetcherCompletion; + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + pageSize:(nullable NSNumber *)pageSize + previousPageToken:(nullable NSString *)previousPageToken + completion:(FIRStorageVoidListError)completion { + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; + if (self) { + _completion = [completion copy]; + _pageSize = pageSize; + _previousPageToken = [previousPageToken copy]; + } + return self; +} + +- (void)dealloc { + [_fetcher stopFetching]; +} + +- (void)enqueue { + __weak FIRStorageListTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageListTask *strongSelf = weakSelf; + + if (!strongSelf) { + return; + } + + NSMutableDictionary *queryParams = [NSMutableDictionary new]; + + NSString *prefix = [self reference].fullPath; + if (prefix.length != 0) { + queryParams[@"prefix"] = [prefix stringByAppendingString:@"/"]; + } + + // Firebase Storage uses file system semantics and treats slashes as separators. GCS's List API + // does not prescribe a separator, and hence we need to provide a slash as the delimiter. + queryParams[@"delimiter"] = @"/"; + + // listAll() doesn't set a pageSize as this allows Firebase Storage to determine how many items + // to return per page. This removes the need to backfill results if Firebase Storage filters + // objects that are considered invalid (such as items with two consecutive slashes). + if (strongSelf->_pageSize != nil) { + queryParams[@"maxResults"] = [strongSelf->_pageSize stringValue]; + } + + if (strongSelf->_previousPageToken) { + queryParams[@"pageToken"] = strongSelf->_previousPageToken; + } + + FIRStorageReference *root = self.reference.root; + NSMutableURLRequest *request = + [[FIRStorageUtils defaultRequestForReference:root queryParams:queryParams] mutableCopy]; + + request.HTTPMethod = @"GET"; + request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime; + + FIRStorageVoidListError callback = strongSelf->_completion; + strongSelf->_completion = nil; + + GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + strongSelf->_fetcher = fetcher; + fetcher.comment = @"ListTask"; + + strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) { + FIRStorageListResult *listResult; + if (error) { + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + } else { + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary != nil) { + listResult = [FIRStorageListResult fromDictionary:responseDictionary + atReference:self.reference]; + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + } + } + + if (callback) { + callback(listResult, self.error); + } + + // Remove retain cycle set up by `strongSelf->_fetcherCompletion` + self->_fetcherCompletion = nil; + }; + + [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + FIRStorageListTask *strongSelf = weakSelf; + if (strongSelf.fetcherCompletion) { + strongSelf.fetcherCompletion(data, error); + } + }]; + }]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageLogger.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageLogger.h new file mode 100644 index 0000000..dba9c93 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageLogger.h @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#import + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +extern FIRLoggerService kFIRLoggerStorage; + +// FIRStorageTokenAuthorizer.m +extern NSString *const kFIRStorageMessageCodeAppCheckError; diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageLogger.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageLogger.m new file mode 100644 index 0000000..7a3fba4 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageLogger.m @@ -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. + */ + +#import "FirebaseStorage/Sources/FIRStorageLogger.h" + +FIRLoggerService kFIRLoggerStorage = @"[Firebase/Storage]"; + +// FIRStorageTokenAuthorizer.m +NSString *const kFIRStorageMessageCodeAppCheckError = @"I-STR000001"; diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageMetadata.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageMetadata.m new file mode 100644 index 0000000..31c1644 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageMetadata.m @@ -0,0 +1,225 @@ +// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageMetadata.h" + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" +#import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h" +#import "FirebaseStorage/Sources/FIRStorageUtils.h" + +// TODO: consider rewriting this using GTLR (GTLRStorageObjects.h) +@implementation FIRStorageMetadata + +#pragma mark - Initializers + +- (instancetype)init { + return [self initWithDictionary:[NSDictionary dictionary]]; +} + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + _initialMetadata = [dictionary copy]; + + _bucket = dictionary[kFIRStorageMetadataBucket]; + _cacheControl = dictionary[kFIRStorageMetadataCacheControl]; + _contentDisposition = dictionary[kFIRStorageMetadataContentDisposition]; + _contentEncoding = dictionary[kFIRStorageMetadataContentEncoding]; + _contentLanguage = dictionary[kFIRStorageMetadataContentLanguage]; + _contentType = dictionary[kFIRStorageMetadataContentType]; + _customMetadata = dictionary[kFIRStorageMetadataCustomMetadata]; + _size = [dictionary[kFIRStorageMetadataSize] longLongValue]; + _generation = [dictionary[kFIRStorageMetadataGeneration] longLongValue]; + _metageneration = [dictionary[kFIRStorageMetadataMetageneration] longLongValue]; + _timeCreated = [self dateFromRFC3339String:dictionary[kFIRStorageMetadataTimeCreated]]; + _updated = [self dateFromRFC3339String:dictionary[kFIRStorageMetadataUpdated]]; + _md5Hash = dictionary[kFIRStorageMetadataMd5Hash]; + // GCS "name" is our path, our "name" is just the last path component of the path + _path = dictionary[kFIRStorageMetadataName]; + _name = [_path lastPathComponent]; + } + return self; +} + +#pragma mark - NSObject overrides + +- (instancetype)copyWithZone:(NSZone *)zone { + FIRStorageMetadata *clone = + [[[self class] allocWithZone:zone] initWithDictionary:[self dictionaryRepresentation]]; + clone.initialMetadata = [self.initialMetadata copy]; + return clone; +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[FIRStorageMetadata class]]) { + return NO; + } + + BOOL isEqualObject = [self isEqualToFIRStorageMetadata:(FIRStorageMetadata *)object]; + return isEqualObject; +} + +- (BOOL)isEqualToFIRStorageMetadata:(FIRStorageMetadata *)metadata { + return [[self dictionaryRepresentation] isEqualToDictionary:[metadata dictionaryRepresentation]]; +} + +- (NSUInteger)hash { + NSUInteger hash = [[self dictionaryRepresentation] hash]; + return hash; +} + +- (NSString *)description { + NSDictionary *metadataDictionary = [self dictionaryRepresentation]; + return [NSString stringWithFormat:@"%@ %p: %@", [self class], self, metadataDictionary]; +} + +#pragma mark - Public methods + +- (NSDictionary *)dictionaryRepresentation { + NSMutableDictionary *metadataDictionary = [[NSMutableDictionary alloc] initWithCapacity:13]; + + if (_bucket) { + metadataDictionary[kFIRStorageMetadataBucket] = _bucket; + } + + if (_cacheControl) { + metadataDictionary[kFIRStorageMetadataCacheControl] = _cacheControl; + } + + if (_contentDisposition) { + metadataDictionary[kFIRStorageMetadataContentDisposition] = _contentDisposition; + } + + if (_contentEncoding) { + metadataDictionary[kFIRStorageMetadataContentEncoding] = _contentEncoding; + } + + if (_contentLanguage) { + metadataDictionary[kFIRStorageMetadataContentLanguage] = _contentLanguage; + } + + if (_contentType) { + metadataDictionary[kFIRStorageMetadataContentType] = _contentType; + } + + if (_md5Hash) { + metadataDictionary[kFIRStorageMetadataMd5Hash] = _md5Hash; + } + + if (_customMetadata) { + metadataDictionary[kFIRStorageMetadataCustomMetadata] = _customMetadata; + } + + if (_generation) { + NSString *generationString = [NSString stringWithFormat:@"%lld", _generation]; + metadataDictionary[kFIRStorageMetadataGeneration] = generationString; + } + + if (_metageneration) { + NSString *metagenerationString = [NSString stringWithFormat:@"%lld", _metageneration]; + metadataDictionary[kFIRStorageMetadataMetageneration] = metagenerationString; + } + + if (_timeCreated) { + metadataDictionary[kFIRStorageMetadataTimeCreated] = [self RFC3339StringFromDate:_timeCreated]; + } + + if (_updated) { + metadataDictionary[kFIRStorageMetadataUpdated] = [self RFC3339StringFromDate:_updated]; + } + + if (_path) { + metadataDictionary[kFIRStorageMetadataName] = _path; + } + + if (_size) { + metadataDictionary[kFIRStorageMetadataSize] = [NSNumber numberWithLongLong:_size]; + } + + return [metadataDictionary copy]; +} + +- (BOOL)isFile { + return _type == FIRStorageMetadataTypeFile; +} + +- (BOOL)isFolder { + return _type == FIRStorageMetadataTypeFolder; +} + +#pragma mark - Private methods + ++ (void)removeMatchingMetadata:(NSMutableDictionary *)metadata + oldMetadata:(NSDictionary *)oldMetadata { + for (NSString *metadataKey in [oldMetadata allKeys]) { + id oldValue = [oldMetadata objectForKey:metadataKey]; + id newValue = [metadata objectForKey:metadataKey]; + + if (oldValue && !newValue) { + [metadata setObject:[NSNull null] forKey:metadataKey]; + } else if ([oldValue isKindOfClass:[NSString class]] && + [newValue isKindOfClass:[NSString class]]) { + if ([oldValue isEqualToString:newValue]) { + [metadata removeObjectForKey:metadataKey]; + } + } else if ([oldValue isKindOfClass:[NSDictionary class]] && + [newValue isKindOfClass:[NSDictionary class]]) { + NSMutableDictionary *nestedMetadata = [newValue mutableCopy]; + [self removeMatchingMetadata:nestedMetadata oldMetadata:oldValue]; + [metadata setObject:[nestedMetadata copy] forKey:metadataKey]; + } + } +} + +- (NSDictionary *)updatedMetadata { + NSMutableDictionary *metadataUpdate = [[self dictionaryRepresentation] mutableCopy]; + [FIRStorageMetadata removeMatchingMetadata:metadataUpdate oldMetadata:_initialMetadata]; + return [metadataUpdate copy]; +} + +#pragma mark - RFC 3339 conversions + +static NSDateFormatter *sRFC3339DateFormatter; + +static void setupDateFormatterOnce(void) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sRFC3339DateFormatter = [[NSDateFormatter alloc] init]; + NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + + [sRFC3339DateFormatter setLocale:enUSPOSIXLocale]; + [sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSZZZZZ"]; + [sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + }); +} + +- (nullable NSDate *)dateFromRFC3339String:(NSString *)dateString { + setupDateFormatterOnce(); + NSDate *rfc3339Date = [sRFC3339DateFormatter dateFromString:dateString]; + return rfc3339Date; +} + +- (nullable NSString *)RFC3339StringFromDate:(NSDate *)date { + setupDateFormatterOnce(); + NSString *rfc3339String = [sRFC3339DateFormatter stringFromDate:date]; + return rfc3339String; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageMetadata_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageMetadata_Private.h new file mode 100644 index 0000000..a2d5d04 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageMetadata_Private.h @@ -0,0 +1,73 @@ +/* + * 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageMetadata.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" + +@class FIRStorageReference; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStorageMetadata () + +@property(readwrite, nonatomic) NSString *name; + +@property(readwrite, nonatomic) NSString *path; + +@property(readwrite, nonatomic) FIRStorageReference *reference; + +/** + * The type of the object, either a "File" or a "Folder". + */ +@property(readwrite) FIRStorageMetadataType type; + +/** + * The original metadata representation received from the server or an empty dictionary + * if the metadata object was initialized by the user. + */ +@property(copy, nonatomic) NSDictionary *initialMetadata; + +/** + * Recursively removes entries in 'metadata' that are unmodified from 'oldMetadata'. + * Adds 'NSNull' for entries that only exist in oldMetadata. + */ ++ (void)removeMatchingMetadata:(NSMutableDictionary *)metadata + oldMetadata:(NSDictionary *)oldMetadata; + +/** + * Computes the updates between the state at initialization and the current state. + * Returns a dictionary with only the updated data. Removed keys are set to NSNull. + */ +- (NSDictionary *)updatedMetadata; + +/** + * Returns an RFC3339 formatted date from a string. + * @param dateString An NSString of the form: yyyy-MM-ddTHH:mm:ss.SSSZ. + * @return An NSDate populated from the string or nil if conversion isn't possible. + */ +- (nullable NSDate *)dateFromRFC3339String:(NSString *)dateString; + +/** + * Returns an RFC3339 formatted string from an NSDate object. + * @param date The NSDate object to be converted to a string. + * @return An NSString of the form: yyyy-MM-ddTHH:mm:ss.SSSZ or nil if conversion isn't possible. + */ +- (nullable NSString *)RFC3339StringFromDate:(NSDate *)date; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageObservableTask.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageObservableTask.m new file mode 100644 index 0000000..1e485df --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageObservableTask.m @@ -0,0 +1,215 @@ +// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageObservableTask.h" +#import "FirebaseStorage/Sources/FIRStorageObservableTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" + +@implementation FIRStorageObservableTask { + @private + // Handlers for pause, resume, progress, success, and failure callbacks + NSMutableDictionary *_resumeHandlers; + NSMutableDictionary *_pauseHandlers; + NSMutableDictionary *_progressHandlers; + NSMutableDictionary *_successHandlers; + NSMutableDictionary *_failureHandlers; + // Reverse map of fetcher handles to status types + NSMutableDictionary *_handleToStatusMap; +} + +@synthesize state = _state; + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue { + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; + if (self) { + _pauseHandlers = [[NSMutableDictionary alloc] init]; + _resumeHandlers = [[NSMutableDictionary alloc] init]; + _progressHandlers = [[NSMutableDictionary alloc] init]; + _successHandlers = [[NSMutableDictionary alloc] init]; + _failureHandlers = [[NSMutableDictionary alloc] init]; + _handleToStatusMap = [[NSMutableDictionary alloc] init]; + } + return self; +} + +#pragma mark - Observers + +- (FIRStorageHandle)observeStatus:(FIRStorageTaskStatus)status + handler:(FIRStorageVoidSnapshot)handler { + FIRStorageVoidSnapshot callback = handler; + + // Note: self.snapshot is synchronized + FIRStorageTaskSnapshot *snapshot = self.snapshot; + // TODO: use an increasing counter instead of a random UUID + NSString *UUIDString = [[NSUUID UUID] UUIDString]; + switch (status) { + case FIRStorageTaskStatusPause: + @synchronized(self) { + [_pauseHandlers setValue:callback forKey:UUIDString]; + } // @synchronized(self) + if (_state == FIRStorageTaskStatePausing || _state == FIRStorageTaskStatePaused) { + [self fireHandlers:_pauseHandlers snapshot:snapshot]; + } + break; + + case FIRStorageTaskStatusResume: + @synchronized(self) { + [_resumeHandlers setValue:callback forKey:UUIDString]; + } // @synchronized(self) + if (_state == FIRStorageTaskStateResuming || _state == FIRStorageTaskStateRunning) { + [self fireHandlers:_resumeHandlers snapshot:snapshot]; + } + break; + + case FIRStorageTaskStatusProgress: + @synchronized(self) { + [_progressHandlers setValue:callback forKey:UUIDString]; + } // @synchronized(self) + if (_state == FIRStorageTaskStateRunning || _state == FIRStorageTaskStateProgress) { + [self fireHandlers:_progressHandlers snapshot:snapshot]; + } + break; + + case FIRStorageTaskStatusSuccess: + @synchronized(self) { + [_successHandlers setValue:callback forKey:UUIDString]; + } // @synchronized(self) + if (_state == FIRStorageTaskStateSuccess) { + [self fireHandlers:_successHandlers snapshot:snapshot]; + } + break; + + case FIRStorageTaskStatusFailure: + @synchronized(self) { + [_failureHandlers setValue:callback forKey:UUIDString]; + } // @synchronized(self) + if (_state == FIRStorageTaskStateFailing || _state == FIRStorageTaskStateFailed) { + [self fireHandlers:_failureHandlers snapshot:snapshot]; + } + break; + + case FIRStorageTaskStatusUnknown: + // Fall through to exception case if an unknown status is passed + + default: + [NSException raise:NSInternalInconsistencyException + format:kFIRStorageInvalidObserverStatus, nil]; + break; + } + + @synchronized(self) { + _handleToStatusMap[UUIDString] = @(status); + } // @synchronized(self) + + return UUIDString; +} + +- (void)removeObserverWithHandle:(FIRStorageHandle)handle { + FIRStorageTaskStatus status = [_handleToStatusMap[handle] intValue]; + NSMutableDictionary *observerDictionary = + [self handlerDictionaryForStatus:status]; + + @synchronized(self) { + [observerDictionary removeObjectForKey:handle]; + [_handleToStatusMap removeObjectForKey:handle]; + } // @synchronized(self) +} + +- (void)removeAllObserversForStatus:(FIRStorageTaskStatus)status { + NSMutableDictionary *observerDictionary = + [self handlerDictionaryForStatus:status]; + [self removeHandlersFromStatusMapForDictionary:observerDictionary]; + + @synchronized(self) { + [observerDictionary removeAllObjects]; + } // @synchronized(self) +} + +- (void)removeAllObservers { + @synchronized(self) { + [_pauseHandlers removeAllObjects]; + [_resumeHandlers removeAllObjects]; + [_progressHandlers removeAllObjects]; + [_successHandlers removeAllObjects]; + [_failureHandlers removeAllObjects]; + [_handleToStatusMap removeAllObjects]; + } // @synchronized(self) +} + +- (NSMutableDictionary *)handlerDictionaryForStatus: + (FIRStorageTaskStatus)status { + switch (status) { + case FIRStorageTaskStatusPause: + return _pauseHandlers; + + case FIRStorageTaskStatusResume: + return _resumeHandlers; + + case FIRStorageTaskStatusProgress: + return _progressHandlers; + + case FIRStorageTaskStatusSuccess: + return _successHandlers; + + case FIRStorageTaskStatusFailure: + return _failureHandlers; + + case FIRStorageTaskStatusUnknown: + return [NSMutableDictionary dictionary]; + + default: + [NSException raise:NSInternalInconsistencyException + format:kFIRStorageInvalidObserverStatus, nil]; + return nil; + } +} + +- (void)removeHandlersFromStatusMapForDictionary: + (NSMutableDictionary *)dict { + @synchronized(self) { + [_handleToStatusMap removeObjectsForKeys:dict.allKeys]; + } // @synchronized(self) +} + +- (void)fireHandlersForStatus:(FIRStorageTaskStatus)status + snapshot:(FIRStorageTaskSnapshot *)snapshot { + NSMutableDictionary *observerDictionary = + [self handlerDictionaryForStatus:status]; + [self fireHandlers:observerDictionary snapshot:snapshot]; +} + +- (void)fireHandlers:(NSMutableDictionary *)handlers + snapshot:(FIRStorageTaskSnapshot *)snapshot { + dispatch_queue_t callbackQueue = self.fetcherService.callbackQueue; + if (!callbackQueue) { + callbackQueue = dispatch_get_main_queue(); + } + + // TODO: iterate over this list in a consistent order + NSMutableDictionary *handlersCopy; + @synchronized(self) { + handlersCopy = [handlers copy]; + } // @synchronized(self) + [handlersCopy + enumerateKeysAndObjectsUsingBlock:^( + NSString *_Nonnull key, FIRStorageVoidSnapshot _Nonnull handler, BOOL *_Nonnull stop) { + dispatch_async(callbackQueue, ^{ + handler(snapshot); + }); + }]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageObservableTask_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageObservableTask_Private.h new file mode 100644 index 0000000..29c9efc --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageObservableTask_Private.h @@ -0,0 +1,51 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageObservableTask.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRStorageReference; +@class FIRStorageTaskSnapshot; +@class GTMSessionFetcherService; + +@interface FIRStorageObservableTask () + +/** + * Creates a new FIRStorageTask initialized with a FIRStorageReference and GTMSessionFetcherService. + * @param reference A FIRStorageReference the task will be performed on. + * @param service A GTMSessionFetcherService which provides the fetchers and configuration for + * requests. + * @param queue The shared queue to use for all Storage operations. + * @return A new FIRStorageTask representing the current task. + */ +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue; + +/** + * Raise events for a given task status by passing along a snapshot of existing task state. + * @param status A FIRStorageTaskStatus to raise events for. + * @param snapshot A FIRStorageTaskSnapshot snapshot of task state to pass through the handler. + */ +- (void)fireHandlersForStatus:(FIRStorageTaskStatus)status + snapshot:(FIRStorageTaskSnapshot *)snapshot; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStoragePath.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStoragePath.h new file mode 100644 index 0000000..53ff7ef --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStoragePath.h @@ -0,0 +1,106 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * Represents a path in GCS, which can be represented as: gs://bucket/path/to/object + * or http[s]://firebasestorage.googleapis.com/v0/b/bucket/o/path/to/object?token=<12345> + * This class also includes helper methods to parse those URI/Ls, as well as to + * add and remove path segments. + */ +@interface FIRStoragePath : NSObject + +/** + * The GCS bucket in the path. + */ +@property(copy, nonatomic) NSString *bucket; + +/** + * The GCS object in the path. + */ +@property(copy, nonatomic, nullable) NSString *object; + +/** + * Parses a generic string (representing some URI or URL) and returns the appropriate path. + * @param string String which is parsed into a path. + * @return Returns an instance of FIRStoragePath or nil if one can't be created. + * @throws Throws an exception if the string is not a valid gs:// URI or http[s]:// URL. + */ ++ (nullable FIRStoragePath *)pathFromString:(NSString *)string; + +/** + * Parses a gs://bucket/path/to/object URI into a GCS path. + * @param aURIString gs:// URI which is parsed into a path. + * @return Returns an instance of FIRStoragePath or nil if one can't be created. + * @throws Throws an exception if the string is not a valid gs:// URI. + */ ++ (nullable FIRStoragePath *)pathFromGSURI:(NSString *)aURIString; + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Constructs an FIRStoragePath object that represents the given bucket and object. + * @param bucket The name of the bucket. + * @param object The name of the object. + * @return An instance of FIRStoragePath representing the @a bucket and @a object. + */ +- (instancetype)initWithBucket:(NSString *)bucket + object:(nullable NSString *)object NS_DESIGNATED_INITIALIZER; + +/** + * Parses a http[s]://firebasestorage.googleapis.com/v0/b/bucket/o/path/to/object...?token=<12345> + * URL into a GCS path. + * @param aURLString http[s]:// URL which is parsed into a path. + * string which is parsed into a path. + * @return Returns an instance of FIRStoragePath or nil if one can't be created. + * @throws Throws an exception if the string is not a valid http[s]:// URL. + */ ++ (nullable FIRStoragePath *)pathFromHTTPURL:(NSString *)aURLString; + +/** + * Creates a new path based off of the current path and a string appended to it. + * Note that all slashes are compressed to a single slash, and leading and trailing slashes + * are removed. + * @param path String to append to the current path. + * @return Returns a new instance of FIRStoragePath with the new path appended. + */ +- (FIRStoragePath *)child:(NSString *)path; + +/** + * Creates a new path based off of the current path with the last path segment removed. + * @return Returns a new instance of FIRStoragePath pointing to the parent path, + * or nil if the current path points to the root. + */ +- (nullable FIRStoragePath *)parent; + +/** + * Creates a new path based off of the root of the bucket. + * @return Returns a new instance of FIRStoragePath pointing to the root of the bucket. + */ +- (FIRStoragePath *)root; + +/** + * Returns a GS URI representing the current path. + * @return Returns a gs://bucket/path/to/object URI representing the current path. + */ +- (NSString *)stringValue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStoragePath.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStoragePath.m new file mode 100644 index 0000000..71f4510 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStoragePath.m @@ -0,0 +1,195 @@ +// 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 "FirebaseStorage/Sources/FIRStoragePath.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" + +@implementation FIRStoragePath + +#pragma mark - Class methods + ++ (nullable FIRStoragePath *)pathFromString:(NSString *)string { + if ([string hasPrefix:@"gs://"]) { + // "gs://bucket/path/to/object" + return [FIRStoragePath pathFromGSURI:string]; + } else if ([string hasPrefix:@"http://"] || [string hasPrefix:@"https://"]) { + // "http[s]://firebasestorage.googleapis.com/bucket/path/to/object?signed_url_params" + return [FIRStoragePath pathFromHTTPURL:string]; + } else { + // Invalid scheme, raise an exception! + [NSException raise:NSInternalInconsistencyException + format:@"URL scheme must be one of gs://, http://, or https:// "]; + return nil; + } +} + ++ (nullable FIRStoragePath *)pathFromGSURI:(NSString *)aURIString { + NSString *bucketName; + NSString *objectName; + NSScanner *scanner = [NSScanner scannerWithString:aURIString]; + BOOL isGSURI = [scanner scanString:@"gs://" intoString:NULL]; + BOOL hasBucket = [scanner scanUpToString:@"/" intoString:&bucketName]; + [scanner scanString:@"/" intoString:NULL]; + [scanner scanUpToString:@"\n" intoString:&objectName]; + + if (!isGSURI || !hasBucket) { + [NSException raise:NSInternalInconsistencyException + format:@"URI must be in the form of gs:///"]; + return nil; + } + + return [[self alloc] initWithBucket:bucketName object:objectName]; +} + ++ (nullable FIRStoragePath *)pathFromHTTPURL:(NSString *)aURLString { + NSString *bucketName; + NSString *objectName; + NSURL *httpsURL = [NSURL URLWithString:aURLString]; + NSArray *pathComponents = httpsURL.pathComponents; // [/, v0, b, , o, ] + + if ([pathComponents count] <= 3 || ![pathComponents[1] isEqual:@"v0"] || + ![pathComponents[2] isEqual:@"b"]) { + [NSException raise:NSInternalInconsistencyException + format:@"URL must be in the form of " + @"http[s]:///v0/b//o/[?token=signed_url_params]"]; + return nil; + } + + bucketName = pathComponents[3]; + + // Have an object name + if ([pathComponents count] > 5) { + NSRange objectRange = NSMakeRange(5, [pathComponents count] - 5); + objectName = [[pathComponents subarrayWithRange:objectRange] componentsJoinedByString:@"/"]; + } + + if (objectName.length == 0) { + objectName = nil; + } + + return [[self alloc] initWithBucket:bucketName object:objectName]; +} + +#pragma mark - Initializers + +- (instancetype)initWithBucket:(NSString *)bucket object:(nullable NSString *)object { + self = [super init]; + if (self) { + _bucket = [bucket copy]; + _object = [self standardizedPathForString:[object copy]]; + } + return self; +} + +#pragma mark - NSObject overrides + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[[self class] allocWithZone:zone] initWithBucket:_bucket object:_object]; +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[FIRStoragePath class]]) { + return NO; + } + + BOOL isObjectEqual = [self isEqualToFIRStoragePath:(FIRStoragePath *)object]; + return isObjectEqual; +} + +- (BOOL)isEqualToFIRStoragePath:(FIRStoragePath *)path { + BOOL isBucketEqual = _bucket == nil && path->_bucket == nil; + BOOL isObjectEqual = _object == nil && path->_object == nil; + + if (_bucket && path->_bucket) { + isBucketEqual = [_bucket isEqual:path->_bucket]; + } + + if (_object && path.object) { + isObjectEqual = [_object isEqual:path->_object]; + } + + BOOL isEqual = isBucketEqual && isObjectEqual; + return isEqual; +} + +- (NSUInteger)hash { + // "...because in those days, you could XOR anything with anything and get something useful..." + // https://www.usenix.org/system/files/1309_14-17_mickens.pdf + NSUInteger hash = [_bucket hash] ^ [_object hash]; + return hash; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@ %p: %@", [self class], self, [self stringValue]]; +} + +- (NSString *)stringValue { + return [NSString stringWithFormat:@"gs://%@/%@", _bucket, _object ?: @""]; +} + +#pragma mark - Public methods + +- (FIRStoragePath *)child:(NSString *)path { + if (path.length == 0) { + return [self copy]; // Return a copy of the same path, nothing happened + } + + NSString *childObject; + if (_object == nil) { + childObject = path; + } else { + childObject = [_object stringByAppendingPathComponent:path]; + } + + FIRStoragePath *childPath = [[FIRStoragePath alloc] initWithBucket:_bucket object:childObject]; + return childPath; +} + +- (nullable FIRStoragePath *)parent { + if (_object.length == 0) { + return nil; + } + + NSString *parentObject = [_object stringByDeletingLastPathComponent]; + FIRStoragePath *parentPath = [[FIRStoragePath alloc] initWithBucket:_bucket object:parentObject]; + return parentPath; +} + +- (FIRStoragePath *)root { + FIRStoragePath *rootPath = [[FIRStoragePath alloc] initWithBucket:_bucket object:nil]; + return rootPath; +} + +#pragma mark - Private methods + +// Removes leading and trailing slashes, and compresses multiple slashes +// to create a canonical representation. +// Example: /foo//bar///baz//// -> foo/bar/baz +- (NSString *)standardizedPathForString:(NSString *)string { + NSMutableArray *components = [[string componentsSeparatedByString:@"/"] mutableCopy]; + NSIndexSet *removedPaths = + [components indexesOfObjectsPassingTest:^BOOL(NSString *string, NSUInteger idx, BOOL *stop) { + return (string.length == 0); + }]; + [components removeObjectsAtIndexes:removedPaths]; + return [components componentsJoinedByString:@"/"]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageReference.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageReference.m new file mode 100644 index 0000000..c69b5ee --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageReference.m @@ -0,0 +1,492 @@ +// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" +#import "FirebaseStorage/Sources/FIRStorageDeleteTask.h" +#import "FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h" +#import "FirebaseStorage/Sources/FIRStorageGetMetadataTask.h" +#import "FirebaseStorage/Sources/FIRStorageListResult_Private.h" +#import "FirebaseStorage/Sources/FIRStorageListTask.h" +#import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h" +#import "FirebaseStorage/Sources/FIRStorageReference_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.h" +#import "FirebaseStorage/Sources/FIRStorageUploadTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorageUtils.h" +#import "FirebaseStorage/Sources/FIRStorage_Private.h" +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h" + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#if SWIFT_PACKAGE +@import GTMSessionFetcherCore; +#else +#import +#import +#endif + +@implementation FIRStorageReference + +- (instancetype)init { + FIRStorage *storage = [FIRStorage storage]; + NSString *storageBucket = storage.app.options.storageBucket; + FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:storageBucket object:nil]; + FIRStorageReference *reference = [self initWithStorage:storage path:path]; + return reference; +} + +- (instancetype)initWithStorage:(FIRStorage *)storage path:(FIRStoragePath *)path { + self = [super init]; + if (self) { + _storage = storage; + _path = path; + } + return self; +} + +#pragma mark - NSObject overrides + +- (instancetype)copyWithZone:(NSZone *)zone { + FIRStorageReference *copiedReference = [[[self class] allocWithZone:zone] initWithStorage:_storage + path:_path]; + return copiedReference; +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[FIRStorageReference class]]) { + return NO; + } + + BOOL isObjectEqual = [self isEqualToFIRStorageReference:(FIRStorageReference *)object]; + return isObjectEqual; +} + +- (BOOL)isEqualToFIRStorageReference:(FIRStorageReference *)reference { + BOOL isEqual = [_storage isEqual:reference.storage] && [_path isEqual:reference.path]; + return isEqual; +} + +- (NSUInteger)hash { + NSUInteger hash = [_storage hash] ^ [_path hash]; + return hash; +} + +- (NSString *)description { + return [self stringValue]; +} + +- (NSString *)stringValue { + NSString *value = [NSString stringWithFormat:@"gs://%@/%@", _path.bucket, _path.object ?: @""]; + return value; +} + +#pragma mark - Property Getters + +- (NSString *)bucket { + NSString *bucket = _path.bucket; + return bucket; +} + +- (NSString *)fullPath { + NSString *path = _path.object; + if (!path) { + path = @""; + } + return path; +} + +- (NSString *)name { + NSString *name = [_path.object lastPathComponent]; + if (!name) { + name = @""; + } + return name; +} + +#pragma mark - Path Operations + +- (FIRStorageReference *)root { + FIRStoragePath *rootPath = [_path root]; + FIRStorageReference *rootReference = [[FIRStorageReference alloc] initWithStorage:_storage + path:rootPath]; + return rootReference; +} + +- (nullable FIRStorageReference *)parent { + FIRStoragePath *parentPath = [_path parent]; + if (!parentPath) { + return nil; + } + + FIRStorageReference *parentReference = [[FIRStorageReference alloc] initWithStorage:_storage + path:parentPath]; + return parentReference; +} + +- (FIRStorageReference *)child:(NSString *)path { + FIRStoragePath *childPath = [_path child:path]; + FIRStorageReference *childReference = [[FIRStorageReference alloc] initWithStorage:_storage + path:childPath]; + return childReference; +} + +#pragma mark - Uploads + +- (FIRStorageUploadTask *)putData:(NSData *)uploadData { + return [self putData:uploadData metadata:nil completion:nil]; +} + +- (FIRStorageUploadTask *)putData:(NSData *)uploadData + metadata:(nullable FIRStorageMetadata *)metadata { + return [self putData:uploadData metadata:metadata completion:nil]; +} + +- (FIRStorageUploadTask *)putData:(NSData *)uploadData + metadata:(nullable FIRStorageMetadata *)metadata + completion:(nullable FIRStorageVoidMetadataError)completion { + if (!metadata) { + metadata = [[FIRStorageMetadata alloc] init]; + } + + metadata.path = _path.object; + metadata.name = [_path.object lastPathComponent]; + FIRStorageUploadTask *task = + [[FIRStorageUploadTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + data:uploadData + metadata:metadata]; + + if (completion) { + __block BOOL completed = NO; + dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue; + if (!callbackQueue) { + callbackQueue = dispatch_get_main_queue(); + } + + [task observeStatus:FIRStorageTaskStatusSuccess + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { + dispatch_async(callbackQueue, ^{ + if (!completed) { + completed = YES; + completion(snapshot.metadata, nil); + } + }); + }]; + [task observeStatus:FIRStorageTaskStatusFailure + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { + dispatch_async(callbackQueue, ^{ + if (!completed) { + completed = YES; + completion(nil, snapshot.error); + } + }); + }]; + } + [task enqueue]; + return task; +} + +- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL { + return [self putFile:fileURL metadata:nil completion:nil]; +} + +- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL + metadata:(nullable FIRStorageMetadata *)metadata { + return [self putFile:fileURL metadata:metadata completion:nil]; +} + +- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL + metadata:(nullable FIRStorageMetadata *)metadata + completion:(nullable FIRStorageVoidMetadataError)completion { + if (!metadata) { + metadata = [[FIRStorageMetadata alloc] init]; + } + + metadata.path = _path.object; + metadata.name = [_path.object lastPathComponent]; + FIRStorageUploadTask *task = + [[FIRStorageUploadTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + file:fileURL + metadata:metadata]; + + if (completion) { + __block BOOL completed = NO; + dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue; + if (!callbackQueue) { + callbackQueue = dispatch_get_main_queue(); + } + + [task observeStatus:FIRStorageTaskStatusSuccess + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { + dispatch_async(callbackQueue, ^{ + if (!completed) { + completed = YES; + completion(snapshot.metadata, nil); + } + }); + }]; + [task observeStatus:FIRStorageTaskStatusFailure + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { + dispatch_async(callbackQueue, ^{ + if (!completed) { + completed = YES; + completion(nil, snapshot.error); + } + }); + }]; + } + [task enqueue]; + return task; +} + +#pragma mark - Downloads + +- (FIRStorageDownloadTask *)dataWithMaxSize:(int64_t)size + completion:(FIRStorageVoidDataError)completion { + __block BOOL completed = NO; + FIRStorageDownloadTask *task = + [[FIRStorageDownloadTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + file:nil]; + + dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue; + if (!callbackQueue) { + callbackQueue = dispatch_get_main_queue(); + } + + [task observeStatus:FIRStorageTaskStatusSuccess + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { + FIRStorageDownloadTask *task = snapshot.task; + dispatch_async(callbackQueue, ^{ + if (!completed) { + completed = YES; + completion(task.downloadData, nil); + } + }); + }]; + + [task observeStatus:FIRStorageTaskStatusFailure + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { + dispatch_async(callbackQueue, ^{ + if (!completed) { + completed = YES; + completion(nil, snapshot.error); + } + }); + }]; + [task + observeStatus:FIRStorageTaskStatusProgress + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { + FIRStorageDownloadTask *task = snapshot.task; + if (task.progress.totalUnitCount > size || task.progress.completedUnitCount > size) { + NSDictionary *infoDictionary = + @{@"totalSize" : @(task.progress.totalUnitCount), + @"maxAllowedSize" : @(size)}; + NSError *error = + [FIRStorageErrors errorWithCode:FIRStorageErrorCodeDownloadSizeExceeded + infoDictionary:infoDictionary]; + [task cancelWithError:error]; + } + }]; + [task enqueue]; + return task; +} + +- (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL { + return [self writeToFile:fileURL completion:nil]; +} + +- (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL + completion:(FIRStorageVoidURLError)completion { + FIRStorageDownloadTask *task = + [[FIRStorageDownloadTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + file:fileURL]; + if (completion) { + __block BOOL completed = NO; + dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue; + if (!callbackQueue) { + callbackQueue = dispatch_get_main_queue(); + } + + [task observeStatus:FIRStorageTaskStatusSuccess + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { + dispatch_async(callbackQueue, ^{ + if (!completed) { + completed = YES; + completion(fileURL, nil); + } + }); + }]; + [task observeStatus:FIRStorageTaskStatusFailure + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { + dispatch_async(callbackQueue, ^{ + if (!completed) { + completed = YES; + completion(nil, snapshot.error); + } + }); + }]; + } + [task enqueue]; + return task; +} + +- (void)downloadURLWithCompletion:(FIRStorageVoidURLError)completion { + FIRStorageGetDownloadURLTask *task = + [[FIRStorageGetDownloadURLTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + completion:completion]; + [task enqueue]; +} + +#pragma mark - List + +- (void)listWithMaxResults:(int64_t)maxResults completion:(FIRStorageVoidListError)completion { + if (maxResults <= 0 || maxResults > 1000) { + completion(nil, + [FIRStorageUtils storageErrorWithDescription: + @"Argument 'maxResults' must be between 1 and 1000 inclusive." + code:FIRStorageErrorCodeInvalidArgument]); + } else { + FIRStorageListTask *task = + [[FIRStorageListTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + pageSize:@(maxResults) + previousPageToken:nil + completion:completion]; + [task enqueue]; + } +} + +- (void)listWithMaxResults:(int64_t)maxResults + pageToken:(NSString *)pageToken + completion:(FIRStorageVoidListError)completion { + if (maxResults <= 0 || maxResults > 1000) { + completion(nil, + [FIRStorageUtils storageErrorWithDescription: + @"Argument 'maxResults' must be between 1 and 1000 inclusive." + code:FIRStorageErrorCodeInvalidArgument]); + } else { + FIRStorageListTask *task = + [[FIRStorageListTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + pageSize:@(maxResults) + previousPageToken:pageToken + completion:completion]; + [task enqueue]; + } +} + +- (void)listAllWithCompletion:(FIRStorageVoidListError)completion { + NSMutableArray *prefixes = [NSMutableArray new]; + NSMutableArray *items = [NSMutableArray new]; + + __weak FIRStorageReference *weakSelf = self; + + __block FIRStorageVoidListError paginatedCompletion = + ^(FIRStorageListResult *listResult, NSError *error) { + if (error) { + completion(nil, error); + return; + } + + FIRStorageReference *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + [prefixes addObjectsFromArray:listResult.prefixes]; + [items addObjectsFromArray:listResult.items]; + + if (listResult.pageToken) { + FIRStorageListTask *nextPage = [[FIRStorageListTask alloc] + initWithReference:self + fetcherService:strongSelf->_storage.fetcherServiceForApp + dispatchQueue:strongSelf->_storage.dispatchQueue + pageSize:nil + previousPageToken:listResult.pageToken + completion:paginatedCompletion]; + [nextPage enqueue]; + } else { + FIRStorageListResult *result = [[FIRStorageListResult alloc] initWithPrefixes:prefixes + items:items + pageToken:nil]; + // Break the retain cycle we set up indirectly by passing the callback to `nextPage`. + paginatedCompletion = nil; + completion(result, nil); + } + }; + + FIRStorageListTask *task = + [[FIRStorageListTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + pageSize:nil + previousPageToken:nil + completion:paginatedCompletion]; + + [task enqueue]; +} + +#pragma mark - Metadata Operations + +- (void)metadataWithCompletion:(FIRStorageVoidMetadataError)completion { + FIRStorageGetMetadataTask *task = + [[FIRStorageGetMetadataTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + completion:completion]; + [task enqueue]; +} + +- (void)updateMetadata:(FIRStorageMetadata *)metadata + completion:(nullable FIRStorageVoidMetadataError)completion { + FIRStorageUpdateMetadataTask *task = + [[FIRStorageUpdateMetadataTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + metadata:metadata + completion:completion]; + [task enqueue]; +} + +#pragma mark - Delete + +- (void)deleteWithCompletion:(nullable FIRStorageVoidError)completion { + FIRStorageDeleteTask *task = + [[FIRStorageDeleteTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue + completion:completion]; + [task enqueue]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageReference_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageReference_Private.h new file mode 100644 index 0000000..01370d9 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageReference_Private.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. + */ + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h" + +#import "FirebaseStorage/Sources/FIRStoragePath.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStorageReference () + +@property(nonatomic, readwrite) FIRStorage *storage; + +/** + * The current path which points to an object in the Google Cloud Storage bucket. + */ +@property(strong, nonatomic) FIRStoragePath *path; + +- (instancetype)initWithStorage:(FIRStorage *)storage + path:(FIRStoragePath *)path NS_DESIGNATED_INITIALIZER; + +- (NSString *)stringValue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTask.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTask.m new file mode 100644 index 0000000..329a19f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTask.m @@ -0,0 +1,73 @@ +// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h" + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h" +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h" +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h" + +#import "FirebaseStorage/Sources/FIRStorageReference_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorage_Private.h" + +#if SWIFT_PACKAGE +@import GTMSessionFetcherCore; +#else +#import +#endif + +@implementation FIRStorageTask + +- (instancetype)init { + @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer." + reason:@"init unavailable, use designated initializer" + userInfo:nil]; +} + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue { + self = [super init]; + if (self) { + _reference = reference; + _baseRequest = [FIRStorageUtils defaultRequestForReference:reference]; + _fetcherService = service; + _fetcherService.maxRetryInterval = _reference.storage.maxOperationRetryInterval; + _dispatchQueue = queue; + } + return self; +} + +- (FIRStorageTaskSnapshot *)snapshot { + @synchronized(self) { + NSProgress *progress = [NSProgress progressWithTotalUnitCount:self.progress.totalUnitCount]; + progress.completedUnitCount = self.progress.completedUnitCount; + FIRStorageTaskSnapshot *snapshot = + [[FIRStorageTaskSnapshot alloc] initWithTask:self + state:self.state + metadata:self.metadata + reference:self.reference + progress:progress + error:[self.error copy]]; + return snapshot; + } +} + +- (void)dispatchAsync:(void (^)(void))block { + dispatch_async(self.dispatchQueue, block); +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTaskSnapshot.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTaskSnapshot.m new file mode 100644 index 0000000..1cb3260 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTaskSnapshot.m @@ -0,0 +1,88 @@ +// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h" + +#import "FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h" + +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" + +@implementation FIRStorageTaskSnapshot + +- (instancetype)initWithTask:(__kindof FIRStorageTask *)task + state:(FIRStorageTaskState)state + metadata:(nullable FIRStorageMetadata *)metadata + reference:(FIRStorageReference *)reference + progress:(nullable NSProgress *)progress + error:(nullable NSError *)error { + self = [super init]; + if (self) { + _task = task; + _metadata = metadata; + _reference = reference; + _progress = progress; + _error = error; + + switch (state) { + case FIRStorageTaskStateQueueing: + case FIRStorageTaskStateRunning: + case FIRStorageTaskStateResuming: + _status = FIRStorageTaskStatusResume; + break; + + case FIRStorageTaskStateProgress: + _status = FIRStorageTaskStatusProgress; + break; + + case FIRStorageTaskStatePaused: + case FIRStorageTaskStatePausing: + _status = FIRStorageTaskStatusPause; + break; + + case FIRStorageTaskStateSuccess: + case FIRStorageTaskStateCompleting: + _status = FIRStorageTaskStatusSuccess; + break; + + case FIRStorageTaskStateCancelled: + case FIRStorageTaskStateFailing: + case FIRStorageTaskStateFailed: + _status = FIRStorageTaskStatusFailure; + break; + + default: + _status = FIRStorageTaskStatusUnknown; + } + } + return self; +} + +- (NSString *)description { + switch (_status) { + case FIRStorageTaskStatusResume: + return @""; + case FIRStorageTaskStatusProgress: + return [NSString stringWithFormat:@"", _progress]; + case FIRStorageTaskStatusPause: + return @""; + case FIRStorageTaskStatusSuccess: + return @""; + case FIRStorageTaskStatusFailure: + return [NSString stringWithFormat:@"", _error]; + default: + return @""; + }; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h new file mode 100644 index 0000000..37b691c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h @@ -0,0 +1,60 @@ +/* + * 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 + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRStorageMetadata; +@class FIRStorageReference; +@class FIRStorageTask; + +@interface FIRStorageTaskSnapshot () + +@property(readwrite, copy, nonatomic) FIRStorageTask *task; +@property(readwrite, copy, nonatomic) FIRStorageMetadata *metadata; +@property(readwrite, copy, nonatomic) FIRStorageReference *reference; +@property(readwrite, strong, nonatomic) NSProgress *progress; +@property(readwrite, copy, nonatomic) NSError *error; + +/** + * Creates a new task snapshot from the given properties. + * @param task The task being represented in this snapshot. + * @param state The current state of the parent task. + * @param metadata The FIRStorageMetadata of a task. Before upload/update, contains the metadata + * to be updated; after, contains the returned metadata. May be nil if no metadata is provided + * or returned. + * @param reference The FIRStorageReference that spawned the task this snapshot is based on. + * @param progress An NSProgress object containing progress of the task this snapshot is based on, + * or nil if the task doesn't report progress. + * @param error An NSError object containing an error that occurred during the task, + * if one occurred. + * @return Returns the constructed snapshot. + */ +- (instancetype)initWithTask:(__kindof FIRStorageTask *)task + state:(FIRStorageTaskState)state + metadata:(nullable FIRStorageMetadata *)metadata + reference:(FIRStorageReference *)reference + progress:(nullable NSProgress *)progress + error:(nullable NSError *)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTask_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTask_Private.h new file mode 100644 index 0000000..7ba01b7 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTask_Private.h @@ -0,0 +1,96 @@ +/* + * 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h" +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" +#import "FirebaseStorage/Sources/FIRStorageErrors.h" +#import "FirebaseStorage/Sources/FIRStorageReference_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h" +#import "FirebaseStorage/Sources/FIRStorageUtils.h" + +#if SWIFT_PACKAGE +@import GTMSessionFetcherCore; +#else +#import +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStorageTask () + +/** + * State for the current task in progress. + */ +@property(atomic) FIRStorageTaskState state; + +/** + * FIRStorageMetadata for the task in progress, or nil if none present. + */ +@property(strong, nonatomic, nullable) FIRStorageMetadata *metadata; + +/** + * Error which occurred during task execution, or nil if no error occurred. + */ +@property(strong, nonatomic, nullable) NSError *error; + +/** + * NSProgress object which tracks the progress of an observable task. + */ +@property(strong, nonatomic) NSProgress *progress; + +/** + * Reference pointing to the location the task is being performed against. + */ +@property(strong, nonatomic) FIRStorageReference *reference; + +/** + * A serial queue for all storage operations. + */ +@property(nonatomic, readonly) dispatch_queue_t dispatchQueue; + +@property(strong, readwrite, nonatomic, nonnull) FIRStorageTaskSnapshot *snapshot; + +@property(readonly, copy, nonatomic) NSURLRequest *baseRequest; + +@property(strong, atomic) GTMSessionFetcher *fetcher; + +@property(readonly, nonatomic) GTMSessionFetcherService *fetcherService; + +@property(readonly, copy) GTMSessionFetcherCompletionHandler fetcherCompletion; + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Creates a new FIRStorageTask initialized with a FIRStorageReference and GTMSessionFetcherService. + * @param reference A FIRStorageReference the task will be performed on. + * @param service A GTMSessionFetcherService which provides the fetchers and configuration for + * requests. + * @param queue The shared queue to use for all Storage operations. + * @return A new FIRStorageTask representing the current task. + */ +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER; + +/** Dispatches a block on the shared Storage queue. */ +- (void)dispatchAsync:(void (^)(void))block; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTokenAuthorizer.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTokenAuthorizer.h new file mode 100644 index 0000000..629c578 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTokenAuthorizer.h @@ -0,0 +1,54 @@ +/* + * 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 +@import GTMSessionFetcherCore; +#else +#import +#endif + +@protocol FIRAuthInterop; +@protocol FIRAppCheckInterop; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Wrapper class for FIRAuthInterop that implements the GTMFetcherAuthorizationProtocol, + * so as to easily provide GTMSessionFetcher fetches a Firebase Authentication JWT + * for the current logged in user. Handles token expiration and other failure cases. + * If no authentication provider exists or no token is found, no token is added + * and the request is passed. + */ +@interface FIRStorageTokenAuthorizer : NSObject + +/** + * Initializes the token authorizer with an instance of FIRApp. + * @param googleAppID The Google AppID of the app to send with the request. + * @param auth An instance that provides access to Auth functionality, if it exists. + * @param appCheck An instance that provides access to AppCheck functionality, if it exists. + * @return Returns an instance of FIRStorageTokenAuthorizer which adds the appropriate + * "Authorization" header to all outbound requests. Note that a token may not be added + * if the Auth instance is nil. This allows for unauthenticated access, if Firebase + * Storage rules allow for it. + */ +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + fetcherService:(GTMSessionFetcherService *)service + authProvider:(nullable id)auth + appCheck:(nullable id)appCheck; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTokenAuthorizer.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTokenAuthorizer.m new file mode 100644 index 0000000..724a1a0 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageTokenAuthorizer.m @@ -0,0 +1,166 @@ +// 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 "FirebaseStorage/Sources/FIRStorageTokenAuthorizer.h" + +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h" +#import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" +#import "FirebaseStorage/Sources/FIRStorageErrors.h" +#import "FirebaseStorage/Sources/FIRStorageLogger.h" + +#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h" + +#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h" +#import "FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h" +#import "Interop/Auth/Public/FIRAuthInterop.h" + +static NSString *const kAppCheckTokenHeader = @"X-Firebase-AppCheck"; +static NSString *const kAuthHeader = @"Authorization"; + +@implementation FIRStorageTokenAuthorizer { + @private + /// Google App ID to pass along with each request. + NSString *_googleAppID; + + /// Auth provider. + id _auth; + id _appCheck; +} + +@synthesize fetcherService = _fetcherService; + +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + fetcherService:(GTMSessionFetcherService *)service + authProvider:(nullable id)auth + appCheck:(nullable id)appCheck { + self = [super init]; + if (self) { + _googleAppID = googleAppID; + _fetcherService = service; + _auth = auth; + _appCheck = appCheck; + } + return self; +} + +#pragma mark - GTMFetcherAuthorizationProtocol methods + +- (void)authorizeRequest:(NSMutableURLRequest *)request + delegate:(id)delegate + didFinishSelector:(SEL)sel { + // Set version header on each request + NSString *versionString = [NSString stringWithFormat:@"ios/%@", FIRFirebaseVersion()]; + [request setValue:versionString forHTTPHeaderField:@"x-firebase-storage-version"]; + + // Set GMP ID on each request + [request setValue:_googleAppID forHTTPHeaderField:@"x-firebase-gmpid"]; + + if (delegate && sel) { + id selfParam = self; + NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setSelector:sel]; + [invocation setTarget:delegate]; + [invocation setArgument:&selfParam atIndex:2]; + [invocation setArgument:&request atIndex:3]; + + dispatch_queue_t callbackQueue = self.fetcherService.callbackQueue; + if (!callbackQueue) { + callbackQueue = dispatch_get_main_queue(); + } + + [invocation retainArguments]; + + dispatch_group_t fetchTokenGroup = dispatch_group_create(); + + if (_auth) { + dispatch_group_enter(fetchTokenGroup); + + [_auth getTokenForcingRefresh:NO + withCallback:^(NSString *_Nullable token, NSError *_Nullable error) { + if (error) { + NSMutableDictionary *errorDictionary = + [NSMutableDictionary dictionaryWithDictionary:error.userInfo]; + errorDictionary[kFIRStorageResponseErrorDomain] = error.domain; + errorDictionary[kFIRStorageResponseErrorCode] = @(error.code); + + NSError *tokenError = + [FIRStorageErrors errorWithCode:FIRStorageErrorCodeUnauthenticated + infoDictionary:errorDictionary]; + [invocation setArgument:&tokenError atIndex:4]; + } else if (token) { + NSString *firebaseToken = + [NSString stringWithFormat:kFIRStorageAuthTokenFormat, token]; + [request setValue:firebaseToken forHTTPHeaderField:kAuthHeader]; + } + + dispatch_group_leave(fetchTokenGroup); + }]; + } + + if (_appCheck) { + dispatch_group_enter(fetchTokenGroup); + + [_appCheck getTokenForcingRefresh:NO + completion:^(id tokenResult) { + [request setValue:tokenResult.token + forHTTPHeaderField:kAppCheckTokenHeader]; + + if (tokenResult.error) { + FIRLogDebug(kFIRLoggerStorage, kFIRStorageMessageCodeAppCheckError, + @"Failed to fetch AppCheck token. Error: %@", + tokenResult.error); + } + + dispatch_group_leave(fetchTokenGroup); + }]; + } + + dispatch_group_notify(fetchTokenGroup, callbackQueue, ^{ + [invocation invoke]; + }); + } +} + +// Note that stopAuthorization, isAuthorizingRequest, and userEmail +// aren't relevant with the Firebase App/Auth implementation of tokens, +// and thus aren't implemented. Token refresh is handled transparently +// for us, and we don't allow the auth request to be stopped. +// Auth is also not required so the world doesn't stop. +- (void)stopAuthorization { + // Noop +} + +- (void)stopAuthorizationForRequest:(NSURLRequest *)request { + // Noop +} + +- (BOOL)isAuthorizingRequest:(NSURLRequest *)request { + return NO; +} + +- (BOOL)isAuthorizedRequest:(NSURLRequest *)request { + NSString *authHeader = request.allHTTPHeaderFields[@"Authorization"]; + BOOL isFirebaseToken = [authHeader hasPrefix:@"Firebase"]; + return isFirebaseToken; +} + +- (NSString *)userEmail { + // Noop + return nil; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.h new file mode 100644 index 0000000..5013404 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.h @@ -0,0 +1,36 @@ +/* + * 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h" + +@class GTMSessionFetcherService; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Task which provides the ability update the metadata on an object in Firebase Storage. + */ +@interface FIRStorageUpdateMetadataTask : FIRStorageTask + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + metadata:(FIRStorageMetadata *)metadata + completion:(FIRStorageVoidMetadataError)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.m new file mode 100644 index 0000000..61c99cb --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.m @@ -0,0 +1,107 @@ +// 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 "FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.h" + +#import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" + +@implementation FIRStorageUpdateMetadataTask { + @private + FIRStorageVoidMetadataError _completion; + // Metadata used in the update request + FIRStorageMetadata *_updateMetadata; +} + +@synthesize fetcher = _fetcher; +@synthesize fetcherCompletion = _fetcherCompletion; + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + metadata:(FIRStorageMetadata *)metadata + completion:(FIRStorageVoidMetadataError)completion { + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; + if (self) { + _updateMetadata = [metadata copy]; + _completion = [completion copy]; + } + return self; +} + +- (void)dealloc { + [_fetcher stopFetching]; +} + +- (void)enqueue { + __weak FIRStorageUpdateMetadataTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageUpdateMetadataTask *strongSelf = weakSelf; + + if (!strongSelf) { + return; + } + + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + NSDictionary *updateDictionary = [strongSelf->_updateMetadata updatedMetadata]; + NSData *updateData = [NSData frs_dataFromJSONDictionary:updateDictionary]; + request.HTTPMethod = @"PATCH"; + request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime; + request.HTTPBody = updateData; + NSString *typeString = @"application/json; charset=UTF-8"; + [request setValue:typeString forHTTPHeaderField:@"Content-Type"]; + NSString *lengthString = [NSString stringWithFormat:@"%zu", (unsigned long)[updateData length]]; + [request setValue:lengthString forHTTPHeaderField:@"Content-Length"]; + + FIRStorageVoidMetadataError callback = strongSelf->_completion; + strongSelf->_completion = nil; + + GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + strongSelf->_fetcher = fetcher; + + strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) { + FIRStorageMetadata *metadata; + if (error) { + if (!self.error) { + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + } + } else { + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary) { + metadata = [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; + [metadata setType:FIRStorageMetadataTypeFile]; + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + } + } + + if (callback) { + callback(metadata, self.error); + } + self->_fetcherCompletion = nil; + }; + + fetcher.comment = @"UpdateMetadataTask"; + + [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + FIRStorageUpdateMetadataTask *strongSelf = weakSelf; + if (strongSelf.fetcherCompletion) { + strongSelf.fetcherCompletion(data, error); + } + }]; + }]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUploadTask.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUploadTask.m new file mode 100644 index 0000000..a73f936 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUploadTask.m @@ -0,0 +1,277 @@ +// 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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageUploadTask.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" +#import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h" +#import "FirebaseStorage/Sources/FIRStorageObservableTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorageTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorageUploadTask_Private.h" +#import "FirebaseStorage/Sources/FIRStorage_Private.h" + +#if SWIFT_PACKAGE +@import GTMSessionFetcherCore; +#else +#import +#endif + +@implementation FIRStorageUploadTask + +@synthesize progress = _progress; +@synthesize fetcherCompletion = _fetcherCompletion; + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + data:(NSData *)uploadData + metadata:(FIRStorageMetadata *)metadata { + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; + if (self) { + _uploadMetadata = [metadata copy]; + _uploadData = [uploadData copy]; + _progress = [NSProgress progressWithTotalUnitCount:[_uploadData length]]; + + if (!_uploadMetadata.contentType) { + _uploadMetadata.contentType = @"application/octet-stream"; + } + } + return self; +} + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + file:(NSURL *)fileURL + metadata:(FIRStorageMetadata *)metadata { + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; + if (self) { + _uploadMetadata = [metadata copy]; + _fileURL = [fileURL copy]; + _progress = [NSProgress progressWithTotalUnitCount:0]; + + NSString *mimeType = [FIRStorageUtils MIMETypeForExtension:[_fileURL pathExtension]]; + + if (!_uploadMetadata.contentType) { + _uploadMetadata.contentType = mimeType ?: @"application/octet-stream"; + } + } + return self; +} + +- (void)dealloc { + [_uploadFetcher stopFetching]; +} + +- (void)enqueue { + __weak FIRStorageUploadTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageUploadTask *strongSelf = weakSelf; + + if (!strongSelf) { + return; + } + + NSError *contentValidationError; + if (![strongSelf isContentToUploadValid:&contentValidationError]) { + strongSelf.error = contentValidationError; + [strongSelf finishTaskWithStatus:FIRStorageTaskStatusFailure snapshot:strongSelf.snapshot]; + return; + } + + strongSelf.state = FIRStorageTaskStateQueueing; + + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + request.HTTPMethod = @"POST"; + request.timeoutInterval = strongSelf.reference.storage.maxUploadRetryTime; + NSData *bodyData = + [NSData frs_dataFromJSONDictionary:[strongSelf->_uploadMetadata dictionaryRepresentation]]; + request.HTTPBody = bodyData; + [request setValue:@"application/json; charset=UTF-8" forHTTPHeaderField:@"Content-Type"]; + NSString *contentLengthString = + [NSString stringWithFormat:@"%zu", (unsigned long)[bodyData length]]; + [request setValue:contentLengthString forHTTPHeaderField:@"Content-Length"]; + + NSURLComponents *components = [NSURLComponents componentsWithURL:request.URL + resolvingAgainstBaseURL:NO]; + + if ([components.host isEqual:kGCSHost]) { + [components setPercentEncodedPath:[@"/upload" stringByAppendingString:components.path]]; + } + + NSDictionary *queryParams = @{@"uploadType" : @"resumable", @"name" : self.uploadMetadata.path}; + [components setPercentEncodedQuery:[FIRStorageUtils queryStringForDictionary:queryParams]]; + request.URL = components.URL; + + GTMSessionUploadFetcher *uploadFetcher = + [GTMSessionUploadFetcher uploadFetcherWithRequest:request + uploadMIMEType:strongSelf->_uploadMetadata.contentType + chunkSize:kGTMSessionUploadFetcherStandardChunkSize + fetcherService:self.fetcherService]; + + if (strongSelf->_uploadData) { + [uploadFetcher setUploadData:strongSelf->_uploadData]; + uploadFetcher.comment = @"Data UploadTask"; + } else if (strongSelf->_fileURL) { + [uploadFetcher setUploadFileURL:strongSelf->_fileURL]; + uploadFetcher.comment = @"File UploadTask"; + } + + uploadFetcher.maxRetryInterval = self.reference.storage.maxUploadRetryInterval; + + [uploadFetcher setSendProgressBlock:^(int64_t bytesSent, int64_t totalBytesSent, + int64_t totalBytesExpectedToSend) { + weakSelf.state = FIRStorageTaskStateProgress; + weakSelf.progress.completedUnitCount = totalBytesSent; + weakSelf.progress.totalUnitCount = totalBytesExpectedToSend; + weakSelf.metadata = self->_uploadMetadata; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:weakSelf.snapshot]; + weakSelf.state = FIRStorageTaskStateRunning; + }]; + + strongSelf->_uploadFetcher = uploadFetcher; + + // Process fetches + strongSelf.state = FIRStorageTaskStateRunning; + + strongSelf->_fetcherCompletion = ^(NSData *_Nullable data, NSError *_Nullable error) { + // Fire last progress updates + [self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot]; + + // Handle potential issues with upload + if (error) { + self.state = FIRStorageTaskStateFailed; + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + self.metadata = self->_uploadMetadata; + + [self finishTaskWithStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot]; + return; + } + + // Upload completed successfully, fire completion callbacks + self.state = FIRStorageTaskStateSuccess; + + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary) { + FIRStorageMetadata *metadata = + [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; + [metadata setType:FIRStorageMetadataTypeFile]; + self.metadata = metadata; + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + } + + [self finishTaskWithStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot]; + }; + + [strongSelf->_uploadFetcher + beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) { + FIRStorageUploadTask *strongSelf = weakSelf; + if (strongSelf.fetcherCompletion) { + strongSelf.fetcherCompletion(data, error); + } + }]; + }]; +} + +- (void)finishTaskWithStatus:(FIRStorageTaskStatus)status + snapshot:(FIRStorageTaskSnapshot *)snapshot { + [self fireHandlersForStatus:status snapshot:self.snapshot]; + [self removeAllObservers]; + self->_fetcherCompletion = nil; +} + +- (BOOL)isContentToUploadValid:(NSError **)outError { + if (_uploadData != nil) { + return YES; + } + + NSError *fileReachabilityError; + if (![_fileURL checkResourceIsReachableAndReturnError:&fileReachabilityError] || + ![self fileURLisFile:_fileURL]) { + if (outError != NULL) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:2]; + userInfo[NSLocalizedDescriptionKey] = [NSString + stringWithFormat:@"File at URL: %@ is not reachable. " + @"Ensure file URL is not a directory, symbolic link, or invalid url.", + _fileURL.absoluteString]; + + if (fileReachabilityError) { + userInfo[NSUnderlyingErrorKey] = fileReachabilityError; + } + + *outError = [NSError errorWithDomain:FIRStorageErrorDomain + code:FIRStorageErrorCodeUnknown + userInfo:userInfo]; + } + + return NO; + } + + return YES; +} + +#pragma mark - Upload Management + +- (void)cancel { + __weak FIRStorageUploadTask *weakSelf = self; + + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStateCancelled; + [weakSelf.uploadFetcher stopFetching]; + if (weakSelf.state != FIRStorageTaskStateSuccess) { + weakSelf.metadata = weakSelf.uploadMetadata; + } + weakSelf.error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeCancelled]; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:weakSelf.snapshot]; + }]; +} + +- (void)pause { + __weak FIRStorageUploadTask *weakSelf = self; + + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStatePaused; + [weakSelf.uploadFetcher pauseFetching]; + if (weakSelf.state != FIRStorageTaskStateSuccess) { + weakSelf.metadata = weakSelf.uploadMetadata; + } + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:weakSelf.snapshot]; + }]; +} + +- (void)resume { + __weak FIRStorageUploadTask *weakSelf = self; + + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStateResuming; + [weakSelf.uploadFetcher resumeFetching]; + if (weakSelf.state != FIRStorageTaskStateSuccess) { + weakSelf.metadata = weakSelf.uploadMetadata; + } + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:weakSelf.snapshot]; + weakSelf.state = FIRStorageTaskStateRunning; + }]; +} + +#pragma mark - Private Helpers + +- (BOOL)fileURLisFile:(NSURL *)fileURL { + NSNumber *isFile = [NSNumber numberWithBool:NO]; + [fileURL getResourceValue:&isFile forKey:NSURLIsRegularFileKey error:nil]; + return [isFile boolValue]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUploadTask_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUploadTask_Private.h new file mode 100644 index 0000000..8d37a8b --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUploadTask_Private.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +@class GTMSessionUploadFetcher; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStorageUploadTask () + +/** + * The data to be uploaded (if uploading bytes). + */ +@property(readonly, copy, nonatomic, nullable) NSData *uploadData; + +/** + * The name of a file on disk to be uploaded (if uploading from a file). + */ +@property(readonly, copy, nonatomic, nullable) NSURL *fileURL; + +/** + * The FIRStorageMetadata about the object being uploaded. + */ +@property(readonly, copy, nonatomic) FIRStorageMetadata *uploadMetadata; + +/** + * GTMSessionUploadFetcher used by all uploads. + */ +@property(strong, atomic) GTMSessionUploadFetcher *uploadFetcher; + +/** + * Initializes an upload task with a base FIRStorageReference and GTMSessionFetcherService. + * @param reference The base FIRStorageReference which fetchers use for configuration. + * @param service The GTMSessionFetcherService which will create fetchers. + * @param queue The shared queue to use for all Storage operations. + * @param uploadData The NSData object to be uploaded. + * @return Returns an instance of FIRStorageUploadTask. + */ +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + data:(NSData *)uploadData + metadata:(FIRStorageMetadata *)metadata; + +/** + * Initializes an upload task with a base FIRStorageReference and GTMSessionFetcherService. + * @param reference The base FIRStorageReference which fetchers use for configuration. + * @param service The GTMSessionFetcherService which will create fetchers. + * @param queue The shared queue to use for all Storage operations. + * @param fileURL The system file URL to upload from. + * @return Returns an instance of FIRStorageUploadTask. + */ +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue + file:(NSURL *)fileURL + metadata:(FIRStorageMetadata *)metadata; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUtils.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUtils.h new file mode 100644 index 0000000..a8a2bd1 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUtils.h @@ -0,0 +1,122 @@ +/* + * 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 + +@class FIRStoragePath; +@class FIRStorageReference; + +NS_ASSUME_NONNULL_BEGIN + +/** + * FIRStorageUtils provides a number of helper methods for commonly used operations + * in Firebase Storage, such as JSON parsing, escaping, and file extensions. + */ +@interface FIRStorageUtils : NSObject + +/** + * Returns a percent encoded string appropriate for GCS. + * See https://cloud.google.com/storage/docs/naming for more details. + * @param string A path to escape characters according to the GCS + * @return A percent encoded string appropriate for GCS operations or nil if string is nil + * or can't be escaped. + */ ++ (nullable NSString *)GCSEscapedString:(NSString *)string; + +/** + * Returns the MIME type for a file extension. + * Example of how to get MIME type here: http://ddeville.me/2011/12/mime-to-UTI-cocoa/ + * @param extension A file extension such as "txt", "png", etc. + * @return The MIME type for the input extension such as "text/plain", "image/png", etc. + * or nil if no type is found. + */ ++ (nullable NSString *)MIMETypeForExtension:(NSString *)extension; + +/** + * Returns a properly escaped query string from a given dictionary of query items to values. + * @param dictionary A dictionary containing query items and associated values. + * @return A properly escaped query string or the empty string for a nil or empty dictionary. + */ ++ (NSString *)queryStringForDictionary:(nullable NSDictionary *)dictionary; + +/** + * Returns a base NSURLRequest used by all tasks. + * @param reference The FIRStorageReference to create a request for. + * @return Returns a properly formatted NSURLRequest of the form: + * scheme://host/version/b//o[/path/to/object] + */ ++ (NSURLRequest *)defaultRequestForReference:(FIRStorageReference *)reference; + +/** + * Returns a base NSURLRequest with custom query parameters. + * @param reference The FIRStorageReference to create a request for. + * @param queryParams A key/value dictionary with query parameters. + * @return Returns a formatted NSURLRequest + */ ++ (NSURLRequest *)defaultRequestForReference:(FIRStorageReference *)reference + queryParams:(NSDictionary *)queryParams; + +/** + * Creates the appropriate GCS percent escaped path for a given FIRStoragePath. + * @param path The FIRStoragePath to encode. + * @return Returns the GCS encoded URL for a given FIRStoragePath. + */ ++ (NSString *)encodedURLForPath:(FIRStoragePath *)path; + +/** + * Creates a NSError in the Firebase Storage domain with given code and description. + * Useful for argument validation. + * @param description The error description to surface to the user. + * @param code The error code. + * @return An NSError in the Firebase Storage error domain. + */ ++ (NSError *)storageErrorWithDescription:(NSString *)description code:(NSInteger)code; + +/** + * Performs a crude translation of the user provided timeouts to the retry intervals that + * GTMSessionFetcher accepts. GTMSessionFetcher times out operations if the time between individual + * retry attempts exceed a certain threshold, while our API contract looks at the total observed + * time of the operation (i.e. the sum of all retries). + * @param retryTime A timeout that caps the sum of all retry attempts + * @return A timeout that caps the timeout of the last retry attempt + */ ++ (NSTimeInterval)computeRetryIntervalFromRetryTime:(NSTimeInterval)retryTime; + +@end + +@interface NSDictionary (FIRStorageNSDictionaryJSONHelpers) + +/** + * Returns a dictionary representation of the data in @a data. + * @param data NSData containing JSON data. + * @return An NSDictionary representation of the JSON, or nil if serialization failed. + */ ++ (nullable instancetype)frs_dictionaryFromJSONData:(nullable NSData *)data; + +@end + +@interface NSData (FIRStorageNSDataJSONHelpers) + +/** + * Returns an NSData instance containing JSON serialized from @a dictionary. + * @param dictionary An NSDictionary containing only types serializable to JSON. + * @return An NSData object representing the binary JSON, or nil if serialization failed. + */ ++ (nullable instancetype)frs_dataFromJSONDictionary:(nullable NSDictionary *)dictionary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUtils.m b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUtils.m new file mode 100644 index 0000000..abf24f6 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorageUtils.m @@ -0,0 +1,182 @@ +// 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 + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#elif TARGET_OS_OSX || TARGET_OS_WATCH +#import +#endif + +#import "FirebaseStorage/Sources/FIRStorageUtils.h" + +#import "FirebaseStorage/Sources/FIRStorageConstants_Private.h" +#import "FirebaseStorage/Sources/FIRStorageErrors.h" +#import "FirebaseStorage/Sources/FIRStoragePath.h" +#import "FirebaseStorage/Sources/FIRStorageReference_Private.h" +#import "FirebaseStorage/Sources/FIRStorage_Private.h" + +#if SWIFT_PACKAGE +@import GTMSessionFetcherCore; +#else +#import +#endif + +// This is the list at https://cloud.google.com/storage/docs/json_api/ without &, ; and +. +NSString *const kGCSObjectAllowedCharacterSet = + @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$'()*,=:@"; + +@implementation FIRStorageUtils + ++ (nullable NSString *)GCSEscapedString:(NSString *)string { + NSCharacterSet *allowedCharacters = + [NSCharacterSet characterSetWithCharactersInString:kGCSObjectAllowedCharacterSet]; + + return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters]; +} + ++ (nullable NSString *)MIMETypeForExtension:(NSString *)extension { + if (extension == nil) { + return nil; + } + + CFStringRef pathExtension = (__bridge_retained CFStringRef)extension; + CFStringRef type = + UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, NULL); + NSString *mimeType = + (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType); + CFRelease(pathExtension); + if (type != NULL) { + CFRelease(type); + } + + return mimeType; +} + ++ (NSString *)queryStringForDictionary:(nullable NSDictionary *)dictionary { + if (!dictionary) { + return @""; + } + + __block NSMutableArray *queryItems = [[NSMutableArray alloc] initWithCapacity:[dictionary count]]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull name, NSString *_Nonnull value, + BOOL *_Nonnull stop) { + NSString *item = + [FIRStorageUtils GCSEscapedString:[NSString stringWithFormat:@"%@=%@", name, value]]; + [queryItems addObject:item]; + }]; + return [queryItems componentsJoinedByString:@"&"]; +} + ++ (NSURLRequest *)defaultRequestForReference:(FIRStorageReference *)reference { + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; + NSURLComponents *components = [[NSURLComponents alloc] init]; + [components setScheme:reference.storage.scheme]; + [components setHost:reference.storage.host]; + [components setPort:reference.storage.port]; + NSString *encodedPath = [self encodedURLForPath:reference.path]; + [components setPercentEncodedPath:encodedPath]; + [request setURL:components.URL]; + return request; +} + ++ (NSURLRequest *)defaultRequestForReference:(FIRStorageReference *)reference + queryParams:(NSDictionary *)queryParams { + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; + NSURLComponents *components = [[NSURLComponents alloc] init]; + [components setScheme:reference.storage.scheme]; + [components setHost:reference.storage.host]; + [components setPort:reference.storage.port]; + + NSMutableArray *queryItems = [NSMutableArray new]; + for (NSString *key in queryParams) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:key value:queryParams[key]]]; + } + [components setQueryItems:queryItems]; + // NSURLComponents does not encode "+" as "%2B". This is however required by our backend, as + // it treats "+" as a shorthand encoding for spaces. See also + // https://stackoverflow.com/questions/31577188/how-to-encode-into-2b-with-nsurlcomponents + [components setPercentEncodedQuery:[[components percentEncodedQuery] + stringByReplacingOccurrencesOfString:@"+" + withString:@"%2B"]]; + + NSString *encodedPath = [self encodedURLForPath:reference.path]; + [components setPercentEncodedPath:encodedPath]; + [request setURL:components.URL]; + return request; +} + ++ (NSString *)encodedURLForPath:(FIRStoragePath *)path { + NSString *bucketName = [FIRStorageUtils GCSEscapedString:path.bucket]; + NSString *objectName = [FIRStorageUtils GCSEscapedString:path.object]; + NSString *bucketFormat = [NSString stringWithFormat:kFIRStorageBucketPathFormat, bucketName]; + NSString *urlPath = [@"/" stringByAppendingPathComponent:bucketFormat]; + if (objectName) { + NSString *objectFormat = [NSString stringWithFormat:kFIRStorageObjectPathFormat, objectName]; + urlPath = [urlPath stringByAppendingFormat:@"/%@", objectFormat]; + } else { + urlPath = [urlPath stringByAppendingString:@"/o"]; + } + return [@"/" stringByAppendingString:[kFIRStorageVersionPath stringByAppendingString:urlPath]]; +} + ++ (NSError *)storageErrorWithDescription:(NSString *)description code:(NSInteger)code { + return [NSError errorWithDomain:FIRStorageErrorDomain + code:code + userInfo:@{NSLocalizedDescriptionKey : description}]; +} + ++ (NSTimeInterval)computeRetryIntervalFromRetryTime:(NSTimeInterval)retryTime { + // GTMSessionFetcher's retry starts at 1 second and then doubles every time. We use this + // information to compute a best-effort estimate of what to translate the user provided retry + // time into. + + // Note that this is the same as 2 << (log2(retryTime) - 1), but deemed more readable. + NSTimeInterval lastInterval = 1.0; + NSTimeInterval sumOfAllIntervals = 1.0; + + while (sumOfAllIntervals < retryTime) { + lastInterval *= 2; + sumOfAllIntervals += lastInterval; + } + + return lastInterval; +} + +@end + +@implementation NSDictionary (FIRStorageNSDictionaryJSONHelpers) + ++ (nullable instancetype)frs_dictionaryFromJSONData:(nullable NSData *)data { + if (!data) { + return nil; + } + return [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableContainers + error:nil]; +} + +@end + +@implementation NSData (FIRStorageNSDataJSONHelpers) + ++ (nullable instancetype)frs_dataFromJSONDictionary:(nullable NSDictionary *)dictionary { + if (!dictionary) { + return nil; + } + return [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil]; +} + +@end diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorage_Private.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorage_Private.h new file mode 100644 index 0000000..e9f2028 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/FIRStorage_Private.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +@class FIRApp; +@class GTMSessionFetcherService; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStorage () + +@property(strong, nonatomic, readwrite) FIRApp *app; + +@property(strong, nonatomic, nullable) GTMSessionFetcherService *fetcherServiceForApp; + +@property(nonatomic, readonly) dispatch_queue_t dispatchQueue; + +@property(strong, nonatomic) NSString *storageBucket; + +@property(strong, nonatomic) NSString *scheme; + +@property(strong, nonatomic) NSString *host; + +@property(strong, nonatomic) NSNumber *port; + +/** + * Maximum time between retry attempts for uploads. + * + * This is used by GTMSessionFetcher and translated from the user provided `maxUploadRetryTime`. + */ +@property(assign, nonatomic) NSTimeInterval maxUploadRetryInterval; + +/** + * Maximum time between retry attempts for downloads. + * + * This is used by GTMSessionFetcher and translated from the user provided `maxDownloadRetryTime`. + */ +@property(assign, nonatomic) NSTimeInterval maxDownloadRetryInterval; + +/** + * Maximum time between retry attempts for any operation that is not an upload or download. + * + * This is used by GTMSessionFetcher and translated from the user provided `maxOperationRetryTime`. + */ +@property(assign, nonatomic) NSTimeInterval maxOperationRetryInterval; + +/** + * Enables/disables GTMSessionFetcher HTTP logging + * @param isLoggingEnabled Boolean passed through to enable/disable GTMSessionFetcher logging + */ ++ (void)setGTMSessionFetcherLoggingEnabled:(BOOL)isLoggingEnabled; + +/** Configures the storage instance. Freezes the host setting. */ +- (void)ensureConfigured; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h new file mode 100644 index 0000000..75ffaaf --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h @@ -0,0 +1,132 @@ +/* + * 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 + +#import "FIRStorageConstants.h" + +@class FIRApp; +@class FIRStorageReference; + +NS_ASSUME_NONNULL_BEGIN + +/** + * FirebaseStorage is a service that supports uploading and downloading binary objects, + * such as images, videos, and other files to Google Cloud Storage. + * + * If you call [FIRStorage storage], the instance will initialize with the default FIRApp, + * [FIRApp defaultApp], and the storage location will come from the provided + * GoogleService-Info.plist. + * + * If you call [FIRStorage storageForApp:] and provide a custom instance of FIRApp, + * the storage location will be specified via the FIROptions#storageBucket property. + */ +NS_SWIFT_NAME(Storage) +@interface FIRStorage : NSObject + +/** + * Creates an instance of FIRStorage, configured with the default FIRApp. + * @return the FIRStorage instance, initialized with the default FIRApp. + */ ++ (instancetype)storage NS_SWIFT_NAME(storage()); + +/** + * Creates an instance of FIRStorage, configured with the custom FIRApp @a app. + * @param app The custom FIRApp used for initialization. + * @return the FIRStorage instance, initialized with the custom FIRApp. + */ ++ (instancetype)storageForApp:(FIRApp *)app NS_SWIFT_NAME(storage(app:)); + +/** + * Creates an instance of FIRStorage, configured with a custom storage bucket @a url. + * @param url The gs:// url to your Firebase Storage Bucket. + * @return the FIRStorage instance, initialized with the custom FIRApp. + */ ++ (instancetype)storageWithURL:(NSString *)url NS_SWIFT_NAME(storage(url:)); + +/** + * Creates an instance of FIRStorage, configured with a custom FIRApp @a app and a custom storage + * bucket @a url. + * @param app The custom FIRApp used for initialization. + * @param url The gs:// url to your Firebase Storage Bucket. + * @return the FIRStorage instance, initialized with the custom FIRApp. + */ ++ (instancetype)storageForApp:(FIRApp *)app URL:(NSString *)url NS_SWIFT_NAME(storage(app:url:)); + +- (instancetype)init NS_UNAVAILABLE; + +/** + * The Firebase App associated with this Firebase Storage instance. + */ +@property(strong, nonatomic, readonly) FIRApp *app; + +/** + * Maximum time in seconds to retry an upload if a failure occurs. + * Defaults to 10 minutes (600 seconds). + */ +@property NSTimeInterval maxUploadRetryTime; + +/** + * Maximum time in seconds to retry a download if a failure occurs. + * Defaults to 10 minutes (600 seconds). + */ +@property NSTimeInterval maxDownloadRetryTime; + +/** + * Maximum time in seconds to retry operations other than upload and download if a failure occurs. + * Defaults to 2 minutes (120 seconds). + */ +@property NSTimeInterval maxOperationRetryTime; + +/** + * Queue that all developer callbacks are fired on. Defaults to the main queue. + */ +@property(strong, nonatomic) dispatch_queue_t callbackQueue; + +/** + * Creates a FIRStorageReference initialized at the root Firebase Storage location. + * @return An instance of FIRStorageReference initialized at the root. + */ +- (FIRStorageReference *)reference; + +/** + * Creates a FIRStorageReference given a gs:// or https:// URL pointing to a Firebase Storage + * location. For example, you can pass in an https:// download URL retrieved from + * [FIRStorageReference downloadURLWithCompletion] or the gs:// URI from + * [FIRStorageReference description]. + * @param string A gs:// or https:// URL to initialize the reference with. + * @return An instance of FIRStorageReference at the given child path. + * @throws Throws an exception if passed in URL is not associated with the FIRApp used to initialize + * this FIRStorage. + */ +- (FIRStorageReference *)referenceForURL:(NSString *)string; + +/** + * Creates a FIRStorageReference initialized at a child Firebase Storage location. + * @param string A relative path from the root to initialize the reference with, + * for instance @"path/to/object". + * @return An instance of FIRStorageReference at the given child path. + */ +- (FIRStorageReference *)referenceWithPath:(NSString *)string; + +/** + * Configures the Storage SDK to use an emulated backend instead of the default remote backend. + */ +- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h new file mode 100644 index 0000000..52c7382 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h @@ -0,0 +1,174 @@ +/* + * 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 + +@class FIRStorageDownloadTask; +@class FIRStorageMetadata; +@class FIRStorageTaskSnapshot; +@class FIRStorageUploadTask; + +NS_ASSUME_NONNULL_BEGIN + +/** + * NSString typedef representing a task listener handle. + */ +typedef NSString *FIRStorageHandle NS_SWIFT_NAME(StorageHandle); + +/** + * Block typedef typically used when downloading data. + * @param data The data returned by the download, or nil if no data available or download failed. + * @param error The error describing failure, if one occurred. + */ +typedef void (^FIRStorageVoidDataError)(NSData *_Nullable data, NSError *_Nullable error) + NS_SWIFT_NAME(StorageVoidDataError); + +/** + * Block typedef typically used when performing "binary" async operations such as delete, + * where the operation either succeeds without an error or fails with an error. + * @param error The error describing failure, if one occurred. + */ +typedef void (^FIRStorageVoidError)(NSError *_Nullable error) NS_SWIFT_NAME(StorageVoidError); + +/** + * Block typedef typically used when retrieving metadata. + * @param metadata The metadata returned by the operation, if metadata exists. + */ +typedef void (^FIRStorageVoidMetadata)(FIRStorageMetadata *_Nullable metadata) + NS_SWIFT_NAME(StorageVoidMetadata); + +/** + * Block typedef typically used when retrieving metadata with the possibility of an error. + * @param metadata The metadata returned by the operation, if metadata exists. + * @param error The error describing failure, if one occurred. + */ +typedef void (^FIRStorageVoidMetadataError)(FIRStorageMetadata *_Nullable metadata, + NSError *_Nullable error) + NS_SWIFT_NAME(StorageVoidMetadataError); + +/** + * Block typedef typically used to asynchronously return a storage task snapshot. + * @param snapshot The returned task snapshot. + */ +typedef void (^FIRStorageVoidSnapshot)(FIRStorageTaskSnapshot *snapshot) + NS_SWIFT_NAME(StorageVoidSnapshot); + +/** + * Block typedef typically used when retrieving a download URL. + * @param URL The download URL associated with the operation. + * @param error The error describing failure, if one occurred. + */ +typedef void (^FIRStorageVoidURLError)(NSURL *_Nullable URL, NSError *_Nullable error) + NS_SWIFT_NAME(StorageVoidURLError); + +/** + * Enum representing the upload and download task status. + */ +typedef NS_ENUM(NSInteger, FIRStorageTaskStatus) { + /** + * Unknown task status. + */ + FIRStorageTaskStatusUnknown, + + /** + * Task is being resumed. + */ + FIRStorageTaskStatusResume, + + /** + * Task reported a progress event. + */ + FIRStorageTaskStatusProgress, + + /** + * Task is paused. + */ + FIRStorageTaskStatusPause, + + /** + * Task has completed successfully. + */ + FIRStorageTaskStatusSuccess, + + /** + * Task has failed and is unrecoverable. + */ + FIRStorageTaskStatusFailure +} NS_SWIFT_NAME(StorageTaskStatus); + +/** + * Firebase Storage error domain. + */ +FOUNDATION_EXPORT NSString *const FIRStorageErrorDomain NS_SWIFT_NAME(StorageErrorDomain); + +/** + * Enum representing the errors raised by Firebase Storage. + */ +typedef NS_ENUM(NSInteger, FIRStorageErrorCode) { + /** An unknown error occurred. */ + FIRStorageErrorCodeUnknown = -13000, + + /** No object exists at the desired reference. */ + FIRStorageErrorCodeObjectNotFound = -13010, + + /** No bucket is configured for Firebase Storage. */ + FIRStorageErrorCodeBucketNotFound = -13011, + + /** No project is configured for Firebase Storage. */ + FIRStorageErrorCodeProjectNotFound = -13012, + + /** + * Quota on your Firebase Storage bucket has been exceeded. + * If you're on the free tier, upgrade to a paid plan. + * If you're on a paid plan, reach out to Firebase support. + */ + FIRStorageErrorCodeQuotaExceeded = -13013, + + /** User is unauthenticated. Authenticate and try again. */ + FIRStorageErrorCodeUnauthenticated = -13020, + + /** + * User is not authorized to perform the desired action. + * Check your rules to ensure they are correct. + */ + FIRStorageErrorCodeUnauthorized = -13021, + + /** + * The maximum time limit on an operation (upload, download, delete, etc.) has been exceeded. + * Try uploading again. + */ + FIRStorageErrorCodeRetryLimitExceeded = -13030, + + /** + * File on the client does not match the checksum of the file received by the server. + * Try uploading again. + */ + FIRStorageErrorCodeNonMatchingChecksum = -13031, + + /** + * Size of the downloaded file exceeds the amount of memory allocated for the download. + * Increase memory cap and try downloading again. + */ + FIRStorageErrorCodeDownloadSizeExceeded = -13032, + + /** User cancelled the operation. */ + FIRStorageErrorCodeCancelled = -13040, + + /** An invalid argument was provided. */ + FIRStorageErrorCodeInvalidArgument = -13050 +} NS_SWIFT_NAME(StorageErrorCode); + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageDownloadTask.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageDownloadTask.h new file mode 100644 index 0000000..c11373f --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageDownloadTask.h @@ -0,0 +1,38 @@ +/* + * 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 + +#import "FIRStorageObservableTask.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * FIRStorageDownloadTask implements resumable downloads from an object in Firebase Storage. + * Downloads can be returned on completion with a completion handler, and can be monitored + * by attaching observers, or controlled by calling FIRStorageTask#pause, FIRStorageTask#resume, + * or FIRStorageTask#cancel. + * Downloads can currently be returned as NSData in memory, or as an NSURL to a file on disk. + * Downloads are performed on a background queue, and callbacks are raised on the developer + * specified callbackQueue in FIRStorage, or the main queue if left unspecified. + * Currently all uploads must be initiated and managed on the main queue. + */ +NS_SWIFT_NAME(StorageDownloadTask) +@interface FIRStorageDownloadTask : FIRStorageObservableTask + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h new file mode 100644 index 0000000..0207c51 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h @@ -0,0 +1,53 @@ +/* + * 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 + +@class FIRStorageReference; + +NS_ASSUME_NONNULL_BEGIN + +/** Contains the prefixes and items returned by a `StorageReference.list()` call. */ +NS_SWIFT_NAME(StorageListResult) +@interface FIRStorageListResult : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** + * The prefixes (folders) returned by the `list()` operation. + * + * @return A list of prefixes (folders). + */ +@property(nonatomic, readonly) NSArray *prefixes; + +/** + * The items (files) returned by the `list()` operation. + * + * @return A list of items (files). + */ +@property(nonatomic, readonly) NSArray *items; + +/** + * Returns a token that can be used to resume a previous `list()` operation. `nil` + * indicates that there are no more results. + * + * @return A page token if more results are available. + */ +@property(nonatomic, readonly, nullable) NSString *pageToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageMetadata.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageMetadata.h new file mode 100644 index 0000000..3749504 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageMetadata.h @@ -0,0 +1,140 @@ +/* + * 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 + +@class FIRStorageReference; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Class which represents the metadata on an object in Firebase Storage. This metadata is + * returned on successful operations, and can be used to retrieve download URLs, content types, + * and a FIRStorage reference to the object in question. Full documentation can be found at the GCS + * Objects#resource docs. + * @see https://cloud.google.com/storage/docs/json_api/v1/objects#resource + */ +NS_SWIFT_NAME(StorageMetadata) +@interface FIRStorageMetadata : NSObject + +/** + * The name of the bucket containing this object. + */ +@property(copy, nonatomic, readonly) NSString *bucket; + +/** + * Cache-Control directive for the object data. + */ +@property(copy, nonatomic, nullable) NSString *cacheControl; + +/** + * Content-Disposition of the object data. + */ +@property(copy, nonatomic, nullable) NSString *contentDisposition; + +/** + * Content-Encoding of the object data. + */ +@property(copy, nonatomic, nullable) NSString *contentEncoding; + +/** + * Content-Language of the object data. + */ +@property(copy, nonatomic, nullable) NSString *contentLanguage; + +/** + * Content-Type of the object data. + */ +@property(copy, nonatomic, nullable) NSString *contentType; + +/** + * MD5 hash of the data; encoded using base64. + */ +@property(copy, nonatomic, nullable, readonly) NSString *md5Hash; + +/** + * The content generation of this object. Used for object versioning. + */ +@property(readonly) int64_t generation; + +/** + * User-provided metadata, in key/value pairs. + */ +@property(copy, nonatomic, nullable) NSDictionary *customMetadata; + +/** + * The version of the metadata for this object at this generation. Used + * for preconditions and for detecting changes in metadata. A metageneration number is only + * meaningful in the context of a particular generation of a particular object. + */ +@property(readonly) int64_t metageneration; + +/** + * The name of this object, in gs://bucket/path/to/object.txt, this is object.txt. + */ +@property(copy, nonatomic, readonly, nullable) NSString *name; + +/** + * The full path of this object, in gs://bucket/path/to/object.txt, this is path/to/object.txt. + */ +@property(copy, nonatomic, readonly, nullable) NSString *path; + +/** + * Content-Length of the data in bytes. + */ +@property(readonly) int64_t size; + +/** + * The creation time of the object in RFC 3339 format. + */ +@property(copy, nonatomic, readonly, nullable) NSDate *timeCreated; + +/** + * The modification time of the object metadata in RFC 3339 format. + */ +@property(copy, nonatomic, readonly, nullable) NSDate *updated; + +/** + * A reference to the object in Firebase Storage. + */ +@property(strong, nonatomic, readonly, nullable) FIRStorageReference *storageReference; + +/** + * Creates an instance of FIRStorageMetadata from the contents of a dictionary. + * @return An instance of FIRStorageMetadata that represents the contents of a dictionary. + */ +- (nullable instancetype)initWithDictionary:(NSDictionary *)dictionary + NS_DESIGNATED_INITIALIZER; + +/** + * Creates an NSDictionary from the contents of the metadata. + * @return An NSDictionary that represents the contents of the metadata. + */ +- (NSDictionary *)dictionaryRepresentation; + +/** + * Determines if the current metadata represents a "file". + */ +@property(readonly, getter=isFile) BOOL file; + +/** + * Determines if the current metadata represents a "folder". + */ +@property(readonly, getter=isFolder) BOOL folder; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageObservableTask.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageObservableTask.h new file mode 100644 index 0000000..d8ad401 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageObservableTask.h @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRStorageTask.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRStorageReference; +@class FIRStorageTaskSnapshot; + +/** + * Extends FIRStorageTask to provide observable semantics such as adding and removing observers. + * Observers produce a FIRStorageHandle, which is used to keep track of and remove specific + * observers at a later date. + * This class is currently not thread safe and can only be called on the main thread. + */ +NS_SWIFT_NAME(StorageObservableTask) +@interface FIRStorageObservableTask : FIRStorageTask + +/** + * Observes changes in the upload status: Resume, Pause, Progress, Success, and Failure. + * @param status The FIRStorageTaskStatus change to observe. + * @param handler A callback that fires every time the status event occurs, + * returns a FIRStorageTaskSnapshot containing the state of the task. + * @return A task handle that can be used to remove the observer at a later date. + */ +- (FIRStorageHandle)observeStatus:(FIRStorageTaskStatus)status + handler:(void (^)(FIRStorageTaskSnapshot *snapshot))handler; + +/** + * Removes the single observer with the provided handle. + * @param handle The handle of the task to remove. + */ +- (void)removeObserverWithHandle:(FIRStorageHandle)handle; + +/** + * Removes all observers for a single status. + * @param status A FIRStorageTaskStatus to remove listeners for. + */ +- (void)removeAllObserversForStatus:(FIRStorageTaskStatus)status; + +/** + * Removes all observers. + */ +- (void)removeAllObservers; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h new file mode 100644 index 0000000..84ad578 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h @@ -0,0 +1,315 @@ +/* + * 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 + +#import "FIRStorage.h" +#import "FIRStorageConstants.h" +#import "FIRStorageDownloadTask.h" +#import "FIRStorageListResult.h" +#import "FIRStorageMetadata.h" +#import "FIRStorageTask.h" +#import "FIRStorageUploadTask.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * FIRStorageReference represents a reference to a Google Cloud Storage object. Developers can + * upload and download objects, as well as get/set object metadata, and delete an object at the + * path. + * @see https://cloud.google.com/storage/ + */ +NS_SWIFT_NAME(StorageReference) +@interface FIRStorageReference : NSObject + +/** + * The FIRStorage service object which created this reference. + */ +@property(nonatomic, readonly) FIRStorage *storage; + +/** + * The name of the Google Cloud Storage bucket associated with this reference, + * in gs://bucket/path/to/object.txt, the bucket would be: 'bucket' + */ +@property(nonatomic, readonly) NSString *bucket; + +/** + * The full path to this object, not including the Google Cloud Storage bucket. + * In gs://bucket/path/to/object.txt, the full path would be: 'path/to/object.txt' + */ +@property(nonatomic, readonly) NSString *fullPath; + +/** + * The short name of the object associated with this reference, + * in gs://bucket/path/to/object.txt, the name of the object would be: 'object.txt' + */ +@property(nonatomic, readonly) NSString *name; + +#pragma mark - Path Operations + +/** + * Creates a new FIRStorageReference pointing to the root object. + * @return A new FIRStorageReference pointing to the root object. + */ +- (FIRStorageReference *)root; + +/** + * Creates a new FIRStorageReference pointing to the parent of the current reference + * or nil if this instance references the root location. + * For example: + * path = foo/bar/baz parent = foo/bar + * path = foo parent = (root) + * path = (root) parent = nil + * @return A new FIRStorageReference pointing to the parent of the current reference. + */ +- (nullable FIRStorageReference *)parent; + +/** + * Creates a new FIRStorageReference pointing to a child object of the current reference. + * path = foo child = bar newPath = foo/bar + * path = foo/bar child = baz newPath = foo/bar/baz + * All leading and trailing slashes will be removed, and consecutive slashes will be + * compressed to single slashes. For example: + * child = /foo/bar newPath = foo/bar + * child = foo/bar/ newPath = foo/bar + * child = foo///bar newPath = foo/bar + * @param path Path to append to the current path. + * @return A new FIRStorageReference pointing to a child location of the current reference. + */ +- (FIRStorageReference *)child:(NSString *)path; + +#pragma mark - Uploads + +/** + * Asynchronously uploads data to the currently specified FIRStorageReference, + * without additional metadata. + * This is not recommended for large files, and one should instead upload a file from disk. + * @param uploadData The NSData to upload. + * @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload. + */ +- (FIRStorageUploadTask *)putData:(NSData *)uploadData NS_SWIFT_NAME(putData(_:)); + +/** + * Asynchronously uploads data to the currently specified FIRStorageReference. + * This is not recommended for large files, and one should instead upload a file from disk. + * @param uploadData The NSData to upload. + * @param metadata FIRStorageMetadata containing additional information (MIME type, etc.) + * about the object being uploaded. + * @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload. + */ +// clang-format off +- (FIRStorageUploadTask *)putData:(NSData *)uploadData + metadata:(nullable FIRStorageMetadata *)metadata +NS_SWIFT_NAME(putData(_:metadata:)); +// clang-format on + +/** + * Asynchronously uploads data to the currently specified FIRStorageReference. + * This is not recommended for large files, and one should instead upload a file from disk. + * @param uploadData The NSData to upload. + * @param metadata FIRStorageMetadata containing additional information (MIME type, etc.) + * about the object being uploaded. + * @param completion A completion block that either returns the object metadata on success, + * or an error on failure. + * @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload. + */ +// clang-format off +- (FIRStorageUploadTask *)putData:(NSData *)uploadData + metadata:(nullable FIRStorageMetadata *)metadata + completion:(nullable void (^)(FIRStorageMetadata *_Nullable metadata, + NSError *_Nullable error))completion + NS_SWIFT_NAME(putData(_:metadata:completion:)); +// clang-format on + +/** + * Asynchronously uploads a file to the currently specified FIRStorageReference, + * without additional metadata. + * @param fileURL A URL representing the system file path of the object to be uploaded. + * @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload. + */ +- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL NS_SWIFT_NAME(putFile(from:)); + +/** + * Asynchronously uploads a file to the currently specified FIRStorageReference. + * @param fileURL A URL representing the system file path of the object to be uploaded. + * @param metadata FIRStorageMetadata containing additional information (MIME type, etc.) + * about the object being uploaded. + * @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload. + */ +// clang-format off +- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL + metadata:(nullable FIRStorageMetadata *)metadata + NS_SWIFT_NAME(putFile(from:metadata:)); +// clang-format on + +/** + * Asynchronously uploads a file to the currently specified FIRStorageReference. + * @param fileURL A URL representing the system file path of the object to be uploaded. + * @param metadata FIRStorageMetadata containing additional information (MIME type, etc.) + * about the object being uploaded. + * @param completion A completion block that either returns the object metadata on success, + * or an error on failure. + * @return An instance of FIRStorageUploadTask, which can be used to monitor or manage the upload. + */ +// clang-format off +- (FIRStorageUploadTask *)putFile:(NSURL *)fileURL + metadata:(nullable FIRStorageMetadata *)metadata + completion:(nullable void (^)(FIRStorageMetadata *_Nullable metadata, + NSError *_Nullable error))completion + NS_SWIFT_NAME(putFile(from:metadata:completion:)); +// clang-format on + +#pragma mark - Downloads + +/** + * Asynchronously downloads the object at the FIRStorageReference to an NSData object in memory. + * An NSData of the provided max size will be allocated, so ensure that the device has enough free + * memory to complete the download. For downloading large files, writeToFile may be a better option. + * @param size The maximum size in bytes to download. If the download exceeds this size, + * the task will be cancelled and an error will be returned. + * @param completion A completion block that either returns the object data on success, + * or an error on failure. + * @return An FIRStorageDownloadTask that can be used to monitor or manage the download. + */ +// clang-format off +- (FIRStorageDownloadTask *)dataWithMaxSize:(int64_t)size + completion:(void (^)(NSData *_Nullable data, + NSError *_Nullable error))completion + NS_SWIFT_NAME(getData(maxSize:completion:)); +// clang-format on + +/** + * Asynchronously retrieves a long lived download URL with a revokable token. + * This can be used to share the file with others, but can be revoked by a developer + * in the Firebase Console. + * @param completion A completion block that either returns the URL on success, + * or an error on failure. + */ +- (void)downloadURLWithCompletion:(void (^)(NSURL *_Nullable URL, + NSError *_Nullable error))completion; + +/** + * Asynchronously downloads the object at the current path to a specified system filepath. + * @param fileURL A file system URL representing the path the object should be downloaded to. + * @return An FIRStorageDownloadTask that can be used to monitor or manage the download. + */ +- (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL; + +/** + * Asynchronously downloads the object at the current path to a specified system filepath. + * @param fileURL A file system URL representing the path the object should be downloaded to. + * @param completion A completion block that fires when the file download completes. + * Returns an NSURL pointing to the file path of the downloaded file on success, + * or an error on failure. + * @return An FIRStorageDownloadTask that can be used to monitor or manage the download. + */ +- (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL + completion:(nullable void (^)(NSURL *_Nullable URL, + NSError *_Nullable error))completion; +#pragma mark - List Support + +/** + * List all items (files) and prefixes (folders) under this StorageReference. + * + * This is a helper method for calling list() repeatedly until there are no more results. + * Consistency of the result is not guaranteed if objects are inserted or removed while this + * operation is executing. All results are buffered in memory. + * + * `listAll(completion:)` is only available for projects using Firebase Rules Version 2. + * + * @param completion A completion handler that will be invoked with all items and prefixes under + * the current StorageReference. + */ +- (void)listAllWithCompletion:(void (^)(FIRStorageListResult *result, + NSError *_Nullable error))completion; + +/** + * List up to `maxResults` items (files) and prefixes (folders) under this StorageReference. + * + * "/" is treated as a path delimiter. Firebase Storage does not support unsupported object + * paths that end with "/" or contain two consecutive "/"s. All invalid objects in GCS will be + * filtered. + * + * `list(maxResults:completion:)` is only available for projects using Firebase Rules Version 2. + * + * @param maxResults The maximum number of results to return in a single page. Must be greater + * than 0 and at most 1000. + * @param completion A completion handler that will be invoked with up to maxResults items and + * prefixes under the current StorageReference. + */ +- (void)listWithMaxResults:(int64_t)maxResults + completion: + (void (^)(FIRStorageListResult *result, NSError *_Nullable error))completion + NS_SWIFT_NAME(list(maxResults:completion:)); + +/** + * Resumes a previous call to list(maxResults:completion:)`, starting after a pagination token. + * Returns the next set of items (files) and prefixes (folders) under this StorageReference. + * + * "/" is treated as a path delimiter. Firebase Storage does not support unsupported object + * paths that end with "/" or contain two consecutive "/"s. All invalid objects in GCS will be + * filtered. + * + * `list(maxResults:pageToken:completion:)`is only available for projects using Firebase Rules + * Version 2. + * + * @param maxResults The maximum number of results to return in a single page. Must be greater + * than 0 and at most 1000. + * @param pageToken A page token from a previous call to list. + * @param completion A completion handler that will be invoked with the next items and prefixes + * under the current StorageReference. + */ +- (void)listWithMaxResults:(int64_t)maxResults + pageToken:(NSString *)pageToken + completion: + (void (^)(FIRStorageListResult *result, NSError *_Nullable error))completion + NS_SWIFT_NAME(list(maxResults:pageToken:completion:)); + +#pragma mark - Metadata Operations + +/** + * Retrieves metadata associated with an object at the current path. + * @param completion A completion block which returns the object metadata on success, + * or an error on failure. + */ +- (void)metadataWithCompletion: + (void (^)(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error))completion + NS_SWIFT_NAME(getMetadata(completion:)); + +/** + * Updates the metadata associated with an object at the current path. + * @param metadata An FIRStorageMetadata object with the metadata to update. + * @param completion A completion block which returns the FIRStorageMetadata on success, + * or an error on failure. + */ +// clang-format off +- (void)updateMetadata:(FIRStorageMetadata *)metadata + completion:(nullable void (^)(FIRStorageMetadata *_Nullable metadata, + NSError *_Nullable error))completion +NS_SWIFT_NAME(updateMetadata(_:completion:)); +// clang-format on + +#pragma mark - Delete + +/** + * Deletes the object at the current path. + * @param completion A completion block which returns nil on success, or an error on failure. + */ +- (void)deleteWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h new file mode 100644 index 0000000..e889d5e --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h @@ -0,0 +1,75 @@ +/* + * 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 + +#import "FIRStorageConstants.h" +#import "FIRStorageMetadata.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * A superclass to all FIRStorage*Tasks, including FIRStorageUploadTask + * and FIRStorageDownloadTask, to provide state transitions, event raising, and common storage + * or metadata and errors. + * Callbacks are always fired on the developer specified callback queue. + * If no queue is specified by the developer, it defaults to the main queue. + * Currently not thread safe, so only call methods on the main thread. + */ +NS_SWIFT_NAME(StorageTask) +@interface FIRStorageTask : NSObject + +/** + * An immutable view of the task and associated metadata, progress, error, etc. + */ +@property(strong, readonly, nonatomic, nonnull) FIRStorageTaskSnapshot *snapshot; + +@end + +/** + * Defines task operations such as pause, resume, cancel, and enqueue for all tasks. + * All tasks are required to implement enqueue, which begins the task, and may optionally + * implement pause, resume, and cancel, which operate on the task to pause, resume, and cancel + * operations. + */ +NS_SWIFT_NAME(StorageTaskManagement) +@protocol FIRStorageTaskManagement + +@required +/** + * Prepares a task and begins execution. + */ +- (void)enqueue; + +@optional +/** + * Pauses a task currently in progress. + */ +- (void)pause; + +/** + * Cancels a task currently in progress. + */ +- (void)cancel; + +/** + * Resumes a task that is paused. + */ +- (void)resume; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h new file mode 100644 index 0000000..59ca4be --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h @@ -0,0 +1,67 @@ +/* + * 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 + +#import "FIRStorageConstants.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRStorageMetadata; +@class FIRStorageReference; +@class FIRStorageTask; + +/** + * FIRStorageTaskSnapshot represents an immutable view of a task. + * A Snapshot contains a task, storage reference, metadata (if it exists), + * progress, and an error (if one occurred). + */ +NS_SWIFT_NAME(StorageTaskSnapshot) +@interface FIRStorageTaskSnapshot : NSObject + +/** + * Subclass of FIRStorageTask this snapshot represents. + */ +@property(readonly, copy, nonatomic) __kindof FIRStorageTask *task; + +/** + * Metadata returned by the task, or nil if no metadata returned. + */ +@property(readonly, copy, nonatomic, nullable) FIRStorageMetadata *metadata; + +/** + * FIRStorageReference this task is operates on. + */ +@property(readonly, copy, nonatomic) FIRStorageReference *reference; + +/** + * NSProgress object which tracks the progress of an upload or download. + */ +@property(readonly, strong, nonatomic, nullable) NSProgress *progress; + +/** + * Error during task execution, or nil if no error occurred. + */ +@property(readonly, copy, nonatomic, nullable) NSError *error; + +/** + * Status of the task. + */ +@property(readonly, nonatomic) FIRStorageTaskStatus status; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageUploadTask.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageUploadTask.h new file mode 100644 index 0000000..c753500 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageUploadTask.h @@ -0,0 +1,38 @@ +/* + * 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 + +#import "FIRStorageObservableTask.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * FIRStorageUploadTask implements resumable uploads to a file in Firebase Storage. + * Uploads can be returned on completion with a completion callback, and can be monitored + * by attaching observers, or controlled by calling FIRStorageTask#pause, FIRStorageTask#resume, + * or FIRStorageTask#cancel. + * Uploads can take NSData in memory, or an NSURL to a file on disk. + * Uploads are performed on a background queue, and callbacks are raised on the developer + * specified callbackQueue in FIRStorage, or the main queue if left unspecified. + * Currently all uploads must be initiated and managed on the main queue. + */ +NS_SWIFT_NAME(StorageUploadTask) +@interface FIRStorageUploadTask : FIRStorageObservableTask + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FirebaseStorage.h b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FirebaseStorage.h new file mode 100644 index 0000000..be9ee24 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/FirebaseStorage/Sources/Public/FirebaseStorage/FirebaseStorage.h @@ -0,0 +1,26 @@ +/* + * 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 "FIRStorage.h" +#import "FIRStorageConstants.h" +#import "FIRStorageDownloadTask.h" +#import "FIRStorageListResult.h" +#import "FIRStorageMetadata.h" +#import "FIRStorageObservableTask.h" +#import "FIRStorageReference.h" +#import "FIRStorageTask.h" +#import "FIRStorageTaskSnapshot.h" +#import "FIRStorageUploadTask.h" diff --git a/saraWhatsUp/Pods/FirebaseStorage/Interop/Auth/Public/FIRAuthInterop.h b/saraWhatsUp/Pods/FirebaseStorage/Interop/Auth/Public/FIRAuthInterop.h new file mode 100644 index 0000000..a33da7c --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/Interop/Auth/Public/FIRAuthInterop.h @@ -0,0 +1,44 @@ +/* + * 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 FIRAuthInterop_h +#define FIRAuthInterop_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRTokenCallback + @brief The type of block which gets called when a token is ready. + */ +typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable error) + NS_SWIFT_NAME(TokenCallback); + +/// Common methods for Auth interoperability. +NS_SWIFT_NAME(AuthInterop) +@protocol FIRAuthInterop + +/// Retrieves the Firebase authentication token, possibly refreshing it if it has expired. +- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(FIRTokenCallback)callback; + +/// Get the current Auth user's UID. Returns nil if there is no user signed in. +- (nullable NSString *)getUserID; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRAuthInterop_h */ diff --git a/saraWhatsUp/Pods/FirebaseStorage/LICENSE b/saraWhatsUp/Pods/FirebaseStorage/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/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/saraWhatsUp/Pods/FirebaseStorage/README.md b/saraWhatsUp/Pods/FirebaseStorage/README.md new file mode 100644 index 0000000..7be298d --- /dev/null +++ b/saraWhatsUp/Pods/FirebaseStorage/README.md @@ -0,0 +1,319 @@ +[![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-appcheck-badge]][gh-actions] +[![Actions Status][gh-appdistribution-badge]][gh-actions] +[![Actions Status][gh-auth-badge]][gh-actions] +[![Actions Status][gh-cocoapods-integration-badge]][gh-actions] +[![Actions Status][gh-core-badge]][gh-actions] +[![Actions Status][gh-core-diagnostics-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-google-utilities-badge]][gh-actions] +[![Actions Status][gh-google-utilities-components-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-mlmodeldownloader-badge]][gh-actions] +[![Actions Status][gh-performance-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] + +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics +and FirebaseML. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. +1. [Standard pod install](README.md#standard-pod-install) +1. [Swift Package Manager](SwiftPackageManager.md) +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). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager.md](SwiftPackageManager.md). + +### Installing from GitHub + +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: +```ruby +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: + +```ruby +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). + +### 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 12.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +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 + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### 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/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@13 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. 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. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md). + +## 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 Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### 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. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduces official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on 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 watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are 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-appcheck-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/app_check/badge.svg +[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg +[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg +[gh-cocoapods-integration-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/cocoapods-integration/badge.svg +[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg +[gh-core-diagnostics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core-diagnostics/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-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg +[gh-google-utilities-components-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities-components/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-mlmodeldownloader-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/mlmodeldownloader/badge.svg +[gh-performance-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/performance/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 diff --git a/saraWhatsUp/Pods/GTMSessionFetcher/LICENSE b/saraWhatsUp/Pods/GTMSessionFetcher/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/saraWhatsUp/Pods/GTMSessionFetcher/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/saraWhatsUp/Pods/GTMSessionFetcher/README.md b/saraWhatsUp/Pods/GTMSessionFetcher/README.md new file mode 100644 index 0000000..ae8ff04 --- /dev/null +++ b/saraWhatsUp/Pods/GTMSessionFetcher/README.md @@ -0,0 +1,23 @@ +# Google Toolbox for Mac - Session Fetcher # + +**Project site**
+**Discussion group** + +[![Build Status](https://github.com/google/gtm-session-fetcher/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/google/gtm-session-fetcher/actions/workflows/main.yml) + +`GTMSessionFetcher` makes it easy for Cocoa applications to perform http +operations. The fetcher is implemented as a wrapper on `NSURLSession`, so its +behavior is asynchronous and uses operating-system settings on iOS and Mac OS X. + +Features include: +- Simple to build; only one source/header file pair is required +- Simple to use: takes just two lines of code to fetch a request +- Supports upload and download sessions +- Flexible cookie storage +- Automatic retry on errors, with exponential backoff +- Support for generating multipart MIME upload streams +- Easy, convenient logging of http requests and responses +- Supports plug-in authentication such as with GTMAppAuth +- Easily testable; self-mocking +- Automatic rate limiting when created by the `GTMSessionFetcherService` factory class +- Fully independent of other projects diff --git a/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h new file mode 100644 index 0000000..1dee658 --- /dev/null +++ b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h @@ -0,0 +1,1386 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// GTMSessionFetcher is a wrapper around NSURLSession for http operations. +// +// What does this offer on top of of NSURLSession? +// +// - Block-style callbacks for useful functionality like progress rather +// than delegate methods. +// - Out-of-process uploads and downloads using NSURLSession, including +// management of fetches after relaunch. +// - Integration with GTMAppAuth for invisible management and refresh of +// authorization tokens. +// - Pretty-printed http logging. +// - Cookies handling that does not interfere with or get interfered with +// by WebKit cookies or on Mac by Safari and other apps. +// - Credentials handling for the http operation. +// - Rate-limiting and cookie grouping when fetchers are created with +// GTMSessionFetcherService. +// +// If the bodyData or bodyFileURL property is set, then a POST request is assumed. +// +// Each fetcher is assumed to be for a one-shot fetch request; don't reuse the object +// for a second fetch. +// +// The fetcher will be self-retained as long as a connection is pending. +// +// To keep user activity private, URLs must have an https scheme (unless the property +// allowedInsecureSchemes is set to permit the scheme.) +// +// Callbacks will be released when the fetch completes or is stopped, so there is no need +// to use weak self references in the callback blocks. +// +// Sample usage: +// +// _fetcherService = [[GTMSessionFetcherService alloc] init]; +// +// GTMSessionFetcher *myFetcher = [_fetcherService fetcherWithURLString:myURLString]; +// myFetcher.retryEnabled = YES; +// myFetcher.comment = @"First profile image"; +// +// // Optionally specify a file URL or NSData for the request body to upload. +// myFetcher.bodyData = [postString dataUsingEncoding:NSUTF8StringEncoding]; +// +// [myFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { +// if (error != nil) { +// // Server status code or network error. +// // +// // If the domain is kGTMSessionFetcherStatusDomain then the error code +// // is a failure status from the server. +// } else { +// // Fetch succeeded. +// } +// }]; +// +// There is also a beginFetch call that takes a pointer and selector for the completion handler; +// a pointer and selector is a better style when the callback is a substantial, separate method. +// +// NOTE: Fetches may retrieve data from the server even though the server +// returned an error, so the criteria for success is a non-nil error. +// The completion handler is called when the server status is >= 300 with an NSError +// having domain kGTMSessionFetcherStatusDomain and code set to the server status. +// +// Status codes are at +// +// +// Background session support: +// +// Out-of-process uploads and downloads may be created by setting the fetcher's +// useBackgroundSession property. Data to be uploaded should be provided via +// the uploadFileURL property; the download destination should be specified with +// the destinationFileURL. NOTE: Background upload files should be in a location +// that will be valid even after the device is restarted, so the file should not +// be uploaded from a system temporary or cache directory. +// +// Background session transfers are slower, and should typically be used only +// for very large downloads or uploads (hundreds of megabytes). +// +// When background sessions are used in iOS apps, the application delegate must +// pass through the parameters from UIApplicationDelegate's +// application:handleEventsForBackgroundURLSession:completionHandler: to the +// fetcher class. +// +// When the application has been relaunched, it may also create a new fetcher +// instance to handle completion of the transfers. +// +// - (void)application:(UIApplication *)application +// handleEventsForBackgroundURLSession:(NSString *)identifier +// completionHandler:(void (^)())completionHandler { +// // Application was re-launched on completing an out-of-process download. +// +// // Pass the URLSession info related to this re-launch to the fetcher class. +// [GTMSessionFetcher application:application +// handleEventsForBackgroundURLSession:identifier +// completionHandler:completionHandler]; +// +// // Get a fetcher related to this re-launch and re-hook up a completionHandler to it. +// GTMSessionFetcher *fetcher = [GTMSessionFetcher fetcherWithSessionIdentifier:identifier]; +// NSURL *destinationFileURL = fetcher.destinationFileURL; +// fetcher.completionHandler = ^(NSData *data, NSError *error) { +// [self downloadCompletedToFile:destinationFileURL error:error]; +// }; +// } +// +// +// Threading and queue support: +// +// Networking always happens on a background thread; there is no advantage to +// changing thread or queue to create or start a fetcher. +// +// Callbacks are run on the main thread; alternatively, the app may set the +// fetcher's callbackQueue to a dispatch queue. +// +// Once the fetcher's beginFetch method has been called, the fetcher's methods and +// properties may be accessed from any thread. +// +// Downloading to disk: +// +// To have downloaded data saved directly to disk, specify a file URL for the +// destinationFileURL property. +// +// HTTP methods and headers: +// +// Alternative HTTP methods, like PUT, and custom headers can be specified by +// creating the fetcher with an appropriate NSMutableURLRequest. +// +// Custom headers can also be provided per-request via an instance of `GTMFetcherDecoratorProtocol` +// passed to `-[GTMSessionFetcherService addDecorator:]`. +// +// Caching: +// +// The fetcher avoids caching. That is best for API requests, but may hurt +// repeat fetches of static data. Apps may enable a persistent disk cache by +// customizing the config: +// +// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher, +// NSURLSessionConfiguration *config) { +// config.URLCache = [NSURLCache sharedURLCache]; +// }; +// +// Or use the standard system config to share cookie storage with web views +// and to enable disk caching: +// +// fetcher.configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; +// +// +// Cookies: +// +// There are three supported mechanisms for remembering cookies between fetches. +// +// By default, a standalone GTMSessionFetcher uses a mutable array held +// statically to track cookies for all instantiated fetchers. This avoids +// cookies being set by servers for the application from interfering with +// Safari and WebKit cookie settings, and vice versa. +// The fetcher cookies are lost when the application quits. +// +// To rely instead on WebKit's global NSHTTPCookieStorage, set the fetcher's +// cookieStorage property: +// myFetcher.cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; +// +// To share cookies with other apps, use the method introduced in iOS 9/OS X 10.11: +// myFetcher.cookieStorage = +// [NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:kMyCompanyContainedID]; +// +// To ignore existing cookies and only have cookies related to the single fetch +// be applied, make a temporary cookie storage object: +// myFetcher.cookieStorage = [[GTMSessionCookieStorage alloc] init]; +// +// Note: cookies set while following redirects will be sent to the server, as +// the redirects are followed by the fetcher. +// +// To completely disable cookies, adjust the session configuration appropriately +// in the fetcher or fetcher service: +// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher, +// NSURLSessionConfiguration *config) { +// config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever; +// config.HTTPShouldSetCookies = NO; +// }; +// +// If the fetcher is created from a GTMSessionFetcherService object +// then the cookie storage mechanism is set to use the cookie storage in the +// service object rather than the static storage. Disabling cookies in the +// session configuration set on a service object will disable cookies for all +// fetchers created from that GTMSessionFetcherService object, since the session +// configuration is propagated to the fetcher. +// +// +// Monitoring data transfers. +// +// The fetcher supports a variety of properties for progress monitoring +// progress with callback blocks. +// GTMSessionFetcherSendProgressBlock sendProgressBlock +// GTMSessionFetcherReceivedProgressBlock receivedProgressBlock +// GTMSessionFetcherDownloadProgressBlock downloadProgressBlock +// +// If supplied by the server, the anticipated total download size is available +// as [[myFetcher response] expectedContentLength] (and may be -1 for unknown +// download sizes.) +// +// +// Automatic retrying of fetches +// +// The fetcher can optionally create a timer and reattempt certain kinds of +// fetch failures (status codes 408, request timeout; 502, gateway failure; +// 503, service unavailable; 504, gateway timeout; networking errors +// NSURLErrorTimedOut and NSURLErrorNetworkConnectionLost.) The user may +// set a retry selector to customize the type of errors which will be retried. +// +// Retries are done in an exponential-backoff fashion (that is, after 1 second, +// 2, 4, 8, and so on.) +// +// Enabling automatic retries looks like this: +// myFetcher.retryEnabled = YES; +// +// With retries enabled, the completion callbacks are called only +// when no more retries will be attempted. Calling the fetcher's stopFetching +// method will terminate the retry timer, without the finished or failure +// selectors being invoked. +// +// Optionally, the client may set the maximum retry interval: +// myFetcher.maxRetryInterval = 60.0; // in seconds; default is 60 seconds +// // for downloads, 600 for uploads +// +// Servers should never send a 400 or 500 status for errors that are retryable +// by clients, as those values indicate permanent failures. In nearly all +// cases, the default standard retry behavior is correct for clients, and no +// custom client retry behavior is needed or appropriate. Servers that send +// non-retryable status codes and expect the client to retry the request are +// faulty. +// +// Still, the client may provide a block to determine if a status code or other +// error should be retried. The block returns YES to set the retry timer or NO +// to fail without additional fetch attempts. +// +// The retry method may return the |suggestedWillRetry| argument to get the +// default retry behavior. Server status codes are present in the +// error argument, and have the domain kGTMSessionFetcherStatusDomain. The +// user's method may look something like this: +// +// myFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *error, +// GTMSessionFetcherRetryResponse response) { +// // Perhaps examine error.domain and error.code, or fetcher.retryCount +// // +// // Respond with YES to start the retry timer, NO to proceed to the failure +// // callback, or suggestedWillRetry to get default behavior for the +// // current error domain and code values. +// response(suggestedWillRetry); +// }; + +#import + +#if TARGET_OS_IPHONE +#import +#endif +#if TARGET_OS_WATCH +#import +#endif + +// By default it is stripped from non DEBUG builds. Developers can override +// this in their project settings. +#ifndef STRIP_GTM_FETCH_LOGGING +#if !DEBUG +#define STRIP_GTM_FETCH_LOGGING 1 +#else +#define STRIP_GTM_FETCH_LOGGING 0 +#endif +#endif + +// Logs in debug builds. +#ifndef GTMSESSION_LOG_DEBUG +#if DEBUG +#define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__) +#else +#define GTMSESSION_LOG_DEBUG(...) \ + do { \ + } while (0) +#endif +#endif + +// Asserts in debug builds (or logs in debug builds if GTMSESSION_ASSERT_AS_LOG +// or NS_BLOCK_ASSERTIONS are defined.) +#ifndef GTMSESSION_ASSERT_DEBUG +#if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG +#undef GTMSESSION_ASSERT_AS_LOG +#define GTMSESSION_ASSERT_AS_LOG 1 +#endif + +#if DEBUG && !GTMSESSION_ASSERT_AS_LOG +#define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__) +#elif DEBUG +#define GTMSESSION_ASSERT_DEBUG(pred, ...) \ + if (!(pred)) { \ + NSLog(__VA_ARGS__); \ + } +#else +#define GTMSESSION_ASSERT_DEBUG(pred, ...) \ + do { \ + } while (0) +#endif +#endif + +// Asserts in debug builds, logs in release builds (or logs in debug builds if +// GTMSESSION_ASSERT_AS_LOG is defined.) +#ifndef GTMSESSION_ASSERT_DEBUG_OR_LOG +#if DEBUG && !GTMSESSION_ASSERT_AS_LOG +#define GTMSESSION_ASSERT_DEBUG_OR_LOG(...) NSAssert(__VA_ARGS__) +#else +#define GTMSESSION_ASSERT_DEBUG_OR_LOG(pred, ...) \ + if (!(pred)) { \ + NSLog(__VA_ARGS__); \ + } +#endif +#endif + +// Macro useful for examining messages from NSURLSession during debugging. +#if 0 +#define GTM_LOG_SESSION_DELEGATE(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__) +#else +#define GTM_LOG_SESSION_DELEGATE(...) +#endif + +// These will be removed in the near future, folks should move off of them. +#ifndef GTM_NULLABLE +#if __has_feature(nullability) // Available starting in Xcode 6.3 +#define GTM_NULLABLE_TYPE __nullable +#define GTM_NONNULL_TYPE __nonnull +#define GTM_NULLABLE nullable +#define GTM_NONNULL_DECL nonnull // GTM_NONNULL is used by GTMDefines.h +#define GTM_NULL_RESETTABLE null_resettable +#define GTM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN +#define GTM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END +#else +#define GTM_NULLABLE_TYPE +#define GTM_NONNULL_TYPE +#define GTM_NULLABLE +#define GTM_NONNULL_DECL +#define GTM_NULL_RESETTABLE +#define GTM_ASSUME_NONNULL_BEGIN +#define GTM_ASSUME_NONNULL_END +#endif // __has_feature(nullability) +#endif // GTM_NULLABLE +#ifndef GTM_DECLARE_GENERICS +#if __has_feature(objc_generics) +#define GTM_DECLARE_GENERICS 1 +#else +#define GTM_DECLARE_GENERICS 0 +#endif +#endif +#ifndef GTM_NSArrayOf +#if GTM_DECLARE_GENERICS +#define GTM_NSArrayOf(value) NSArray +#define GTM_NSDictionaryOf(key, value) NSDictionary +#else +#define GTM_NSArrayOf(value) NSArray +#define GTM_NSDictionaryOf(key, value) NSDictionary +#endif // __has_feature(objc_generics) +#endif // GTM_NSArrayOf + +// For iOS, the fetcher can declare itself a background task to allow fetches +// to finish when the app leaves the foreground. +// +// (This is unrelated to providing a background configuration, which allows +// out-of-process uploads and downloads.) +// +// To disallow use of background tasks during fetches, the target should define +// GTM_BACKGROUND_TASK_FETCHING to 0, or alternatively may set the +// skipBackgroundTask property to YES. +#if !defined(GTM_BACKGROUND_TASK_FETCHING) && \ + (TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST) +#define GTM_BACKGROUND_TASK_FETCHING 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(GTMBridgeFetcher) +// The bridge macros are deprecated, and should be replaced; GTMHTTPFetcher is no longer +// supported and all code should switch to use GTMSessionFetcher types directly. +#define GTMBridgeFetcher GTMSessionFetcher +#define GTMBridgeFetcherService GTMSessionFetcherService +#define GTMBridgeFetcherServiceProtocol GTMSessionFetcherServiceProtocol +#define GTMBridgeAssertValidSelector GTMSessionFetcherAssertValidSelector +#define GTMBridgeCookieStorage GTMSessionCookieStorage +#define GTMBridgeCleanedUserAgentString GTMFetcherCleanedUserAgentString +#define GTMBridgeSystemVersionString GTMFetcherSystemVersionString +#define GTMBridgeApplicationIdentifier GTMFetcherApplicationIdentifier +#define kGTMBridgeFetcherStatusDomain kGTMSessionFetcherStatusDomain +#define kGTMBridgeFetcherStatusBadRequest GTMSessionFetcherStatusBadRequest +#endif + +// When creating background sessions to perform out-of-process uploads and +// downloads, on app launch any background sessions must be reconnected in +// order to receive events that occurred while the app was not running. +// +// The fetcher will automatically attempt to recreate the sessions on app +// start, but doing so reads from NSUserDefaults. This may have launch-time +// performance impacts. +// +// To avoid launch performance impacts, on iPhone/iPad with iOS 13+ the +// GTMSessionFetcher class will register for the app launch notification and +// perform the reconnect then. +// +// Apps targeting Mac or older iOS SDKs can opt into the new behavior by defining +// GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH=1. +// +// Apps targeting new SDKs can force the old behavior by defining +// GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH = 0. +#ifndef GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH +// Default to the on-launch behavior for iOS 13+. +#if TARGET_OS_IOS && defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 +#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 1 +#else +#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 0 +#endif +#endif + +NS_ASSUME_NONNULL_BEGIN + +// Notifications +// +// Fetch started and stopped, and fetch retry delay started and stopped. +extern NSString *const kGTMSessionFetcherStartedNotification; +extern NSString *const kGTMSessionFetcherStoppedNotification; +extern NSString *const kGTMSessionFetcherRetryDelayStartedNotification; +extern NSString *const kGTMSessionFetcherRetryDelayStoppedNotification; + +// Completion handler notification. This is intended for use by code capturing +// and replaying fetch requests and results for testing. For fetches where +// destinationFileURL or accumulateDataBlock is set for the fetcher, the data +// will be nil for successful fetches. +// +// This notification is posted on the main thread. +extern NSString *const kGTMSessionFetcherCompletionInvokedNotification; +extern NSString *const kGTMSessionFetcherCompletionDataKey; +extern NSString *const kGTMSessionFetcherCompletionErrorKey; + +// Constants for NSErrors created by the fetcher (excluding server status errors, +// and error objects originating in the OS.) +extern NSString *const kGTMSessionFetcherErrorDomain; + +// The fetcher turns server error status values (3XX, 4XX, 5XX) into NSErrors +// with domain kGTMSessionFetcherStatusDomain. +// +// Any server response body data accompanying the status error is added to the +// userInfo dictionary with key kGTMSessionFetcherStatusDataKey. +extern NSString *const kGTMSessionFetcherStatusDomain; +extern NSString *const kGTMSessionFetcherStatusDataKey; +extern NSString *const kGTMSessionFetcherStatusDataContentTypeKey; + +// When a fetch fails with an error, these keys are included in the error userInfo +// dictionary if retries were attempted. +extern NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey; +extern NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey; + +// Background session support requires access to NSUserDefaults. +// If [NSUserDefaults standardUserDefaults] doesn't yield the correct NSUserDefaults for your usage, +// ie for an App Extension, then implement this class/method to return the correct NSUserDefaults. +// https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW6 +@interface GTMSessionFetcherUserDefaultsFactory : NSObject + ++ (NSUserDefaults *)fetcherUserDefaults; + +@end + +#ifdef __cplusplus +} +#endif + +typedef NS_ENUM(NSInteger, GTMSessionFetcherError) { + GTMSessionFetcherErrorDownloadFailed = -1, + GTMSessionFetcherErrorUploadChunkUnavailable = -2, + GTMSessionFetcherErrorBackgroundExpiration = -3, + GTMSessionFetcherErrorBackgroundFetchFailed = -4, + GTMSessionFetcherErrorInsecureRequest = -5, + GTMSessionFetcherErrorTaskCreationFailed = -6, +}; + +typedef NS_ENUM(NSInteger, GTMSessionFetcherStatus) { + // Standard http status codes. + GTMSessionFetcherStatusNotModified = 304, + GTMSessionFetcherStatusBadRequest = 400, + GTMSessionFetcherStatusUnauthorized = 401, + GTMSessionFetcherStatusForbidden = 403, + GTMSessionFetcherStatusPreconditionFailed = 412 +}; + +#ifdef __cplusplus +extern "C" { +#endif + +@class GTMSessionCookieStorage; +@class GTMSessionFetcher; + +// The configuration block is for modifying the NSURLSessionConfiguration only. +// DO NOT change any fetcher properties in the configuration block. +typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher, + NSURLSessionConfiguration *configuration); +typedef void (^GTMSessionFetcherSystemCompletionHandler)(void); +typedef void (^GTMSessionFetcherCompletionHandler)(NSData *_Nullable data, + NSError *_Nullable error); +typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream); +typedef void (^GTMSessionFetcherBodyStreamProvider)( + GTMSessionFetcherBodyStreamProviderResponse response); +typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)( + NSURLSessionResponseDisposition disposition); +typedef void (^GTMSessionFetcherDidReceiveResponseBlock)( + NSURLResponse *response, GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock); +typedef void (^GTMSessionFetcherChallengeDispositionBlock)( + NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *_Nullable credential); +typedef void (^GTMSessionFetcherChallengeBlock)( + GTMSessionFetcher *fetcher, NSURLAuthenticationChallenge *challenge, + GTMSessionFetcherChallengeDispositionBlock dispositionBlock); +typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest *_Nullable redirectedRequest); +typedef void (^GTMSessionFetcherWillRedirectBlock)(NSHTTPURLResponse *redirectResponse, + NSURLRequest *redirectRequest, + GTMSessionFetcherWillRedirectResponse response); +typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData *_Nullable buffer); +typedef void (^GTMSessionFetcherSimulateByteTransferBlock)(NSData *_Nullable buffer, + int64_t bytesWritten, + int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite); +typedef void (^GTMSessionFetcherReceivedProgressBlock)(int64_t bytesWritten, + int64_t totalBytesWritten); +typedef void (^GTMSessionFetcherDownloadProgressBlock)(int64_t bytesWritten, + int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite); +typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent, int64_t totalBytesSent, + int64_t totalBytesExpectedToSend); +typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)( + NSCachedURLResponse *_Nullable cachedResponse); +typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)( + NSCachedURLResponse *proposedResponse, + GTMSessionFetcherWillCacheURLResponseResponse responseBlock); +typedef void (^GTMSessionFetcherRetryResponse)(BOOL shouldRetry); +typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry, NSError *_Nullable error, + GTMSessionFetcherRetryResponse response); + +API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)) +typedef void (^GTMSessionFetcherMetricsCollectionBlock)(NSURLSessionTaskMetrics *metrics); + +typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse *_Nullable response, + NSData *_Nullable data, NSError *_Nullable error); +typedef void (^GTMSessionFetcherTestBlock)(GTMSessionFetcher *fetcherToTest, + GTMSessionFetcherTestResponse testResponse); + +void GTMSessionFetcherAssertValidSelector(id _Nullable obj, SEL _Nullable sel, ...); + +// Utility functions for applications self-identifying to servers via a +// user-agent header + +// The "standard" user agent includes the application identifier, taken from the bundle, +// followed by a space and the system version string. Pass nil to use +mainBundle as the source +// of the bundle identifier. +// +// Applications may use this as a starting point for their own user agent strings, perhaps +// with additional sections appended. Use GTMFetcherCleanedUserAgentString() below to +// clean up any string being added to the user agent. +NSString *GTMFetcherStandardUserAgentString(NSBundle *_Nullable bundle); + +// Make a generic name and version for the current application, like +// com.example.MyApp/1.2.3 relying on the bundle identifier and the +// CFBundleShortVersionString or CFBundleVersion. +// +// The bundle ID may be overridden as the base identifier string by +// adding to the bundle's Info.plist a "GTMUserAgentID" key. +// +// The application version may be overridden by adding to the bundle's +// Info.plist a "GTMUserAgentVersion" key. +// +// If no bundle ID or override is available, the process name preceded +// by "proc_" is used. +NSString *GTMFetcherApplicationIdentifier(NSBundle *_Nullable bundle); + +// Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1 hw/iPod1_1" +NSString *GTMFetcherSystemVersionString(void); + +// Make a parseable user-agent identifier from the given string, replacing whitespace +// and commas with underscores, and removing other characters that may interfere +// with parsing of the full user-agent string. +// +// For example, @"[My App]" would become @"My_App" +NSString *GTMFetcherCleanedUserAgentString(NSString *str); + +// Grab the data from an input stream. Since streams cannot be assumed to be rewindable, +// this may be destructive; the caller can try to rewind the stream (by setting the +// NSStreamFileCurrentOffsetKey property) or can just use the NSData to make a new +// NSInputStream. This function is intended to facilitate testing rather than be used in +// production. +// +// This function operates synchronously on the current thread. Depending on how the +// input stream is implemented, it may be appropriate to dispatch to a different +// queue before calling this function. +// +// Failure is indicated by a returned data value of nil. +NSData *_Nullable GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError); + +#ifdef __cplusplus +} // extern "C" +#endif + +// Completion handler passed to -[GTMFetcherDecoratorProtocol fetcherWillStart:completionHandler:]. +typedef void (^GTMFetcherDecoratorFetcherWillStartCompletionHandler)(NSURLRequest *_Nullable, + NSError *_Nullable); + +// Allows intercepting a request and optionally modifying it before the request (or a retry) +// is sent. See `-[GTMSessionFetcherService addDecorator:]` and `-[GTMSessionFetcherService +// removeDecorator:]`. +// +// Decorator methods must be thread-safe, as they might be invoked on any queue. +@protocol GTMFetcherDecoratorProtocol + +// Invoked just before a fetcher's request starts. +// +// After the decorator's work is complete, the decorator must invoke `handler(request, error)` +// either synchronously or asynchronously (on any queue). +// +// If no changes are to be made, pass `nil` for both `request` and `error`. +// +// Otherwise, if `error` is non-nil, then the fetcher is stopped with the given error, and any +// further decorators' `-fetcherWillStart:completionHandler:` methods are not invoked. +// +// Otherwise, the decorator may use `[fetcher.request mutableCopy]`, make changes to the mutable +// copy of the request, and pass the result to the handler via the `request` parameter. +// +// To distinguish the initial fetch from retries, the decorator can look at `fetcher.retryCount`. +// +// This method must not block the caller (e.g., performing synchronous I/O). Perform any blocking +// work or I/O on a different queue, then invoke `handler` with the results after the blocking work +// completes. +- (void)fetcherWillStart:(GTMSessionFetcher *)fetcher + completionHandler:(GTMFetcherDecoratorFetcherWillStartCompletionHandler)handler; + +// Invoked just after a fetcher's request finishes (either on success or on failure). +// +// After the decorator's work is complete, the decorator must invoke `handler()` either +// synchronously or asynchronously (on any queue). +// +// To access the result of the fetch, the decorator can look at `fetcher.response`. +// +// This method must not block the caller (e.g., performing synchronous I/O). Perform any blocking +// work or I/O on a different queue, then invoke `handler` with the results after the blocking work +// completes. +- (void)fetcherDidFinish:(GTMSessionFetcher *)fetcher + withData:(nullable NSData *)data + error:(nullable NSError *)error + completionHandler:(void (^)(void))handler; + +@end + +// This protocol allows abstract references to the fetcher service, primarily for +// fetchers (which may be compiled without the fetcher service class present.) +// +// Apps should not need to use this protocol. +@protocol GTMSessionFetcherServiceProtocol +// This protocol allows us to call into the service without requiring +// GTMSessionFetcherService sources in this project + +@property(atomic, strong) dispatch_queue_t callbackQueue; + +- (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher; +- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher; + +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request; +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher; + +@property(atomic, assign) BOOL reuseSession; +- (nullable NSURLSession *)session; +- (nullable NSURLSession *)sessionForFetcherCreation; +- (nullable id)sessionDelegate; +- (nullable NSDate *)stoppedAllFetchersDate; + +@property(atomic, readonly, strong, nullable) NSOperationQueue *delegateQueue; + +@optional +// This property is optional, for now, to enable releasing the feature without breaking existing +// code that fakes the service but doesn't implement this. +@property(atomic, readonly, strong, nullable) NSArray> *decorators; + +@end // @protocol GTMSessionFetcherServiceProtocol + +#ifndef GTM_FETCHER_AUTHORIZATION_PROTOCOL +#define GTM_FETCHER_AUTHORIZATION_PROTOCOL 1 +@protocol GTMFetcherAuthorizationProtocol +@required +// This protocol allows us to call the authorizer without requiring its sources +// in this project. +- (void)authorizeRequest:(nullable NSMutableURLRequest *)request + delegate:(id)delegate + didFinishSelector:(SEL)sel; + +- (void)stopAuthorization; + +- (void)stopAuthorizationForRequest:(NSURLRequest *)request; + +- (BOOL)isAuthorizingRequest:(NSURLRequest *)request; + +- (BOOL)isAuthorizedRequest:(NSURLRequest *)request; + +@property(atomic, strong, readonly, nullable) NSString *userEmail; + +@optional + +// Indicate if authorization may be attempted. Even if this succeeds, +// authorization may fail if the user's permissions have been revoked. +@property(atomic, readonly) BOOL canAuthorize; + +// For development only, allow authorization of non-SSL requests, allowing +// transmission of the bearer token unencrypted. +@property(atomic, assign) BOOL shouldAuthorizeAllRequests; + +- (void)authorizeRequest:(nullable NSMutableURLRequest *)request + completionHandler:(void (^)(NSError *_Nullable error))handler; + +@property(atomic, weak, nullable) id fetcherService; + +- (BOOL)primeForRefresh; + +@end +#endif // GTM_FETCHER_AUTHORIZATION_PROTOCOL + +#if GTM_BACKGROUND_TASK_FETCHING +// A protocol for an alternative target for messages from GTMSessionFetcher to UIApplication. +// Set the target using +[GTMSessionFetcher setSubstituteUIApplication:] +@protocol GTMUIApplicationProtocol +- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName + expirationHandler:(void (^__nullable)(void))handler; +- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier; +@end +#endif + +#pragma mark - + +// GTMSessionFetcher objects are used for async retrieval of an http get or post +// +// See additional comments at the beginning of this file +@interface GTMSessionFetcher : NSObject + +// Create a fetcher +// +// fetcherWithRequest will return an autoreleased fetcher, but if +// the connection is successfully created, the connection should retain the +// fetcher for the life of the connection as well. So the caller doesn't have +// to retain the fetcher explicitly unless they want to be able to cancel it. ++ (instancetype)fetcherWithRequest:(nullable NSURLRequest *)request; + +// Convenience methods that make a request, like +fetcherWithRequest ++ (instancetype)fetcherWithURL:(NSURL *)requestURL; ++ (instancetype)fetcherWithURLString:(NSString *)requestURLString; + +// Methods for creating fetchers to continue previous fetches. ++ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData; ++ (nullable instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier; + +// Returns an array of currently active fetchers for background sessions, +// both restarted and newly created ones. ++ (NSArray *)fetchersForBackgroundSessions; + +// Designated initializer. +// +// Applications should create fetchers with a "fetcherWith..." method on a fetcher +// service or a class method, not with this initializer. +// +// The configuration should typically be nil. Applications needing to customize +// the configuration may do so by setting the configurationBlock property. +- (instancetype)initWithRequest:(nullable NSURLRequest *)request + configuration:(nullable NSURLSessionConfiguration *)configuration; + +// The fetcher's request. This may not be set after beginFetch has been invoked. The request +// may change due to redirects. +@property(atomic, strong, nullable) NSURLRequest *request; + +// Set a header field value on the request. Header field value changes will not +// affect a fetch after the fetch has begun. +- (void)setRequestValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field; + +// Data used for resuming a download task. +@property(atomic, readonly, nullable) NSData *downloadResumeData; + +// The configuration; this must be set before the fetch begins. If no configuration is +// set or inherited from the fetcher service, then the fetcher uses an ephemeral config. +// +// NOTE: This property should typically be nil. Applications needing to customize +// the configuration should do so by setting the configurationBlock property. +// That allows the fetcher to pick an appropriate base configuration, with the +// application setting only the configuration properties it needs to customize. +@property(atomic, strong, nullable) NSURLSessionConfiguration *configuration; + +// A block the client may use to customize the configuration used to create the session. +// +// This is called synchronously, either on the thread that begins the fetch or, during a retry, +// on the main thread. The configuration block may be called repeatedly if multiple fetchers are +// created. +// +// The configuration block is for modifying the NSURLSessionConfiguration only. +// DO NOT change any fetcher properties in the configuration block. Fetcher properties +// may be set in the fetcher service prior to fetcher creation, or on the fetcher prior +// to invoking beginFetch. +@property(atomic, copy, nullable) GTMSessionFetcherConfigurationBlock configurationBlock; + +// A session is created as needed by the fetcher. A fetcher service object +// may maintain sessions for multiple fetches to the same host. +@property(atomic, strong, nullable) NSURLSession *session; + +// The task in flight. +@property(atomic, readonly, nullable) NSURLSessionTask *sessionTask; + +// The background session identifier. +@property(atomic, readonly, nullable) NSString *sessionIdentifier; + +// Indicates a fetcher created to finish a background session task. +@property(atomic, readonly) BOOL wasCreatedFromBackgroundSession; + +// Indicates the client has committed to reconnecting this background session when +// the app restarts. If this value is YES, the session fetcher will not automatically +// call beginFetchWithCompletionHandler: on the restored fetcher on app start, and +// the session will not handle system events until the client explicitly does. +@property(atomic, assign) BOOL clientWillReconnectBackgroundSession; + +// Additional user-supplied data to encode into the session identifier. Since session identifier +// length limits are unspecified, this should be kept small. Key names beginning with an underscore +// are reserved for use by the fetcher. +@property(atomic, strong, nullable) NSDictionary *sessionUserInfo; + +// The human-readable description to be assigned to the task. +@property(atomic, copy, nullable) NSString *taskDescription; + +// The priority assigned to the task, if any. Use NSURLSessionTaskPriorityLow, +// NSURLSessionTaskPriorityDefault, or NSURLSessionTaskPriorityHigh. +@property(atomic, assign) float taskPriority; + +// The fetcher encodes information used to resume a session in the session identifier. +// This method, intended for internal use returns the encoded information. The sessionUserInfo +// dictionary is stored as identifier metadata. +- (nullable NSDictionary *)sessionIdentifierMetadata; + +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH +// The app should pass to this method the completion handler passed in the app delegate method +// application:handleEventsForBackgroundURLSession:completionHandler: ++ (void)application:(UIApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler; +#endif + +// Indicate that a newly created session should be a background session. +// A new session identifier will be created by the fetcher. +// +// Warning: The only thing background sessions are for is rare download +// of huge, batched files of data. And even just for those, there's a lot +// of pain and hackery needed to get transfers to actually happen reliably +// with background sessions. +// +// Don't try to upload or download in many background sessions, since the system +// will impose an exponentially increasing time penalty to prevent the app from +// getting too much background execution time. +// +// References: +// +// "Moving to Fewer, Larger Transfers" +// https://forums.developer.apple.com/thread/14853 +// +// "NSURLSession’s Resume Rate Limiter" +// https://forums.developer.apple.com/thread/14854 +// +// "Background Session Task state persistence" +// https://forums.developer.apple.com/thread/11554 +// +@property(atomic, assign) BOOL useBackgroundSession; + +// Indicates if the fetcher was started using a background session. +@property(atomic, readonly, getter=isUsingBackgroundSession) BOOL usingBackgroundSession; + +// Indicates if uploads should use an upload task. This is always set for file or stream-provider +// bodies, but may be set explicitly for NSData bodies. +@property(atomic, assign) BOOL useUploadTask; + +// Indicates that the fetcher is using a session that may be shared with other fetchers. +@property(atomic, readonly) BOOL canShareSession; + +// By default, the fetcher allows only secure (https) schemes unless this +// property is set, or the GTM_ALLOW_INSECURE_REQUESTS build flag is set. +// +// For example, during debugging when fetching from a development server that lacks SSL support, +// this may be set to @[ @"http" ], or when the fetcher is used to retrieve local files, +// this may be set to @[ @"file" ]. +// +// This should be left as nil for release builds to avoid creating the opportunity for +// leaking private user behavior and data. If a server is providing insecure URLs +// for fetching by the client app, report the problem as server security & privacy bug. +// +// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when +// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist. +@property(atomic, copy, nullable) NSArray *allowedInsecureSchemes; + +// By default, the fetcher prohibits localhost requests unless this property is set, +// or the GTM_ALLOW_INSECURE_REQUESTS build flag is set. +// +// For localhost requests, the URL scheme is not checked when this property is set. +// +// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when +// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist. +@property(atomic, assign) BOOL allowLocalhostRequest; + +// By default, the fetcher requires valid server certs. This may be bypassed +// temporarily for development against a test server with an invalid cert. +@property(atomic, assign) BOOL allowInvalidServerCertificates; + +// Cookie storage object for this fetcher. If nil, the fetcher will use a static cookie +// storage instance shared among fetchers. If this fetcher was created by a fetcher service +// object, it will be set to use the service object's cookie storage. See Cookies section above for +// the full discussion. +// +// Because as of Jan 2014 standalone instances of NSHTTPCookieStorage do not actually +// store any cookies (Radar 15735276) we use our own subclass, GTMSessionCookieStorage, +// to hold cookies in memory. +@property(atomic, strong, nullable) NSHTTPCookieStorage *cookieStorage; + +// Setting the credential is optional; it is used if the connection receives +// an authentication challenge. +@property(atomic, strong, nullable) NSURLCredential *credential; + +// Setting the proxy credential is optional; it is used if the connection +// receives an authentication challenge from a proxy. +@property(atomic, strong, nullable) NSURLCredential *proxyCredential; + +// If body data, body file URL, or body stream provider is not set, then a GET request +// method is assumed. +@property(atomic, strong, nullable) NSData *bodyData; + +// File to use as the request body. This forces use of an upload task. +@property(atomic, strong, nullable) NSURL *bodyFileURL; + +// Length of body to send, expected or actual. +@property(atomic, readonly) int64_t bodyLength; + +// The body stream provider may be called repeatedly to provide a body. +// Setting a body stream provider forces use of an upload task. +@property(atomic, copy, nullable) GTMSessionFetcherBodyStreamProvider bodyStreamProvider; + +// Object to add authorization to the request, if needed. +// +// This may not be changed once beginFetch has been invoked. +@property(atomic, strong, nullable) id authorizer; + +// The service object that created and monitors this fetcher, if any. +@property(atomic, strong) id service; + +// The host, if any, used to classify this fetcher in the fetcher service. +@property(atomic, copy, nullable) NSString *serviceHost; + +// The priority, if any, used for starting fetchers in the fetcher service. +// +// Lower values are higher priority; the default is 0, and values may +// be negative or positive. This priority affects only the start order of +// fetchers that are being delayed by a fetcher service when the running fetchers +// exceeds the service's maxRunningFetchersPerHost. A priority of NSIntegerMin will +// exempt this fetcher from delay. +@property(atomic, assign) NSInteger servicePriority; + +// The delegate's optional didReceiveResponse block may be used to inspect or alter +// the session task response. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock; + +// The delegate's optional challenge block may be used to inspect or alter +// the session task challenge. +// +// If this block is not set, the fetcher's default behavior for the NSURLSessionTask +// didReceiveChallenge: delegate method is to use the fetcher's respondToChallenge: method +// which relies on the fetcher's credential and proxyCredential properties. +// +// Warning: This may be called repeatedly if the challenge fails. Check +// challenge.previousFailureCount to identify repeated invocations. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherChallengeBlock challengeBlock; + +// The delegate's optional willRedirect block may be used to inspect or alter +// the redirection. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherWillRedirectBlock willRedirectBlock; + +// The optional send progress block reports body bytes uploaded. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherSendProgressBlock sendProgressBlock; + +// The optional accumulate block may be set by clients wishing to accumulate data +// themselves rather than let the fetcher append each buffer to an NSData. +// +// When this is called with nil data (such as on redirect) the client +// should empty its accumulation buffer. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherAccumulateDataBlock accumulateDataBlock; + +// The optional received progress block may be used to monitor data +// received from a data task. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherReceivedProgressBlock receivedProgressBlock; + +// The delegate's optional downloadProgress block may be used to monitor download +// progress in writing to disk. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherDownloadProgressBlock downloadProgressBlock; + +// The delegate's optional willCacheURLResponse block may be used to alter the cached +// NSURLResponse. The user may prevent caching by passing nil to the block's response. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) + GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock; + +// Enable retrying; see comments at the top of this file. Setting +// retryEnabled=YES resets the min and max retry intervals. +@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled; + +// Retry block is optional for retries. +// +// If present, this block should call the response block with YES to cause a retry or NO to end the +// fetch. +// See comments at the top of this file. +@property(atomic, copy, nullable) GTMSessionFetcherRetryBlock retryBlock; + +// The optional block for collecting the metrics of the present session. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) + GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock API_AVAILABLE( + ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)); + +// Retry intervals must be strictly less than maxRetryInterval, else +// they will be limited to maxRetryInterval and no further retries will +// be attempted. Setting maxRetryInterval to 0.0 will reset it to the +// default value, 60 seconds for downloads and 600 seconds for uploads. +@property(atomic, assign) NSTimeInterval maxRetryInterval; + +// Starting retry interval. Setting minRetryInterval to 0.0 will reset it +// to a random value between 1.0 and 2.0 seconds. Clients should normally not +// set this except for unit testing. +@property(atomic, assign) NSTimeInterval minRetryInterval; + +// Multiplier used to increase the interval between retries, typically 2.0. +// Clients should not need to set this. +@property(atomic, assign) double retryFactor; + +// Number of retries attempted. +@property(atomic, readonly) NSUInteger retryCount; + +// Interval delay to precede next retry. +@property(atomic, readonly) NSTimeInterval nextRetryInterval; + +#if GTM_BACKGROUND_TASK_FETCHING +// Skip use of a UIBackgroundTask, thus requiring fetches to complete when the app is in the +// foreground. +// +// Targets should define GTM_BACKGROUND_TASK_FETCHING to 0 to avoid use of a UIBackgroundTask +// on iOS to allow fetches to complete in the background. This property is available when +// it's not practical to set the preprocessor define. +@property(atomic, assign) BOOL skipBackgroundTask; +#endif // GTM_BACKGROUND_TASK_FETCHING + +// Begin fetching the request +// +// The delegate may optionally implement the callback or pass nil for the selector or handler. +// +// The delegate and all callback blocks are retained between the beginFetch call until after the +// finish callback, or until the fetch is stopped. +// +// An error is passed to the callback for server statuses 300 or +// higher, with the status stored as the error object's code. +// +// finishedSEL has a signature like: +// - (void)fetcher:(GTMSessionFetcher *)fetcher +// finishedWithData:(NSData *)data +// error:(NSError *)error; +// +// If the application has specified a destinationFileURL or an accumulateDataBlock +// for the fetcher, the data parameter passed to the callback will be nil. + +- (void)beginFetchWithDelegate:(nullable id)delegate didFinishSelector:(nullable SEL)finishedSEL; + +- (void)beginFetchWithCompletionHandler:(nullable GTMSessionFetcherCompletionHandler)handler; + +// Returns YES if this fetcher is in the process of fetching a URL. +@property(atomic, readonly, getter=isFetching) BOOL fetching; + +// Cancel the fetch of the request that's currently in progress. The completion handler +// will not be called. +- (void)stopFetching; + +// A block to be called when the fetch completes. +@property(atomic, copy, nullable) GTMSessionFetcherCompletionHandler completionHandler; + +// A block to be called if download resume data becomes available. +@property(atomic, strong, nullable) void (^resumeDataBlock)(NSData *); + +// Return the status code from the server response. +@property(atomic, readonly) NSInteger statusCode; + +// Return the http headers from the response. +@property(atomic, strong, readonly, nullable) NSDictionary *responseHeaders; + +// The response, once it's been received. +@property(atomic, strong, readonly, nullable) NSURLResponse *response; + +// Bytes downloaded so far. +@property(atomic, readonly) int64_t downloadedLength; + +// Buffer of currently-downloaded data, if available. +@property(atomic, readonly, strong, nullable) NSData *downloadedData; + +// Local path to which the downloaded file will be moved. +// +// If a file already exists at the path, it will be overwritten. +// Will create the enclosing folders if they are not present. +@property(atomic, strong, nullable) NSURL *destinationFileURL; + +// The time this fetcher originally began fetching. This is useful as a time +// barrier for ignoring irrelevant fetch notifications or callbacks. +@property(atomic, strong, readonly, nullable) NSDate *initialBeginFetchDate; + +// userData is retained solely for the convenience of the client. +@property(atomic, strong, nullable) id userData; + +// Stored property values are retained solely for the convenience of the client. +@property(atomic, copy, nullable) NSDictionary *properties; + +- (void)setProperty:(nullable id)obj + forKey:(NSString *)key; // Pass nil for obj to remove the property. +- (nullable id)propertyForKey:(NSString *)key; + +- (void)addPropertiesFromDictionary:(NSDictionary *)dict; + +// Comments are useful for logging, so are strongly recommended for each fetcher. +@property(atomic, copy, nullable) NSString *comment; + +- (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2); + +// Log of request and response, if logging is enabled +@property(atomic, copy, nullable) NSString *log; + +// Callbacks are run on this queue. If none is supplied, the main queue is used. +// +// CAUTION: This block MUST be a serial queue. Setting a concurrent queue can result in callbacks +// being dispatched concurrently, leading events to appear out-of-order. +@property(atomic, strong, null_resettable) dispatch_queue_t callbackQueue; + +// The queue used internally by the session to invoke its delegate methods in the fetcher. +// +// Application callbacks are always called by the fetcher on the callbackQueue above, +// not on this queue. Apps should generally not change this queue. +// +// The default delegate queue is the main queue. +// +// This value is ignored after the session has been created, so this +// property should be set in the fetcher service rather in the fetcher as it applies +// to a shared session. +@property(atomic, strong, null_resettable) NSOperationQueue *sessionDelegateQueue; + +// DEPRECATED: Callers should use XCTestExpectation instead. +// +// Spin the run loop or sleep the thread, discarding events, until the fetch has completed. +// +// This is only for use in testing or in tools without a user interface. +// +// Note: Synchronous fetches should never be used by shipping apps; they are +// sufficient reason for rejection from the app store. +// +// Returns NO if timed out. +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds + __deprecated_msg("Use XCTestExpectation instead"); + +// Test block is optional for testing. +// +// If present, this block will cause the fetcher to skip starting the session, and instead +// use the test block response values when calling the completion handler and delegate code. +// +// Test code can set this on the fetcher or on the fetcher service. For testing libraries +// that use a fetcher without exposing either the fetcher or the fetcher service, the global +// method setGlobalTestBlock: will set the block for all fetchers that do not have a test +// block set. +// +// The test code can pass nil for all response parameters to indicate that the fetch +// should proceed. +// +// Applications can exclude test block support by setting GTM_DISABLE_FETCHER_TEST_BLOCK. +@property(atomic, copy, nullable) GTMSessionFetcherTestBlock testBlock; + ++ (void)setGlobalTestBlock:(nullable GTMSessionFetcherTestBlock)block; + +// When using the testBlock, |testBlockAccumulateDataChunkCount| is the desired number of chunks to +// divide the response data into if the client has streaming enabled. The data will be divided up to +// |testBlockAccumulateDataChunkCount| chunks; however, the exact amount may vary depending on the +// size of the response data (e.g. a 1-byte response can only be divided into one chunk). +@property(atomic, readwrite) NSUInteger testBlockAccumulateDataChunkCount; + +#if GTM_BACKGROUND_TASK_FETCHING +// For testing or to override UIApplication invocations, apps may specify an alternative +// target for messages to UIApplication. ++ (void)setSubstituteUIApplication:(nullable id)substituteUIApplication; ++ (nullable id)substituteUIApplication; +#endif // GTM_BACKGROUND_TASK_FETCHING + +// Exposed for testing. ++ (GTMSessionCookieStorage *)staticCookieStorage; ++ (BOOL)appAllowsInsecureRequests; + +#if STRIP_GTM_FETCH_LOGGING +// If logging is stripped, provide a stub for the main method +// for controlling logging. ++ (void)setLoggingEnabled:(BOOL)flag; ++ (BOOL)isLoggingEnabled; + +#else + +// These methods let an application log specific body text, such as the text description of a binary +// request or response. The application should set the fetcher to defer response body logging until +// the response has been received and the log response body has been set by the app. For example: +// +// fetcher.logRequestBody = [binaryObject stringDescription]; +// fetcher.deferResponseBodyLogging = YES; +// [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { +// if (error == nil) { +// fetcher.logResponseBody = [[[MyThing alloc] initWithData:data] stringDescription]; +// } +// fetcher.deferResponseBodyLogging = NO; +// }]; + +@property(atomic, copy, nullable) NSString *logRequestBody; +@property(atomic, assign) BOOL deferResponseBodyLogging; +@property(atomic, copy, nullable) NSString *logResponseBody; + +// Internal logging support. +@property(atomic, readonly) NSData *loggedStreamData; +@property(atomic, assign) BOOL hasLoggedError; +@property(atomic, strong, nullable) NSURL *redirectedFromURL; +- (void)appendLoggedStreamData:(NSData *)dataToAdd; +- (void)clearLoggedStreamData; + +#endif // STRIP_GTM_FETCH_LOGGING + +@end + +@interface GTMSessionFetcher (BackwardsCompatibilityOnly) +// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves; +// this method is deprecated and will be removed soon. +- (void)setCookieStorageMethod:(NSInteger)method + __deprecated_msg("Create an NSHTTPCookieStorage and set .cookieStorage directly."); +@end + +// Until we can just instantiate NSHTTPCookieStorage for local use, we'll +// implement all the public methods ourselves. This stores cookies only in +// memory. Additional methods are provided for testing. +// +// iOS 9/OS X 10.11 added +[NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:] +// which may also be used to create cookie storage. +@interface GTMSessionCookieStorage : NSHTTPCookieStorage + +// Add the array off cookies to the storage, replacing duplicates. +// Also removes expired cookies from the storage. +- (void)setCookies:(nullable NSArray *)cookies; + +- (void)removeAllCookies; + +@end + +// Macros to monitor synchronization blocks in debug builds. +// These report problems using GTMSessionCheckDebug. +// +// GTMSessionMonitorSynchronized Start monitoring a top-level-only +// @sync scope. +// GTMSessionMonitorRecursiveSynchronized Start monitoring a top-level or +// recursive @sync scope. +// GTMSessionCheckSynchronized Verify that the current execution +// is inside a @sync scope. +// GTMSessionCheckNotSynchronized Verify that the current execution +// is not inside a @sync scope. +// +// Example usage: +// +// - (void)myExternalMethod { +// @synchronized(self) { +// GTMSessionMonitorSynchronized(self) +// +// - (void)myInternalMethod { +// GTMSessionCheckSynchronized(self); +// +// - (void)callMyCallbacks { +// GTMSessionCheckNotSynchronized(self); +// +// GTMSessionCheckNotSynchronized is available for verifying the code isn't +// in a deadlockable @sync state when posting notifications and invoking +// callbacks. Don't use GTMSessionCheckNotSynchronized immediately before a +// @sync scope; the normal recursiveness check of GTMSessionMonitorSynchronized +// can catch those. + +#ifdef __OBJC__ +// If asserts are entirely no-ops, the synchronization monitor is just a bunch +// of counting code that doesn't report exceptional circumstances in any way. +// Only build the synchronization monitor code if NS_BLOCK_ASSERTIONS is not +// defined or asserts are being logged instead. +#if DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG) +#define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) varname##counter +#define __GTMSessionMonitorSynchronizedVariable(varname, counter) \ + __GTMSessionMonitorSynchronizedVariableInner(varname, counter) + +#define GTMSessionMonitorSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:NO \ + functionName:__func__] + +#define GTMSessionMonitorRecursiveSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:YES \ + functionName:__func__] + +#define GTMSessionCheckSynchronized(obj) \ + { \ + GTMSESSION_ASSERT_DEBUG( \ + [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \ + @" on " #obj " in %s. Call stack:\n%@", \ + __func__, [NSThread callStackSymbols]); \ + } + +#define GTMSessionCheckNotSynchronized(obj) \ + { \ + GTMSESSION_ASSERT_DEBUG( \ + ![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \ + @" on " #obj " in %s by %@. Call stack:\n%@", \ + __func__, [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + [NSThread callStackSymbols]); \ + } + +// GTMSessionSyncMonitorInternal is a private class that keeps track of the +// beginning and end of synchronized scopes. +// +// This class should not be used directly, but only via the +// GTMSessionMonitorSynchronized macro. +@interface GTMSessionSyncMonitorInternal : NSObject +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName; +// Return the names of the functions that hold sync on the object, or nil if none. ++ (nullable NSArray *)functionsHoldingSynchronizationOnObject:(id)object; +@end + +#else +#define GTMSessionMonitorSynchronized(obj) \ + do { \ + } while (0) +#define GTMSessionMonitorRecursiveSynchronized(obj) \ + do { \ + } while (0) +#define GTMSessionCheckSynchronized(obj) \ + do { \ + } while (0) +#define GTMSessionCheckNotSynchronized(obj) \ + do { \ + } while (0) +#endif // !DEBUG +#endif // __OBJC__ + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m new file mode 100644 index 0000000..08d2a69 --- /dev/null +++ b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m @@ -0,0 +1,4758 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcher.h" +#if TARGET_OS_OSX && GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH +// To reconnect background sessions on Mac outside +load requires importing and linking +// AppKit to access the NSApplicationDidFinishLaunching symbol. +#import +#endif + +#import + +#ifndef STRIP_GTM_FETCH_LOGGING +#error GTMSessionFetcher headers should have defaulted this if it wasn't already defined. +#endif + +NS_ASSUME_NONNULL_BEGIN + +NSString *const kGTMSessionFetcherStartedNotification = @"kGTMSessionFetcherStartedNotification"; +NSString *const kGTMSessionFetcherStoppedNotification = @"kGTMSessionFetcherStoppedNotification"; +NSString *const kGTMSessionFetcherRetryDelayStartedNotification = + @"kGTMSessionFetcherRetryDelayStartedNotification"; +NSString *const kGTMSessionFetcherRetryDelayStoppedNotification = + @"kGTMSessionFetcherRetryDelayStoppedNotification"; + +NSString *const kGTMSessionFetcherCompletionInvokedNotification = + @"kGTMSessionFetcherCompletionInvokedNotification"; +NSString *const kGTMSessionFetcherCompletionDataKey = @"data"; +NSString *const kGTMSessionFetcherCompletionErrorKey = @"error"; + +NSString *const kGTMSessionFetcherErrorDomain = @"com.google.GTMSessionFetcher"; +NSString *const kGTMSessionFetcherStatusDomain = @"com.google.HTTPStatus"; +NSString *const kGTMSessionFetcherStatusDataKey = + @"data"; // data returned with a kGTMSessionFetcherStatusDomain error +NSString *const kGTMSessionFetcherStatusDataContentTypeKey = @"data_content_type"; + +NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey = + @"kGTMSessionFetcherNumberOfRetriesDoneKey"; +NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey = + @"kGTMSessionFetcherElapsedIntervalWithRetriesKey"; + +static NSString *const kGTMSessionIdentifierPrefix = @"com.google.GTMSessionFetcher"; +static NSString *const kGTMSessionIdentifierDestinationFileURLMetadataKey = @"_destURL"; +static NSString *const kGTMSessionIdentifierBodyFileURLMetadataKey = @"_bodyURL"; +static NSString *const kGTMSessionIdentifierClientReconnectMetadataKey = @"_clientWillReconnect"; + +// The default max retry interview is 10 minutes for uploads (POST/PUT/PATCH), +// 1 minute for downloads. +static const NSTimeInterval kUnsetMaxRetryInterval = -1.0; +static const NSTimeInterval kDefaultMaxDownloadRetryInterval = 60.0; +static const NSTimeInterval kDefaultMaxUploadRetryInterval = 60.0 * 10.; + +// The maximum data length that can be loaded to the error userInfo +static const int64_t kMaximumDownloadErrorDataLength = 20000; + +#ifdef GTMSESSION_PERSISTED_DESTINATION_KEY +// Projects using unique class names should also define a unique persisted destination key. +static NSString *const kGTMSessionFetcherPersistedDestinationKey = + GTMSESSION_PERSISTED_DESTINATION_KEY; +#else +static NSString *const kGTMSessionFetcherPersistedDestinationKey = + @"com.google.GTMSessionFetcher.downloads"; +#endif + +NS_ASSUME_NONNULL_END + +// +// GTMSessionFetcher +// + +#if 0 +#define GTM_LOG_BACKGROUND_SESSION(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__) +#else +#define GTM_LOG_BACKGROUND_SESSION(...) +#endif + +#ifndef GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY +#define GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY 1 +#endif + +#if ((defined(TARGET_OS_MACCATALYST) && TARGET_OS_MACCATALYST) || \ + (TARGET_OS_OSX && defined(__MAC_10_15) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_15) || \ + (TARGET_OS_IOS && defined(__IPHONE_13_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_13_0) || \ + (TARGET_OS_WATCH && defined(__WATCHOS_6_0) && \ + __WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_6_0) || \ + (TARGET_OS_TV && defined(__TVOS_13_0) && __TVOS_VERSION_MIN_REQUIRED >= __TVOS_13_0)) +#define GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 1 +#define GTM_SDK_SUPPORTS_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 1 +#elif ((TARGET_OS_OSX && defined(__MAC_10_15) && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_15) || \ + (TARGET_OS_IOS && defined(__IPHONE_13_0) && \ + __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) || \ + (TARGET_OS_WATCH && defined(__WATCHOS_6_0) && \ + __WATCH_OS_VERSION_MAX_ALLOWED >= __WATCHOS_6_0) || \ + (TARGET_OS_TV && defined(__TVOS_13_0) && __TVOS_VERSION_MAX_ALLOWED >= __TVOS_13_0)) +#define GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 0 +#define GTM_SDK_SUPPORTS_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 1 +#else +#define GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 0 +#define GTM_SDK_SUPPORTS_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 0 +#endif + +#if ((defined(TARGET_OS_MACCATALYST) && TARGET_OS_MACCATALYST) || \ + (TARGET_OS_OSX && defined(__MAC_10_15) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_15) || \ + (TARGET_OS_IOS && defined(__IPHONE_13_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_13_0) || \ + (TARGET_OS_WATCH && defined(__WATCHOS_6_0) && \ + __WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_6_0) || \ + (TARGET_OS_TV && defined(__TVOS_13_0) && __TVOS_VERSION_MIN_REQUIRED >= __TVOS_13_0)) +#define GTM_SDK_REQUIRES_SECTRUSTEVALUATEWITHERROR 1 +#else +#define GTM_SDK_REQUIRES_SECTRUSTEVALUATEWITHERROR 0 +#endif + +#if __has_attribute(swift_async) +// Once Clang 13/Xcode 13 can be assumed, can switch to NS_SWIFT_DISABLE_ASYNC. +#define GTM_SWIFT_DISABLE_ASYNC __attribute__((swift_async(none))) +#else +#define GTM_SWIFT_DISABLE_ASYNC +#endif + +@interface GTMSessionFetcher () + +@property(atomic, strong, readwrite, nullable) NSData *downloadedData; +@property(atomic, strong, readwrite, nullable) NSData *downloadResumeData; + +#if GTM_BACKGROUND_TASK_FETCHING +// Should always be accessed within an @synchronized(self). +@property(assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier; +#endif + +@property(atomic, readwrite, getter=isUsingBackgroundSession) BOOL usingBackgroundSession; + +@end + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (GTMSessionFetcherLoggingInternal) +- (void)logFetchWithError:(NSError *)error; +- (void)logNowWithError:(nullable NSError *)error; +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream; +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider; +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +NS_ASSUME_NONNULL_BEGIN + +static NSTimeInterval InitialMinRetryInterval(void) { + return 1.0 + ((double)(arc4random_uniform(0x0FFFF)) / (double)0x0FFFF); +} + +static BOOL IsLocalhost(NSString *_Nullable host) { + // We check if there's host, and then make the comparisons. + if (host == nil) return NO; + return ([host caseInsensitiveCompare:@"localhost"] == NSOrderedSame || [host isEqual:@"::1"] || + [host isEqual:@"127.0.0.1"]); +} + +static NSDictionary *_Nullable GTMErrorUserInfoForData(NSData *_Nullable data, + NSDictionary *_Nullable responseHeaders) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + + if (data.length > 0) { + userInfo[kGTMSessionFetcherStatusDataKey] = data; + + NSString *contentType = responseHeaders[@"Content-Type"]; + if (contentType) { + userInfo[kGTMSessionFetcherStatusDataContentTypeKey] = contentType; + } + } + + return userInfo.count > 0 ? userInfo : nil; +} + +static GTMSessionFetcherTestBlock _Nullable gGlobalTestBlock; + +@implementation GTMSessionFetcher { + NSMutableURLRequest *_request; // after beginFetch, changed only in delegate callbacks + BOOL _useUploadTask; // immutable after beginFetch + NSURL *_bodyFileURL; // immutable after beginFetch + GTMSessionFetcherBodyStreamProvider _bodyStreamProvider; // immutable after beginFetch + NSURLSession *_session; + BOOL _shouldInvalidateSession; // immutable after beginFetch + NSURLSession *_sessionNeedingInvalidation; + NSURLSessionConfiguration *_configuration; + NSURLSessionTask *_sessionTask; + NSString *_taskDescription; + float _taskPriority; + NSURLResponse *_response; + NSString *_sessionIdentifier; + BOOL _wasCreatedFromBackgroundSession; + BOOL _clientWillReconnectBackgroundSession; + BOOL _didCreateSessionIdentifier; + NSString *_sessionIdentifierUUID; + BOOL _userRequestedBackgroundSession; + BOOL _usingBackgroundSession; + NSMutableData *_Nullable _downloadedData; + NSError *_downloadFinishedError; + NSData *_downloadResumeData; // immutable after construction + NSData *_Nullable _downloadTaskErrorData; // Data for when download task fails + NSURL *_destinationFileURL; + int64_t _downloadedLength; + NSURLCredential *_credential; // username & password + NSURLCredential *_proxyCredential; // credential supplied to proxy servers + BOOL _isStopNotificationNeeded; // set when start notification has been sent + BOOL _isUsingTestBlock; // set when a test block was provided (remains set when the block is + // released) + id _userData; // retained, if set by caller + NSMutableDictionary *_properties; // more data retained for caller + dispatch_queue_t _callbackQueue; + dispatch_group_t _callbackGroup; // read-only after creation + NSOperationQueue *_delegateQueue; // immutable after beginFetch + + id _authorizer; // immutable after beginFetch + + // The service object that created and monitors this fetcher, if any. + id + _service; // immutable; set by the fetcher service upon creation + NSString *_serviceHost; + NSInteger _servicePriority; // immutable after beginFetch + BOOL _hasStoppedFetching; // counterpart to _initialBeginFetchDate + BOOL _userStoppedFetching; + + BOOL _isRetryEnabled; // user wants auto-retry + NSTimer *_retryTimer; + NSUInteger _retryCount; + NSTimeInterval _maxRetryInterval; // default 60 (download) or 600 (upload) seconds + NSTimeInterval _minRetryInterval; // random between 1 and 2 seconds + NSTimeInterval _retryFactor; // default interval multiplier is 2 + NSTimeInterval _lastRetryInterval; + NSDate *_initialBeginFetchDate; // date that beginFetch was first invoked; immutable after + // initial beginFetch + NSDate *_initialRequestDate; // date of first request to the target server (ignoring auth) + BOOL _hasAttemptedAuthRefresh; // accessed only in shouldRetryNowForStatus: + + NSString *_comment; // comment for log + NSString *_log; +#if !STRIP_GTM_FETCH_LOGGING + NSMutableData *_loggedStreamData; + NSURL *_redirectedFromURL; + NSString *_logRequestBody; + NSString *_logResponseBody; + BOOL _hasLoggedError; + BOOL _deferResponseBodyLogging; +#endif +} + +#if !GTMSESSION_UNIT_TESTING ++ (void)load { +#if GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH && TARGET_OS_IPHONE + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(reconnectFetchersForBackgroundSessionsOnAppLaunch:) + name:UIApplicationDidFinishLaunchingNotification + object:nil]; +#elif GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH && TARGET_OS_OSX + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(reconnectFetchersForBackgroundSessionsOnAppLaunch:) + name:NSApplicationDidFinishLaunchingNotification + object:nil]; +#else + [self fetchersForBackgroundSessions]; +#endif +} + ++ (void)reconnectFetchersForBackgroundSessionsOnAppLaunch:(NSNotification *)notification { + // Give all other app-did-launch handlers a chance to complete before + // reconnecting the fetchers. Not doing this may lead to reconnecting + // before the app delegate has a chance to run. + dispatch_async(dispatch_get_main_queue(), ^{ + [self fetchersForBackgroundSessions]; + }); +} +#endif // !GTMSESSION_UNIT_TESTING + ++ (instancetype)fetcherWithRequest:(nullable NSURLRequest *)request { + return [[self alloc] initWithRequest:request configuration:nil]; +} + ++ (instancetype)fetcherWithURL:(NSURL *)requestURL { + return [self fetcherWithRequest:[NSURLRequest requestWithURL:requestURL]]; +} + ++ (instancetype)fetcherWithURLString:(NSString *)requestURLString { + return [self fetcherWithURL:(NSURL *)[NSURL URLWithString:requestURLString]]; +} + ++ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData { + GTMSessionFetcher *fetcher = [self fetcherWithRequest:nil]; + fetcher.comment = @"Resuming download"; + fetcher.downloadResumeData = resumeData; + return fetcher; +} + ++ (nullable instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (!fetcher && [sessionIdentifier hasPrefix:kGTMSessionIdentifierPrefix]) { + fetcher = [self fetcherWithRequest:nil]; + [fetcher setSessionIdentifier:sessionIdentifier]; + [sessionIdentifierToFetcherMap setObject:fetcher forKey:sessionIdentifier]; + fetcher->_wasCreatedFromBackgroundSession = YES; + [fetcher setCommentWithFormat:@"Resuming %@", fetcher && fetcher->_sessionIdentifierUUID + ? fetcher->_sessionIdentifierUUID + : @"?"]; + } + return fetcher; +} + ++ (NSMapTable *)sessionIdentifierToFetcherMap { + // TODO: What if a service is involved in creating the fetcher? Currently, when re-creating + // fetchers, if a service was involved, it is not re-created. Should the service maintain a map? + static NSMapTable *gSessionIdentifierToFetcherMap = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gSessionIdentifierToFetcherMap = [NSMapTable strongToWeakObjectsMapTable]; + }); + return gSessionIdentifierToFetcherMap; +} + +#if !GTM_ALLOW_INSECURE_REQUESTS ++ (BOOL)appAllowsInsecureRequests { + // If the main bundle Info.plist key NSAppTransportSecurity is present, and it specifies + // NSAllowsArbitraryLoads, then we need to explicitly enforce secure schemes. +#if GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY + static BOOL allowsInsecureRequests; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSBundle *mainBundle = [NSBundle mainBundle]; + NSDictionary *appTransportSecurity = + [mainBundle objectForInfoDictionaryKey:@"NSAppTransportSecurity"]; + allowsInsecureRequests = + [[appTransportSecurity objectForKey:@"NSAllowsArbitraryLoads"] boolValue]; + }); + return allowsInsecureRequests; +#else + // For builds targeting iOS 8 or 10.10 and earlier, we want to require fetcher + // security checks. + return YES; +#endif // GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY +} +#else // GTM_ALLOW_INSECURE_REQUESTS ++ (BOOL)appAllowsInsecureRequests { + return YES; +} +#endif // !GTM_ALLOW_INSECURE_REQUESTS + +- (instancetype)init { + return [self initWithRequest:nil configuration:nil]; +} + +- (instancetype)initWithRequest:(NSURLRequest *)request { + return [self initWithRequest:request configuration:nil]; +} + +- (instancetype)initWithRequest:(nullable NSURLRequest *)request + configuration:(nullable NSURLSessionConfiguration *)configuration { + self = [super init]; + if (self) { +#if GTM_BACKGROUND_TASK_FETCHING + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; +#endif + _request = [request mutableCopy]; + _configuration = configuration; + + NSData *bodyData = request.HTTPBody; + if (bodyData) { + _bodyLength = (int64_t)bodyData.length; + } else { + _bodyLength = NSURLSessionTransferSizeUnknown; + } + + _callbackQueue = dispatch_get_main_queue(); + _callbackGroup = dispatch_group_create(); + _delegateQueue = [NSOperationQueue mainQueue]; + + _minRetryInterval = InitialMinRetryInterval(); + _maxRetryInterval = kUnsetMaxRetryInterval; + + _taskPriority = -1.0f; // Valid values if set are 0.0...1.0. + + _testBlockAccumulateDataChunkCount = 1; + +#if !STRIP_GTM_FETCH_LOGGING + // Encourage developers to set the comment property or use + // setCommentWithFormat: by providing a default string. + _comment = @"(No fetcher comment set)"; +#endif + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + // disallow use of fetchers in a copy property + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (NSString *)description { + NSString *requestStr = self.request.URL.description; + if (requestStr.length == 0) { + if (self.downloadResumeData.length > 0) { + requestStr = @""; + } else if (_wasCreatedFromBackgroundSession) { + requestStr = @""; + } else { + requestStr = @""; + } + } + return [NSString stringWithFormat:@"%@ %p (%@)", [self class], self, requestStr]; +} + +- (void)dealloc { + GTMSESSION_ASSERT_DEBUG(!_isStopNotificationNeeded, @"unbalanced fetcher notification for %@", + _request.URL); + [self forgetSessionIdentifierForFetcherWithoutSyncCheck]; + + // Note: if a session task or a retry timer was pending, then this instance + // would be retained by those so it wouldn't be getting dealloc'd, + // hence we don't need to stopFetch here +} + +#pragma mark - + +// Begin fetching the URL (or begin a retry fetch). The delegate is retained +// for the duration of the fetch connection. + +- (void)beginFetchWithCompletionHandler:(nullable GTMSessionFetcherCompletionHandler)handler { + GTMSessionCheckNotSynchronized(self); + _completionHandler = [handler copy]; + + // The user may have called setDelegate: earlier if they want to use other + // delegate-style callbacks during the fetch; otherwise, the delegate is nil, + // which is fine. + [self beginFetchMayDelay:YES mayAuthorize:YES mayDecorate:YES]; +} + +// Begin fetching the URL for a retry fetch. The delegate and completion handler +// are already provided, and do not need to be copied. +- (void)beginFetchForRetry { + GTMSessionCheckNotSynchronized(self); + [self beginFetchMayDelay:YES mayAuthorize:YES mayDecorate:YES]; +} + +- (GTMSessionFetcherCompletionHandler)completionHandlerWithTarget:(nullable id)target + didFinishSelector:(nullable SEL)finishedSelector { + GTMSessionFetcherAssertValidSelector(target, finishedSelector, @encode(GTMSessionFetcher *), + @encode(NSData *), @encode(NSError *), 0); + GTMSessionFetcherCompletionHandler completionHandler = ^(NSData *data, NSError *error) { + if (target && finishedSelector) { + id selfArg = self; // Placate ARC. + NSMethodSignature *sig = [target methodSignatureForSelector:finishedSelector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setSelector:(SEL)finishedSelector]; + [invocation setTarget:target]; + [invocation setArgument:&selfArg atIndex:2]; + [invocation setArgument:&data atIndex:3]; + [invocation setArgument:&error atIndex:4]; + [invocation invoke]; + } + }; + return completionHandler; +} + +- (void)beginFetchWithDelegate:(nullable id)target + didFinishSelector:(nullable SEL)finishedSelector { + GTMSessionCheckNotSynchronized(self); + + GTMSessionFetcherCompletionHandler handler = [self completionHandlerWithTarget:target + didFinishSelector:finishedSelector]; + [self beginFetchWithCompletionHandler:handler]; +} + +- (void)beginFetchMayDelay:(BOOL)mayDelay + mayAuthorize:(BOOL)mayAuthorize + mayDecorate:(BOOL)mayDecorate { + // This is the internal entry point for re-starting fetches. + GTMSessionCheckNotSynchronized(self); + + NSMutableURLRequest *fetchRequest = + _request; // The request property is now externally immutable. + NSURL *fetchRequestURL = fetchRequest.URL; + NSString *priorSessionIdentifier = self.sessionIdentifier; + + // A utility block for creating error objects when we fail to start the fetch. + NSError * (^beginFailureError)(NSInteger) = ^(NSInteger code) { + NSString *urlString = fetchRequestURL.absoluteString; + NSDictionary *userInfo = + @{NSURLErrorFailingURLStringErrorKey : (urlString ? urlString : @"(missing URL)")}; + return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain code:code userInfo:userInfo]; + }; + + // Catch delegate queue maxConcurrentOperationCount values other than 1, particularly + // NSOperationQueueDefaultMaxConcurrentOperationCount (-1), to avoid the additional complexity + // of simultaneous or out-of-order delegate callbacks. + GTMSESSION_ASSERT_DEBUG(_delegateQueue.maxConcurrentOperationCount == 1, + @"delegate queue %@ should support one concurrent operation, not %ld", + _delegateQueue.name, (long)_delegateQueue.maxConcurrentOperationCount); + + if (!_initialBeginFetchDate) { + // This ivar is set only here on the initial beginFetch so need not be synchronized. + _initialBeginFetchDate = [[NSDate alloc] init]; + } + + if (self.sessionTask != nil) { + // If cached fetcher returned through fetcherWithSessionIdentifier:, then it's + // already begun, but don't consider this a failure, since the user need not know this. + if (self.sessionIdentifier != nil) { + return; + } + GTMSESSION_ASSERT_DEBUG(NO, @"Fetch object %@ being reused; this should never happen", self); + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorDownloadFailed)]; + return; + } + + if (fetchRequestURL == nil && !_downloadResumeData && !priorSessionIdentifier) { + GTMSESSION_ASSERT_DEBUG(NO, @"Beginning a fetch requires a request with a URL"); + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorDownloadFailed)]; + return; + } + + // We'll respect the user's request for a background session (unless this is + // an upload fetcher, which does its initial request foreground.) + self.usingBackgroundSession = self.useBackgroundSession && [self canFetchWithBackgroundSession]; + + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSError *fileCheckError; + if (![bodyFileURL checkResourceIsReachableAndReturnError:&fileCheckError]) { + // This assert fires when the file being uploaded no longer exists once + // the fetcher is ready to start the upload. + GTMSESSION_ASSERT_DEBUG_OR_LOG(0, @"Body file is unreachable: %@\n %@", bodyFileURL.path, + fileCheckError); + [self failToBeginFetchWithError:fileCheckError]; + return; + } + } + + NSString *requestScheme = fetchRequestURL.scheme; + BOOL isDataRequest = [requestScheme isEqual:@"data"]; + if (isDataRequest) { + // NSURLSession does not support data URLs in background sessions. +#if DEBUG + if (priorSessionIdentifier || self.sessionIdentifier) { + GTMSESSION_LOG_DEBUG(@"Converting background to foreground session for %@", fetchRequest); + } +#endif + // If priorSessionIdentifier is allowed to stay non-nil, a background session can + // still be created. + priorSessionIdentifier = nil; + [self setSessionIdentifierInternal:nil]; + self.usingBackgroundSession = NO; + } + +#if GTM_ALLOW_INSECURE_REQUESTS + BOOL shouldCheckSecurity = NO; +#else + BOOL shouldCheckSecurity = + (fetchRequestURL != nil && !isDataRequest && [[self class] appAllowsInsecureRequests]); +#endif + + if (shouldCheckSecurity) { + // Allow https only for requests, unless overridden by the client. + // + // Non-https requests may too easily be snooped, so we disallow them by default. + // + // file: and data: schemes are usually safe if they are hardcoded in the client or provided + // by a trusted source, but since it's fairly rare to need them, it's safest to make clients + // explicitly allow them. + BOOL isSecure = + requestScheme != nil && [requestScheme caseInsensitiveCompare:@"https"] == NSOrderedSame; + if (!isSecure) { + BOOL allowRequest = NO; + NSString *host = fetchRequestURL.host; + + // Check schemes first. A file scheme request may be allowed here, or as a localhost request. + for (NSString *allowedScheme in _allowedInsecureSchemes) { + if (requestScheme != nil && + [requestScheme caseInsensitiveCompare:allowedScheme] == NSOrderedSame) { + allowRequest = YES; + break; + } + } + if (!allowRequest) { + // Check for localhost requests. Security checks only occur for non-https requests, so + // this check won't happen for an https request to localhost. + BOOL isLocalhostRequest = + (host.length == 0 && [fetchRequestURL isFileURL]) || IsLocalhost(host); + if (isLocalhostRequest) { + if (self.allowLocalhostRequest) { + allowRequest = YES; + } else { + GTMSESSION_ASSERT_DEBUG(NO, + @"Fetch request for localhost but fetcher" + @" allowLocalhostRequest is not set: %@", + fetchRequestURL); + } + } else { + GTMSESSION_ASSERT_DEBUG(NO, + @"Insecure fetch request has a scheme (%@)" + @" not found in fetcher allowedInsecureSchemes (%@): %@", + requestScheme, _allowedInsecureSchemes ?: @" @[] ", + fetchRequestURL); + } + } + + if (!allowRequest) { +#if !DEBUG + NSLog(@"Insecure fetch disallowed for %@", + fetchRequestURL.description ?: @"nil request URL"); +#endif + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorInsecureRequest)]; + return; + } + } // !isSecure + } // (requestURL != nil) && !isDataRequest + + if (self.cookieStorage == nil) { + self.cookieStorage = [[self class] staticCookieStorage]; + } + + BOOL isRecreatingSession = (self.sessionIdentifier != nil) && (fetchRequest == nil); + + self.canShareSession = (_service != nil) && !isRecreatingSession && !self.usingBackgroundSession; + + if (!self.session && self.canShareSession) { + self.session = [_service sessionForFetcherCreation]; + // If _session is nil, then the service's session creation semaphore will block + // until this fetcher invokes fetcherDidCreateSession: below, so this *must* invoke + // that method, even if the session fails to be created. + } + + if (!self.session) { + // Create a session. + if (!_configuration) { + if (priorSessionIdentifier || self.usingBackgroundSession) { + NSString *sessionIdentifier = priorSessionIdentifier; + if (!sessionIdentifier) { + sessionIdentifier = [self createSessionIdentifierWithMetadata:nil]; + } + NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap]; + [sessionIdentifierToFetcherMap setObject:self forKey:self.sessionIdentifier]; + + _configuration = [NSURLSessionConfiguration + backgroundSessionConfigurationWithIdentifier:sessionIdentifier]; + self.usingBackgroundSession = YES; + self.canShareSession = NO; + } else { + _configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + } +#if !GTM_ALLOW_INSECURE_REQUESTS +#if GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION + _configuration.TLSMinimumSupportedProtocolVersion = tls_protocol_version_TLSv12; +#elif GTM_SDK_SUPPORTS_TLSMINIMUMSUPPORTEDPROTOCOLVERSION + if (@available(iOS 13, tvOS 13, watchOS 6, macOS 10.15, *)) { + _configuration.TLSMinimumSupportedProtocolVersion = tls_protocol_version_TLSv12; + } else { + _configuration.TLSMinimumSupportedProtocol = kTLSProtocol12; + } +#else + _configuration.TLSMinimumSupportedProtocol = kTLSProtocol12; +#endif // GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION +#endif + } // !_configuration + _configuration.HTTPCookieStorage = self.cookieStorage; + + if (_configurationBlock) { + _configurationBlock(self, _configuration); + } + + id delegate = [_service sessionDelegate]; + if (!delegate || !self.canShareSession) { + delegate = self; + } + self.session = [NSURLSession sessionWithConfiguration:_configuration + delegate:delegate + delegateQueue:self.sessionDelegateQueue]; + GTMSESSION_ASSERT_DEBUG(self.session, @"Couldn't create session"); + + // Tell the service about the session created by this fetcher. This also signals the + // service's semaphore to allow other fetchers to request this session. + [_service fetcherDidCreateSession:self]; + + // If this assertion fires, the client probably tried to use a session identifier that was + // already used. The solution is to make the client use a unique identifier (or better yet let + // the session fetcher assign the identifier). + GTMSESSION_ASSERT_DEBUG(self.session.delegate == delegate, @"Couldn't assign delegate."); + + if (self.session) { + BOOL isUsingSharedDelegate = (delegate != self); + if (!isUsingSharedDelegate) { + _shouldInvalidateSession = YES; + } + } + } + + if (isRecreatingSession) { + _shouldInvalidateSession = YES; + + // Let's make sure there are tasks still running or if not that we get a callback from a + // completed one; otherwise, we assume the tasks failed. + // This is the observed behavior perhaps 25% of the time within the Simulator running 7.0.3 on + // exiting the app after starting an upload and relaunching the app if we manage to relaunch + // after the task has completed, but before the system relaunches us in the background. + [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, + NSArray *downloadTasks) { + if (dataTasks.count == 0 && uploadTasks.count == 0 && downloadTasks.count == 0) { + double const kDelayInSeconds = 1.0; // We should get progress indication or completion soon + dispatch_time_t checkForFeedbackDelay = + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelayInSeconds * NSEC_PER_SEC)); + dispatch_after(checkForFeedbackDelay, dispatch_get_main_queue(), ^{ + if (!self.sessionTask && !fetchRequest) { + // If our task and/or request haven't been restored, then we assume task feedback lost. + [self removePersistedBackgroundSessionFromDefaults]; + NSError *sessionError = + [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorBackgroundFetchFailed + userInfo:nil]; + [self failToBeginFetchWithError:sessionError]; + } + }); + } + }]; + return; + } + + self.downloadedData = nil; + self.downloadedLength = 0; + + if (_servicePriority == NSIntegerMin) { + mayDelay = NO; + } + if (mayDelay && _service) { + BOOL shouldFetchNow = [_service fetcherShouldBeginFetching:self]; + if (!shouldFetchNow) { + // The fetch is deferred, but will happen later. + // + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after the fetcher is restarted. + if (self.canShareSession) { + self.session = nil; + } + return; + } + } + + NSString *effectiveHTTPMethod = [fetchRequest valueForHTTPHeaderField:@"X-HTTP-Method-Override"]; + if (effectiveHTTPMethod == nil) { + effectiveHTTPMethod = fetchRequest.HTTPMethod; + } + BOOL isEffectiveHTTPGet = (effectiveHTTPMethod == nil || [effectiveHTTPMethod isEqual:@"GET"]); + + BOOL needsUploadTask = (self.useUploadTask || self.bodyFileURL || self.bodyStreamProvider); + if (_bodyData || self.bodyStreamProvider || fetchRequest.HTTPBodyStream) { + if (isEffectiveHTTPGet) { + fetchRequest.HTTPMethod = @"POST"; + isEffectiveHTTPGet = NO; + } + + if (_bodyData) { + if (!needsUploadTask) { + fetchRequest.HTTPBody = _bodyData; + } +#if !STRIP_GTM_FETCH_LOGGING + } else if (fetchRequest.HTTPBodyStream) { + if ([self respondsToSelector:@selector(loggedInputStreamForInputStream:)]) { + fetchRequest.HTTPBodyStream = + [self performSelector:@selector(loggedInputStreamForInputStream:) + withObject:fetchRequest.HTTPBodyStream]; + } +#endif + } + } + + // We authorize after setting up the http method and body in the request + // because OAuth 1 may need to sign the request body + if (mayAuthorize && _authorizer && !isDataRequest) { + BOOL isAuthorized = [_authorizer isAuthorizedRequest:fetchRequest]; + if (!isAuthorized) { + // Authorization needed. + // + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after authorization completes. + if (self.canShareSession) { + self.session = nil; + } + + // Authorizing the request will recursively call this beginFetch:mayDelay: + // or failToBeginFetchWithError:. + [self authorizeRequest]; + return; + } + } + + if (mayDecorate && [_service respondsToSelector:@selector(decorators)]) { + NSArray> *decorators = _service.decorators; + if (decorators.count) { + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after decoration completes. + // + // The service will still hold on to the session, so as long as decoration doesn't take more + // than 30 seconds since the last request, the service's session will be re-used when the + // fetch actually starts. + if (self.canShareSession) { + self.session = nil; + } + [self applyDecoratorsAtRequestWillStart:decorators startingAtIndex:0]; + return; + } + } + + // set the default upload or download retry interval, if necessary + if ([self isRetryEnabled] && self.maxRetryInterval <= 0) { + if (isEffectiveHTTPGet || [effectiveHTTPMethod isEqual:@"HEAD"]) { + [self setMaxRetryInterval:kDefaultMaxDownloadRetryInterval]; + } else { + [self setMaxRetryInterval:kDefaultMaxUploadRetryInterval]; + } + } + + // finally, start the connection + NSURLSessionTask *newSessionTask; + BOOL needsDataAccumulator = NO; + if (_downloadResumeData) { + newSessionTask = [_session downloadTaskWithResumeData:_downloadResumeData]; + GTMSESSION_ASSERT_DEBUG_OR_LOG( + newSessionTask, @"Failed downloadTaskWithResumeData for %@, resume data %lu bytes", + _session, (unsigned long)_downloadResumeData.length); + } else if (_destinationFileURL && !isDataRequest) { + newSessionTask = [_session downloadTaskWithRequest:fetchRequest]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, @"Failed downloadTaskWithRequest for %@, %@", + _session, fetchRequest); + } else if (needsUploadTask) { + if (bodyFileURL) { + newSessionTask = [_session uploadTaskWithRequest:fetchRequest fromFile:bodyFileURL]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithRequest for %@, %@, file %@", _session, + fetchRequest, bodyFileURL.path); + } else if (self.bodyStreamProvider) { + newSessionTask = [_session uploadTaskWithStreamedRequest:fetchRequest]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithStreamedRequest for %@, %@", _session, + fetchRequest); + } else { + GTMSESSION_ASSERT_DEBUG_OR_LOG(_bodyData != nil, @"Upload task needs body data, %@", + fetchRequest); + newSessionTask = [_session uploadTaskWithRequest:fetchRequest + fromData:(NSData *_Nonnull)_bodyData]; + GTMSESSION_ASSERT_DEBUG_OR_LOG( + newSessionTask, @"Failed uploadTaskWithRequest for %@, %@, body data %lu bytes", _session, + fetchRequest, (unsigned long)_bodyData.length); + } + needsDataAccumulator = YES; + } else { + newSessionTask = [_session dataTaskWithRequest:fetchRequest]; + needsDataAccumulator = YES; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, @"Failed dataTaskWithRequest for %@, %@", + _session, fetchRequest); + } + self.sessionTask = newSessionTask; + + if (!newSessionTask) { + // We shouldn't get here; if we're here, an earlier assertion should have fired to explain + // which session task creation failed. + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorTaskCreationFailed)]; + return; + } + + if (needsDataAccumulator && _accumulateDataBlock == nil) { + self.downloadedData = [NSMutableData data]; + } + if (_taskDescription) { + newSessionTask.taskDescription = _taskDescription; + } + if (_taskPriority >= 0) { + newSessionTask.priority = _taskPriority; + } + +#if GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSESSION_ASSERT_DEBUG(_testBlock == nil && gGlobalTestBlock == nil, @"test blocks disabled"); + _testBlock = nil; +#else + if (!_testBlock) { + if (gGlobalTestBlock) { + // Note that the test block may pass nil for all of its response parameters, + // indicating that the fetch should actually proceed. This is useful when the + // global test block has been set, and the app is only testing a specific + // fetcher. The block simulation code will then resume the task. + _testBlock = gGlobalTestBlock; + } + } + _isUsingTestBlock = (_testBlock != nil); +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK + +#if GTM_BACKGROUND_TASK_FETCHING + id app = [[self class] fetcherUIApplication]; + // Background tasks seem to interfere with out-of-process uploads and downloads. + if (app && !self.skipBackgroundTask && !self.usingBackgroundSession) { + // Tell UIApplication that we want to continue even when the app is in the + // background. +#if DEBUG + NSString *bgTaskName = + [NSString stringWithFormat:@"%@-%@", [self class], fetchRequest.URL.host]; +#else + NSString *bgTaskName = @"GTMSessionFetcher"; +#endif + // Since a request can be started from any thread, we also have to ensure the + // variable for accessing it is safe across the initial thread and the handler + // (incase it gets failed immediately from the app already heading into the + // background). + __block UIBackgroundTaskIdentifier guardedTaskID = UIBackgroundTaskInvalid; + UIBackgroundTaskIdentifier returnedTaskID = + [app beginBackgroundTaskWithName:bgTaskName + expirationHandler:^{ + // Background task expiration callback - this block is always invoked by + // UIApplication on the main thread. + UIBackgroundTaskIdentifier localTaskID; + @synchronized(self) { + localTaskID = guardedTaskID; + } + if (localTaskID != UIBackgroundTaskInvalid) { + @synchronized(self) { + if (localTaskID == self.backgroundTaskIdentifier) { + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + } + [app endBackgroundTask:localTaskID]; + } + }]; + @synchronized(self) { + guardedTaskID = returnedTaskID; + self.backgroundTaskIdentifier = returnedTaskID; + } + } +#endif + + if (!_initialRequestDate) { + _initialRequestDate = [[NSDate alloc] init]; + } + + // We don't expect to reach here even on retry or auth until a stop notification has been sent + // for the previous task, but we should ensure that we don't unbalance that. + GTMSESSION_ASSERT_DEBUG(!_isStopNotificationNeeded, @"Start notification without a prior stop"); + [self sendStopNotificationIfNeeded]; + + [self addPersistedBackgroundSessionToDefaults]; + + [self setStopNotificationNeeded:YES]; + + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherStartedNotification + userInfo:nil + requireAsync:NO]; + + // The service needs to know our task if it is serving as NSURLSession delegate. + [_service fetcherDidBeginFetching:self]; + + if (_testBlock) { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + [self simulateFetchForTestBlock]; +#endif + } else { + // We resume the session task after posting the notification since the + // delegate callbacks may happen immediately if the fetch is started off + // the main thread or the session delegate queue is on a background thread, + // and we don't want to post a start notification after a premature finish + // of the session task. + [newSessionTask resume]; + } +} + +NSData *_Nullable GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError) { + NSMutableData *data = [NSMutableData data]; + + [inputStream open]; + NSInteger numberOfBytesRead = 0; + while ([inputStream hasBytesAvailable]) { + uint8_t buffer[512]; + numberOfBytesRead = [inputStream read:buffer maxLength:sizeof(buffer)]; + if (numberOfBytesRead > 0) { + [data appendBytes:buffer length:(NSUInteger)numberOfBytesRead]; + } else { + break; + } + } + [inputStream close]; + NSError *streamError = inputStream.streamError; + + if (streamError) { + data = nil; + } + if (outError) { + *outError = streamError; + } + return data; +} + +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + +- (void)simulateFetchForTestBlock { + // This is invoked on the same thread as the beginFetch method was. + // + // Callbacks will all occur on the callback queue. + _testBlock(self, ^(NSURLResponse *response, NSData *responseData, NSError *error) { + // Callback from test block. + if (response == nil && responseData == nil && error == nil) { + // Assume the fetcher should execute rather than be tested. + self->_testBlock = nil; + self->_isUsingTestBlock = NO; + [self->_sessionTask resume]; + return; + } + + GTMSessionFetcherBodyStreamProvider bodyStreamProvider = self.bodyStreamProvider; + if (bodyStreamProvider) { + bodyStreamProvider(^(NSInputStream *bodyStream) { + // Read from the input stream into an NSData buffer. We'll drain the stream + // explicitly on a background queue. + [self + invokeOnCallbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) + afterUserStopped:NO + block:^{ + NSError *streamError; + NSData *streamedData = + GTMDataFromInputStream(bodyStream, &streamError); + + dispatch_async(dispatch_get_main_queue(), ^{ + // Continue callbacks on the main thread, since serial behavior + // is more reliable for tests. + [self + simulateDataCallbacksForTestBlockWithBodyData:streamedData + response:response + responseData:responseData + error: + (error + ?: streamError)]; + }); + }]; + }); + } else { + // No input stream; use the supplied data or file URL. + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSError *readError; + self->_bodyData = [NSData dataWithContentsOfURL:bodyFileURL + options:NSDataReadingMappedIfSafe + error:&readError]; + error = readError; + } + + // No stream provider. + + // In real fetches, nothing happens until the run loop spins, so apps have leeway to + // set callbacks after they call beginFetch. We'll mirror that fetcher behavior by + // delaying callbacks here at least to the next spin of the run loop. That keeps + // immediate, synchronous setting of callback blocks after beginFetch working in tests. + dispatch_async(dispatch_get_main_queue(), ^{ + [self simulateDataCallbacksForTestBlockWithBodyData:self->_bodyData + response:response + responseData:responseData + error:error]; + }); + } + }); +} + +- (void)simulateByteTransferReportWithDataLength:(int64_t)totalDataLength + block:(GTMSessionFetcherSendProgressBlock)block { + // This utility method simulates transfer progress with up to three callbacks. + // It is used to call back to any of the progress blocks. + int64_t sendReportSize = totalDataLength / 3 + 1; + int64_t totalSent = 0; + while (totalSent < totalDataLength) { + int64_t bytesRemaining = totalDataLength - totalSent; + sendReportSize = MIN(sendReportSize, bytesRemaining); + totalSent += sendReportSize; + [self invokeOnCallbackQueueUnlessStopped:^{ + block(sendReportSize, totalSent, totalDataLength); + }]; + } +} + +- (void)simulateDataCallbacksForTestBlockWithBodyData:(nullable NSData *)bodyData + response:(NSURLResponse *)response + responseData:(NSData *)suppliedData + error:(NSError *)suppliedError { + __block NSData *responseData = suppliedData; + __block NSError *responseError = suppliedError; + + // This method does the test simulation of callbacks once the upload + // and download data are known. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Get copies of ivars we'll access in async invocations. This simulation assumes + // they won't change during fetcher execution. + NSURL *destinationFileURL = _destinationFileURL; + GTMSessionFetcherWillRedirectBlock willRedirectBlock = _willRedirectBlock; + GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock = _didReceiveResponseBlock; + GTMSessionFetcherSendProgressBlock sendProgressBlock = _sendProgressBlock; + GTMSessionFetcherDownloadProgressBlock downloadProgressBlock = _downloadProgressBlock; + GTMSessionFetcherAccumulateDataBlock accumulateDataBlock = _accumulateDataBlock; + GTMSessionFetcherReceivedProgressBlock receivedProgressBlock = _receivedProgressBlock; + GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock = + _willCacheURLResponseBlock; + GTMSessionFetcherChallengeBlock challengeBlock = _challengeBlock; + + // Simulate receipt of redirection. + if (willRedirectBlock) { + __auto_type block = ^{ + willRedirectBlock((NSHTTPURLResponse *)response, self->_request, + ^(NSURLRequest *redirectRequest){ + // For simulation, we'll assume + // the app will just continue. + }); + }; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES block:block]; + } + + // If the fetcher has a challenge block, simulate a challenge. + // + // It might be nice to eventually let the user determine which testBlock + // fetches get challenged rather than always executing the supplied + // challenge block. + if (challengeBlock) { + __auto_type block = ^{ + NSURL *requestURL = self->_request.URL; + NSString *host = requestURL.host; + NSURLProtectionSpace *pspace = + [[NSURLProtectionSpace alloc] initWithHost:host + port:requestURL.port.integerValue + protocol:requestURL.scheme + realm:nil + authenticationMethod:NSURLAuthenticationMethodHTTPBasic]; + id unusedSender = + (id)[NSNull null]; + NSURLAuthenticationChallenge *challenge = + [[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:pspace + proposedCredential:nil + previousFailureCount:0 + failureResponse:nil + error:nil + sender:unusedSender]; + challengeBlock(self, challenge, + ^(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential *_Nullable credential){ + // We could change the + // responseData and responseError + // based on the disposition, + // but it's easier for apps to + // just supply the expected data + // and error + // directly to the test block. So + // this simulation ignores the + // disposition. + }); + }; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES block:block]; + } + + // Simulate receipt of an initial response. + if (response && didReceiveResponseBlock) { + __auto_type block = ^{ + didReceiveResponseBlock(response, ^(NSURLSessionResponseDisposition desiredDisposition){ + // For simulation, we'll assume + // the disposition is to continue. + }); + }; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES block:block]; + } + + // Simulate reporting send progress. + if (sendProgressBlock) { + __auto_type block = + ^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) { + // This is invoked on the callback queue unless + // stopped. + sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpectedToSend); + }; + [self simulateByteTransferReportWithDataLength:(int64_t)bodyData.length block:block]; + } + + if (destinationFileURL) { + // Simulate download to file progress. + if (downloadProgressBlock) { + __auto_type block = ^(int64_t bytesDownloaded, int64_t totalBytesDownloaded, + int64_t totalBytesExpectedToDownload) { + // This is invoked on the callback queue unless + // stopped. + downloadProgressBlock(bytesDownloaded, totalBytesDownloaded, + totalBytesExpectedToDownload); + }; + [self simulateByteTransferReportWithDataLength:(int64_t)responseData.length block:block]; + } + + NSError *writeError; + [responseData writeToURL:destinationFileURL options:NSDataWritingAtomic error:&writeError]; + if (writeError) { + // Tell the test code that writing failed. + responseError = writeError; + } + } else { + // Simulate download to NSData progress. + if ((accumulateDataBlock || receivedProgressBlock) && responseData) { + __auto_type block = ^(NSData *data, int64_t bytesReceived, int64_t totalBytesReceived, + int64_t totalBytesExpectedToReceive) { + // This is invoked on the callback queue unless stopped. + if (accumulateDataBlock) { + accumulateDataBlock(data); + } + + if (receivedProgressBlock) { + receivedProgressBlock(bytesReceived, totalBytesReceived); + } + }; + [self simulateByteTransferWithData:responseData block:block]; + } + + if (!accumulateDataBlock) { + _downloadedData = [responseData mutableCopy]; + } + + if (willCacheURLResponseBlock) { + // Simulate letting the client inspect and alter the cached response. + NSData *cachedData = responseData ?: [[NSData alloc] init]; // Always have non-nil data. + NSCachedURLResponse *cachedResponse = + [[NSCachedURLResponse alloc] initWithResponse:response data:cachedData]; + __auto_type block = ^{ + willCacheURLResponseBlock(cachedResponse, ^(NSCachedURLResponse *responseToCache){ + // The app may provide an + // alternative response, or + // nil to defeat caching. + }); + }; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES block:block]; + } + } + _response = response; + } // @synchronized(self) + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + // Rather than invoke failToBeginFetchWithError: we want to simulate completion of + // a connection that started and ended, so we'll call down to finishWithError: + NSInteger status = responseError ? responseError.code : 200; + if (status >= 200 && status <= 399) { + [self finishWithError:nil shouldRetry:NO]; + } else { + [self shouldRetryNowForStatus:status + error:responseError + forceAssumeRetry:NO + response:^(BOOL shouldRetry) { + [self finishWithError:responseError shouldRetry:shouldRetry]; + }]; + } + }]; +} + +- (void)simulateByteTransferWithData:(NSData *)responseData + block:(GTMSessionFetcherSimulateByteTransferBlock)transferBlock { + // This utility method simulates transfering data to the client. It divides the data into at most + // "chunkCount" chunks and then passes each chunk along with a progress update to transferBlock. + // This function can be used with accumulateDataBlock or receivedProgressBlock. + + NSUInteger chunkCount = MAX(self.testBlockAccumulateDataChunkCount, (NSUInteger)1); + NSUInteger totalDataLength = responseData.length; + NSUInteger sendDataSize = totalDataLength / chunkCount + 1; + NSUInteger totalSent = 0; + while (totalSent < totalDataLength) { + NSUInteger bytesRemaining = totalDataLength - totalSent; + sendDataSize = MIN(sendDataSize, bytesRemaining); + NSData *chunkData = [responseData subdataWithRange:NSMakeRange(totalSent, sendDataSize)]; + totalSent += sendDataSize; + [self invokeOnCallbackQueueUnlessStopped:^{ + transferBlock(chunkData, (int64_t)sendDataSize, (int64_t)totalSent, (int64_t)totalDataLength); + }]; + } +} + +#endif // !GTM_DISABLE_FETCHER_TEST_BLOCK + +- (void)setSessionTask:(NSURLSessionTask *)sessionTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionTask != sessionTask) { + _sessionTask = sessionTask; + if (_sessionTask) { + // Request could be nil on restoring this fetcher from a background session. + if (!_request) { + _request = [_sessionTask.originalRequest mutableCopy]; + } + } + } + } // @synchronized(self) +} + +- (nullable NSURLSessionTask *)sessionTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionTask; + } // @synchronized(self) +} + ++ (NSUserDefaults *)fetcherUserDefaults { + static NSUserDefaults *gFetcherUserDefaults = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class fetcherUserDefaultsClass = NSClassFromString(@"GTMSessionFetcherUserDefaultsFactory"); + if (fetcherUserDefaultsClass) { + gFetcherUserDefaults = [fetcherUserDefaultsClass fetcherUserDefaults]; + } else { + gFetcherUserDefaults = [NSUserDefaults standardUserDefaults]; + } + }); + return gFetcherUserDefaults; +} + +- (void)addPersistedBackgroundSessionToDefaults { + NSString *sessionIdentifier = self.sessionIdentifier; + if (!sessionIdentifier) { + return; + } + NSArray *oldBackgroundSessions = [[self class] activePersistedBackgroundSessions]; + if ([oldBackgroundSessions containsObject:_sessionIdentifier]) { + return; + } + NSMutableArray *newBackgroundSessions = [NSMutableArray arrayWithArray:oldBackgroundSessions]; + [newBackgroundSessions addObject:sessionIdentifier]; + GTM_LOG_BACKGROUND_SESSION(@"Add to background sessions: %@", newBackgroundSessions); + + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + [userDefaults setObject:newBackgroundSessions forKey:kGTMSessionFetcherPersistedDestinationKey]; + [userDefaults synchronize]; +} + +- (void)removePersistedBackgroundSessionFromDefaults { + NSString *sessionIdentifier = self.sessionIdentifier; + if (!sessionIdentifier) return; + + NSArray *oldBackgroundSessions = [[self class] activePersistedBackgroundSessions]; + if (!oldBackgroundSessions) { + return; + } + NSMutableArray *newBackgroundSessions = [NSMutableArray arrayWithArray:oldBackgroundSessions]; + NSUInteger sessionIndex = [newBackgroundSessions indexOfObject:sessionIdentifier]; + if (sessionIndex == NSNotFound) { + return; + } + [newBackgroundSessions removeObjectAtIndex:sessionIndex]; + GTM_LOG_BACKGROUND_SESSION(@"Remove from background sessions: %@", newBackgroundSessions); + + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + if (newBackgroundSessions.count == 0) { + [userDefaults removeObjectForKey:kGTMSessionFetcherPersistedDestinationKey]; + } else { + [userDefaults setObject:newBackgroundSessions forKey:kGTMSessionFetcherPersistedDestinationKey]; + } + [userDefaults synchronize]; +} + ++ (nullable NSArray *)activePersistedBackgroundSessions { + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + NSArray *oldBackgroundSessions = + [userDefaults arrayForKey:kGTMSessionFetcherPersistedDestinationKey]; + if (oldBackgroundSessions.count == 0) { + return nil; + } + NSMutableArray *activeBackgroundSessions = nil; + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + for (NSString *sessionIdentifier in oldBackgroundSessions) { + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (fetcher) { + if (!activeBackgroundSessions) { + activeBackgroundSessions = [[NSMutableArray alloc] init]; + } + [activeBackgroundSessions addObject:sessionIdentifier]; + } + } + return activeBackgroundSessions; +} + ++ (NSArray *)fetchersForBackgroundSessions { + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + NSArray *backgroundSessions = + [userDefaults arrayForKey:kGTMSessionFetcherPersistedDestinationKey]; + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + NSMutableArray *fetchers = [NSMutableArray array]; + for (NSString *sessionIdentifier in backgroundSessions) { + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (!fetcher) { + fetcher = [self fetcherWithSessionIdentifier:sessionIdentifier]; + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"Unexpected invalid session identifier: %@", + sessionIdentifier); + if (!fetcher.clientWillReconnectBackgroundSession) { + [fetcher beginFetchWithCompletionHandler:nil]; + } + } + GTM_LOG_BACKGROUND_SESSION(@"%@ restoring session %@ by creating fetcher %@ %p", [self class], + sessionIdentifier, fetcher, fetcher); + if (fetcher != nil) { + [fetchers addObject:fetcher]; + } + } + return fetchers; +} + +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH ++ (void)application:(UIApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler + GTM_SWIFT_DISABLE_ASYNC { + GTMSessionFetcher *fetcher = [self fetcherWithSessionIdentifier:identifier]; + if (fetcher != nil) { + fetcher.systemCompletionHandler = completionHandler; + } else { + GTM_LOG_BACKGROUND_SESSION(@"%@ did not create background session identifier: %@", [self class], + identifier); + } +} +#endif + +- (nullable NSString *)sessionIdentifier { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionIdentifier; + } // @synchronized(self) +} + +- (void)setSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(!_session, @"Unable to set session identifier after session created"); + _sessionIdentifier = [sessionIdentifier copy]; + _usingBackgroundSession = YES; + _canShareSession = NO; + [self restoreDefaultStateForSessionIdentifierMetadata]; + } // @synchronized(self) +} + +- (void)setSessionIdentifierInternal:(nullable NSString *)sessionIdentifier { + // This internal method only does a synchronized set of the session identifier. + // It does not have side effects on the background session, shared session, or + // session identifier metadata. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _sessionIdentifier = [sessionIdentifier copy]; + } // @synchronized(self) +} + +- (nullable NSDictionary *)sessionUserInfo { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionUserInfo == nil) { + // We'll return the metadata dictionary with internal keys removed. This avoids the user + // re-using the userInfo dictionary later and accidentally including the internal keys. + NSMutableDictionary *metadata = [[self sessionIdentifierMetadataUnsynchronized] mutableCopy]; + NSSet *keysToRemove = [metadata keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) { + return [key hasPrefix:@"_"]; + }]; + [metadata removeObjectsForKeys:[keysToRemove allObjects]]; + if (metadata.count > 0) { + _sessionUserInfo = metadata; + } + } + return _sessionUserInfo; + } // @synchronized(self) +} + +- (void)setSessionUserInfo:(nullable NSDictionary *)dictionary { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(_sessionIdentifier == nil, @"Too late to assign userInfo"); + _sessionUserInfo = dictionary; + } // @synchronized(self) +} + +- (nullable NSDictionary *)sessionIdentifierDefaultMetadata { + GTMSessionCheckSynchronized(self); + + NSMutableDictionary *defaultUserInfo = [[NSMutableDictionary alloc] init]; + if (_destinationFileURL) { + defaultUserInfo[kGTMSessionIdentifierDestinationFileURLMetadataKey] = + [_destinationFileURL absoluteString]; + } + if (_bodyFileURL) { + defaultUserInfo[kGTMSessionIdentifierBodyFileURLMetadataKey] = [_bodyFileURL absoluteString]; + } + if (_clientWillReconnectBackgroundSession) { + defaultUserInfo[kGTMSessionIdentifierClientReconnectMetadataKey] = @"YES"; + } + return (defaultUserInfo.count > 0) ? defaultUserInfo : nil; +} + +- (void)restoreDefaultStateForSessionIdentifierMetadata { + GTMSessionCheckSynchronized(self); + + NSDictionary *metadata = [self sessionIdentifierMetadataUnsynchronized]; + NSString *destinationFileURLString = metadata[kGTMSessionIdentifierDestinationFileURLMetadataKey]; + if (destinationFileURLString) { + _destinationFileURL = [NSURL URLWithString:destinationFileURLString]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring destination file URL: %@", _destinationFileURL); + } + NSString *bodyFileURLString = metadata[kGTMSessionIdentifierBodyFileURLMetadataKey]; + if (bodyFileURLString) { + _bodyFileURL = [NSURL URLWithString:bodyFileURLString]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring body file URL: %@", _bodyFileURL); + } + NSString *clientReconnectString = metadata[kGTMSessionIdentifierClientReconnectMetadataKey]; + if (clientReconnectString) { + _clientWillReconnectBackgroundSession = [clientReconnectString boolValue]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring clientWillReconnectBackgroundSession: %@", + (_clientWillReconnectBackgroundSession ? @"YES" : @"NO")); + } +} + +- (nullable NSDictionary *)sessionIdentifierMetadata { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [self sessionIdentifierMetadataUnsynchronized]; + } +} + +- (nullable NSDictionary *)sessionIdentifierMetadataUnsynchronized { + GTMSessionCheckSynchronized(self); + + // Session Identifier format: "com.google.__ + if (!_sessionIdentifier) { + return nil; + } + NSScanner *metadataScanner = [NSScanner scannerWithString:_sessionIdentifier]; + [metadataScanner setCharactersToBeSkipped:nil]; + NSString *metadataString; + NSString *uuid; + if ([metadataScanner scanUpToString:@"_" intoString:NULL] && + [metadataScanner scanString:@"_" intoString:NULL] && + [metadataScanner scanUpToString:@"_" intoString:&uuid] && + [metadataScanner scanString:@"_" intoString:NULL] && + [metadataScanner scanUpToString:@"\n" intoString:&metadataString]) { + _sessionIdentifierUUID = uuid; + NSData *metadataData = [metadataString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *error; + NSDictionary *metadataDict = [NSJSONSerialization JSONObjectWithData:metadataData + options:0 + error:&error]; + GTM_LOG_BACKGROUND_SESSION(@"User Info from session identifier: %@ %@", metadataDict, + error ? error : @""); + return metadataDict; + } + return nil; +} + +- (NSString *)createSessionIdentifierWithMetadata:(nullable NSDictionary *)metadataToInclude { + NSString *result; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Session Identifier format: "com.google.__ + GTMSESSION_ASSERT_DEBUG(!_sessionIdentifier, @"Session identifier already created"); + _sessionIdentifierUUID = [[NSUUID UUID] UUIDString]; + _sessionIdentifier = + [NSString stringWithFormat:@"%@_%@", kGTMSessionIdentifierPrefix, _sessionIdentifierUUID]; + // Start with user-supplied keys so they cannot accidentally override the fetcher's keys. + NSMutableDictionary *metadataDict = + [NSMutableDictionary dictionaryWithDictionary:(NSDictionary *_Nonnull)_sessionUserInfo]; + + if (metadataToInclude) { + [metadataDict addEntriesFromDictionary:(NSDictionary *)metadataToInclude]; + } + NSDictionary *defaultMetadataDict = [self sessionIdentifierDefaultMetadata]; + if (defaultMetadataDict) { + [metadataDict addEntriesFromDictionary:defaultMetadataDict]; + } + if (metadataDict.count > 0) { + NSData *metadataData = [NSJSONSerialization dataWithJSONObject:metadataDict + options:0 + error:NULL]; + GTMSESSION_ASSERT_DEBUG(metadataData != nil, + @"Session identifier user info failed to convert to JSON"); + if (metadataData.length > 0) { + NSString *metadataString = [[NSString alloc] initWithData:metadataData + encoding:NSUTF8StringEncoding]; + _sessionIdentifier = [_sessionIdentifier stringByAppendingFormat:@"_%@", metadataString]; + } + } + _didCreateSessionIdentifier = YES; + result = _sessionIdentifier; + } // @synchronized(self) + return result; +} + +- (void)failToBeginFetchWithError:(NSError *)error { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _hasStoppedFetching = YES; + } + + if (error == nil) { + error = [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorDownloadFailed + userInfo:nil]; + } + + [self invokeFetchCallbacksOnCallbackQueueWithData:nil + error:error + mayDecorate:YES + shouldReleaseCallbacks:YES]; + + [_service fetcherDidStop:self]; + + self.authorizer = nil; +} + ++ (GTMSessionCookieStorage *)staticCookieStorage { + static GTMSessionCookieStorage *gCookieStorage = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gCookieStorage = [[GTMSessionCookieStorage alloc] init]; + }); + return gCookieStorage; +} + +#if GTM_BACKGROUND_TASK_FETCHING + +- (void)endBackgroundTask { + // Whenever the connection stops or background execution expires, + // we need to tell UIApplication we're done. + UIBackgroundTaskIdentifier bgTaskID; + @synchronized(self) { + bgTaskID = self.backgroundTaskIdentifier; + if (bgTaskID != UIBackgroundTaskInvalid) { + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + } + + if (bgTaskID != UIBackgroundTaskInvalid) { + id app = [[self class] fetcherUIApplication]; + [app endBackgroundTask:bgTaskID]; + } +} + +#endif // GTM_BACKGROUND_TASK_FETCHING + +- (void)authorizeRequest { + GTMSessionCheckNotSynchronized(self); + + id authorizer = self.authorizer; + SEL asyncAuthSel = @selector(authorizeRequest:delegate:didFinishSelector:); + if ([authorizer respondsToSelector:asyncAuthSel]) { + SEL callbackSel = @selector(authorizer:request:finishedWithError:); + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + [authorizer authorizeRequest:mutableRequest delegate:self didFinishSelector:callbackSel]; + } else { + GTMSESSION_ASSERT_DEBUG(authorizer == nil, @"invalid authorizer for fetch"); + + // No authorizing possible, and authorizing happens only after any delay; + // just begin fetching + [self beginFetchMayDelay:NO mayAuthorize:NO mayDecorate:YES]; + } +} + +- (void)authorizer:(id)auth + request:(NSMutableURLRequest *)authorizedRequest + finishedWithError:(NSError *)error { + GTMSessionCheckNotSynchronized(self); + + if (error != nil) { + // We can't fetch without authorization + [self failToBeginFetchWithError:error]; + } else { + @synchronized(self) { + _request = authorizedRequest; + } + [self beginFetchMayDelay:NO mayAuthorize:NO mayDecorate:YES]; + } +} + +- (void)applyDecoratorsAtRequestWillStart:(NSArray> *)decorators + startingAtIndex:(NSUInteger)index { + GTMSessionCheckNotSynchronized(self); + if (index >= decorators.count) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher decorate requestWillStart %zu decorators complete", + decorators.count); + [self beginFetchMayDelay:NO mayAuthorize:NO mayDecorate:NO]; + return; + } + + __weak __typeof__(self) weakSelf = self; + id decorator = decorators[index]; + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher decorate requestWillStart %zu decorators, index %zu, " + @"retry count %zu, decorator %@", + decorators.count, index, self.retryCount, decorator); + [decorator fetcherWillStart:self + completionHandler:^(NSURLRequest *_Nullable newRequest, NSError *_Nullable error) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher decorator requestWillStart index %zu " + @"complete, newRequest %@, error %@", + index, newRequest, error); + __strong __typeof__(self) strongSelf = weakSelf; + if (!strongSelf) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher destroyed before requestWillStart " + @"decorators completed, ignoring."); + return; + } + if (error) { + [self failToBeginFetchWithError:(NSError *_Nonnull)error]; + return; + } + if (newRequest) { + // Copying `NSURLRequest` should be cheap, but in case profiling shows this + // operation is prohibitively expensive, this API might need to be changed to allow + // clients to manipulate `self.request` directly. + [strongSelf updateMutableRequest:[newRequest mutableCopy]]; + } + [strongSelf applyDecoratorsAtRequestWillStart:decorators startingAtIndex:index + 1]; + }]; +} + +- (void)applyDecoratorsAtRequestDidFinish:(NSArray> *)decorators + withData:(nullable NSData *)data + error:(nullable NSError *)error + startingAtIndex:(NSUInteger)index + shouldReleaseCallbacks:(BOOL)shouldReleaseCallbacks { + GTMSessionCheckNotSynchronized(self); + if (index >= decorators.count) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher decorate requestDidFinish %zu decorators complete", + decorators.count); + [self invokeFetchCallbacksOnCallbackQueueWithData:data + error:error + mayDecorate:NO + shouldReleaseCallbacks:shouldReleaseCallbacks]; + return; + } + + __weak __typeof__(self) weakSelf = self; + id decorator = decorators[index]; + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher decorate requestDidFinish %zu decorators, index %zu, " + @"retry count %zu, decorator %@", + decorators.count, index, self.retryCount, decorator); + [decorator fetcherDidFinish:self + withData:data + error:error + completionHandler:^{ + GTMSESSION_LOG_DEBUG( + @"GTMSessionFetcher decorator requestDidFinish index %zu complete", index); + __strong __typeof__(self) strongSelf = weakSelf; + if (!strongSelf) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher destroyed before requestDidFinish " + @"decorators completed, ignoring."); + return; + } + [strongSelf applyDecoratorsAtRequestDidFinish:decorators + withData:data + error:error + startingAtIndex:index + 1 + shouldReleaseCallbacks:shouldReleaseCallbacks]; + }]; +} + +- (BOOL)canFetchWithBackgroundSession { + // Subclasses may override. + return YES; +} + +// Returns YES if the fetcher has been started and has not yet stopped. +// +// Fetching includes waiting for authorization or for retry, waiting to be allowed by the +// service object to start the request, and actually fetching the request. +- (BOOL)isFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [self isFetchingUnsynchronized]; + } +} + +- (BOOL)isFetchingUnsynchronized { + GTMSessionCheckSynchronized(self); + + BOOL hasBegun = (_initialBeginFetchDate != nil); + return hasBegun && !_hasStoppedFetching; +} + +- (nullable NSURLResponse *)response { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + return response; + } // @synchronized(self) +} + +- (nullable NSURLResponse *)responseUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = _sessionTask.response; + if (!response) response = _response; + return response; +} + +- (NSInteger)statusCode { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSInteger statusCode = [self statusCodeUnsynchronized]; + return statusCode; + } // @synchronized(self) +} + +- (NSInteger)statusCodeUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + NSInteger statusCode; + + if ([response respondsToSelector:@selector(statusCode)]) { + statusCode = [(NSHTTPURLResponse *)response statusCode]; + } else { + // Default to zero, in hopes of hinting "Unknown" (we can't be + // sure that things are OK enough to use 200). + statusCode = 0; + } + return statusCode; +} + +- (nullable NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + + NSURLResponse *response = self.response; + if ([response respondsToSelector:@selector(allHeaderFields)]) { + NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; + return headers; + } + return nil; +} + +- (nullable NSDictionary *)responseHeadersUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + if ([response respondsToSelector:@selector(allHeaderFields)]) { + NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; + return headers; + } + return nil; +} + +- (void)releaseCallbacks { + // Avoid releasing blocks in the sync section since objects dealloc'd by + // the blocks being released may call back into the fetcher or fetcher + // service. + dispatch_queue_t NS_VALID_UNTIL_END_OF_SCOPE holdCallbackQueue; + GTMSessionFetcherCompletionHandler NS_VALID_UNTIL_END_OF_SCOPE holdCompletionHandler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + holdCallbackQueue = _callbackQueue; + holdCompletionHandler = _completionHandler; + + _callbackQueue = nil; + _completionHandler = nil; // Setter overridden in upload. Setter assumed to be used externally. + } + + // Set local callback pointers to nil here rather than let them release at the end of the scope + // to make any problems due to the blocks being released be a bit more obvious in a stack trace. + holdCallbackQueue = nil; + holdCompletionHandler = nil; + + self.configurationBlock = nil; + self.didReceiveResponseBlock = nil; + self.challengeBlock = nil; + self.willRedirectBlock = nil; + self.sendProgressBlock = nil; + self.receivedProgressBlock = nil; + self.downloadProgressBlock = nil; + self.accumulateDataBlock = nil; + self.willCacheURLResponseBlock = nil; + self.retryBlock = nil; + self.testBlock = nil; + self.resumeDataBlock = nil; + if (@available(iOS 10.0, *)) { + self.metricsCollectionBlock = nil; + } +} + +- (void)forgetSessionIdentifierForFetcher { + GTMSessionCheckSynchronized(self); + [self forgetSessionIdentifierForFetcherWithoutSyncCheck]; +} + +- (void)forgetSessionIdentifierForFetcherWithoutSyncCheck { + // This should be called inside a @synchronized block (except during dealloc.) + if (_sessionIdentifier) { + NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap]; + [sessionIdentifierToFetcherMap removeObjectForKey:_sessionIdentifier]; + _sessionIdentifier = nil; + _didCreateSessionIdentifier = NO; + } +} + +// External stop method +- (void)stopFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Prevent enqueued callbacks from executing. + _userStoppedFetching = YES; + } // @synchronized(self) + [self stopFetchReleasingCallbacks:YES]; +} + +// Cancel the fetch of the URL that's currently in progress. +// +// If shouldReleaseCallbacks is NO then the fetch will be retried so the callbacks +// need to still be retained. +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks { + [self removePersistedBackgroundSessionFromDefaults]; + + id service; + NSMutableURLRequest *request; + + // If the task or the retry timer is all that's retaining the fetcher, + // we want to be sure this instance survives stopping at least long enough for + // the stack to unwind. + __autoreleasing GTMSessionFetcher *holdSelf = self; + + BOOL hasCanceledTask = NO; + + [holdSelf destroyRetryTimer]; + + BOOL sendStopNotification = YES; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _hasStoppedFetching = YES; + + service = _service; + request = _request; + + if (_sessionTask) { + // In case cancelling the task or session calls this recursively, we want + // to ensure that we'll only release the task and delegate once, + // so first set _sessionTask to nil + // + // This may be called in a callback from the task, so use autorelease to avoid + // releasing the task in its own callback. + __autoreleasing NSURLSessionTask *oldTask = _sessionTask; + if (!_isUsingTestBlock) { + _response = _sessionTask.response; + } + _sessionTask = nil; + + if ([oldTask state] != NSURLSessionTaskStateCompleted) { + // For download tasks, when the fetch is stopped, we may provide resume data that can + // be used to create a new session. + BOOL mayResume = (_resumeDataBlock && + [oldTask respondsToSelector:@selector(cancelByProducingResumeData:)]); + if (!mayResume) { + [oldTask cancel]; + // A side effect of stopping the task is that URLSession:task:didCompleteWithError: + // will be invoked asynchronously on the delegate queue. + } else { + void (^resumeBlock)(NSData *) = _resumeDataBlock; + _resumeDataBlock = nil; + + // Save callbackQueue since releaseCallbacks clears it. + dispatch_queue_t callbackQueue = _callbackQueue; + dispatch_group_enter(_callbackGroup); + [(NSURLSessionDownloadTask *)oldTask cancelByProducingResumeData:^(NSData *resumeData) { + [self invokeOnCallbackQueue:callbackQueue + afterUserStopped:YES + block:^{ + resumeBlock(resumeData); + dispatch_group_leave(self->_callbackGroup); + }]; + }]; + } + hasCanceledTask = YES; + } + } + + // If the task was canceled, wait until the URLSession:task:didCompleteWithError: to call + // finishTasksAndInvalidate, since calling it immediately tends to crash, see radar 18471901. + if (_session) { + BOOL shouldInvalidate = _shouldInvalidateSession; +#if TARGET_OS_IPHONE + // Don't invalidate if we've got a systemCompletionHandler, since + // URLSessionDidFinishEventsForBackgroundURLSession: won't be called if invalidated. + shouldInvalidate = shouldInvalidate && !self.systemCompletionHandler; +#endif + if (shouldInvalidate) { + __autoreleasing NSURLSession *oldSession = _session; + _session = nil; + + if (!hasCanceledTask) { + [oldSession finishTasksAndInvalidate]; + } else { + sendStopNotification = NO; + _sessionNeedingInvalidation = oldSession; + } + } + } + } // @synchronized(self) + + // If the NSURLSession needs to be invalidated, but needs to wait until the delegate method + // URLSession:task:didCompleteWithError: is called, delay sending the fetch stopped notification + // until then; otherwise send it now. + if (sendStopNotification) { + [self sendStopNotificationIfNeeded]; + } + + [_authorizer stopAuthorizationForRequest:request]; + + if (shouldReleaseCallbacks) { + [self releaseCallbacks]; + + self.authorizer = nil; + } + + [service fetcherDidStop:self]; + +#if GTM_BACKGROUND_TASK_FETCHING + [self endBackgroundTask]; +#endif +} + +- (void)setStopNotificationNeeded:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _isStopNotificationNeeded = flag; + } // @synchronized(self) +} + +- (void)sendStopNotificationIfNeeded { + BOOL sendNow = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_isStopNotificationNeeded) { + _isStopNotificationNeeded = NO; + sendNow = YES; + } + } // @synchronized(self) + + if (sendNow) { + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherStoppedNotification + userInfo:nil + requireAsync:NO]; + } +} + +- (void)retryFetch { + [self stopFetchReleasingCallbacks:NO]; + + // A retry will need a configuration with a fresh session identifier. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionIdentifier && _didCreateSessionIdentifier) { + [self forgetSessionIdentifierForFetcher]; + _configuration = nil; + } + + if (_canShareSession) { + // Force a grab of the current session from the fetcher service in case + // the service's old one has become invalid. + _session = nil; + } + } // @synchronized(self) + + [self beginFetchForRetry]; +} + +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds { + // Uncovered in upload fetcher testing, because the chunk fetcher is being waited on, and gets + // released by the upload code. The uploader just holds onto it with an ivar, and that gets + // nilled in the chunk fetcher callback. + // Used once in while loop just to avoid unused variable compiler warning. + __autoreleasing GTMSessionFetcher *holdSelf = self; + + NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + + BOOL shouldSpinRunLoop = + ([NSThread isMainThread] && + (!self.callbackQueue || self.callbackQueue == dispatch_get_main_queue())); + BOOL expired = NO; + + // Loop until the callbacks have been called and released, and until + // the connection is no longer pending, until there are no callback dispatches + // in flight, or until the timeout has expired. + int64_t delta = (int64_t)(100 * NSEC_PER_MSEC); // 100 ms + while (1) { + BOOL isTaskInProgress = + (holdSelf->_sessionTask && [_sessionTask state] != NSURLSessionTaskStateCompleted); + BOOL needsToCallCompletion = (_completionHandler != nil); + BOOL isCallbackInProgress = + (_callbackGroup && + dispatch_group_wait(_callbackGroup, dispatch_time(DISPATCH_TIME_NOW, delta))); + + if (!isTaskInProgress && !needsToCallCompletion && !isCallbackInProgress) break; + + expired = ([giveUpDate timeIntervalSinceNow] < 0); + if (expired) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher waitForCompletionWithTimeout:%0.1f expired -- " + @"%@%@%@", + timeoutInSeconds, isTaskInProgress ? @"taskInProgress " : @"", + needsToCallCompletion ? @"needsToCallCompletion " : @"", + isCallbackInProgress ? @"isCallbackInProgress" : @""); + break; + } + + // Run the current run loop 1/1000 of a second to give the networking + // code a chance to work + const NSTimeInterval kSpinInterval = 0.001; + if (shouldSpinRunLoop) { + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:kSpinInterval]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + [NSThread sleepForTimeInterval:kSpinInterval]; + } + } + return !expired; +} + ++ (void)setGlobalTestBlock:(nullable GTMSessionFetcherTestBlock)block { +#if GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSESSION_ASSERT_DEBUG(block == nil, @"test blocks disabled"); +#endif + gGlobalTestBlock = [block copy]; +} + +#if GTM_BACKGROUND_TASK_FETCHING + +static _Nullable id gSubstituteUIApp; + ++ (void)setSubstituteUIApplication:(nullable id)app { + gSubstituteUIApp = app; +} + ++ (nullable id)substituteUIApplication { + return gSubstituteUIApp; +} + ++ (nullable id)fetcherUIApplication { + id app = gSubstituteUIApp; + if (app) return app; + + // iOS App extensions should not call [UIApplication sharedApplication], even + // if UIApplication responds to it. + + static Class applicationClass = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + BOOL isAppExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + if (!isAppExtension) { + Class cls = NSClassFromString(@"UIApplication"); + if (cls && [cls respondsToSelector:NSSelectorFromString(@"sharedApplication")]) { + applicationClass = cls; + } + } + }); + + if (applicationClass) { + app = (id)[applicationClass sharedApplication]; + } + return app; +} +#endif // GTM_BACKGROUND_TASK_FETCHING + +#pragma mark NSURLSession Delegate Methods + +// NSURLSession documentation indicates that redirectRequest can be passed to the handler +// but empirically redirectRequest lacks the HTTP body, so passing it will break POSTs. +// Instead, we construct a new request, a copy of the original, with overrides from the +// redirect. + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)redirectResponse + newRequest:(NSURLRequest *)redirectRequest + completionHandler:(void (^)(NSURLRequest *_Nullable))handler { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE( + @"%@ %p URLSession:%@ task:%@ willPerformHTTPRedirection:%@ newRequest:%@", [self class], + self, session, task, redirectResponse, redirectRequest); + + if ([self userStoppedFetching]) { + handler(nil); + return; + } + if (redirectRequest && redirectResponse) { + // Copy the original request, including the body. + NSURLRequest *originalRequest = self.request; + NSMutableURLRequest *newRequest = [originalRequest mutableCopy]; + + // The new requests's URL overrides the original's URL. + [newRequest setURL:[GTMSessionFetcher redirectURLWithOriginalRequestURL:originalRequest.URL + redirectRequestURL:redirectRequest.URL]]; + + // Any headers in the redirect override headers in the original. + NSDictionary *redirectHeaders = redirectRequest.allHTTPHeaderFields; + for (NSString *key in redirectHeaders) { + NSString *value = [redirectHeaders objectForKey:key]; + [newRequest setValue:value forHTTPHeaderField:key]; + } + + redirectRequest = newRequest; + + // Log the response we just received + [self setResponse:redirectResponse]; + [self logNowWithError:nil]; + + GTMSessionFetcherWillRedirectBlock willRedirectBlock = self.willRedirectBlock; + if (willRedirectBlock) { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + __auto_type block = ^{ + willRedirectBlock(redirectResponse, redirectRequest, ^(NSURLRequest *clientRequest) { + // Update the request for future logging. + [self updateMutableRequest:[clientRequest mutableCopy]]; + + handler(clientRequest); + }); + }; + [self invokeOnCallbackQueueAfterUserStopped:YES block:block]; + } // @synchronized(self) + return; + } + // Continues here if the client did not provide a redirect block. + + // Update the request for future logging. + [self updateMutableRequest:[redirectRequest mutableCopy]]; + } + handler(redirectRequest); +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))handler { + [self setSessionTask:dataTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didReceiveResponse:%@", [self class], + self, session, dataTask, response); + __auto_type accumulateAndFinish = ^(NSURLSessionResponseDisposition dispositionValue) { + // This method is called when the server has determined that it + // has enough information to create the NSURLResponse + // it can be called multiple times, for example in the case of a + // redirect, so each time we reset the data. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL hadPreviousData = self->_downloadedLength > 0; + + [self->_downloadedData setLength:0]; + self->_downloadedLength = 0; + + if (hadPreviousData && (dispositionValue != NSURLSessionResponseCancel)) { + // Tell the accumulate block to discard prior data. + GTMSessionFetcherAccumulateDataBlock accumulateBlock = self->_accumulateDataBlock; + if (accumulateBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateBlock(nil); + }]; + } + } + } // @synchronized(self) + handler(dispositionValue); + }; + + GTMSessionFetcherDidReceiveResponseBlock receivedResponseBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + receivedResponseBlock = _didReceiveResponseBlock; + if (receivedResponseBlock) { + // We will ultimately need to call back to NSURLSession's handler with the disposition value + // for this delegate method even if the user has stopped the fetcher. + __auto_type block = ^{ + receivedResponseBlock(response, ^(NSURLSessionResponseDisposition desiredDisposition) { + accumulateAndFinish(desiredDisposition); + }); + }; + [self invokeOnCallbackQueueAfterUserStopped:YES block:block]; + } + } // @synchronized(self) + + if (receivedResponseBlock == nil) { + accumulateAndFinish(NSURLSessionResponseAllow); + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didBecomeDownloadTask:%@", + [self class], self, session, dataTask, downloadTask); + [self setSessionTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential *_Nullable credential))handler { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didReceiveChallenge:%@", [self class], + self, session, task, challenge); + + GTMSessionFetcherChallengeBlock challengeBlock = self.challengeBlock; + if (challengeBlock) { + // The fetcher user has provided custom challenge handling. + // + // We will ultimately need to call back to NSURLSession's handler with the disposition value + // for this delegate method even if the user has stopped the fetcher. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + challengeBlock(self, challenge, handler); + }]; + } + } else { + // No challenge block was provided by the client. + [self respondToChallenge:challenge completionHandler:handler]; + } +} + +- (void)respondToChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential *_Nullable credential))handler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSInteger previousFailureCount = [challenge previousFailureCount]; + if (previousFailureCount <= 2) { + NSURLProtectionSpace *protectionSpace = [challenge protectionSpace]; + NSString *authenticationMethod = [protectionSpace authenticationMethod]; + if ([authenticationMethod isEqual:NSURLAuthenticationMethodServerTrust]) { + // SSL. + // + // Background sessions seem to require an explicit check of the server trust object + // rather than default handling. + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + if (serverTrust == NULL) { + // No server trust information is available. + handler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } else { + // Server trust information is available. + __auto_type callback = ^(SecTrustRef trustRef, BOOL allow) { + if (allow) { + NSURLCredential *trustCredential = [NSURLCredential credentialForTrust:trustRef]; + handler(NSURLSessionAuthChallengeUseCredential, trustCredential); + } else { + GTMSESSION_LOG_DEBUG(@"Cancelling authentication challenge for %@", + self->_request.URL); + handler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + }; + if (_allowInvalidServerCertificates) { + callback(serverTrust, YES); + } else { + [[self class] evaluateServerTrust:serverTrust + forRequest:_request + completionHandler:callback]; + } + } + return; + } + + NSURLCredential *credential = _credential; + + if ([[challenge protectionSpace] isProxy] && _proxyCredential != nil) { + credential = _proxyCredential; + } + + if (credential) { + handler(NSURLSessionAuthChallengeUseCredential, credential); + } else { + // The credential is still nil; tell the OS to use the default handling. This is needed + // for things that can come out of the keychain (proxies, client certificates, etc.). + // + // Note: Looking up a credential with NSURLCredentialStorage's + // defaultCredentialForProtectionSpace: is *not* the same invoking the handler with + // NSURLSessionAuthChallengePerformDefaultHandling. In the case of + // NSURLAuthenticationMethodClientCertificate, you can get nil back from + // NSURLCredentialStorage, while using this code path instead works. + handler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } + + } else { + // We've failed auth 3 times. The completion handler will be called with code + // NSURLErrorCancelled. + handler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + } // @synchronized(self) +} + +// Return redirect URL based on the original request URL and redirect request URL. +// +// Method disallows any scheme changes between the original request URL and redirect request URL +// aside from "http" to "https". If a change in scheme is detected the redirect URL inherits the +// scheme from the original request URL. ++ (nullable NSURL *)redirectURLWithOriginalRequestURL:(nullable NSURL *)originalRequestURL + redirectRequestURL:(nullable NSURL *)redirectRequestURL { + // In the case of an NSURLSession redirect, neither URL should ever be nil; as a sanity check + // if either is nil return the other URL. + if (!redirectRequestURL) return originalRequestURL; + if (!originalRequestURL) return redirectRequestURL; + + NSString *originalScheme = originalRequestURL.scheme; + NSString *redirectScheme = redirectRequestURL.scheme; + BOOL insecureToSecureRedirect = + (originalScheme != nil && [originalScheme caseInsensitiveCompare:@"http"] == NSOrderedSame && + redirectScheme != nil && [redirectScheme caseInsensitiveCompare:@"https"] == NSOrderedSame); + + // This can't really be nil for the inputs, but to keep the analyzer happy + // for the -caseInsensitiveCompare: call below, give it a value if it were. + if (!originalScheme) originalScheme = @"https"; + + // Check for changes to the scheme and disallow any changes except for http to https. + if (!insecureToSecureRedirect && + (redirectScheme.length != originalScheme.length || + [redirectScheme caseInsensitiveCompare:originalScheme] != NSOrderedSame)) { + NSURLComponents *components = + [NSURLComponents componentsWithURL:(NSURL *_Nonnull)redirectRequestURL + resolvingAgainstBaseURL:NO]; + components.scheme = originalScheme; + return components.URL; + } + + return redirectRequestURL; +} + +// Validate the certificate chain. +// +// This may become a public method if it appears to be useful to users. ++ (void)evaluateServerTrust:(SecTrustRef)serverTrust + forRequest:(NSURLRequest *)request + completionHandler:(void (^)(SecTrustRef trustRef, BOOL allow))handler { + // Retain the trust object to avoid a SecTrustEvaluate() crash on iOS 7. + CFRetain(serverTrust); + + // Evaluate the certificate chain. + // + // The delegate queue may be the main thread. Trust evaluation could cause some + // blocking network activity, so we must evaluate async, as documented at + // https://developer.apple.com/library/ios/technotes/tn2232/ + // + // We must also avoid multiple uses of the trust object, per docs: + // "It is not safe to call this function concurrently with any other function that uses + // the same trust management object, or to re-enter this function for the same trust + // management object." + // + // SecTrustEvaluateAsync both does sync execution of Evaluate and calls back on the + // queue passed to it, according to at sources in + // http://www.opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-55050.9/lib/SecTrust.cpp + // It would require a global serial queue to ensure the evaluate happens only on a + // single thread at a time, so we'll stick with using SecTrustEvaluate on a background + // thread. + dispatch_queue_t evaluateBackgroundQueue = + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(evaluateBackgroundQueue, ^{ + // It looks like the implementation of SecTrustEvaluate() on Mac grabs a global lock, + // so it may be redundant for us to also lock, but it's easy to synchronize here + // anyway. + BOOL shouldAllow; +#if GTM_SDK_REQUIRES_SECTRUSTEVALUATEWITHERROR + CFErrorRef errorRef = NULL; + @synchronized([GTMSessionFetcher class]) { + GTMSessionMonitorSynchronized([GTMSessionFetcher class]); + + // SecTrustEvaluateWithError handles both the "proceed" and "unspecified" cases, + // so it is not necessary to check the trust result the evaluation returns true. + shouldAllow = SecTrustEvaluateWithError(serverTrust, &errorRef); + } + + if (errorRef) { + GTMSESSION_LOG_DEBUG(@"Error %d evaluating trust for %@", (int)CFErrorGetCode(errorRef), + request); + CFRelease(errorRef); + } +#else + SecTrustResultType trustEval = kSecTrustResultInvalid; + OSStatus trustError; + @synchronized([GTMSessionFetcher class]) { + GTMSessionMonitorSynchronized([GTMSessionFetcher class]); + + trustError = SecTrustEvaluate(serverTrust, &trustEval); + } + if (trustError != errSecSuccess) { + GTMSESSION_LOG_DEBUG(@"Error %d evaluating trust for %@", + (int)trustError, request); + shouldAllow = NO; + } else { + // Having a trust level "unspecified" by the user is the usual result, described at + // https://developer.apple.com/library/mac/qa/qa1360 + if (trustEval == kSecTrustResultUnspecified + || trustEval == kSecTrustResultProceed) { + shouldAllow = YES; + } else { + shouldAllow = NO; + GTMSESSION_LOG_DEBUG(@"Challenge SecTrustResultType %u for %@, properties: %@", + trustEval, request.URL.host, + CFBridgingRelease(SecTrustCopyProperties(serverTrust))); + } + } +#endif // GTM_SDK_REQUIRES_SECTRUSTEVALUATEWITHERROR + handler(serverTrust, shouldAllow); + + CFRelease(serverTrust); + }); +} + +- (void)invokeOnCallbackQueueUnlessStopped:(void (^)(void))block { + [self invokeOnCallbackQueueAfterUserStopped:NO block:block]; +} + +- (void)invokeOnCallbackQueueAfterUserStopped:(BOOL)afterStopped block:(void (^)(void))block { + GTMSessionCheckSynchronized(self); + + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:afterStopped block:block]; +} + +- (void)invokeOnCallbackUnsynchronizedQueueAfterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + // testBlock simulation code may not be synchronizing when this is invoked. + [self invokeOnCallbackQueue:_callbackQueue afterUserStopped:afterStopped block:block]; +} + +- (void)invokeOnCallbackQueue:(dispatch_queue_t)callbackQueue + afterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + if (callbackQueue) { + dispatch_group_async(_callbackGroup, callbackQueue, ^{ + if (!afterStopped) { + NSDate *serviceStoppedAllDate = [self->_service stoppedAllFetchersDate]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Avoid a race between stopFetching and the callback. + if (self->_userStoppedFetching) { + return; + } + + // Also avoid calling back if the service has stopped all fetchers + // since this one was created. The fetcher may have stopped before + // stopAllFetchers was invoked, so _userStoppedFetching wasn't set, + // but the app still won't expect the callback to fire after + // the service's stopAllFetchers was invoked. + if (serviceStoppedAllDate && + [self->_initialBeginFetchDate compare:serviceStoppedAllDate] != NSOrderedDescending) { + // stopAllFetchers was called after this fetcher began. + return; + } + } // @synchronized(self) + } + block(); + }); + } +} + +- (void)invokeFetchCallbacksOnCallbackQueueWithData:(nullable NSData *)data + error:(nullable NSError *)error + mayDecorate:(BOOL)mayDecorate + shouldReleaseCallbacks:(BOOL)shouldReleaseCallbacks { + if (mayDecorate && [_service respondsToSelector:@selector(decorators)]) { + NSArray> *decorators = _service.decorators; + if (decorators.count) { + [self applyDecoratorsAtRequestDidFinish:decorators + withData:data + error:error + startingAtIndex:0 + shouldReleaseCallbacks:shouldReleaseCallbacks]; + return; + } + } + + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher invoking fetch callbacks, data %@, error %@", data, + error); + + // Callbacks will be released in the method stopFetchReleasingCallbacks: + GTMSessionFetcherCompletionHandler handler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + handler = _completionHandler; + + if (handler) { + [self invokeOnCallbackQueueUnlessStopped:^{ + handler(data, error); + + // Post a notification, primarily to allow code to collect responses for + // testing. + // + // The observing code is not likely on the fetcher's callback + // queue, so this posts explicitly to the main queue. + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (data) { + userInfo[kGTMSessionFetcherCompletionDataKey] = data; + } + if (error) { + userInfo[kGTMSessionFetcherCompletionErrorKey] = error; + } + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherCompletionInvokedNotification + userInfo:userInfo + requireAsync:NO]; + }]; + } + } // @synchronized(self) + + if (shouldReleaseCallbacks) { + [self releaseCallbacks]; + } +} + +- (void)postNotificationOnMainThreadWithName:(NSString *)noteName + userInfo:(nullable NSDictionary *)userInfo + requireAsync:(BOOL)requireAsync { + dispatch_block_t postBlock = ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:noteName + object:self + userInfo:userInfo]; + }; + + if ([NSThread isMainThread] && !requireAsync) { + // Post synchronously for compatibility with older code using the fetcher. + + // Avoid calling out to other code from inside a sync block to avoid risk + // of a deadlock or of recursive sync. + GTMSessionCheckNotSynchronized(self); + + postBlock(); + } else { + dispatch_async(dispatch_get_main_queue(), postBlock); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)uploadTask + needNewBodyStream:(void (^)(NSInputStream *_Nullable bodyStream))completionHandler { + [self setSessionTask:uploadTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ needNewBodyStream:", [self class], self, + session, uploadTask); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSessionFetcherBodyStreamProvider provider = _bodyStreamProvider; +#if !STRIP_GTM_FETCH_LOGGING + if ([self respondsToSelector:@selector(loggedStreamProviderForStreamProvider:)]) { + provider = [self performSelector:@selector(loggedStreamProviderForStreamProvider:) + withObject:provider]; + } +#endif + if (provider) { + [self invokeOnCallbackQueueUnlessStopped:^{ + provider(completionHandler); + }]; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"NSURLSession expects a stream provider"); + + completionHandler(nil); + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didSendBodyData:%lld" + @" totalBytesSent:%lld totalBytesExpectedToSend:%lld", + [self class], self, session, task, bytesSent, totalBytesSent, + totalBytesExpectedToSend); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (!_sendProgressBlock) { + return; + } + // We won't hold on to send progress block; it's ok to not send it if the upload finishes. + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherSendProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = self->_sendProgressBlock; + } + if (progressBlock) { + progressBlock(bytesSent, totalBytesSent, totalBytesExpectedToSend); + } + }]; + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + [self setSessionTask:dataTask]; + NSUInteger bufferLength = data.length; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ didReceiveData:%p (%llu bytes)", + [self class], self, session, dataTask, data, + (unsigned long long)bufferLength); + if (bufferLength == 0) { + // Observed on completing an out-of-process upload. + return; + } + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSessionFetcherAccumulateDataBlock accumulateBlock = _accumulateDataBlock; + if (accumulateBlock) { + // Let the client accumulate the data. + _downloadedLength += bufferLength; + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateBlock(data); + }]; + } else if (!_userStoppedFetching) { + // Append to the mutable data buffer unless the fetch has been cancelled. + + // Resumed upload tasks may not yet have a data buffer. + if (_downloadedData == nil) { + // Using NSClassFromString for iOS 6 compatibility. + GTMSESSION_ASSERT_DEBUG( + ![dataTask isKindOfClass:NSClassFromString(@"NSURLSessionDownloadTask")], + @"Resumed download tasks should not receive data bytes"); + _downloadedData = [[NSMutableData alloc] init]; + } + + [_downloadedData appendData:data]; + _downloadedLength = (int64_t)_downloadedData.length; + + // We won't hold on to receivedProgressBlock here; it's ok to not send + // it if the transfer finishes. + if (_receivedProgressBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherReceivedProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = self->_receivedProgressBlock; + } + if (progressBlock) { + progressBlock((int64_t)bufferLength, self->_downloadedLength); + } + }]; + } + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler + GTM_SWIFT_DISABLE_ASYNC { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ dataTask:%@ willCacheResponse:%@ %@", [self class], + self, session, dataTask, proposedResponse, proposedResponse.response); + GTMSessionFetcherWillCacheURLResponseBlock callback; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + callback = _willCacheURLResponseBlock; + + if (callback) { + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + callback(proposedResponse, completionHandler); + }]; + } + } // @synchronized(self) + if (!callback) { + completionHandler(proposedResponse); + } +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalBytesWritten + totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didWriteData:%lld" + @" bytesWritten:%lld totalBytesExpectedToWrite:%lld", + [self class], self, session, downloadTask, bytesWritten, + totalBytesWritten, totalBytesExpectedToWrite); + [self setSessionTask:downloadTask]; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if ((totalBytesExpectedToWrite != NSURLSessionTransferSizeUnknown) && + (totalBytesExpectedToWrite < totalBytesWritten)) { + // Have observed cases were bytesWritten == totalBytesExpectedToWrite, + // but totalBytesWritten > totalBytesExpectedToWrite, so setting to unkown in these cases. + totalBytesExpectedToWrite = NSURLSessionTransferSizeUnknown; + } + + GTMSessionFetcherDownloadProgressBlock progressBlock; + progressBlock = self->_downloadProgressBlock; + if (progressBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + progressBlock(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + }]; + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset + expectedTotalBytes:(int64_t)expectedTotalBytes { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didResumeAtOffset:%lld" + @" expectedTotalBytes:%lld", + [self class], self, session, downloadTask, fileOffset, + expectedTotalBytes); + [self setSessionTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didFinishDownloadingToURL:(NSURL *)downloadLocationURL { + // Download may have relaunched app, so update _sessionTask. + [self setSessionTask:downloadTask]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ downloadTask:%@ didFinishDownloadingToURL:%@", + [self class], self, session, downloadTask, downloadLocationURL); + NSNumber *fileSizeNum; + [downloadLocationURL getResourceValue:&fileSizeNum forKey:NSURLFileSizeKey error:NULL]; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURL *destinationURL = _destinationFileURL; + + _downloadedLength = fileSizeNum.longLongValue; + + // Overwrite any previous file at the destination URL. + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSError *removeError; + if (![fileMgr removeItemAtURL:destinationURL error:&removeError] && + removeError.code != NSFileNoSuchFileError) { + GTMSESSION_LOG_DEBUG(@"Could not remove previous file at %@ due to %@", + downloadLocationURL.path, removeError); + } + + NSInteger statusCode = [self statusCodeUnsynchronized]; + if (statusCode < 200 || statusCode > 399) { + // In OS X 10.11, the response body is written to a file even on a server + // status error. For convenience of the fetcher client, we'll skip saving the + // downloaded body to the destination URL so that clients do not need to know + // to delete the file following fetch errors. + GTMSESSION_LOG_DEBUG(@"Abandoning download due to status %ld, file %@", (long)statusCode, + downloadLocationURL.path); + + // On error code, add the contents of the temporary file to _downloadTaskErrorData + // This way fetcher clients have access to error details possibly passed by the server. + if (_downloadedLength > 0 && _downloadedLength <= kMaximumDownloadErrorDataLength) { + _downloadTaskErrorData = [NSData dataWithContentsOfURL:downloadLocationURL]; + } else if (_downloadedLength > kMaximumDownloadErrorDataLength) { + GTMSESSION_LOG_DEBUG(@"Download error data for file %@ not passed to userInfo due to size " + @"%lld", + downloadLocationURL.path, _downloadedLength); + } + } else { + NSError *moveError; + NSURL *destinationFolderURL = [destinationURL URLByDeletingLastPathComponent]; + BOOL didMoveDownload = NO; + if ([fileMgr createDirectoryAtURL:destinationFolderURL + withIntermediateDirectories:YES + attributes:nil + error:&moveError]) { + didMoveDownload = [fileMgr moveItemAtURL:downloadLocationURL + toURL:destinationURL + error:&moveError]; + } + if (!didMoveDownload) { + _downloadFinishedError = moveError; + } + GTM_LOG_BACKGROUND_SESSION(@"%@ %p Moved download from \"%@\" to \"%@\" %@", [self class], + self, downloadLocationURL.path, destinationURL.path, + error ? error : @""); + } + } // @synchronized(self) +} + +/* Sent as the last message related to a specific task. Error may be + * nil, which implies that no error occurred and this task is complete. + */ +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error { + [self setSessionTask:task]; + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ task:%@ didCompleteWithError:%@", [self class], + self, session, task, error); + + NSInteger status = self.statusCode; + BOOL forceAssumeRetry = NO; + BOOL succeeded = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + // The task is never resumed when a testBlock is used. When the session is destroyed, + // we should ignore the callback, since the testBlock support code itself invokes + // shouldRetryNowForStatus: and finishWithError:shouldRetry: + if (_isUsingTestBlock) return; +#endif + + if (error == nil) { + error = _downloadFinishedError; + } + succeeded = (error == nil && status >= 0 && status < 300); + if (succeeded) { + // Succeeded. + _bodyLength = task.countOfBytesSent; + } + } // @synchronized(self) + + if (succeeded) { + [self finishWithError:nil shouldRetry:NO]; + return; + } + // For background redirects, no delegate method is called, so we cannot restore a stripped + // Authorization header, so if a 403 ("Forbidden") was generated due to a missing OAuth 2 header, + // set the current request's URL to the redirected URL, so we in effect restore the Authorization + // header. + if ((status == 403) && self.usingBackgroundSession) { + NSURL *redirectURL = self.response.URL; + NSURLRequest *request = self.request; + if (![request.URL isEqual:redirectURL]) { + NSString *authorizationHeader = [request.allHTTPHeaderFields objectForKey:@"Authorization"]; + if (authorizationHeader != nil) { + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + mutableRequest.URL = redirectURL; + [self updateMutableRequest:mutableRequest]; + // Avoid assuming the session is still valid. + self.session = nil; + forceAssumeRetry = YES; + } + } + } + + // If invalidating the session was deferred in stopFetchReleasingCallbacks: then do it now. + NSURLSession *oldSession = self.sessionNeedingInvalidation; + if (oldSession) { + [self setSessionNeedingInvalidation:NULL]; + [oldSession finishTasksAndInvalidate]; + } + + // Failed. + [self shouldRetryNowForStatus:status + error:error + forceAssumeRetry:forceAssumeRetry + response:^(BOOL shouldRetry) { + [self finishWithError:error shouldRetry:shouldRetry]; + }]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics + API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)) { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock = _metricsCollectionBlock; + if (metricsCollectionBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + metricsCollectionBlock(metrics); + }]; + } + } +} + +#if TARGET_OS_IPHONE +- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSessionDidFinishEventsForBackgroundURLSession:%@", + [self class], self, session); + [self removePersistedBackgroundSessionFromDefaults]; + + GTMSessionFetcherSystemCompletionHandler handler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + handler = self.systemCompletionHandler; + self.systemCompletionHandler = nil; + } // @synchronized(self) + if (handler) { + GTM_LOG_BACKGROUND_SESSION(@"%@ %p Calling system completionHandler", [self class], self); + handler(); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLSession *oldSession = _session; + _session = nil; + if (_shouldInvalidateSession) { + [oldSession finishTasksAndInvalidate]; + } + } // @synchronized(self) + } +} +#endif + +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error { + // This may happen repeatedly for retries. On authentication callbacks, the retry + // may begin before the prior session sends the didBecomeInvalid delegate message. + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", [self class], self, + session, error); + if (session == (NSURLSession *)self.session) { + GTM_LOG_SESSION_DELEGATE(@" Unexpected retained invalid session: %@", session); + self.session = nil; + } +} + +- (void)finishWithError:(nullable NSError *)error shouldRetry:(BOOL)shouldRetry { + [self removePersistedBackgroundSessionFromDefaults]; + + BOOL shouldStopFetching = YES; + NSData *downloadedData = nil; +#if !STRIP_GTM_FETCH_LOGGING + BOOL shouldDeferLogging = NO; +#endif + BOOL shouldBeginRetryTimer = NO; + NSInteger status = [self statusCode]; + NSURL *destinationURL = self.destinationFileURL; + + BOOL fetchSucceeded = (error == nil && status >= 0 && status < 300); + +#if !STRIP_GTM_FETCH_LOGGING + if (!fetchSucceeded) { + if (!shouldDeferLogging && !self.hasLoggedError) { + [self logNowWithError:error]; + self.hasLoggedError = YES; + } + } +#endif // !STRIP_GTM_FETCH_LOGGING + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if !STRIP_GTM_FETCH_LOGGING + shouldDeferLogging = _deferResponseBodyLogging; +#endif + if (fetchSucceeded) { + // Success + if ((_downloadedData.length > 0) && (destinationURL != nil)) { + // Overwrite any previous file at the destination URL. + NSFileManager *fileMgr = [NSFileManager defaultManager]; + [fileMgr removeItemAtURL:destinationURL error:NULL]; + NSURL *destinationFolderURL = [destinationURL URLByDeletingLastPathComponent]; + BOOL didMoveDownload = NO; + if ([fileMgr createDirectoryAtURL:destinationFolderURL + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + didMoveDownload = [_downloadedData writeToURL:destinationURL + options:NSDataWritingAtomic + error:&error]; + } + if (didMoveDownload) { + _downloadedData = nil; + } else { + _downloadFinishedError = error; + } + } + downloadedData = _downloadedData; + } else { + // Unsuccessful with error or status over 300. Retry or notify the delegate of failure + if (shouldRetry) { + // Retrying. + shouldBeginRetryTimer = YES; + shouldStopFetching = NO; + } else { + if (error == nil) { + // Create an error. + NSDictionary *userInfo = GTMErrorUserInfoForData( + _downloadedData.length > 0 ? _downloadedData : _downloadTaskErrorData, + [self responseHeadersUnsynchronized]); + + error = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:status + userInfo:userInfo]; + } else { + // If the error had resume data, and the client supplied a resume block, pass the + // data to the client. + void (^resumeBlock)(NSData *) = _resumeDataBlock; + _resumeDataBlock = nil; + if (resumeBlock) { + NSData *resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]; + if (resumeData) { + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + resumeBlock(resumeData); + }]; + } + } + } + if (_downloadedData.length > 0) { + downloadedData = _downloadedData; + } + // If the error occurred after retries, report the number and duration of the + // retries. This provides a clue to a developer looking at the error description + // that the fetcher did retry before failing with this error. + if (_retryCount > 0) { + NSMutableDictionary *userInfoWithRetries = + [NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)error.userInfo]; + NSTimeInterval timeSinceInitialRequest = -[_initialRequestDate timeIntervalSinceNow]; + [userInfoWithRetries setObject:@(timeSinceInitialRequest) + forKey:kGTMSessionFetcherElapsedIntervalWithRetriesKey]; + [userInfoWithRetries setObject:@(_retryCount) + forKey:kGTMSessionFetcherNumberOfRetriesDoneKey]; + error = [NSError errorWithDomain:(NSString *)error.domain + code:error.code + userInfo:userInfoWithRetries]; + } + } + } + } // @synchronized(self) + + if (shouldBeginRetryTimer) { + [self beginRetryTimer]; + } + + // We want to send the stop notification before calling the delegate's + // callback selector, since the callback selector may release all of + // the fetcher properties that the client is using to track the fetches. + // + // We'll also stop now so that, to any observers watching the notifications, + // it doesn't look like our wait for a retry (which may be long, + // 30 seconds or more) is part of the network activity. + [self sendStopNotificationIfNeeded]; + + if (shouldStopFetching) { + // The upload subclass doesn't want to release callbacks until upload chunks have completed. + BOOL shouldRelease = [self shouldReleaseCallbacksUponCompletion]; + [self invokeFetchCallbacksOnCallbackQueueWithData:downloadedData + error:error + mayDecorate:YES + shouldReleaseCallbacks:shouldRelease]; + [self stopFetchReleasingCallbacks:NO]; + } + +#if !STRIP_GTM_FETCH_LOGGING + // _hasLoggedError is only set by this method + if (!shouldDeferLogging && !_hasLoggedError) { + [self logNowWithError:error]; + } +#endif +} + +- (BOOL)shouldReleaseCallbacksUponCompletion { + // A subclass can override this to keep callbacks around after the + // connection has finished successfully + return YES; +} + +- (void)logNowWithError:(nullable NSError *)error { + GTMSessionCheckNotSynchronized(self); + + // If the logging category is available, then log the current request, + // response, data, and error + if ([self respondsToSelector:@selector(logFetchWithError:)]) { + [self performSelector:@selector(logFetchWithError:) withObject:error]; + } +} + +#pragma mark Retries + +- (BOOL)isRetryError:(NSError *)error { + struct RetryRecord { + __unsafe_unretained NSString *const domain; + NSInteger code; + }; + + struct RetryRecord retries[] = { + {kGTMSessionFetcherStatusDomain, 408}, // request timeout + {kGTMSessionFetcherStatusDomain, 502}, // failure gatewaying to another server + {kGTMSessionFetcherStatusDomain, 503}, // service unavailable + {kGTMSessionFetcherStatusDomain, 504}, // request timeout + {NSURLErrorDomain, NSURLErrorTimedOut}, + {NSURLErrorDomain, NSURLErrorNetworkConnectionLost}, + {nil, 0}}; + + // NSError's isEqual always returns false for equal but distinct instances + // of NSError, so we have to compare the domain and code values explicitly + NSString *domain = error.domain; + NSInteger code = error.code; + for (int idx = 0; retries[idx].domain != nil; idx++) { + if (code == retries[idx].code && [domain isEqual:retries[idx].domain]) { + return YES; + } + } + return NO; +} + +// shouldRetryNowForStatus:error: responds with YES if the user has enabled retries +// and the status or error is one that is suitable for retrying. "Suitable" +// means either the isRetryError:'s list contains the status or error, or the +// user's retry block is present and returns YES when called, or the +// authorizer may be able to fix. +- (void)shouldRetryNowForStatus:(NSInteger)status + error:(NSError *)error + forceAssumeRetry:(BOOL)forceAssumeRetry + response:(GTMSessionFetcherRetryResponse)response { + // Determine if a refreshed authorizer may avoid an authorization error + BOOL willRetry = NO; + + // We assume _authorizer is immutable after beginFetch, and _hasAttemptedAuthRefresh is modified + // only in this method, and this method is invoked on the serial delegate queue. + // + // We want to avoid calling the authorizer from inside a sync block. + BOOL isFirstAuthError = (_authorizer != nil && !_hasAttemptedAuthRefresh && + status == GTMSessionFetcherStatusUnauthorized); // 401 + + BOOL hasPrimed = NO; + if (isFirstAuthError) { + if ([_authorizer respondsToSelector:@selector(primeForRefresh)]) { + hasPrimed = [_authorizer primeForRefresh]; + } + } + + BOOL shouldRetryForAuthRefresh = NO; + if (hasPrimed) { + shouldRetryForAuthRefresh = YES; + _hasAttemptedAuthRefresh = YES; + [self updateRequestValue:nil forHTTPHeaderField:@"Authorization"]; + } + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL shouldDoRetry = [self isRetryEnabledUnsynchronized]; + if (shouldDoRetry && ![self hasRetryAfterInterval]) { + // Determine if we're doing exponential backoff retries + shouldDoRetry = [self nextRetryIntervalUnsynchronized] < _maxRetryInterval; + + if (shouldDoRetry) { + // If an explicit max retry interval was set, we expect repeated backoffs to take + // up to roughly twice that for repeated fast failures. If the initial attempt is + // already more than 3 times the max retry interval, then failures have taken a long time + // (such as from network timeouts) so don't retry again to avoid the app becoming + // unexpectedly unresponsive. + if (_maxRetryInterval > 0) { + NSTimeInterval maxAllowedIntervalBeforeRetry = _maxRetryInterval * 3; + NSTimeInterval timeSinceInitialRequest = -[_initialRequestDate timeIntervalSinceNow]; + if (timeSinceInitialRequest > maxAllowedIntervalBeforeRetry) { + shouldDoRetry = NO; + } + } + } + } + BOOL canRetry = shouldRetryForAuthRefresh || forceAssumeRetry || shouldDoRetry; + if (canRetry) { + NSDictionary *userInfo = + GTMErrorUserInfoForData(_downloadedData, [self responseHeadersUnsynchronized]); + NSError *statusError = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:status + userInfo:userInfo]; + if (error == nil) { + error = statusError; + } + willRetry = shouldRetryForAuthRefresh || forceAssumeRetry || [self isRetryError:error] || + ((error != statusError) && [self isRetryError:statusError]); + + // If the user has installed a retry callback, consult that. + GTMSessionFetcherRetryBlock retryBlock = _retryBlock; + if (retryBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + retryBlock(willRetry, error, response); + }]; + return; + } + } + } // @synchronized(self) + response(willRetry); +} + +- (BOOL)hasRetryAfterInterval { + GTMSessionCheckSynchronized(self); + + NSDictionary *responseHeaders = [self responseHeadersUnsynchronized]; + NSString *retryAfterValue = [responseHeaders valueForKey:@"Retry-After"]; + return (retryAfterValue != nil); +} + +- (NSTimeInterval)retryAfterInterval { + GTMSessionCheckSynchronized(self); + + NSDictionary *responseHeaders = [self responseHeadersUnsynchronized]; + NSString *retryAfterValue = [responseHeaders valueForKey:@"Retry-After"]; + if (retryAfterValue == nil) { + return 0; + } + // Retry-After formatted as HTTP-date | delta-seconds + // Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + NSDateFormatter *rfc1123DateFormatter = [[NSDateFormatter alloc] init]; + rfc1123DateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; + rfc1123DateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + rfc1123DateFormatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss z"; + NSDate *retryAfterDate = [rfc1123DateFormatter dateFromString:retryAfterValue]; + NSTimeInterval retryAfterInterval = + (retryAfterDate != nil) ? retryAfterDate.timeIntervalSinceNow : retryAfterValue.intValue; + retryAfterInterval = MAX(0, retryAfterInterval); + return retryAfterInterval; +} + +- (void)beginRetryTimer { + if (![NSThread isMainThread]) { + // Defer creating and starting the timer until we're on the main thread to ensure it has + // a run loop. + dispatch_group_async(_callbackGroup, dispatch_get_main_queue(), ^{ + [self beginRetryTimer]; + }); + return; + } + + [self destroyRetryTimer]; + +#if GTM_BACKGROUND_TASK_FETCHING + // Don't keep a background task active while awaiting retry, which can lead to the + // app exceeding the allotted time for keeping the background task open, causing the + // system to terminate the app. When the retry starts, a new background task will + // be created. + [self endBackgroundTask]; +#endif // GTM_BACKGROUND_TASK_FETCHING + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval nextInterval = [self nextRetryIntervalUnsynchronized]; + NSTimeInterval maxInterval = _maxRetryInterval; + NSTimeInterval newInterval = MIN(nextInterval, (maxInterval > 0 ? maxInterval : DBL_MAX)); + NSTimeInterval newIntervalTolerance = (newInterval / 10) > 1.0 ?: 1.0; + + _lastRetryInterval = newInterval; + + _retryTimer = [NSTimer timerWithTimeInterval:newInterval + target:self + selector:@selector(retryTimerFired:) + userInfo:nil + repeats:NO]; + _retryTimer.tolerance = newIntervalTolerance; + [[NSRunLoop mainRunLoop] addTimer:_retryTimer forMode:NSDefaultRunLoopMode]; + } // @synchronized(self) + + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherRetryDelayStartedNotification + userInfo:nil + requireAsync:NO]; +} + +- (void)retryTimerFired:(NSTimer *)timer { + [self destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _retryCount++; + } // @synchronized(self) + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + [self retryFetch]; + }]; +} + +- (void)destroyRetryTimer { + BOOL shouldNotify = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_retryTimer) { + [_retryTimer invalidate]; + _retryTimer = nil; + shouldNotify = YES; + } + } + + if (shouldNotify) { + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherRetryDelayStoppedNotification + userInfo:nil + requireAsync:NO]; + } +} + +- (NSUInteger)retryCount { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _retryCount; + } // @synchronized(self) +} + +- (NSTimeInterval)nextRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval interval = [self nextRetryIntervalUnsynchronized]; + return interval; + } // @synchronized(self) +} + +- (NSTimeInterval)nextRetryIntervalUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSInteger statusCode = [self statusCodeUnsynchronized]; + if ((statusCode == 503) && [self hasRetryAfterInterval]) { + NSTimeInterval secs = [self retryAfterInterval]; + return secs; + } + // The next wait interval is the factor (2.0) times the last interval, + // but never less than the minimum interval. + NSTimeInterval secs = _lastRetryInterval * _retryFactor; + if (_maxRetryInterval > 0) { + secs = MIN(secs, _maxRetryInterval); + } + secs = MAX(secs, _minRetryInterval); + + return secs; +} + +- (NSTimer *)retryTimer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _retryTimer; + } // @synchronized(self) +} + +- (BOOL)isRetryEnabled { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isRetryEnabled; + } // @synchronized(self) +} + +- (BOOL)isRetryEnabledUnsynchronized { + GTMSessionCheckSynchronized(self); + + return _isRetryEnabled; +} + +- (void)setRetryEnabled:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag && !_isRetryEnabled) { + // We defer initializing these until the user calls setRetryEnabled + // to avoid using the random number generator if it's not needed. + // However, this means min and max intervals for this fetcher are reset + // as a side effect of calling setRetryEnabled. + // + // Make an initial retry interval random between 1.0 and 2.0 seconds + _minRetryInterval = InitialMinRetryInterval(); + _maxRetryInterval = kUnsetMaxRetryInterval; + _retryFactor = 2.0; + _lastRetryInterval = 0.0; + } + _isRetryEnabled = flag; + } // @synchronized(self) +}; + +- (NSTimeInterval)maxRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _maxRetryInterval; + } // @synchronized(self) +} + +- (void)setMaxRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _maxRetryInterval = secs; + } else { + _maxRetryInterval = kUnsetMaxRetryInterval; + } + } // @synchronized(self) +} + +- (double)minRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _minRetryInterval; + } // @synchronized(self) +} + +- (void)setMinRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _minRetryInterval = secs; + } else { + // Set min interval to a random value between 1.0 and 2.0 seconds + // so that if multiple clients start retrying at the same time, they'll + // repeat at different times and avoid overloading the server + _minRetryInterval = InitialMinRetryInterval(); + } + } // @synchronized(self) +} + +#pragma mark iOS System Completion Handlers + +#if TARGET_OS_IPHONE +static NSMutableDictionary *gSystemCompletionHandlers = nil; + +- (nullable GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler { + return [[self class] systemCompletionHandlerForSessionIdentifier:_sessionIdentifier]; +} + +- (void)setSystemCompletionHandler: + (nullable GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler { + [[self class] setSystemCompletionHandler:systemCompletionHandler + forSessionIdentifier:_sessionIdentifier]; +} + ++ (void)setSystemCompletionHandler: + (nullable GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler + forSessionIdentifier:(NSString *)sessionIdentifier { + if (!sessionIdentifier) { + NSLog(@"%s with nil identifier", __PRETTY_FUNCTION__); + return; + } + + @synchronized([GTMSessionFetcher class]) { + if (gSystemCompletionHandlers == nil && systemCompletionHandler != nil) { + gSystemCompletionHandlers = [[NSMutableDictionary alloc] init]; + } + // Use setValue: to remove the object if completionHandler is nil. + [gSystemCompletionHandlers setValue:systemCompletionHandler forKey:sessionIdentifier]; + } +} + ++ (nullable GTMSessionFetcherSystemCompletionHandler)systemCompletionHandlerForSessionIdentifier: + (NSString *)sessionIdentifier { + if (!sessionIdentifier) { + return nil; + } + @synchronized([GTMSessionFetcher class]) { + return [gSystemCompletionHandlers objectForKey:sessionIdentifier]; + } +} +#endif // TARGET_OS_IPHONE + +#pragma mark Getters and Setters + +// clang-format off +// Don't re-format the @synthesize blocks: +@synthesize downloadResumeData = _downloadResumeData, + configuration = _configuration, + configurationBlock = _configurationBlock, + sessionTask = _sessionTask, + wasCreatedFromBackgroundSession = _wasCreatedFromBackgroundSession, + clientWillReconnectBackgroundSession = _clientWillReconnectBackgroundSession, + sessionUserInfo = _sessionUserInfo, + taskDescription = _taskDescription, + taskPriority = _taskPriority, + usingBackgroundSession = _usingBackgroundSession, + canShareSession = _canShareSession, + completionHandler = _completionHandler, + credential = _credential, + proxyCredential = _proxyCredential, + bodyData = _bodyData, + bodyLength = _bodyLength, + service = _service, + serviceHost = _serviceHost, + accumulateDataBlock = _accumulateDataBlock, + receivedProgressBlock = _receivedProgressBlock, + downloadProgressBlock = _downloadProgressBlock, + resumeDataBlock = _resumeDataBlock, + didReceiveResponseBlock = _didReceiveResponseBlock, + challengeBlock = _challengeBlock, + willRedirectBlock = _willRedirectBlock, + sendProgressBlock = _sendProgressBlock, + willCacheURLResponseBlock = _willCacheURLResponseBlock, + retryBlock = _retryBlock, + metricsCollectionBlock = _metricsCollectionBlock, + retryFactor = _retryFactor, + allowedInsecureSchemes = _allowedInsecureSchemes, + allowLocalhostRequest = _allowLocalhostRequest, + allowInvalidServerCertificates = _allowInvalidServerCertificates, + cookieStorage = _cookieStorage, + callbackQueue = _callbackQueue, + initialBeginFetchDate = _initialBeginFetchDate, + testBlock = _testBlock, + testBlockAccumulateDataChunkCount = _testBlockAccumulateDataChunkCount, + comment = _comment, + log = _log; + +#if !STRIP_GTM_FETCH_LOGGING +@synthesize redirectedFromURL = _redirectedFromURL, + logRequestBody = _logRequestBody, + logResponseBody = _logResponseBody, + hasLoggedError = _hasLoggedError; +#endif + +#if GTM_BACKGROUND_TASK_FETCHING +@synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier, + skipBackgroundTask = _skipBackgroundTask; +#endif +// clang-format on + +- (nullable NSURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_request copy]; + } // @synchronized(self) +} + +- (void)setRequest:(nullable NSURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (![self isFetchingUnsynchronized]) { + _request = [request mutableCopy]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"request may not be set after beginFetch has been invoked"); + } + } // @synchronized(self) +} + +- (nullable NSMutableURLRequest *)mutableRequestForTesting { + // Allow tests only to modify the request, useful during retries. + return _request; +} + +// Internal method for updating the request property such as on redirects. +- (void)updateMutableRequest:(nullable NSMutableURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _request = request; + } // @synchronized(self) +} + +// Set a header field value on the request. Header field value changes will not +// affect a fetch after the fetch has begun. +- (void)setRequestValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field { + if (![self isFetching]) { + [self updateRequestValue:value forHTTPHeaderField:field]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"request may not be set after beginFetch has been invoked"); + } +} + +// Internal method for updating request headers. +- (void)updateRequestValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_request setValue:value forHTTPHeaderField:field]; + } // @synchronized(self) +} + +- (void)setResponse:(nullable NSURLResponse *)response { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _response = response; + } // @synchronized(self) +} + +- (int64_t)bodyLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_bodyLength == NSURLSessionTransferSizeUnknown) { + if (_bodyData) { + _bodyLength = (int64_t)_bodyData.length; + } else if (_bodyFileURL) { + NSNumber *fileSizeNum = nil; + NSError *fileSizeError = nil; + if ([_bodyFileURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:&fileSizeError]) { + _bodyLength = [fileSizeNum longLongValue]; + } + } + } + return _bodyLength; + } // @synchronized(self) +} + +- (BOOL)useUploadTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _useUploadTask; + } // @synchronized(self) +} + +- (void)setUseUploadTask:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag != _useUploadTask) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"useUploadTask should not change after beginFetch has been invoked"); + _useUploadTask = flag; + } + } // @synchronized(self) +} + +- (nullable NSURL *)bodyFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _bodyFileURL; + } // @synchronized(self) +} + +- (void)setBodyFileURL:(nullable NSURL *)fileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // The comparison here is a trivial optimization and forgiveness for any client that + // repeatedly sets the property, so it just uses pointer comparison rather than isEqual:. + if (fileURL != _bodyFileURL) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"fileURL should not change after beginFetch has been invoked"); + + _bodyFileURL = fileURL; + } + } // @synchronized(self) +} + +- (nullable GTMSessionFetcherBodyStreamProvider)bodyStreamProvider { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _bodyStreamProvider; + } // @synchronized(self) +} + +- (void)setBodyStreamProvider:(nullable GTMSessionFetcherBodyStreamProvider)block { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"stream provider should not change after beginFetch has been invoked"); + + _bodyStreamProvider = [block copy]; + } // @synchronized(self) +} + +- (nullable id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _authorizer; + } // @synchronized(self) +} + +- (void)setAuthorizer:(nullable id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (authorizer != _authorizer) { + if ([self isFetchingUnsynchronized]) { + GTMSESSION_ASSERT_DEBUG(0, + @"authorizer should not change after beginFetch has been invoked"); + } else { + _authorizer = authorizer; + } + } + } // @synchronized(self) +} + +- (nullable NSData *)downloadedData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _downloadedData; + } // @synchronized(self) +} + +- (void)setDownloadedData:(nullable NSData *)data { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _downloadedData = [data mutableCopy]; + } // @synchronized(self) +} + +- (int64_t)downloadedLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _downloadedLength; + } // @synchronized(self) +} + +- (void)setDownloadedLength:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _downloadedLength = length; + } // @synchronized(self) +} + +- (nonnull dispatch_queue_t)callbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _callbackQueue; + } // @synchronized(self) +} + +- (void)setCallbackQueue:(nullable dispatch_queue_t)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _callbackQueue = queue ?: dispatch_get_main_queue(); + } // @synchronized(self) +} + +- (nullable NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _session; + } // @synchronized(self) +} + +- (NSInteger)servicePriority { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _servicePriority; + } // @synchronized(self) +} + +- (void)setServicePriority:(NSInteger)value { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (value != _servicePriority) { + GTMSESSION_ASSERT_DEBUG( + ![self isFetchingUnsynchronized], + @"servicePriority should not change after beginFetch has been invoked"); + + _servicePriority = value; + } + } // @synchronized(self) +} + +- (void)setSession:(nullable NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = session; + } // @synchronized(self) +} + +- (BOOL)canShareSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _canShareSession; + } // @synchronized(self) +} + +- (void)setCanShareSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _canShareSession = flag; + } // @synchronized(self) +} + +- (BOOL)useBackgroundSession { + // This reflects if the user requested a background session, not necessarily + // if one was created. That is tracked with _usingBackgroundSession. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userRequestedBackgroundSession; + } // @synchronized(self) +} + +- (void)setUseBackgroundSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag != _userRequestedBackgroundSession) { + GTMSESSION_ASSERT_DEBUG( + ![self isFetchingUnsynchronized], + @"useBackgroundSession should not change after beginFetch has been invoked"); + + _userRequestedBackgroundSession = flag; + } + } // @synchronized(self) +} + +- (BOOL)isUsingBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _usingBackgroundSession; + } // @synchronized(self) +} + +- (void)setUsingBackgroundSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _usingBackgroundSession = flag; + } // @synchronized(self) +} + +- (nullable NSURLSession *)sessionNeedingInvalidation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionNeedingInvalidation; + } // @synchronized(self) +} + +- (void)setSessionNeedingInvalidation:(nullable NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _sessionNeedingInvalidation = session; + } // @synchronized(self) +} + +- (nonnull NSOperationQueue *)sessionDelegateQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateQueue; + } // @synchronized(self) +} + +- (void)setSessionDelegateQueue:(nullable NSOperationQueue *)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (queue != _delegateQueue) { + if ([self isFetchingUnsynchronized]) { + GTMSESSION_ASSERT_DEBUG(0, @"sessionDelegateQueue should not change after fetch begins"); + } else { + _delegateQueue = queue ?: [NSOperationQueue mainQueue]; + } + } + } // @synchronized(self) +} + +- (BOOL)userStoppedFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userStoppedFetching; + } // @synchronized(self) +} + +- (nullable id)userData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userData; + } // @synchronized(self) +} + +- (void)setUserData:(nullable id)theObj { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _userData = theObj; + } // @synchronized(self) +} + +- (nullable NSURL *)destinationFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _destinationFileURL; + } // @synchronized(self) +} + +- (void)setDestinationFileURL:(nullable NSURL *)destinationFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (((_destinationFileURL == nil) && (destinationFileURL == nil)) || + [_destinationFileURL isEqual:destinationFileURL]) { + return; + } + if (_sessionIdentifier) { + // This is something we don't expect to happen in production. + // However if it ever happen, leave a system log. + NSLog(@"%@: Destination File URL changed from (%@) to (%@) after session identifier has " + @"been created.", + [self class], _destinationFileURL, destinationFileURL); +#if DEBUG + // On both the simulator and devices, the path can change to the download file, but the name + // shouldn't change. Technically, this isn't supported in the fetcher, but the change of + // URL is expected to happen only across development runs through Xcode. + NSString *oldFilename = [_destinationFileURL lastPathComponent]; + NSString *newFilename = [destinationFileURL lastPathComponent]; +#pragma unused(oldFilename) +#pragma unused(newFilename) + GTMSESSION_ASSERT_DEBUG( + [oldFilename isEqualToString:newFilename], + @"Destination File URL cannot be changed after session identifier has been created"); +#endif + } + _destinationFileURL = destinationFileURL; + } // @synchronized(self) +} + +- (void)setProperties:(nullable NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _properties = [dict mutableCopy]; + } // @synchronized(self) +} + +- (nullable NSDictionary *)properties { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _properties; + } // @synchronized(self) +} + +- (void)setProperty:(nullable id)obj forKey:(NSString *)key { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_properties == nil && obj != nil) { + _properties = [[NSMutableDictionary alloc] init]; + } + [_properties setValue:obj forKey:key]; + } // @synchronized(self) +} + +- (nullable id)propertyForKey:(NSString *)key { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_properties objectForKey:key]; + } // @synchronized(self) +} + +- (void)addPropertiesFromDictionary:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_properties == nil && dict != nil) { + [self setProperties:[dict mutableCopy]]; + } else { + [_properties addEntriesFromDictionary:dict]; + } + } // @synchronized(self) +} + +- (void)setCommentWithFormat:(id)format, ... { +#if !STRIP_GTM_FETCH_LOGGING + NSString *result = format; + if (format) { + va_list argList; + va_start(argList, format); + + result = [[NSString alloc] initWithFormat:format arguments:argList]; + va_end(argList); + } + [self setComment:result]; +#endif +} + +#if !STRIP_GTM_FETCH_LOGGING +- (NSData *)loggedStreamData { + return _loggedStreamData; +} + +- (void)appendLoggedStreamData:dataToAdd { + if (!_loggedStreamData) { + _loggedStreamData = [NSMutableData data]; + } + [_loggedStreamData appendData:dataToAdd]; +} + +- (void)clearLoggedStreamData { + _loggedStreamData = nil; +} + +- (void)setDeferResponseBodyLogging:(BOOL)deferResponseBodyLogging { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (deferResponseBodyLogging != _deferResponseBodyLogging) { + _deferResponseBodyLogging = deferResponseBodyLogging; + if (!deferResponseBodyLogging && !self.hasLoggedError) { + [_delegateQueue addOperationWithBlock:^{ + [self logNowWithError:nil]; + }]; + } + } + } // @synchronized(self) +} + +- (BOOL)deferResponseBodyLogging { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _deferResponseBodyLogging; + } // @synchronized(self) +} + +#else ++ (void)setLoggingEnabled:(BOOL)flag { +} + ++ (BOOL)isLoggingEnabled { + return NO; +} +#endif // STRIP_GTM_FETCH_LOGGING + +@end + +@implementation GTMSessionFetcher (BackwardsCompatibilityOnly) + +- (void)setCookieStorageMethod:(NSInteger)method { + // For backwards compatibility with the old fetcher, we'll support the old constants. + // + // Clients using the GTMSessionFetcher class should set the cookie storage explicitly + // themselves. + NSHTTPCookieStorage *storage = nil; + switch (method) { + case 0: // kGTMHTTPFetcherCookieStorageMethodStatic + // nil storage will use [[self class] staticCookieStorage] when the fetch begins. + break; + case 1: // kGTMHTTPFetcherCookieStorageMethodFetchHistory + // Do nothing; use whatever was set by the fetcher service. + return; + case 2: // kGTMHTTPFetcherCookieStorageMethodSystemDefault + storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + break; + case 3: // kGTMHTTPFetcherCookieStorageMethodNone + // Create temporary storage for this fetcher only. + storage = [[GTMSessionCookieStorage alloc] init]; + break; + default: + GTMSESSION_ASSERT_DEBUG(0, @"Invalid cookie storage method: %d", (int)method); + } + self.cookieStorage = storage; +} + +@end + +@implementation GTMSessionCookieStorage { + NSMutableArray *_cookies; + NSHTTPCookieAcceptPolicy _policy; +} + +- (id)init { + self = [super init]; + if (self != nil) { + _cookies = [[NSMutableArray alloc] init]; + } + return self; +} + +- (nullable NSArray *)cookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_cookies copy]; + } // @synchronized(self) +} + +- (void)setCookie:(NSHTTPCookie *)cookie { + if (!cookie) return; + if (_policy == NSHTTPCookieAcceptPolicyNever) return; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self internalSetCookie:cookie]; + } // @synchronized(self) +} + +// Note: this should only be called from inside a @synchronized(self) block. +- (void)internalSetCookie:(NSHTTPCookie *)newCookie { + GTMSessionCheckSynchronized(self); + + if (_policy == NSHTTPCookieAcceptPolicyNever) return; + + BOOL isValidCookie = + (newCookie.name.length > 0 && newCookie.domain.length > 0 && newCookie.path.length > 0); + GTMSESSION_ASSERT_DEBUG(isValidCookie, @"invalid cookie: %@", newCookie); + + if (isValidCookie) { + // Remove the cookie if it's currently in the array. + NSHTTPCookie *oldCookie = [self cookieMatchingCookie:newCookie]; + if (oldCookie) { + [_cookies removeObjectIdenticalTo:oldCookie]; + } + + if (![[self class] hasCookieExpired:newCookie]) { + [_cookies addObject:newCookie]; + } + } +} + +// Add all cookies in the new cookie array to the storage, +// replacing stored cookies as appropriate. +// +// Side effect: removes expired cookies from the storage array. +- (void)setCookies:(nullable NSArray *)newCookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self removeExpiredCookies]; + + for (NSHTTPCookie *newCookie in newCookies) { + [self internalSetCookie:newCookie]; + } + } // @synchronized(self) +} + +- (void)setCookies:(NSArray *)cookies + forURL:(nullable NSURL *)URL + mainDocumentURL:(nullable NSURL *)mainDocumentURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_policy == NSHTTPCookieAcceptPolicyNever) { + return; + } + + if (_policy == NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain) { + NSString *mainHost = mainDocumentURL.host; + NSString *associatedHost = URL.host; + if (!mainHost || ![associatedHost hasSuffix:mainHost]) { + return; + } + } + } // @synchronized(self) + [self setCookies:cookies]; +} + +- (void)deleteCookie:(NSHTTPCookie *)cookie { + if (!cookie) return; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSHTTPCookie *foundCookie = [self cookieMatchingCookie:cookie]; + if (foundCookie) { + [_cookies removeObjectIdenticalTo:foundCookie]; + } + } // @synchronized(self) +} + +// Retrieve all cookies appropriate for the given URL, considering +// domain, path, cookie name, expiration, security setting. +// Side effect: removed expired cookies from the storage array. +- (nullable NSArray *)cookiesForURL:(NSURL *)theURL { + NSMutableArray *foundCookies = nil; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self removeExpiredCookies]; + + // We'll prepend "." to the desired domain, since we want the + // actual domain "nytimes.com" to still match the cookie domain + // ".nytimes.com" when we check it below with hasSuffix. + NSString *host = theURL.host.lowercaseString; + NSString *path = theURL.path; + NSString *scheme = [theURL scheme]; + + NSString *requestingDomain = nil; + BOOL isLocalhostRetrieval = NO; + + if (IsLocalhost(host)) { + isLocalhostRetrieval = YES; + } else { + if (host.length > 0) { + requestingDomain = [@"." stringByAppendingString:host]; + } + } + + for (NSHTTPCookie *storedCookie in _cookies) { + NSString *cookieDomain = storedCookie.domain.lowercaseString; + NSString *cookiePath = storedCookie.path; + BOOL cookieIsSecure = [storedCookie isSecure]; + + BOOL isDomainOK; + + if (isLocalhostRetrieval) { + // Prior to 10.5.6, the domain stored into NSHTTPCookies for localhost + // is "localhost.local" + isDomainOK = (IsLocalhost(cookieDomain) || [cookieDomain isEqual:@"localhost.local"]); + } else { + // Ensure we're matching exact domain names. We prepended a dot to the + // requesting domain, so we can also prepend one here if needed before + // checking if the request contains the cookie domain. + if (![cookieDomain hasPrefix:@"."]) { + cookieDomain = [@"." stringByAppendingString:cookieDomain]; + } + isDomainOK = [requestingDomain hasSuffix:cookieDomain]; + } + + BOOL isPathOK = [cookiePath isEqual:@"/"] || [path hasPrefix:cookiePath]; + BOOL isSecureOK = + (!cookieIsSecure || [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame); + + if (isDomainOK && isPathOK && isSecureOK) { + if (foundCookies == nil) { + foundCookies = [NSMutableArray array]; + } + [foundCookies addObject:storedCookie]; + } + } + } // @synchronized(self) + return foundCookies; +} + +// Override methods from the NSHTTPCookieStorage (NSURLSessionTaskAdditions) category. +- (void)storeCookies:(NSArray *)cookies forTask:(NSURLSessionTask *)task { + NSURLRequest *currentRequest = task.currentRequest; + [self setCookies:cookies forURL:currentRequest.URL mainDocumentURL:nil]; +} + +- (void)getCookiesForTask:(NSURLSessionTask *)task + completionHandler:(void (^)(NSArray *))completionHandler { + if (completionHandler) { + NSURLRequest *currentRequest = task.currentRequest; + NSURL *currentRequestURL = currentRequest.URL; + NSArray *cookies = [self cookiesForURL:currentRequestURL]; + completionHandler(cookies); + } +} + +// Return a cookie from the array with the same name, domain, and path as the +// given cookie, or else return nil if none found. +// +// Both the cookie being tested and all cookies in the storage array should +// be valid (non-nil name, domains, paths). +// +// Note: this should only be called from inside a @synchronized(self) block +- (nullable NSHTTPCookie *)cookieMatchingCookie:(NSHTTPCookie *)cookie { + GTMSessionCheckSynchronized(self); + + NSString *name = cookie.name; + NSString *domain = cookie.domain; + NSString *path = cookie.path; + + GTMSESSION_ASSERT_DEBUG(name && domain && path, + @"Invalid stored cookie (name:%@ domain:%@ path:%@)", name, domain, path); + + for (NSHTTPCookie *storedCookie in _cookies) { + if ([storedCookie.name isEqual:name] && [storedCookie.domain isEqual:domain] && + [storedCookie.path isEqual:path]) { + return storedCookie; + } + } + return nil; +} + +// Internal routine to remove any expired cookies from the array, excluding +// cookies with nil expirations. +// +// Note: this should only be called from inside a @synchronized(self) block +- (void)removeExpiredCookies { + GTMSessionCheckSynchronized(self); + + // Count backwards since we're deleting items from the array + for (NSInteger idx = (NSInteger)_cookies.count - 1; idx >= 0; idx--) { + NSHTTPCookie *storedCookie = [_cookies objectAtIndex:(NSUInteger)idx]; + if ([[self class] hasCookieExpired:storedCookie]) { + [_cookies removeObjectAtIndex:(NSUInteger)idx]; + } + } +} + ++ (BOOL)hasCookieExpired:(NSHTTPCookie *)cookie { + NSDate *expiresDate = [cookie expiresDate]; + if (expiresDate == nil) { + // Cookies seem to have a Expires property even when the expiresDate method returns nil. + id expiresVal = [[cookie properties] objectForKey:NSHTTPCookieExpires]; + if ([expiresVal isKindOfClass:[NSDate class]]) { + expiresDate = expiresVal; + } + } + BOOL hasExpired = (expiresDate != nil && [expiresDate timeIntervalSinceNow] < 0); + return hasExpired; +} + +- (void)removeAllCookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_cookies removeAllObjects]; + } // @synchronized(self) +} + +- (NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _policy; + } // @synchronized(self) +} + +- (void)setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _policy = cookieAcceptPolicy; + } // @synchronized(self) +} + +@end + +void GTMSessionFetcherAssertValidSelector(id _Nullable obj, SEL _Nullable sel, ...) { + // Verify that the object's selector is implemented with the proper + // number and type of arguments +#if DEBUG + va_list argList; + va_start(argList, sel); + + if (obj && sel) { + // Check that the selector is implemented + if (![obj respondsToSelector:sel]) { + NSLog(@"\"%@\" selector \"%@\" is unimplemented or misnamed", + NSStringFromClass([(id)obj class]), NSStringFromSelector((SEL)sel)); + NSCAssert(0, @"callback selector unimplemented or misnamed"); + } else { + const char *expectedArgType; + unsigned int argCount = 2; // skip self and _cmd + NSMethodSignature *sig = [obj methodSignatureForSelector:sel]; + + // Check that each expected argument is present and of the correct type + while ((expectedArgType = va_arg(argList, const char *)) != 0) { + if ([sig numberOfArguments] > argCount) { + const char *foundArgType = [sig getArgumentTypeAtIndex:argCount]; + + if (0 != strncmp(foundArgType, expectedArgType, strlen(expectedArgType))) { + NSLog(@"\"%@\" selector \"%@\" argument %d should be type %s", + NSStringFromClass([(id)obj class]), NSStringFromSelector((SEL)sel), + (argCount - 2), expectedArgType); + NSCAssert(0, @"callback selector argument type mistake"); + } + } + argCount++; + } + + // Check that the proper number of arguments are present in the selector + if (argCount != [sig numberOfArguments]) { + NSLog(@"\"%@\" selector \"%@\" should have %d arguments", + NSStringFromClass([(id)obj class]), NSStringFromSelector((SEL)sel), (argCount - 2)); + NSCAssert(0, @"callback selector arguments incorrect"); + } + } + } + + va_end(argList); +#endif +} + +NSString *GTMFetcherCleanedUserAgentString(NSString *str) { + // Reference http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html + // and http://www-archive.mozilla.org/build/user-agent-strings.html + + if (str == nil) return @""; + + NSMutableString *result = [NSMutableString stringWithString:str]; + + // Replace spaces and commas with underscores + [result replaceOccurrencesOfString:@" " + withString:@"_" + options:0 + range:NSMakeRange(0, result.length)]; + [result replaceOccurrencesOfString:@"," + withString:@"_" + options:0 + range:NSMakeRange(0, result.length)]; + + // Delete http token separators and remaining whitespace + static NSCharacterSet *charsToDelete = nil; + if (charsToDelete == nil) { + // Make a set of unwanted characters + NSString *const kSeparators = @"()<>@;:\\\"/[]?={}"; + + NSMutableCharacterSet *mutableChars = + [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy]; + [mutableChars addCharactersInString:kSeparators]; + charsToDelete = [mutableChars copy]; // hang on to an immutable copy + } + + while (1) { + NSRange separatorRange = [result rangeOfCharacterFromSet:charsToDelete]; + if (separatorRange.location == NSNotFound) break; + + [result deleteCharactersInRange:separatorRange]; + }; + + return result; +} + +NSString *GTMFetcherSystemVersionString(void) { + static NSString *sSavedSystemString; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ +#if TARGET_OS_WATCH + // watchOS - WKInterfaceDevice + + WKInterfaceDevice *currentDevice = [WKInterfaceDevice currentDevice]; + + NSString *rawModel = [currentDevice model]; + NSString *model = GTMFetcherCleanedUserAgentString(rawModel); + + NSString *systemVersion = [currentDevice systemVersion]; + +#if TARGET_OS_SIMULATOR + NSString *hardwareModel = @"sim"; +#else + NSString *hardwareModel; + struct utsname unameRecord; + if (uname(&unameRecord) == 0) { + NSString *machineName = @(unameRecord.machine); + hardwareModel = GTMFetcherCleanedUserAgentString(machineName); + } + if (hardwareModel.length == 0) { + hardwareModel = @"unk"; + } +#endif + + sSavedSystemString = + [[NSString alloc] initWithFormat:@"%@/%@ hw/%@", model, systemVersion, hardwareModel]; + // Example: Apple_Watch/3.0 hw/Watch1_2 +#elif TARGET_OS_TV || TARGET_OS_IOS + // iOS and tvOS have UIDevice, use that. + UIDevice *currentDevice = [UIDevice currentDevice]; + + NSString *rawModel = [currentDevice model]; + NSString *model = GTMFetcherCleanedUserAgentString(rawModel); + + NSString *systemVersion = [currentDevice systemVersion]; + +#if TARGET_OS_SIMULATOR + NSString *hardwareModel = @"sim"; +#else + NSString *hardwareModel; + struct utsname unameRecord; + if (uname(&unameRecord) == 0) { + NSString *machineName = @(unameRecord.machine); + hardwareModel = GTMFetcherCleanedUserAgentString(machineName); + } + if (hardwareModel.length == 0) { + hardwareModel = @"unk"; + } +#endif + + sSavedSystemString = [[NSString alloc] initWithFormat:@"%@/%@ hw/%@", + model, systemVersion, hardwareModel]; + // Example: iPod_Touch/2.2 hw/iPod1_1 + // Example: Apple_TV/9.2 hw/AppleTV5,3 +#elif TARGET_OS_OSX + // Mac build + NSProcessInfo *procInfo = [NSProcessInfo processInfo]; + NSString *versString; + NSOperatingSystemVersion version = procInfo.operatingSystemVersion; + versString = [NSString stringWithFormat:@"%ld.%ld.%ld", (long)version.majorVersion, + (long)version.minorVersion, (long)version.patchVersion]; + + sSavedSystemString = [[NSString alloc] initWithFormat:@"MacOSX/%@", versString]; +#elif defined(_SYS_UTSNAME_H) + // Foundation-only build + struct utsname unameRecord; + uname(&unameRecord); + + sSavedSystemString = [NSString stringWithFormat:@"%s/%s", + unameRecord.sysname, unameRecord.release]; // "Darwin/8.11.1" +#else +#error No branch taken for a default user agent +#endif + }); + return sSavedSystemString; +} + +NSString *GTMFetcherStandardUserAgentString(NSBundle *_Nullable bundle) { + NSString *result = [NSString stringWithFormat:@"%@ %@", GTMFetcherApplicationIdentifier(bundle), + GTMFetcherSystemVersionString()]; + return result; +} + +NSString *GTMFetcherApplicationIdentifier(NSBundle *_Nullable bundle) { + @synchronized([GTMSessionFetcher class]) { + static NSMutableDictionary *sAppIDMap = nil; + + // If there's a bundle ID, use that; otherwise, use the process name + if (bundle == nil) { + bundle = [NSBundle mainBundle]; + } + NSString *bundleID = [bundle bundleIdentifier]; + if (bundleID == nil) { + bundleID = @""; + } + + NSString *identifier = [sAppIDMap objectForKey:bundleID]; + if (identifier) return identifier; + + // Apps may add a string to the info.plist to uniquely identify different builds. + identifier = [bundle objectForInfoDictionaryKey:@"GTMUserAgentID"]; + if (identifier.length == 0) { + if (bundleID.length > 0) { + identifier = bundleID; + } else { + // Fall back on the procname, prefixed by "proc" to flag that it's + // autogenerated and perhaps unreliable + NSString *procName = [[NSProcessInfo processInfo] processName]; + identifier = [NSString stringWithFormat:@"proc_%@", procName]; + } + } + + // Clean up whitespace and special characters + identifier = GTMFetcherCleanedUserAgentString(identifier); + + // If there's a version number, append that + NSString *version = [bundle objectForInfoDictionaryKey:@"GTMUserAgentVersion"]; + if (version.length == 0) { + version = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + if (version.length == 0) { + version = [bundle objectForInfoDictionaryKey:@"CFBundleVersion"]; + } + } + + // Clean up whitespace and special characters + version = GTMFetcherCleanedUserAgentString(version); + + // Glue the two together (cleanup done above or else cleanup would strip the + // slash) + if (version.length > 0) { + identifier = [identifier stringByAppendingFormat:@"/%@", version]; + } + + if (sAppIDMap == nil) { + sAppIDMap = [[NSMutableDictionary alloc] init]; + } + [sAppIDMap setObject:identifier forKey:bundleID]; + return identifier; + } +} + +#if DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG) +@implementation GTMSessionSyncMonitorInternal { + NSValue *_objectKey; // The synchronize target object. + const char *_functionName; // The function containing the monitored sync block. +} + +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName { + self = [super init]; + if (self) { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + _objectKey = [NSValue valueWithNonretainedObject:object]; + _functionName = functionName; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + if (counters == nil) { + counters = [NSMutableDictionary dictionary]; + threadDict[(id)threadKey] = counters; + } + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSUInteger numberOfSyncingFunctions = functionNamesCounter.count; + + if (!allowRecursive) { + BOOL isTopLevelSyncScope = (numberOfSyncingFunctions == 0); + NSArray *stack = [NSThread callStackSymbols]; + GTMSESSION_ASSERT_DEBUG(isTopLevelSyncScope, + @"*** Recursive sync on %@ at %s; previous sync at %@\n%@", + [object class], functionName, functionNamesCounter.allObjects, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + } + + if (!functionNamesCounter) { + functionNamesCounter = [NSCountedSet set]; + counters[_objectKey] = functionNamesCounter; + } + [functionNamesCounter addObject:(id _Nonnull) @(functionName)]; + } + return self; +} + +- (void)dealloc { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSString *functionNameStr = @(_functionName); + NSUInteger numberOfSyncsByThisFunction = [functionNamesCounter countForObject:functionNameStr]; + NSArray *stack = [NSThread callStackSymbols]; + GTMSESSION_ASSERT_DEBUG(numberOfSyncsByThisFunction > 0, @"Sync not found on %@ at %s\n%@", + [_objectKey.nonretainedObjectValue class], _functionName, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + [functionNamesCounter removeObject:functionNameStr]; + if (functionNamesCounter.count == 0) { + [counters removeObjectForKey:_objectKey]; + } +} + ++ (nullable NSArray *)functionsHoldingSynchronizationOnObject:(id)object { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + NSValue *localObjectKey = [NSValue valueWithNonretainedObject:object]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[localObjectKey]; + return functionNamesCounter.count > 0 ? functionNamesCounter.allObjects : nil; +} +@end +#endif // DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG) +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h new file mode 100644 index 0000000..b3c1b43 --- /dev/null +++ b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.h @@ -0,0 +1,111 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GTMSessionFetcher.h" + +// GTM HTTP Logging +// +// All traffic using GTMSessionFetcher can be easily logged. Call +// +// [GTMSessionFetcher setLoggingEnabled:YES]; +// +// to begin generating log files. +// +// Unless explicitly set by the application using +setLoggingDirectory:, +// logs are put into a default directory, located at: +// * macOS: ~/Desktop/GTMHTTPDebugLogs +// * iOS simulator: ~/GTMHTTPDebugLogs (in application sandbox) +// * iOS device: ~/Documents/GTMHTTPDebugLogs (in application sandbox) +// +// Tip: use the Finder's "Sort By Date" to find the most recent logs. +// +// Each run of an application gets a separate set of log files. An html +// file is generated to simplify browsing the run's http transactions. +// The html file includes javascript links for inline viewing of uploaded +// and downloaded data. +// +// A symlink is created in the logs folder to simplify finding the html file +// for the latest run of the application; the symlink is called +// +// AppName_http_log_newest.html +// +// For better viewing of XML logs, use Camino or Firefox rather than Safari. +// +// Each fetcher may be given a comment to be inserted as a label in the logs, +// such as +// [fetcher setCommentWithFormat:@"retrieve item %@", itemName]; +// +// Projects may define STRIP_GTM_FETCH_LOGGING to remove logging code. + +#if !STRIP_GTM_FETCH_LOGGING + +@interface GTMSessionFetcher (GTMSessionFetcherLogging) + +// Note: on macOS the default logs directory is ~/Desktop/GTMHTTPDebugLogs; on +// iOS simulators it will be the ~/GTMHTTPDebugLogs (in the app sandbox); on +// iOS devices it will be in ~/Documents/GTMHTTPDebugLogs (in the app sandbox). +// These directories will be created as needed, and are excluded from backups +// to iCloud and iTunes. +// +// If a custom directory is set, the directory should already exist. It is +// the application's responsibility to exclude any custom directory from +// backups, if desired. ++ (void)setLoggingDirectory:(NSString *)path; ++ (NSString *)loggingDirectory; + +// client apps can turn logging on and off ++ (void)setLoggingEnabled:(BOOL)isLoggingEnabled; ++ (BOOL)isLoggingEnabled; + +// client apps can turn off logging to a file if they want to only check +// the fetcher's log property ++ (void)setLoggingToFileEnabled:(BOOL)isLoggingToFileEnabled; ++ (BOOL)isLoggingToFileEnabled; + +// client apps can optionally specify process name and date string used in +// log file names ++ (void)setLoggingProcessName:(NSString *)processName; ++ (NSString *)loggingProcessName; + ++ (void)setLoggingDateStamp:(NSString *)dateStamp; ++ (NSString *)loggingDateStamp; + +// client apps can specify the directory for the log for this specific run: +// +// [GTMSessionFetcher setLogDirectoryForCurrentRun:logDirectoryPath]; +// +// Setting this overrides the logging directory, process name, and date stamp when writing +// the log file. ++ (void)setLogDirectoryForCurrentRun:(NSString *)logDirectoryForCurrentRun; ++ (NSString *)logDirectoryForCurrentRun; + +// Prunes old log directories that have not been modified since the provided date. +// This will not delete the current run's log directory. ++ (void)deleteLogDirectoriesOlderThanDate:(NSDate *)date; + +// internal; called by fetcher +- (void)logFetchWithError:(NSError *)error; +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream; +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider; + +// internal; accessors useful for viewing logs ++ (NSString *)processNameLogPrefix; ++ (NSString *)symlinkNameSuffix; ++ (NSString *)htmlFileName; + +@end + +#endif // !STRIP_GTM_FETCH_LOGGING diff --git a/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m new file mode 100644 index 0000000..c728820 --- /dev/null +++ b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m @@ -0,0 +1,965 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#include +#include + +#import "GTMSessionFetcherLogging.h" + +#ifndef STRIP_GTM_FETCH_LOGGING +#error GTMSessionFetcher headers should have defaulted this if it wasn't already defined. +#endif + +#if !STRIP_GTM_FETCH_LOGGING + +// Sensitive credential strings are replaced in logs with _snip_ +// +// Apps that must see the contents of sensitive tokens can set this to 1 +#ifndef SKIP_GTM_FETCH_LOGGING_SNIPPING +#define SKIP_GTM_FETCH_LOGGING_SNIPPING 0 +#endif + +// If GTMReadMonitorInputStream is available, it can be used for +// capturing uploaded streams of data +// +// We locally declare methods of GTMReadMonitorInputStream so we +// do not need to import the header, as some projects may not have it available +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMReadMonitorInputStream : NSInputStream + ++ (instancetype)inputStreamWithStream:(NSInputStream *)input; + +@property(assign) id readDelegate; +@property(assign) SEL readSelector; + +@end +#else +@class GTMReadMonitorInputStream; +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionFetcher (GTMSessionFetcherLoggingUtilities) + ++ (NSString *)headersStringForDictionary:(NSDictionary *)dict; ++ (NSString *)snipSubstringOfString:(NSString *)originalStr + betweenStartString:(NSString *)startStr + endString:(NSString *)endStr; +- (void)inputStream:(GTMReadMonitorInputStream *)stream + readIntoBuffer:(void *)buffer + length:(int64_t)length; + +@end + +@implementation GTMSessionFetcher (GTMSessionFetcherLogging) + +// fetchers come and fetchers go, but statics are forever +static BOOL gIsLoggingEnabled = NO; +static BOOL gIsLoggingToFile = YES; +static NSString *gLoggingDirectoryPath = nil; +static NSString *gLogDirectoryForCurrentRun = nil; +static NSString *gLoggingDateStamp = nil; +static NSString *gLoggingProcessName = nil; + ++ (void)setLoggingDirectory:(NSString *)path { + gLoggingDirectoryPath = [path copy]; +} + ++ (NSString *)loggingDirectory { + if (!gLoggingDirectoryPath) { + NSArray *paths = nil; +#if TARGET_IPHONE_SIMULATOR + // default to a directory called GTMHTTPDebugLogs into a sandbox-safe + // directory that a developer can find easily, the application home + paths = @[ NSHomeDirectory() ]; +#elif TARGET_OS_IPHONE + // Neither ~/Desktop nor ~/Home is writable on an actual iOS, watchOS, or tvOS device. + // Put it in ~/Documents. + paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); +#else + // default to a directory called GTMHTTPDebugLogs in the desktop folder + paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES); +#endif + + NSString *desktopPath = paths.firstObject; + if (desktopPath) { + NSString *const kGTMLogFolderName = @"GTMHTTPDebugLogs"; + NSString *logsFolderPath = [desktopPath stringByAppendingPathComponent:kGTMLogFolderName]; + + NSFileManager *fileMgr = [NSFileManager defaultManager]; + BOOL isDir; + BOOL doesFolderExist = [fileMgr fileExistsAtPath:logsFolderPath isDirectory:&isDir]; + if (!doesFolderExist) { + // make the directory + doesFolderExist = [fileMgr createDirectoryAtPath:logsFolderPath + withIntermediateDirectories:YES + attributes:nil + error:NULL]; + if (doesFolderExist) { + // The directory has been created. Exclude it from backups. + NSURL *pathURL = [NSURL fileURLWithPath:logsFolderPath isDirectory:YES]; + [pathURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:NULL]; + } + } + + if (doesFolderExist) { + // it's there; store it in the global + gLoggingDirectoryPath = [logsFolderPath copy]; + } + } + } + return gLoggingDirectoryPath; +} + ++ (void)setLogDirectoryForCurrentRun:(NSString *)logDirectoryForCurrentRun { + // Set the path for this run's logs. + gLogDirectoryForCurrentRun = [logDirectoryForCurrentRun copy]; +} + ++ (NSString *)logDirectoryForCurrentRun { + // make a directory for this run's logs, like SyncProto_logs_10-16_01-56-58PM + if (gLogDirectoryForCurrentRun) return gLogDirectoryForCurrentRun; + + NSString *parentDir = [self loggingDirectory]; + NSString *logNamePrefix = [self processNameLogPrefix]; + NSString *dateStamp = [self loggingDateStamp]; + NSString *dirName = [NSString stringWithFormat:@"%@%@", logNamePrefix, dateStamp]; + NSString *logDirectory = [parentDir stringByAppendingPathComponent:dirName]; + + if (gIsLoggingToFile) { + NSFileManager *fileMgr = [NSFileManager defaultManager]; + // Be sure that the first time this app runs, it's not writing to a preexisting folder + static BOOL gShouldReuseFolder = NO; + if (!gShouldReuseFolder) { + gShouldReuseFolder = YES; + NSString *origLogDir = logDirectory; + for (int ctr = 2; ctr < 20; ++ctr) { + if (![fileMgr fileExistsAtPath:logDirectory]) break; + + // append a digit + logDirectory = [origLogDir stringByAppendingFormat:@"_%d", ctr]; + } + } + if (![fileMgr createDirectoryAtPath:logDirectory + withIntermediateDirectories:YES + attributes:nil + error:NULL]) + return nil; + } + gLogDirectoryForCurrentRun = logDirectory; + + return gLogDirectoryForCurrentRun; +} + ++ (void)setLoggingEnabled:(BOOL)isLoggingEnabled { + gIsLoggingEnabled = isLoggingEnabled; +} + ++ (BOOL)isLoggingEnabled { + return gIsLoggingEnabled; +} + ++ (void)setLoggingToFileEnabled:(BOOL)isLoggingToFileEnabled { + gIsLoggingToFile = isLoggingToFileEnabled; +} + ++ (BOOL)isLoggingToFileEnabled { + return gIsLoggingToFile; +} + ++ (void)setLoggingProcessName:(NSString *)processName { + gLoggingProcessName = [processName copy]; +} + ++ (NSString *)loggingProcessName { + // get the process name (once per run) replacing spaces with underscores + if (!gLoggingProcessName) { + NSString *procName = [[NSProcessInfo processInfo] processName]; + gLoggingProcessName = [procName stringByReplacingOccurrencesOfString:@" " withString:@"_"]; + } + return gLoggingProcessName; +} + ++ (void)setLoggingDateStamp:(NSString *)dateStamp { + gLoggingDateStamp = [dateStamp copy]; +} + ++ (NSString *)loggingDateStamp { + // We'll pick one date stamp per run, so a run that starts at a later second + // will get a unique results html file + if (!gLoggingDateStamp) { + // produce a string like 08-21_01-41-23PM + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + [formatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [formatter setDateFormat:@"M-dd_hh-mm-ssa"]; + + gLoggingDateStamp = [formatter stringFromDate:[NSDate date]]; + } + return gLoggingDateStamp; +} + ++ (NSString *)processNameLogPrefix { + static NSString *gPrefix = nil; + if (!gPrefix) { + NSString *processName = [self loggingProcessName]; + gPrefix = [[NSString alloc] initWithFormat:@"%@_log_", processName]; + } + return gPrefix; +} + ++ (NSString *)symlinkNameSuffix { + return @"_log_newest.html"; +} + ++ (NSString *)htmlFileName { + return @"aperçu_http_log.html"; +} + ++ (void)deleteLogDirectoriesOlderThanDate:(NSDate *)cutoffDate { + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSURL *parentDir = [NSURL fileURLWithPath:[[self class] loggingDirectory]]; + NSURL *logDirectoryForCurrentRun = + [NSURL fileURLWithPath:[[self class] logDirectoryForCurrentRun]]; + NSError *error; + NSArray *contents = [fileMgr contentsOfDirectoryAtURL:parentDir + includingPropertiesForKeys:@[ NSURLContentModificationDateKey ] + options:0 + error:&error]; + for (NSURL *itemURL in contents) { + if ([itemURL isEqual:logDirectoryForCurrentRun]) continue; + + NSDate *modDate; + if ([itemURL getResourceValue:&modDate forKey:NSURLContentModificationDateKey error:&error]) { + if ([modDate compare:cutoffDate] == NSOrderedAscending) { + if (![fileMgr removeItemAtURL:itemURL error:&error]) { + NSLog(@"deleteLogDirectoriesOlderThanDate failed to delete %@: %@", itemURL.path, error); + } + } + } else { + NSLog(@"deleteLogDirectoriesOlderThanDate failed to get mod date of %@: %@", itemURL.path, + error); + } + } +} + +// formattedStringFromData returns a prettyprinted string for XML or JSON input, +// and a plain string for other input data +- (NSString *)formattedStringFromData:(NSData *)inputData + contentType:(NSString *)contentType + JSON:(NSDictionary **)outJSON { + if (!inputData) return nil; + + // if the content type is JSON and we have the parsing class available, use that + if ([contentType hasPrefix:@"application/json"] && inputData.length > 5) { + // convert from JSON string to NSObjects and back to a formatted string + NSMutableDictionary *obj = + [NSJSONSerialization JSONObjectWithData:inputData + options:NSJSONReadingMutableContainers + error:NULL]; + if (obj) { + if (outJSON) *outJSON = obj; + if ([obj isKindOfClass:[NSMutableDictionary class]]) { + // for security and privacy, omit OAuth 2 response access and refresh tokens + if ([obj valueForKey:@"refresh_token"] != nil) { + [obj setObject:@"_snip_" forKey:@"refresh_token"]; + } + if ([obj valueForKey:@"access_token"] != nil) { + [obj setObject:@"_snip_" forKey:@"access_token"]; + } + } + NSData *data = [NSJSONSerialization dataWithJSONObject:obj + options:NSJSONWritingPrettyPrinted + error:NULL]; + if (data) { + NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return jsonStr; + } + } + } + +#if !TARGET_OS_IPHONE && !GTM_SKIP_LOG_XMLFORMAT + // verify that this data starts with the bytes indicating XML + + NSString *const kXMLLintPath = @"/usr/bin/xmllint"; + static BOOL gHasCheckedAvailability = NO; + static BOOL gIsXMLLintAvailable = NO; + + if (!gHasCheckedAvailability) { + gIsXMLLintAvailable = [[NSFileManager defaultManager] fileExistsAtPath:kXMLLintPath]; + gHasCheckedAvailability = YES; + } + if (gIsXMLLintAvailable && inputData.length > 5 && strncmp(inputData.bytes, " 0) { + // success + inputData = formattedData; + } + } +#else + // we can't call external tasks on the iPhone; leave the XML unformatted +#endif + + NSString *dataStr = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding]; + return dataStr; +} + +// stringFromStreamData creates a string given the supplied data +// +// If NSString can create a UTF-8 string from the data, then that is returned. +// +// Otherwise, this routine tries to find a MIME boundary at the beginning of the data block, and +// uses that to break up the data into parts. Each part will be used to try to make a UTF-8 string. +// For parts that fail, a replacement string showing the part header and <> is supplied +// in place of the binary data. + +- (NSString *)stringFromStreamData:(NSData *)data contentType:(NSString *)contentType { + if (!data) return nil; + + // optimistically, see if the whole data block is UTF-8 + NSString *streamDataStr = [self formattedStringFromData:data contentType:contentType JSON:NULL]; + if (streamDataStr) return streamDataStr; + + // Munge a buffer by replacing non-ASCII bytes with underscores, and turn that munged buffer an + // NSString. That gives us a string we can use with NSScanner. + NSMutableData *mutableData = [NSMutableData dataWithData:data]; + unsigned char *bytes = (unsigned char *)mutableData.mutableBytes; + + for (unsigned int idx = 0; idx < mutableData.length; ++idx) { + if (bytes[idx] > 0x7F || bytes[idx] == 0) { + bytes[idx] = '_'; + } + } + + NSString *mungedStr = [[NSString alloc] initWithData:mutableData encoding:NSUTF8StringEncoding]; + if (mungedStr) { + // scan for the boundary string + NSString *boundary = nil; + NSScanner *scanner = [NSScanner scannerWithString:mungedStr]; + + if ([scanner scanUpToString:@"\r\n" intoString:&boundary] && [boundary hasPrefix:@"--"]) { + // we found a boundary string; use it to divide the string into parts + NSArray *mungedParts = [mungedStr componentsSeparatedByString:boundary]; + + // look at each munged part in the original string, and try to convert those into UTF-8 + NSMutableArray *origParts = [NSMutableArray array]; + NSUInteger offset = 0; + for (NSString *mungedPart in mungedParts) { + NSUInteger partSize = mungedPart.length; + NSData *origPartData = [data subdataWithRange:NSMakeRange(offset, partSize)]; + NSString *origPartStr = [[NSString alloc] initWithData:origPartData + encoding:NSUTF8StringEncoding]; + if (origPartStr) { + // we could make this original part into UTF-8; use the string + [origParts addObject:origPartStr]; + } else { + // this part can't be made into UTF-8; scan the header, if we can + NSString *header = nil; + NSScanner *headerScanner = [NSScanner scannerWithString:mungedPart]; + if (![headerScanner scanUpToString:@"\r\n\r\n" intoString:&header]) { + // we couldn't find a header + header = @""; + } + // make a part string with the header and <> + NSString *binStr = [NSString + stringWithFormat:@"\r%@\r<<%lu bytes>>\r", header, (long)(partSize - header.length)]; + [origParts addObject:binStr]; + } + offset += partSize + boundary.length; + } + // rejoin the original parts + streamDataStr = [origParts componentsJoinedByString:boundary]; + } + } + if (!streamDataStr) { + // give up; just make a string showing the uploaded bytes + streamDataStr = [NSString stringWithFormat:@"<<%u bytes>>", (unsigned int)data.length]; + } + return streamDataStr; +} + +// logFetchWithError is called following a successful or failed fetch attempt +// +// This method does all the work for appending to and creating log files + +- (void)logFetchWithError:(NSError *)error { + if (![[self class] isLoggingEnabled]) return; + NSString *logDirectory = [[self class] logDirectoryForCurrentRun]; + if (!logDirectory) return; + NSString *processName = [[self class] loggingProcessName]; + + // TODO: add Javascript to display response data formatted in hex + + // each response's NSData goes into its own xml or txt file, though all responses for this run of + // the app share a main html file. This counter tracks all fetch responses for this app run. + // + // we'll use a local variable since this routine may be reentered while waiting for XML formatting + // to be completed by an external task + static int gResponseCounter = 0; + int responseCounter = ++gResponseCounter; + + NSURLResponse *response = [self response]; + NSDictionary *responseHeaders = [self responseHeaders]; + NSString *responseDataStr = nil; + NSDictionary *responseJSON = nil; + + // if there's response data, decide what kind of file to put it in based on the first bytes of the + // file or on the mime type supplied by the server + NSString *responseMIMEType = [response MIMEType]; + BOOL isResponseImage = NO; + + // file name for an image data file + NSString *responseDataFileName = nil; + + int64_t responseDataLength = self.downloadedLength; + if (responseDataLength > 0) { + NSData *downloadedData = self.downloadedData; + if (downloadedData == nil && responseDataLength > 0 && responseDataLength < 20000 && + self.destinationFileURL) { + // There's a download file that's not too big, so get the data to display from the downloaded + // file. + NSURL *destinationURL = self.destinationFileURL; + downloadedData = [NSData dataWithContentsOfURL:destinationURL]; + } + NSString *responseType = [responseHeaders valueForKey:@"Content-Type"]; + responseDataStr = [self formattedStringFromData:downloadedData + contentType:responseType + JSON:&responseJSON]; + NSString *responseDataExtn = nil; + NSData *dataToWrite = nil; + if (responseDataStr) { + // we were able to make a UTF-8 string from the response data + if ([responseMIMEType isEqual:@"application/atom+xml"] || + [responseMIMEType hasSuffix:@"/xml"]) { + responseDataExtn = @"xml"; + dataToWrite = [responseDataStr dataUsingEncoding:NSUTF8StringEncoding]; + } + } else if ([responseMIMEType isEqual:@"image/jpeg"]) { + responseDataExtn = @"jpg"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else if ([responseMIMEType isEqual:@"image/gif"]) { + responseDataExtn = @"gif"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else if ([responseMIMEType isEqual:@"image/png"]) { + responseDataExtn = @"png"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else { + // add more non-text types here + } + // if we have an extension, save the raw data in a file with that extension + if (responseDataExtn && dataToWrite) { + // generate a response file base name like + NSString *responseBaseName = + [NSString stringWithFormat:@"fetch_%d_response", responseCounter]; + responseDataFileName = [responseBaseName stringByAppendingPathExtension:responseDataExtn]; + NSString *responseDataFilePath = + [logDirectory stringByAppendingPathComponent:responseDataFileName]; + + NSError *downloadedError = nil; + if (gIsLoggingToFile && ![dataToWrite writeToFile:responseDataFilePath + options:0 + error:&downloadedError]) { + NSLog(@"%@ logging write error:%@ (%@)", [self class], downloadedError, + responseDataFileName); + } + } + } + // we'll have one main html file per run of the app + NSString *htmlName = [[self class] htmlFileName]; + NSString *htmlPath = [logDirectory stringByAppendingPathComponent:htmlName]; + + // if the html file exists (from logging previous fetches) we don't need + // to re-write the header or the scripts + NSFileManager *fileMgr = [NSFileManager defaultManager]; + BOOL didFileExist = [fileMgr fileExistsAtPath:htmlPath]; + + NSMutableString *outputHTML = [NSMutableString string]; + + // we need a header to say we'll have UTF-8 text + if (!didFileExist) { + [outputHTML + appendFormat:@"%@ HTTP fetch log %@", + processName, [[self class] loggingDateStamp]]; + } + // now write the visible html elements + NSString *copyableFileName = [NSString stringWithFormat:@"fetch_%d.txt", responseCounter]; + + NSDate *now = [NSDate date]; + // write the date & time, the comment, and the link to the plain-text (copyable) log + [outputHTML appendFormat:@"%@      ", now]; + + NSString *comment = [self comment]; + if (comment.length > 0) { + [outputHTML appendFormat:@"%@      ", comment]; + } + [outputHTML + appendFormat:@"request/response log
", copyableFileName]; + NSTimeInterval elapsed = -self.initialBeginFetchDate.timeIntervalSinceNow; + [outputHTML appendFormat:@"elapsed: %5.3fsec
", elapsed]; + + // write the request URL + NSURLRequest *request = self.request; + NSString *requestMethod = request.HTTPMethod; + NSURL *requestURL = request.URL; + + // Save the request URL for next time in case this redirects. + NSString *redirectedFromURLString = [self.redirectedFromURL absoluteString]; + self.redirectedFromURL = [requestURL copy]; + if (redirectedFromURLString) { + [outputHTML appendFormat:@"redirected from %@
", + redirectedFromURLString]; + } + [outputHTML appendFormat:@"request: %@ %@
\n", requestMethod, requestURL]; + + // write the request headers + NSDictionary *requestHeaders = request.allHTTPHeaderFields; + NSUInteger numberOfRequestHeaders = requestHeaders.count; + if (numberOfRequestHeaders > 0) { + // Indicate if the request is authorized; warn if the request is authorized but non-SSL + NSString *auth = [requestHeaders objectForKey:@"Authorization"]; + NSString *headerDetails = @""; + if (auth) { + BOOL isInsecure = [[requestURL scheme] isEqual:@"http"]; + if (isInsecure) { + // 26A0 = âš  + headerDetails = + @"   authorized, non-SSL "; + } else { + headerDetails = @"   authorized"; + } + } + NSString *cookiesHdr = [requestHeaders objectForKey:@"Cookie"]; + if (cookiesHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   cookies"]; + } + NSString *matchHdr = [requestHeaders objectForKey:@"If-Match"]; + if (matchHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   if-match"]; + } + matchHdr = [requestHeaders objectForKey:@"If-None-Match"]; + if (matchHdr) { + headerDetails = + [headerDetails stringByAppendingString:@"   if-none-match"]; + } + [outputHTML appendFormat:@"   headers: %d %@
", (int)numberOfRequestHeaders, + headerDetails]; + } else { + [outputHTML appendFormat:@"   headers: none
"]; + } + // write the request post data + NSData *bodyData = nil; + NSData *loggedStreamData = self.loggedStreamData; + if (loggedStreamData) { + bodyData = loggedStreamData; + } else { + bodyData = self.bodyData; + if (bodyData == nil) { + bodyData = self.request.HTTPBody; + } + } + uint64_t bodyDataLength = bodyData.length; + + if (bodyData.length == 0) { + // If the data is in a body upload file URL, read that in if it's not huge. + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSNumber *fileSizeNum = nil; + NSError *fileSizeError = nil; + if ([bodyFileURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:&fileSizeError]) { + bodyDataLength = [fileSizeNum unsignedLongLongValue]; + if (bodyDataLength > 0 && bodyDataLength < 50000) { + bodyData = [NSData dataWithContentsOfURL:bodyFileURL + options:NSDataReadingUncached + error:&fileSizeError]; + } + } + } + } + NSString *bodyDataStr = nil; + NSString *postType = [requestHeaders valueForKey:@"Content-Type"]; + + if (bodyDataLength > 0) { + [outputHTML appendFormat:@"   data: %llu bytes, %@
\n", + bodyDataLength, postType ? postType : @"(no type)"]; + NSString *logRequestBody = self.logRequestBody; + if (logRequestBody) { + bodyDataStr = [logRequestBody copy]; + self.logRequestBody = nil; + } else { + bodyDataStr = [self stringFromStreamData:bodyData contentType:postType]; + if (bodyDataStr) { + // remove OAuth 2 client secret and refresh token + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"client_secret=" + endString:@"&"]; + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"refresh_token=" + endString:@"&"]; + // remove ClientLogin password + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"&Passwd=" + endString:@"&"]; + } + } + } else { + // no post data + } + // write the response status, MIME type, URL + NSInteger status = [self statusCode]; + if (response) { + NSString *statusString = @""; + if (status != 0) { + if (status == 200 || status == 201) { + statusString = [NSString stringWithFormat:@"%ld", (long)status]; + + // report any JSON-RPC error + if ([responseJSON isKindOfClass:[NSDictionary class]]) { + NSDictionary *jsonError = [responseJSON objectForKey:@"error"]; + if ([jsonError isKindOfClass:[NSDictionary class]]) { + NSString *jsonCode = [[jsonError valueForKey:@"code"] description]; + NSString *jsonMessage = [jsonError valueForKey:@"message"]; + if (jsonCode || jsonMessage) { + // 2691 = âš‘ + NSString *const jsonErrFmt = @"   JSON error: %@ %@  ⚑"; + statusString = + [statusString stringByAppendingFormat:jsonErrFmt, jsonCode ? jsonCode : @"", + jsonMessage ? jsonMessage : @""]; + } + } + } + } else { + // purple for anything other than 200 or 201 + NSString *flag = status >= 400 ? @" ⚑" : @""; // 2691 = âš‘ + NSString *explanation = [NSHTTPURLResponse localizedStringForStatusCode:status]; + NSString *const statusFormat = @"%ld %@ %@"; + statusString = [NSString stringWithFormat:statusFormat, (long)status, explanation, flag]; + } + } + // show the response URL only if it's different from the request URL + NSString *responseURLStr = @""; + NSURL *responseURL = response.URL; + + if (responseURL && ![responseURL isEqual:request.URL]) { + NSString *const responseURLFormat = + @"response URL: %@
\n"; + responseURLStr = [NSString stringWithFormat:responseURLFormat, [responseURL absoluteString]]; + } + [outputHTML appendFormat:@"response:  status %@
\n%@", statusString, + responseURLStr]; + // Write the response headers + NSUInteger numberOfResponseHeaders = responseHeaders.count; + if (numberOfResponseHeaders > 0) { + // Indicate if the server is setting cookies + NSString *cookiesSet = [responseHeaders valueForKey:@"Set-Cookie"]; + NSString *cookiesStr = + cookiesSet ? @"  sets cookies" : @""; + // Indicate if the server is redirecting + NSString *location = [responseHeaders valueForKey:@"Location"]; + BOOL isRedirect = status >= 300 && status <= 399 && location != nil; + NSString *redirectsStr = + isRedirect ? @"  redirects" : @""; + [outputHTML appendFormat:@"   headers: %d %@ %@
\n", + (int)numberOfResponseHeaders, cookiesStr, redirectsStr]; + } else { + [outputHTML appendString:@"   headers: none
\n"]; + } + } + // error + if (error) { + [outputHTML appendFormat:@"Error: %@
\n", error.description]; + } + // Write the response data + if (responseDataFileName) { + if (isResponseImage) { + // Make a small inline image that links to the full image file + [outputHTML appendFormat:@"   data: %lld bytes, %@
", + responseDataLength, responseMIMEType]; + NSString *const fmt = @"image\n"; + [outputHTML appendFormat:fmt, responseDataFileName, responseDataFileName]; + } else { + // The response data was XML; link to the xml file + NSString *const fmt = @"   data: %lld bytes, " + @"%@   %@\n"; + [outputHTML appendFormat:fmt, responseDataLength, responseMIMEType, responseDataFileName, + [responseDataFileName pathExtension]]; + } + } else { + // The response data was not an image; just show the length and MIME type + [outputHTML appendFormat:@"   data: %lld bytes, %@\n", + responseDataLength, + responseMIMEType ? responseMIMEType : @"(no response type)"]; + } + // Make a single string of the request and response, suitable for copying + // to the clipboard and pasting into a bug report + NSMutableString *copyable = [NSMutableString string]; + if (comment) { + [copyable appendFormat:@"%@\n\n", comment]; + } + [copyable appendFormat:@"%@ elapsed: %5.3fsec\n", now, elapsed]; + if (redirectedFromURLString) { + [copyable appendFormat:@"Redirected from %@\n", redirectedFromURLString]; + } + [copyable appendFormat:@"Request: %@ %@\n", requestMethod, requestURL]; + if (requestHeaders.count > 0) { + [copyable appendFormat:@"Request headers:\n%@\n", + [[self class] headersStringForDictionary:requestHeaders]]; + } + if (bodyDataLength > 0) { + [copyable appendFormat:@"Request body: (%llu bytes)\n", bodyDataLength]; + if (bodyDataStr) { + [copyable appendFormat:@"%@\n", bodyDataStr]; + } + [copyable appendString:@"\n"]; + } + if (response) { + [copyable appendFormat:@"Response: status %d\n", (int)status]; + [copyable appendFormat:@"Response headers:\n%@\n", + [[self class] headersStringForDictionary:responseHeaders]]; + [copyable appendFormat:@"Response body: (%lld bytes)\n", responseDataLength]; + if (responseDataLength > 0) { + NSString *logResponseBody = self.logResponseBody; + if (logResponseBody) { + // The user has provided the response body text. + responseDataStr = [logResponseBody copy]; + self.logResponseBody = nil; + } + if (responseDataStr != nil) { + [copyable appendFormat:@"%@\n", responseDataStr]; + } else { + // Even though it's redundant, we'll put in text to indicate that all the bytes are binary. + if (self.destinationFileURL) { + [copyable appendFormat:@"<<%lld bytes>> to file %@\n", responseDataLength, + self.destinationFileURL.path]; + } else { + [copyable appendFormat:@"<<%lld bytes>>\n", responseDataLength]; + } + } + } + } + if (error) { + [copyable appendFormat:@"Error: %@\n", error]; + } + // Save to log property before adding the separator + self.log = copyable; + + [copyable appendString:@"-----------------------------------------------------------\n"]; + + // Write the copyable version to another file (linked to at the top of the html file, above) + // + // Ideally, something to just copy this to the clipboard like + // Copy here." + // would work everywhere, but it only works in Safari as of 8/2010 + if (gIsLoggingToFile) { + NSString *parentDir = [[self class] loggingDirectory]; + NSString *copyablePath = [logDirectory stringByAppendingPathComponent:copyableFileName]; + NSError *copyableError = nil; + if (![copyable writeToFile:copyablePath + atomically:NO + encoding:NSUTF8StringEncoding + error:©ableError]) { + // Error writing to file + NSLog(@"%@ logging write error:%@ (%@)", [self class], copyableError, copyablePath); + } + [outputHTML appendString:@"

"]; + + // Append the HTML to the main output file + const char *htmlBytes = outputHTML.UTF8String; + NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:htmlPath append:YES]; + [stream open]; + [stream write:(const uint8_t *)htmlBytes maxLength:strlen(htmlBytes)]; + [stream close]; + + // Make a symlink to the latest html + NSString *const symlinkNameSuffix = [[self class] symlinkNameSuffix]; + NSString *symlinkName = [processName stringByAppendingString:symlinkNameSuffix]; + NSString *symlinkPath = [parentDir stringByAppendingPathComponent:symlinkName]; + + [fileMgr removeItemAtPath:symlinkPath error:NULL]; + [fileMgr createSymbolicLinkAtPath:symlinkPath withDestinationPath:htmlPath error:NULL]; +#if TARGET_OS_IPHONE + static BOOL gReportedLoggingPath = NO; + if (!gReportedLoggingPath) { + gReportedLoggingPath = YES; + NSLog(@"GTMSessionFetcher logging to \"%@\"", parentDir); + } +#endif + } +} + +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream { + if (!inputStream) return nil; + if (![GTMSessionFetcher isLoggingEnabled]) return inputStream; + + [self clearLoggedStreamData]; // Clear any previous data. + Class monitorClass = NSClassFromString(@"GTMReadMonitorInputStream"); + if (!monitorClass) { + NSString const *str = @"<>"; + NSData *stringData = [str dataUsingEncoding:NSUTF8StringEncoding]; + [self appendLoggedStreamData:stringData]; + return inputStream; + } + inputStream = [monitorClass inputStreamWithStream:inputStream]; + + GTMReadMonitorInputStream *readMonitorInputStream = (GTMReadMonitorInputStream *)inputStream; + [readMonitorInputStream setReadDelegate:self]; + SEL readSel = @selector(inputStream:readIntoBuffer:length:); + [readMonitorInputStream setReadSelector:readSel]; + + return inputStream; +} + +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider { + if (!streamProvider) return nil; + if (![GTMSessionFetcher isLoggingEnabled]) return streamProvider; + + [self clearLoggedStreamData]; // Clear any previous data. + Class monitorClass = NSClassFromString(@"GTMReadMonitorInputStream"); + if (!monitorClass) { + NSString const *str = @"<>"; + NSData *stringData = [str dataUsingEncoding:NSUTF8StringEncoding]; + [self appendLoggedStreamData:stringData]; + return streamProvider; + } + GTMSessionFetcherBodyStreamProvider loggedStreamProvider = + ^(GTMSessionFetcherBodyStreamProviderResponse response) { + streamProvider(^(NSInputStream *bodyStream) { + bodyStream = [self loggedInputStreamForInputStream:bodyStream]; + response(bodyStream); + }); + }; + return loggedStreamProvider; +} + +@end + +@implementation GTMSessionFetcher (GTMSessionFetcherLoggingUtilities) + +- (void)inputStream:(GTMReadMonitorInputStream *)stream + readIntoBuffer:(void *)buffer + length:(int64_t)length { + // append the captured data + NSData *data = [NSData dataWithBytesNoCopy:buffer length:(NSUInteger)length freeWhenDone:NO]; + [self appendLoggedStreamData:data]; +} + +#pragma mark Fomatting Utilities + ++ (NSString *)snipSubstringOfString:(NSString *)originalStr + betweenStartString:(NSString *)startStr + endString:(NSString *)endStr { +#if SKIP_GTM_FETCH_LOGGING_SNIPPING + return originalStr; +#else + if (!originalStr) return nil; + + // Find the start string, and replace everything between it + // and the end string (or the end of the original string) with "_snip_" + NSRange startRange = [originalStr rangeOfString:startStr]; + if (startRange.location == NSNotFound) return originalStr; + + // We found the start string + NSUInteger originalLength = originalStr.length; + NSUInteger startOfTarget = NSMaxRange(startRange); + NSRange targetAndRest = NSMakeRange(startOfTarget, originalLength - startOfTarget); + NSRange endRange = [originalStr rangeOfString:endStr options:0 range:targetAndRest]; + NSRange replaceRange; + if (endRange.location == NSNotFound) { + // Found no end marker so replace to end of string + replaceRange = targetAndRest; + } else { + // Replace up to the endStr + replaceRange = NSMakeRange(startOfTarget, endRange.location - startOfTarget); + } + NSString *result = [originalStr stringByReplacingCharactersInRange:replaceRange + withString:@"_snip_"]; + return result; +#endif // SKIP_GTM_FETCH_LOGGING_SNIPPING +} + ++ (NSString *)headersStringForDictionary:(NSDictionary *)dict { + // Format the dictionary in http header style, like + // Accept: application/json + // Cache-Control: no-cache + // Content-Type: application/json; charset=utf-8 + // + // Pad the key names, but not beyond 16 chars, since long custom header + // keys just create too much whitespace + NSArray *keys = [dict.allKeys sortedArrayUsingSelector:@selector(compare:)]; + + NSMutableString *str = [NSMutableString string]; + for (NSString *key in keys) { + NSString *value = [dict valueForKey:key]; + if ([key isEqual:@"Authorization"]) { + // Remove OAuth 1 token + value = [[self class] snipSubstringOfString:value + betweenStartString:@"oauth_token=\"" + endString:@"\""]; + + // Remove OAuth 2 bearer token (draft 16, and older form) + value = [[self class] snipSubstringOfString:value + betweenStartString:@"Bearer " + endString:@"\n"]; + value = [[self class] snipSubstringOfString:value + betweenStartString:@"OAuth " + endString:@"\n"]; + + // Remove Google ClientLogin + value = [[self class] snipSubstringOfString:value + betweenStartString:@"GoogleLogin auth=" + endString:@"\n"]; + } + [str appendFormat:@" %@: %@\n", key, value]; + } + return str; +} + +@end + +#endif // !STRIP_GTM_FETCH_LOGGING diff --git a/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h new file mode 100644 index 0000000..68f3ac5 --- /dev/null +++ b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.h @@ -0,0 +1,210 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// For best performance and convenient usage, fetchers should be generated by a common +// GTMSessionFetcherService instance, like +// +// _fetcherService = [[GTMSessionFetcherService alloc] init]; +// GTMSessionFetcher* myFirstFetcher = [_fetcherService fetcherWithRequest:request1]; +// GTMSessionFetcher* mySecondFetcher = [_fetcherService fetcherWithRequest:request2]; + +#import "GTMSessionFetcher.h" + +NS_ASSUME_NONNULL_BEGIN + +// Notifications. + +// This notification indicates a reusable session has become invalid. It is intended mainly for the +// service's unit tests. +// +// The notification object is the fetcher service. +// The invalid session is provided via the userInfo kGTMSessionFetcherServiceSessionKey key. +extern NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification; +extern NSString *const kGTMSessionFetcherServiceSessionKey; + +@interface GTMSessionFetcherService : NSObject + +// Queues of delayed and running fetchers. Each dictionary contains arrays +// of GTMSessionFetcher *fetchers, keyed by NSString *host +@property(atomic, strong, readonly, nullable) + NSDictionary *delayedFetchersByHost; +@property(atomic, strong, readonly, nullable) + NSDictionary *runningFetchersByHost; + +// A max value of 0 means no fetchers should be delayed. +// The default limit is 10 simultaneous fetchers targeting each host. +// This does not apply to fetchers whose useBackgroundSession property is YES. Since services are +// not resurrected on an app relaunch, delayed fetchers would effectively be abandoned. +@property(atomic, assign) NSUInteger maxRunningFetchersPerHost; + +// Properties to be applied to each fetcher; see GTMSessionFetcher.h for descriptions +@property(atomic, strong, nullable) NSURLSessionConfiguration *configuration; +@property(atomic, copy, nullable) GTMSessionFetcherConfigurationBlock configurationBlock; +@property(atomic, strong, nullable) NSHTTPCookieStorage *cookieStorage; +@property(atomic, strong, null_resettable) dispatch_queue_t callbackQueue; +@property(atomic, copy, nullable) GTMSessionFetcherChallengeBlock challengeBlock; +@property(atomic, strong, nullable) NSURLCredential *credential; +@property(atomic, strong) NSURLCredential *proxyCredential; +@property(atomic, copy, nullable) NSArray *allowedInsecureSchemes; +@property(atomic, assign) BOOL allowLocalhostRequest; +@property(atomic, assign) BOOL allowInvalidServerCertificates; +@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled; +@property(atomic, copy, nullable) GTMSessionFetcherRetryBlock retryBlock; +@property(atomic, assign) NSTimeInterval maxRetryInterval; +@property(atomic, assign) NSTimeInterval minRetryInterval; +@property(atomic, copy, nullable) NSDictionary *properties; +@property(atomic, copy, nullable) + GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock API_AVAILABLE( + ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)); + +#if GTM_BACKGROUND_TASK_FETCHING +@property(atomic, assign) BOOL skipBackgroundTask; +#endif + +// A default useragent of GTMFetcherStandardUserAgentString(nil) will be given to each fetcher +// created by this service unless the request already has a user-agent header set. +// This default will be added starting with builds with the SDKs for OS X 10.11 and iOS 9. +// +// To use the configuration's default user agent, set this property to nil. +@property(atomic, copy, nullable) NSString *userAgent; + +// The authorizer to attach to the created fetchers. If a specific fetcher should +// not authorize its requests, the fetcher's authorizer property may be set to nil +// before the fetch begins. +@property(atomic, strong, nullable) id authorizer; + +// Delegate queue used by the session when calling back to the fetcher. The default +// is the main queue. Changing this does not affect the queue used to call back to the +// application; that is specified by the callbackQueue property above. +@property(atomic, strong, null_resettable) NSOperationQueue *sessionDelegateQueue; + +// When enabled, indicates the same session should be used by subsequent fetchers. +// +// This is enabled by default. +@property(atomic, assign) BOOL reuseSession; + +// Sets the delay until an unused session is invalidated. +// The default interval is 60 seconds. +// +// If the interval is set to 0, then any reused session is not invalidated except by +// explicitly invoking -resetSession. Be aware that setting the interval to 0 thus +// causes the session's delegate to be retained until the session is explicitly reset. +@property(atomic, assign) NSTimeInterval unusedSessionTimeout; + +// If shouldReuseSession is enabled, this will force creation of a new session when future +// fetchers begin. +- (void)resetSession; + +// Create a fetcher +// +// These methods will return a fetcher. If successfully created, the connection +// will hold a strong reference to it for the life of the connection as well. +// So the caller doesn't have to hold onto the fetcher explicitly unless they +// want to be able to monitor or cancel it. +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request; +- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL; +- (GTMSessionFetcher *)fetcherWithURLString:(NSString *)requestURLString; + +// Common method for fetcher creation. +// +// -fetcherWithRequest:fetcherClass: may be overridden to customize creation of +// fetchers. This is the ONLY method in the GTMSessionFetcher library intended to +// be overridden. +- (id)fetcherWithRequest:(NSURLRequest *)request fetcherClass:(Class)fetcherClass; + +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher; + +- (NSUInteger)numberOfFetchers; // running + delayed fetchers +- (NSUInteger)numberOfRunningFetchers; +- (NSUInteger)numberOfDelayedFetchers; + +// Return a list of all running or delayed fetchers. This includes fetchers created +// by the service which have been started and have not yet stopped. +// +// Returns an array of fetcher objects, or nil if none. +- (nullable NSArray *)issuedFetchers; + +// Search for running or delayed fetchers with the specified URL. +// +// Returns an array of fetcher objects found, or nil if none found. +- (nullable NSArray *)issuedFetchersWithRequestURL:(NSURL *)requestURL; + +- (void)stopAllFetchers; + +// Holds a weak reference to `decorator`. When creating a fetcher via +// `-fetcherWithRequest:fetcherClass:`, each registered `decorator` can inspect and potentially +// change the fetcher's request before it starts. Decorators are invoked in the order in which +// they are passed to this method. +- (void)addDecorator:(id)decorator; + +// Removes a `decorator` previously passed to `-removeDecorator:`. +- (void)removeDecorator:(id)decorator; + +// Methods for use by the fetcher class only. +- (nullable NSURLSession *)session; +- (nullable NSURLSession *)sessionForFetcherCreation; +- (nullable id)sessionDelegate; +- (nullable NSDate *)stoppedAllFetchersDate; + +// The testBlock can inspect its fetcher parameter's request property to +// determine which fetcher is being faked. +@property(atomic, copy, nullable) GTMSessionFetcherTestBlock testBlock; + +@end + +@interface GTMSessionFetcherService (TestingSupport) + +// Convenience methods to create a fetcher service for testing. +// +// Fetchers generated by this mock fetcher service will not perform any +// network operation, but will invoke callbacks and provide the supplied data +// or error to the completion handler. +// +// You can make more customized mocks by setting the test block property of the service +// or fetcher; the test block can inspect the fetcher's request or other properties. +// +// See the description of the testBlock property below. ++ (instancetype)mockFetcherServiceWithFakedData:(nullable NSData *)fakedDataOrNil + fakedError:(nullable NSError *)fakedErrorOrNil; ++ (instancetype)mockFetcherServiceWithFakedData:(nullable NSData *)fakedDataOrNil + fakedResponse:(NSHTTPURLResponse *)fakedResponse + fakedError:(nullable NSError *)fakedErrorOrNil; + +// DEPRECATED: Callers should use XCTestExpectation instead. +// +// Spin the run loop and discard events (or, if not on the main thread, just sleep the thread) +// until all running and delayed fetchers have completed. +// +// This is only for use in testing or in tools without a user interface. +// +// Synchronous fetches should never be done by shipping apps; they are +// sufficient reason for rejection from the app store. +// +// Returns NO if timed out. +- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds + __deprecated_msg("Use XCTestExpectation instead"); + +@end + +@interface GTMSessionFetcherService (BackwardsCompatibilityOnly) + +// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves; +// this property is deprecated and will be removed soon. +@property(atomic, assign) NSInteger cookieStorageMethod __deprecated_msg( + "Create an NSHTTPCookieStorage and set .cookieStorage directly."); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m new file mode 100644 index 0000000..e920328 --- /dev/null +++ b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m @@ -0,0 +1,1383 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcherService.h" + +NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification = + @"kGTMSessionFetcherServiceSessionBecameInvalidNotification"; +NSString *const kGTMSessionFetcherServiceSessionKey = @"kGTMSessionFetcherServiceSessionKey"; + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (ServiceMethods) +- (BOOL)beginFetchMayDelay:(BOOL)mayDelay + mayAuthorize:(BOOL)mayAuthorize + mayDecorate:(BOOL)mayDecorate; +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionFetcherService () + +@property(atomic, strong, readwrite) NSDictionary *delayedFetchersByHost; +@property(atomic, strong, readwrite) NSDictionary *runningFetchersByHost; + +// Ordered collection of id, held weakly. +@property(atomic, strong, readonly) NSPointerArray *decoratorsPointerArray; + +@end + +// Since NSURLSession doesn't support a separate delegate per task (!), instances of this +// class serve as a session delegate trampoline. +// +// This class maps a session's tasks to fetchers, and resends delegate messages to the task's +// fetcher. +@interface GTMSessionFetcherSessionDelegateDispatcher : NSObject + +// The session for the tasks in this dispatcher's task-to-fetcher map. +@property(atomic) NSURLSession *session; + +// The timer interval for invalidating a session that has no active tasks. +@property(atomic) NSTimeInterval discardInterval; + +// The current discard timer. +@property(atomic, readonly) NSTimer *discardTimer; + +- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService + sessionDiscardInterval:(NSTimeInterval)discardInterval; + +- (void)setFetcher:(GTMSessionFetcher *)fetcher forTask:(NSURLSessionTask *)task; +- (void)removeFetcher:(GTMSessionFetcher *)fetcher; + +// Before using a session, tells the delegate dispatcher to stop the discard timer. +- (void)startSessionUsage; + +// When abandoning a delegate dispatcher, we want to avoid the session retaining +// the delegate after tasks complete. +- (void)abandon; + +@end + +@implementation GTMSessionFetcherService { + NSMutableDictionary *_delayedFetchersByHost; + NSMutableDictionary *_runningFetchersByHost; + NSUInteger _maxRunningFetchersPerHost; + + // When this ivar is nil, the service will not reuse sessions. + GTMSessionFetcherSessionDelegateDispatcher *_delegateDispatcher; + + // Fetchers will wait on this if another fetcher is creating the shared NSURLSession. + dispatch_semaphore_t _sessionCreationSemaphore; + + dispatch_queue_t _callbackQueue; + NSOperationQueue *_delegateQueue; + NSHTTPCookieStorage *_cookieStorage; + NSString *_userAgent; + NSTimeInterval _timeout; + + NSURLCredential *_credential; // Username & password. + NSURLCredential *_proxyCredential; // Credential supplied to proxy servers. + + NSInteger _cookieStorageMethod; + + id _authorizer; + + // For waitForCompletionOfAllFetchersWithTimeout: we need to wait on stopped fetchers since + // they've not yet finished invoking their queued callbacks. This array is nil except when + // waiting on fetchers. + NSMutableArray *_stoppedFetchersToWaitFor; + + // For fetchers that enqueued their callbacks before stopAllFetchers was called on the service, + // set a barrier so the callbacks know to bail out. + NSDate *_stoppedAllFetchersDate; +} + +// Clang-format likes to cram all @synthesize items onto the fewest lines, rather than one-per. +// clang-format off +@synthesize maxRunningFetchersPerHost = _maxRunningFetchersPerHost, + configuration = _configuration, + configurationBlock = _configurationBlock, + cookieStorage = _cookieStorage, + userAgent = _userAgent, + challengeBlock = _challengeBlock, + credential = _credential, + proxyCredential = _proxyCredential, + allowedInsecureSchemes = _allowedInsecureSchemes, + allowLocalhostRequest = _allowLocalhostRequest, + allowInvalidServerCertificates = _allowInvalidServerCertificates, + retryEnabled = _retryEnabled, + retryBlock = _retryBlock, + maxRetryInterval = _maxRetryInterval, + minRetryInterval = _minRetryInterval, + metricsCollectionBlock = _metricsCollectionBlock, + properties = _properties, + unusedSessionTimeout = _unusedSessionTimeout, + decoratorsPointerArray = _decoratorsPointerArray, + testBlock = _testBlock; +// clang-format on + +#if GTM_BACKGROUND_TASK_FETCHING +@synthesize skipBackgroundTask = _skipBackgroundTask; +#endif + +- (instancetype)init { + self = [super init]; + if (self) { + _delayedFetchersByHost = [[NSMutableDictionary alloc] init]; + _runningFetchersByHost = [[NSMutableDictionary alloc] init]; + _maxRunningFetchersPerHost = 10; + _cookieStorageMethod = -1; + _unusedSessionTimeout = 60.0; + _delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc] + initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + _callbackQueue = dispatch_get_main_queue(); + + _delegateQueue = [[NSOperationQueue alloc] init]; + _delegateQueue.maxConcurrentOperationCount = 1; + _delegateQueue.name = @"com.google.GTMSessionFetcher.NSURLSessionDelegateQueue"; + + _sessionCreationSemaphore = dispatch_semaphore_create(1); + + // Starting with the SDKs for OS X 10.11/iOS 9, the service has a default useragent. + // Apps can remove this and get the default system "CFNetwork" useragent by setting the + // fetcher service's userAgent property to nil. + _userAgent = GTMFetcherStandardUserAgentString(nil); + } + return self; +} + +- (void)dealloc { + [self detachAuthorizer]; + [_delegateDispatcher abandon]; +} + +#pragma mark Generate a new fetcher + +// Clients may override this method. Clients should not override any other library methods. +- (id)fetcherWithRequest:(NSURLRequest *)request fetcherClass:(Class)fetcherClass { + GTMSessionFetcher *fetcher = [[fetcherClass alloc] initWithRequest:request + configuration:self.configuration]; + fetcher.callbackQueue = self.callbackQueue; + fetcher.sessionDelegateQueue = self.sessionDelegateQueue; + fetcher.challengeBlock = self.challengeBlock; + fetcher.credential = self.credential; + fetcher.proxyCredential = self.proxyCredential; + fetcher.authorizer = self.authorizer; + fetcher.cookieStorage = self.cookieStorage; + fetcher.allowedInsecureSchemes = self.allowedInsecureSchemes; + fetcher.allowLocalhostRequest = self.allowLocalhostRequest; + fetcher.allowInvalidServerCertificates = self.allowInvalidServerCertificates; + fetcher.configurationBlock = self.configurationBlock; + fetcher.retryEnabled = self.retryEnabled; + fetcher.retryBlock = self.retryBlock; + fetcher.maxRetryInterval = self.maxRetryInterval; + fetcher.minRetryInterval = self.minRetryInterval; + if (@available(iOS 10.0, *)) { + fetcher.metricsCollectionBlock = self.metricsCollectionBlock; + } + fetcher.properties = self.properties; + fetcher.service = self; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if (self.cookieStorageMethod >= 0) { + [fetcher setCookieStorageMethod:self.cookieStorageMethod]; + } +#pragma clang diagnostic pop + +#if GTM_BACKGROUND_TASK_FETCHING + fetcher.skipBackgroundTask = self.skipBackgroundTask; +#endif + + NSString *userAgent = self.userAgent; + if (userAgent.length > 0 && [request valueForHTTPHeaderField:@"User-Agent"] == nil) { + [fetcher setRequestValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + fetcher.testBlock = self.testBlock; + + return fetcher; +} + +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request { + return [self fetcherWithRequest:request fetcherClass:[GTMSessionFetcher class]]; +} + +- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL { + return [self fetcherWithRequest:[NSURLRequest requestWithURL:requestURL]]; +} + +- (GTMSessionFetcher *)fetcherWithURLString:(NSString *)requestURLString { + NSURL *url = [NSURL URLWithString:requestURLString]; + return [self fetcherWithURL:url]; +} + +- (void)addDecorator:(id)decorator { + @synchronized(self) { + if (!_decoratorsPointerArray) { + _decoratorsPointerArray = [NSPointerArray weakObjectsPointerArray]; + } + [_decoratorsPointerArray addPointer:(__bridge void *)decorator]; + } +} + +- (nullable NSArray> *)decorators { + @synchronized(self) { + return _decoratorsPointerArray.allObjects; + } +} + +- (void)removeDecorator:(id)decorator { + @synchronized(self) { + NSUInteger i = 0; + for (id decoratorCandidate in _decoratorsPointerArray) { + if (decoratorCandidate == decorator) { + break; + } + ++i; + } + GTMSESSION_ASSERT_DEBUG(i < _decoratorsPointerArray.count, + @"decorator %@ must be passed to -addDecorator: before removing", + decorator); + if (i < _decoratorsPointerArray.count) { + [_decoratorsPointerArray removePointerAtIndex:i]; + } + } +} + +// Returns a session for the fetcher's host, or nil. +- (NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLSession *session = _delegateDispatcher.session; + return session; + } +} + +// Returns a session for the fetcher's host, or nil. For shared sessions, this +// waits on a semaphore, blocking other fetchers while the caller creates the +// session if needed. +- (NSURLSession *)sessionForFetcherCreation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + if (!_delegateDispatcher) { + // This fetcher is creating a non-shared session, so skip the semaphore usage. + return nil; + } + } + + // Wait if another fetcher is currently creating a session; avoid waiting + // inside the @synchronized block, as that can deadlock. + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Before getting the NSURLSession for task creation, it is + // important to invalidate and nil out the session discard timer; otherwise + // the session can be invalidated between when it is returned to the + // fetcher, and when the fetcher attempts to create its NSURLSessionTask. + [_delegateDispatcher startSessionUsage]; + + NSURLSession *session = _delegateDispatcher.session; + if (session) { + // The calling fetcher will receive a preexisting session, so + // we can allow other fetchers to create a session. + dispatch_semaphore_signal(_sessionCreationSemaphore); + } else { + // No existing session was obtained, so the calling fetcher will create the session; + // it *must* invoke fetcherDidCreateSession: to signal the dispatcher's semaphore after + // the session has been created (or fails to be created) to avoid a hang. + } + return session; + } +} + +- (id)sessionDelegate { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateDispatcher; + } +} + +#pragma mark Queue Management + +- (void)addRunningFetcher:(GTMSessionFetcher *)fetcher forHost:(NSString *)host { + // Add to the array of running fetchers for this host, creating the array if needed. + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + if (runningForHost == nil) { + runningForHost = [NSMutableArray arrayWithObject:fetcher]; + [_runningFetchersByHost setObject:runningForHost forKey:host]; + } else { + [runningForHost addObject:fetcher]; + } +} + +- (void)addDelayedFetcher:(GTMSessionFetcher *)fetcher forHost:(NSString *)host { + // Add to the array of delayed fetchers for this host, creating the array if needed. + NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + if (delayedForHost == nil) { + delayedForHost = [NSMutableArray arrayWithObject:fetcher]; + [_delayedFetchersByHost setObject:delayedForHost forKey:host]; + } else { + [delayedForHost addObject:fetcher]; + } +} + +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSString *host = fetcher.request.URL.host; + if (host == nil) { + return NO; + } + NSArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + NSUInteger idx = [delayedForHost indexOfObjectIdenticalTo:fetcher]; + BOOL isDelayed = (delayedForHost != nil) && (idx != NSNotFound); + return isDelayed; + } +} + +- (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher { + // Entry point from the fetcher + NSURL *requestURL = fetcher.request.URL; + NSString *host = requestURL.host; + + // Addresses "file:///path" case where localhost is the implicit host. + if (host.length == 0 && [requestURL isFileURL]) { + host = @"localhost"; + } + + if (host.length == 0) { + // Data URIs legitimately have no host, reject other hostless URLs. + GTMSESSION_ASSERT_DEBUG([[requestURL scheme] isEqual:@"data"], @"%@ lacks host", fetcher); + return YES; + } + + BOOL shouldBeginResult; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + if (runningForHost != nil && [runningForHost indexOfObjectIdenticalTo:fetcher] != NSNotFound) { + GTMSESSION_ASSERT_DEBUG(NO, @"%@ was already running", fetcher); + return YES; + } + + BOOL shouldRunNow = (fetcher.usingBackgroundSession || _maxRunningFetchersPerHost == 0 || + _maxRunningFetchersPerHost > + [[self class] numberOfNonBackgroundSessionFetchers:runningForHost]); + if (shouldRunNow) { + [self addRunningFetcher:fetcher forHost:host]; + shouldBeginResult = YES; + } else { + [self addDelayedFetcher:fetcher forHost:host]; + shouldBeginResult = NO; + } + } // @synchronized(self) + + // We'll save the host that serves as the key for this fetcher's array + // to avoid any chance of the underlying request changing, stranding + // the fetcher in the wrong array + fetcher.serviceHost = host; + + return shouldBeginResult; +} + +- (void)startFetcher:(GTMSessionFetcher *)fetcher { + [fetcher beginFetchMayDelay:NO mayAuthorize:YES mayDecorate:YES]; +} + +// Internal utility. Returns a fetcher's delegate if it's a dispatcher, or nil if the fetcher +// is its own delegate (possibly via proxy) and has no dispatcher. +- (GTMSessionFetcherSessionDelegateDispatcher *)delegateDispatcherForFetcher: + (GTMSessionFetcher *)fetcher { + GTMSessionCheckNotSynchronized(self); + + NSURLSession *fetcherSession = fetcher.session; + if (fetcherSession) { + id fetcherDelegate = fetcherSession.delegate; + // If the delegate is non-nil and claims to be a GTMSessionFetcher, there is no dispatcher; + // assume the fetcher is the delegate or has been proxied (some third-party frameworks + // are known to swizzle NSURLSession to proxy its delegate). + BOOL hasDispatcher = + (fetcherDelegate != nil && ![fetcherDelegate isKindOfClass:[GTMSessionFetcher class]]); + if (hasDispatcher) { + GTMSESSION_ASSERT_DEBUG( + [fetcherDelegate isKindOfClass:[GTMSessionFetcherSessionDelegateDispatcher class]], + @"Fetcher delegate class: %@", [fetcherDelegate class]); + return (GTMSessionFetcherSessionDelegateDispatcher *)fetcherDelegate; + } + } + return nil; +} + +- (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher { + if (fetcher.canShareSession) { + NSURLSession *fetcherSession = fetcher.session; + GTMSESSION_ASSERT_DEBUG(fetcherSession != nil, @"Fetcher missing its session: %@", fetcher); + + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + if (delegateDispatcher) { + GTMSESSION_ASSERT_DEBUG(delegateDispatcher.session == nil, + @"Fetcher made an extra session: %@", fetcher); + + // Save this fetcher's session. + delegateDispatcher.session = fetcherSession; + + // Allow other fetchers to request this session now. + dispatch_semaphore_signal(_sessionCreationSemaphore); + } + } +} + +- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher { + // If this fetcher has a separate delegate with a shared session, then + // this fetcher should be added to the delegate's map of tasks to fetchers. + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + if (delegateDispatcher) { + GTMSESSION_ASSERT_DEBUG(fetcher.canShareSession, @"Inappropriate shared session: %@", fetcher); + + // There should already be a session, from this or a previous fetcher. + // + // Sanity check that the fetcher's session is the delegate's shared session. + NSURLSession *sharedSession = delegateDispatcher.session; + NSURLSession *fetcherSession = fetcher.session; + GTMSESSION_ASSERT_DEBUG(sharedSession != nil, @"Missing delegate session: %@", fetcher); + GTMSESSION_ASSERT_DEBUG(fetcherSession == sharedSession, + @"Inconsistent session: %@ %@ (shared: %@)", fetcher, fetcherSession, + sharedSession); + + if (sharedSession != nil && fetcherSession == sharedSession) { + NSURLSessionTask *task = fetcher.sessionTask; + GTMSESSION_ASSERT_DEBUG(task != nil, @"Missing session task: %@", fetcher); + + if (task) { + [delegateDispatcher setFetcher:fetcher forTask:task]; + } + } + } +} + +- (void)stopFetcher:(GTMSessionFetcher *)fetcher { + [fetcher stopFetching]; +} + +- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher { + // Entry point from the fetcher + NSString *host = fetcher.serviceHost; + if (!host) { + // fetcher has been stopped previously + return; + } + + // This removeFetcher: invocation is a fallback; typically, fetchers are removed from the task + // map when the task completes. + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + [delegateDispatcher removeFetcher:fetcher]; + + NSMutableArray *fetchersToStart; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // If a test is waiting for all fetchers to stop, it needs to wait for this one + // to invoke its callbacks on the callback queue. + [_stoppedFetchersToWaitFor addObject:fetcher]; + + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + [runningForHost removeObject:fetcher]; + + NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + [delayedForHost removeObject:fetcher]; + + while (delayedForHost.count > 0 && + [[self class] numberOfNonBackgroundSessionFetchers:runningForHost] < + _maxRunningFetchersPerHost) { + // Start another delayed fetcher running, scanning for the minimum + // priority value, defaulting to FIFO for equal priorities + GTMSessionFetcher *nextFetcher = nil; + for (GTMSessionFetcher *delayedFetcher in delayedForHost) { + if (nextFetcher == nil || delayedFetcher.servicePriority < nextFetcher.servicePriority) { + nextFetcher = delayedFetcher; + } + } + + if (nextFetcher) { + [self addRunningFetcher:nextFetcher forHost:host]; + runningForHost = [_runningFetchersByHost objectForKey:host]; + + [delayedForHost removeObjectIdenticalTo:nextFetcher]; + + if (!fetchersToStart) { + fetchersToStart = [NSMutableArray array]; + } + [fetchersToStart addObject:nextFetcher]; + } + } + + if (runningForHost.count == 0) { + // None left; remove the empty array + [_runningFetchersByHost removeObjectForKey:host]; + } + + if (delayedForHost.count == 0) { + [_delayedFetchersByHost removeObjectForKey:host]; + } + } // @synchronized(self) + + // Start fetchers outside of the synchronized block to avoid a deadlock. + for (GTMSessionFetcher *nextFetcher in fetchersToStart) { + [self startFetcher:nextFetcher]; + } + + // The fetcher is no longer in the running or the delayed array, + // so remove its host and thread properties + fetcher.serviceHost = nil; +} + +- (NSUInteger)numberOfFetchers { + NSUInteger running = [self numberOfRunningFetchers]; + NSUInteger delayed = [self numberOfDelayedFetchers]; + return running + delayed; +} + +- (NSUInteger)numberOfRunningFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger sum = 0; + for (NSString *host in _runningFetchersByHost) { + NSArray *fetchers = [_runningFetchersByHost objectForKey:host]; + sum += fetchers.count; + } + return sum; + } +} + +- (NSUInteger)numberOfDelayedFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger sum = 0; + for (NSString *host in _delayedFetchersByHost) { + NSArray *fetchers = [_delayedFetchersByHost objectForKey:host]; + sum += fetchers.count; + } + return sum; + } +} + +- (NSArray *)issuedFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSMutableArray *allFetchers = [NSMutableArray array]; + void (^accumulateFetchers)(id, id, BOOL *) = + ^(NSString *host, NSArray *fetchersForHost, BOOL *stop) { + [allFetchers addObjectsFromArray:fetchersForHost]; + }; + [_runningFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers]; + [_delayedFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers]; + + GTMSESSION_ASSERT_DEBUG(allFetchers.count == [NSSet setWithArray:allFetchers].count, + @"Fetcher appears multiple times\n running: %@\n delayed: %@", + _runningFetchersByHost, _delayedFetchersByHost); + + return allFetchers.count > 0 ? allFetchers : nil; + } +} + +- (NSArray *)issuedFetchersWithRequestURL:(NSURL *)requestURL { + NSString *host = requestURL.host; + if (host.length == 0) return nil; + + NSURL *targetURL = [requestURL absoluteURL]; + + NSArray *allFetchers = [self issuedFetchers]; + NSIndexSet *indexes = [allFetchers + indexesOfObjectsPassingTest:^BOOL(GTMSessionFetcher *fetcher, NSUInteger idx, BOOL *stop) { + NSURL *fetcherURL = [fetcher.request.URL absoluteURL]; + return [fetcherURL isEqual:targetURL]; + }]; + + NSArray *result = nil; + if (indexes.count > 0) { + result = [allFetchers objectsAtIndexes:indexes]; + } + return result; +} + +- (void)stopAllFetchers { + NSArray *delayedFetchersByHost; + NSArray *runningFetchersByHost; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Set the time barrier so fetchers know not to call back even if + // the stop calls below occur after the fetchers naturally + // stopped and so were removed from _runningFetchersByHost, + // but while the callbacks were already enqueued before stopAllFetchers + // was invoked. + _stoppedAllFetchersDate = [[NSDate alloc] init]; + + // Remove fetchers from the delayed list to avoid fetcherDidStop: from + // starting more fetchers running as a side effect of stopping one + delayedFetchersByHost = _delayedFetchersByHost.allValues; + [_delayedFetchersByHost removeAllObjects]; + + runningFetchersByHost = _runningFetchersByHost.allValues; + [_runningFetchersByHost removeAllObjects]; + } + + for (NSArray *delayedForHost in delayedFetchersByHost) { + for (GTMSessionFetcher *fetcher in delayedForHost) { + [self stopFetcher:fetcher]; + } + } + + for (NSArray *runningForHost in runningFetchersByHost) { + for (GTMSessionFetcher *fetcher in runningForHost) { + [self stopFetcher:fetcher]; + } + } +} + +- (NSDate *)stoppedAllFetchersDate { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _stoppedAllFetchersDate; + } +} + +#pragma mark Accessors + +- (BOOL)reuseSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateDispatcher != nil; + } +} + +- (void)setReuseSession:(BOOL)shouldReuse { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL wasReusing = (_delegateDispatcher != nil); + if (shouldReuse != wasReusing) { + [self abandonDispatcher]; + if (shouldReuse) { + _delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc] + initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + } else { + _delegateDispatcher = nil; + } + } + } +} + +- (void)resetSession { + GTMSessionCheckNotSynchronized(self); + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + [self resetSessionInternal]; + } + + dispatch_semaphore_signal(_sessionCreationSemaphore); +} + +- (void)resetSessionInternal { + GTMSessionCheckSynchronized(self); + + // The old dispatchers may be retained as delegates of any ongoing sessions by those sessions. + if (_delegateDispatcher) { + [self abandonDispatcher]; + _delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc] + initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + } +} + +- (void)resetSessionForDispatcherDiscardTimer:(NSTimer *)timer { + GTMSessionCheckNotSynchronized(self); + + dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_delegateDispatcher.discardTimer == timer) { + // If the delegate dispatcher's current discardTimer is the same object as the timer + // that fired, no fetcher has recently attempted to start using the session by calling + // startSessionUsage, which invalidates and nils out the timer. + [self resetSessionInternal]; + } else { + // A fetcher has invalidated the timer between its triggering and now, potentially + // meaning a fetcher has requested access to the NSURLSession, and may be in the process + // of starting a new task. The dispatcher should not be abandoned, as this can lead + // to a race condition between calling -finishTasksAndInvalidate on the NSURLSession + // and the fetcher attempting to create a new task. + } + } + + dispatch_semaphore_signal(_sessionCreationSemaphore); +} + +- (NSTimeInterval)unusedSessionTimeout { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _unusedSessionTimeout; + } +} + +- (void)setUnusedSessionTimeout:(NSTimeInterval)timeout { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _unusedSessionTimeout = timeout; + _delegateDispatcher.discardInterval = timeout; + } +} + +// This method should be called inside of @synchronized(self) +- (void)abandonDispatcher { + GTMSessionCheckSynchronized(self); + [_delegateDispatcher abandon]; +} + +- (NSDictionary *)runningFetchersByHost { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_runningFetchersByHost copy]; + } +} + +- (void)setRunningFetchersByHost:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _runningFetchersByHost = [dict mutableCopy]; + } +} + +- (NSDictionary *)delayedFetchersByHost { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_delayedFetchersByHost copy]; + } +} + +- (void)setDelayedFetchersByHost:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delayedFetchersByHost = [dict mutableCopy]; + } +} + +- (id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _authorizer; + } +} + +- (void)setAuthorizer:(id)obj { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (obj != _authorizer) { + [self detachAuthorizer]; + } + + _authorizer = obj; + } + + // Use the fetcher service for the authorization fetches if the auth + // object supports fetcher services + if ([obj respondsToSelector:@selector(setFetcherService:)]) { + [obj setFetcherService:self]; + } +} + +// This should be called inside a @synchronized(self) block except during dealloc. +- (void)detachAuthorizer { + // This method is called by the fetcher service's dealloc and setAuthorizer: + // methods; do not override. + // + // The fetcher service retains the authorizer, and the authorizer has a + // weak pointer to the fetcher service (a non-zeroing pointer for + // compatibility with iOS 4 and Mac OS X 10.5/10.6.) + // + // When this fetcher service no longer uses the authorizer, we want to remove + // the authorizer's dependence on the fetcher service. Authorizers can still + // function without a fetcher service. + if ([_authorizer respondsToSelector:@selector(fetcherService)]) { + id authFetcherService = [_authorizer fetcherService]; + if (authFetcherService == self) { + [_authorizer setFetcherService:nil]; + } + } +} + +- (nonnull dispatch_queue_t)callbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _callbackQueue; + } // @synchronized(self) +} + +- (void)setCallbackQueue:(dispatch_queue_t)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _callbackQueue = queue ?: dispatch_get_main_queue(); + } // @synchronized(self) +} + +- (NSOperationQueue *)sessionDelegateQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateQueue; + } // @synchronized(self) +} + +- (void)setSessionDelegateQueue:(NSOperationQueue *)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateQueue = queue ?: [NSOperationQueue mainQueue]; + } // @synchronized(self) +} + +- (NSOperationQueue *)delegateQueue { + // Provided for compatibility with the old fetcher service. The gtm-oauth2 code respects + // any custom delegate queue for calling the app. + return nil; +} + ++ (NSUInteger)numberOfNonBackgroundSessionFetchers:(NSArray *)fetchers { + NSUInteger sum = 0; + for (GTMSessionFetcher *fetcher in fetchers) { + if (!fetcher.usingBackgroundSession) { + ++sum; + } + } + return sum; +} + +@end + +@implementation GTMSessionFetcherService (TestingSupport) + ++ (instancetype)mockFetcherServiceWithFakedData:(NSData *)fakedDataOrNil + fakedError:(NSError *)fakedErrorOrNil { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + NSURL *url = [NSURL URLWithString:@"http://example.invalid"]; + NSHTTPURLResponse *fakedResponse = + [[NSHTTPURLResponse alloc] initWithURL:url + statusCode:(fakedErrorOrNil ? 500 : 200)HTTPVersion:@"HTTP/1.1" + headerFields:nil]; + return [self mockFetcherServiceWithFakedData:fakedDataOrNil + fakedResponse:fakedResponse + fakedError:fakedErrorOrNil]; +#else + GTMSESSION_ASSERT_DEBUG(0, @"Test blocks disabled"); + return nil; +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK +} + ++ (instancetype)mockFetcherServiceWithFakedData:(NSData *)fakedDataOrNil + fakedResponse:(NSHTTPURLResponse *)fakedResponse + fakedError:(NSError *)fakedErrorOrNil { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSessionFetcherService *service = [[self alloc] init]; + service.allowedInsecureSchemes = @[ @"http" ]; + service.testBlock = + ^(GTMSessionFetcher *fetcherToTest, GTMSessionFetcherTestResponse testResponse) { + testResponse(fakedResponse, fakedDataOrNil, fakedErrorOrNil); + }; + return service; +#else + GTMSESSION_ASSERT_DEBUG(0, @"Test blocks disabled"); + return nil; +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK +} + +#pragma mark Synchronous Wait for Unit Testing + +- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds { + NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + _stoppedFetchersToWaitFor = [NSMutableArray array]; + + BOOL shouldSpinRunLoop = [NSThread isMainThread]; + const NSTimeInterval kSpinInterval = 0.001; + BOOL didTimeOut = NO; + while (([self numberOfFetchers] > 0 || _stoppedFetchersToWaitFor.count > 0)) { + didTimeOut = [giveUpDate timeIntervalSinceNow] < 0; + if (didTimeOut) break; + + GTMSessionFetcher *stoppedFetcher = _stoppedFetchersToWaitFor.firstObject; + if (stoppedFetcher) { + [_stoppedFetchersToWaitFor removeObject:stoppedFetcher]; + [stoppedFetcher waitForCompletionWithTimeout:10.0 * kSpinInterval]; + } + + if (shouldSpinRunLoop) { + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:kSpinInterval]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + [NSThread sleepForTimeInterval:kSpinInterval]; + } + } + _stoppedFetchersToWaitFor = nil; + + return !didTimeOut; +} + +@end + +@implementation GTMSessionFetcherService (BackwardsCompatibilityOnly) + +- (NSInteger)cookieStorageMethod { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _cookieStorageMethod; + } +} + +- (void)setCookieStorageMethod:(NSInteger)cookieStorageMethod { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _cookieStorageMethod = cookieStorageMethod; + } +} + +@end + +@implementation GTMSessionFetcherSessionDelegateDispatcher { + __weak GTMSessionFetcherService *_parentService; + NSURLSession *_session; + + // The task map maps NSURLSessionTasks to GTMSessionFetchers + NSMutableDictionary *_taskToFetcherMap; + // The discard timer will invalidate sessions after the session's last task completes. + NSTimer *_discardTimer; + NSTimeInterval _discardInterval; +} + +@synthesize discardInterval = _discardInterval, session = _session; + +- (instancetype)init { + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService + sessionDiscardInterval:(NSTimeInterval)discardInterval { + self = [super init]; + if (self) { + _discardInterval = discardInterval; + _parentService = parentService; + } + return self; +} + +- (NSString *)description { + return + [NSString stringWithFormat:@"%@ %p %@ %@", [self class], self, _session ?: @"", + _taskToFetcherMap.count > 0 ? _taskToFetcherMap : @""]; +} + +- (NSTimer *)discardTimer { + GTMSessionCheckNotSynchronized(self); + @synchronized(self) { + return _discardTimer; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)startDiscardTimer { + GTMSessionCheckSynchronized(self); + [_discardTimer invalidate]; + _discardTimer = nil; + if (_discardInterval > 0) { + _discardTimer = [NSTimer timerWithTimeInterval:_discardInterval + target:self + selector:@selector(discardTimerFired:) + userInfo:nil + repeats:NO]; + [_discardTimer setTolerance:(_discardInterval / 10)]; + [[NSRunLoop mainRunLoop] addTimer:_discardTimer forMode:NSRunLoopCommonModes]; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)destroyDiscardTimer { + GTMSessionCheckSynchronized(self); + [_discardTimer invalidate]; + _discardTimer = nil; +} + +- (void)discardTimerFired:(NSTimer *)timer { + GTMSessionFetcherService *service; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger numberOfTasks = _taskToFetcherMap.count; + if (numberOfTasks == 0) { + service = _parentService; + } + } + + // Inform the service that the discard timer has fired, and should check whether the + // service can abandon us. -resetSession cannot be called directly, as there is a + // race condition that must be guarded against with the NSURLSession being returned + // from sessionForFetcherCreation outside other locks. The service can take steps + // to prevent resetting the session if that has occurred. + // + // The service must be called from outside the @synchronized block. + [service resetSessionForDispatcherDiscardTimer:timer]; +} + +- (void)abandon { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self destroySessionAndTimer]; + } +} + +- (void)startSessionUsage { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self destroyDiscardTimer]; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)destroySessionAndTimer { + GTMSessionCheckSynchronized(self); + [self destroyDiscardTimer]; + + // Break any retain cycle from the session holding the delegate. + [_session finishTasksAndInvalidate]; + + // Immediately clear the session so no new task may be issued with it. + // + // The _taskToFetcherMap needs to stay valid until the outstanding tasks finish. + _session = nil; +} + +- (void)setFetcher:(GTMSessionFetcher *)fetcher forTask:(NSURLSessionTask *)task { + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"missing fetcher"); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_taskToFetcherMap == nil) { + _taskToFetcherMap = [[NSMutableDictionary alloc] init]; + } + + if (fetcher) { + [_taskToFetcherMap setObject:fetcher forKey:task]; + [self destroyDiscardTimer]; + } + } +} + +- (void)removeFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Typically, a fetcher should be removed when its task invokes + // URLSession:task:didCompleteWithError:. + // + // When fetching with a testBlock, though, the task completed delegate + // method may not be invoked, requiring cleanup here. + NSArray *tasks = [_taskToFetcherMap allKeysForObject:fetcher]; + GTMSESSION_ASSERT_DEBUG(tasks.count <= 1, @"fetcher task not unmapped: %@", tasks); + [_taskToFetcherMap removeObjectsForKeys:tasks]; + + if (_taskToFetcherMap.count == 0) { + [self startDiscardTimer]; + } + } +} + +// This helper method provides synchronized access to the task map for the delegate +// methods below. +- (id)fetcherForTask:(NSURLSessionTask *)task { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_taskToFetcherMap objectForKey:task]; + } +} + +- (void)removeTaskFromMap:(NSURLSessionTask *)task { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_taskToFetcherMap removeObjectForKey:task]; + } +} + +- (void)setSession:(NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = session; + } +} + +- (NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _session; + } +} + +- (NSTimeInterval)discardInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _discardInterval; + } +} + +- (void)setDiscardInterval:(NSTimeInterval)interval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _discardInterval = interval; + } +} + +// NSURLSessionDelegate protocol methods. + +// - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session; +// +// TODO(seh): How do we route this to an appropriate fetcher? + +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error { + GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", [self class], self, + session, error); + NSDictionary *localTaskToFetcherMap; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = nil; + + localTaskToFetcherMap = [_taskToFetcherMap copy]; + } + + // Any "suspended" tasks may not have received callbacks from NSURLSession when the session + // completes; we'll call them now. + [localTaskToFetcherMap enumerateKeysAndObjectsUsingBlock:^( + NSURLSessionTask *task, GTMSessionFetcher *fetcher, BOOL *stop) { + if (fetcher.session == session) { + // Our delegate method URLSession:task:didCompleteWithError: will rely on + // _taskToFetcherMap so that should still contain this fetcher. + NSError *canceledError = [NSError errorWithDomain:NSURLErrorDomain + code:NSURLErrorCancelled + userInfo:nil]; + [self URLSession:session task:task didCompleteWithError:canceledError]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"Unexpected session in fetcher: %@ has %@ (expected %@)", fetcher, + fetcher.session, session); + } + }]; + + // Our tests rely on this notification to know the session discard timer fired. + NSDictionary *userInfo = @{kGTMSessionFetcherServiceSessionKey : session}; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherServiceSessionBecameInvalidNotification + object:_parentService + userInfo:userInfo]; +} + +#pragma mark - NSURLSessionTaskDelegate + +// NSURLSessionTaskDelegate protocol methods. +// +// We won't test here if the fetcher responds to these since we only want this +// class to implement the same delegate methods the fetcher does (so NSURLSession's +// tests for respondsToSelector: will have the same result whether the session +// delegate is the fetcher or this dispatcher.) + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + willPerformHTTPRedirection:response + newRequest:request + completionHandler:completionHandler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))handler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session task:task didReceiveChallenge:challenge completionHandler:handler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + needNewBodyStream:(void (^)(NSInputStream *bodyStream))handler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session task:task needNewBodyStream:handler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + didSendBodyData:bytesSent + totalBytesSent:totalBytesSent + totalBytesExpectedToSend:totalBytesExpectedToSend]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error { + id fetcher = [self fetcherForTask:task]; + + // This is the usual way tasks are removed from the task map. + [self removeTaskFromMap:task]; + + [fetcher URLSession:session task:task didCompleteWithError:error]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics + API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)) { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session task:task didFinishCollectingMetrics:metrics]; +} + +// NSURLSessionDataDelegate protocol methods. + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition))handler { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + didReceiveResponse:response + completionHandler:handler]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { + id fetcher = [self fetcherForTask:dataTask]; + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"Missing fetcher for %@", dataTask); + [self removeTaskFromMap:dataTask]; + if (fetcher) { + GTMSESSION_ASSERT_DEBUG([fetcher isKindOfClass:[GTMSessionFetcher class]], + @"Expecting GTMSessionFetcher"); + [self setFetcher:(GTMSessionFetcher *)fetcher forTask:downloadTask]; + } + + [fetcher URLSession:session dataTask:dataTask didBecomeDownloadTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session dataTask:dataTask didReceiveData:data]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *))handler { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + willCacheResponse:proposedResponse + completionHandler:handler]; +} + +// NSURLSessionDownloadDelegate protocol methods. + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didFinishDownloadingToURL:(NSURL *)location { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalWritten + totalBytesExpectedToWrite:(int64_t)totalExpected { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask + didWriteData:bytesWritten + totalBytesWritten:totalWritten + totalBytesExpectedToWrite:totalExpected]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset + expectedTotalBytes:(int64_t)expectedTotalBytes { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask + didResumeAtOffset:fileOffset + expectedTotalBytes:expectedTotalBytes]; +} + +@end diff --git a/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h new file mode 100644 index 0000000..ddfddf2 --- /dev/null +++ b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.h @@ -0,0 +1,173 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// GTMSessionUploadFetcher implements Google's resumable upload protocol. + +// +// This subclass of GTMSessionFetcher simulates the series of fetches +// needed for chunked upload as a single fetch operation. +// +// Protocol document: TBD +// +// To the client, the only fetcher that exists is this class; the subsidiary +// fetchers needed for uploading chunks are not visible (though the most recent +// chunk fetcher may be accessed via the -activeFetcher or -chunkFetcher methods, and +// -responseHeaders and -statusCode reflect results from the most recent chunk +// fetcher.) +// +// Chunk fetchers are discarded as soon as they have completed. +// +// The protocol also allows for a cancellation notification request to be sent to the +// server to allow discarding of the currently uploaded data and this will be sent +// automatically upon calling stopFetching if the upload has already started. +// +// Note: Unlike the fetcher superclass, the methods of GTMSessionUploadFetcher should +// only be used from the main thread until further work is done to make this subclass +// thread-safe. + +#import "GTMSessionFetcher.h" +#import "GTMSessionFetcherService.h" + +NS_ASSUME_NONNULL_BEGIN + +// The value to use for file size parameters when the file size is not yet known. +extern int64_t const kGTMSessionUploadFetcherUnknownFileSize; + +// Unless an application knows it needs a smaller chunk size, it should use the standard +// chunk size, which sends the entire file as a single chunk to minimize upload overhead. +// Setting an explicit chunk size that comfortably fits in memory is advisable for large +// uploads. +extern int64_t const kGTMSessionUploadFetcherStandardChunkSize; + +// When uploading requires data buffer allocations (such as uploading from an NSData or +// an NSFileHandle) this is the maximum buffer size that will be created by the fetcher. +extern int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize; + +// Notification that the upload location URL was provided by the server. +extern NSString *const kGTMSessionFetcherUploadLocationObtainedNotification; + +// Block to provide data during uploads. +// +// Response data may be allocated with dataWithBytesNoCopy:length:freeWhenDone: for efficiency, +// and released after the response block returns. +// +// If the length of the file being uploaded is unknown or already set, send +// kGTMSessionUploadFetcherUnknownFileSize for |fullUploadLength|. Otherwise, set |fullUploadLength| +// to its proper value. +// +// Pass nil as the data (and optionally an NSError) for a failure. +typedef void (^GTMSessionUploadFetcherDataProviderResponse)(NSData *_Nullable data, + int64_t fullUploadLength, + NSError *_Nullable error); +// Do not call the response with an NSData object with less data than the requested length unless +// you are passing the fullUploadLength to the fetcher for the first time and it is the last chunk +// of data in the file being uploaded. +typedef void (^GTMSessionUploadFetcherDataProvider)( + int64_t offset, int64_t length, GTMSessionUploadFetcherDataProviderResponse response); + +// Block to be notified about the final status of the cancellation request started in stopFetching. +// +// |fetcher| will be the cancel request that was sent to the server, or nil if stopFetching is not +// going to send a cancel request. If |fetcher| is provided, the other parameters correspond to the +// completion handler of the cancellation request fetcher. +typedef void (^GTMSessionUploadFetcherCancellationHandler)(GTMSessionFetcher *_Nullable fetcher, + NSData *_Nullable data, + NSError *_Nullable error); + +@interface GTMSessionUploadFetcher : GTMSessionFetcher + +// Create an upload fetcher specifying either the request or the resume location URL, +// then set an upload data source using one of these: +// +// setUploadFileURL: +// setUploadDataLength:provider: +// setUploadFileHandle: +// setUploadData: + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil; + +// Allows cellular access. ++ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil; + ++ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + allowsCellularAccess:(BOOL)allowsCellularAccess + fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil; + +// Allows dataProviders for files of unknown length. Pass kGTMSessionUploadFetcherUnknownFileSize as +// |fullLength| if the length is unknown. +- (void)setUploadDataLength:(int64_t)fullLength + provider:(nullable GTMSessionUploadFetcherDataProvider)block; + ++ (NSArray *)uploadFetchersForBackgroundSessions; ++ (nullable instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier; + +- (void)pauseFetching; +- (void)resumeFetching; +- (BOOL)isPaused; + +@property(atomic, strong, nullable) NSURL *uploadLocationURL; +@property(atomic, strong, nullable) NSData *uploadData; +@property(atomic, strong, nullable) NSURL *uploadFileURL; +@property(atomic, strong, nullable) NSFileHandle *uploadFileHandle; +@property(atomic, copy, readonly, nullable) GTMSessionUploadFetcherDataProvider uploadDataProvider; +@property(atomic, copy) NSString *uploadMIMEType; +@property(atomic, readonly, assign) int64_t chunkSize; +@property(atomic, readonly, assign) int64_t currentOffset; +// Reflects the original NSURLRequest's @c allowCellularAccess property. +@property(atomic, readonly, assign) BOOL allowsCellularAccess; + +// The fetcher for the current data chunk, if any +@property(atomic, strong, nullable) GTMSessionFetcher *chunkFetcher; + +// The active fetcher is the current chunk fetcher, or the upload fetcher itself +// if no chunk fetcher has yet been created. +@property(atomic, readonly) GTMSessionFetcher *activeFetcher; + +// The last request made by an active fetcher. Useful for testing. +@property(atomic, readonly, nullable) NSURLRequest *lastChunkRequest; + +// The status code from the most recently-completed fetch. +@property(atomic, assign) NSInteger statusCode; + +// Invoked as part of the stop fetching process. Invoked immediately if there is no upload in +// progress, otherwise invoked with the results of the attempt to notify the server that the +// upload will not continue. +// +// Unlike other callbacks, since this is related specifically to the stopFetching flow it is not +// cleared by stopFetching. It will instead clear itself after it is invoked or if the completion +// has occured before stopFetching is called. +@property(atomic, copy, nullable) GTMSessionUploadFetcherCancellationHandler cancellationHandler; + +// Exposed for testing only. +@property(atomic, readonly, nullable) dispatch_queue_t delegateCallbackQueue; +@property(atomic, readonly, nullable) GTMSessionFetcherCompletionHandler delegateCompletionHandler; + +@end + +@interface GTMSessionFetcher (GTMSessionUploadFetcherMethods) + +@property(readonly, nullable) GTMSessionUploadFetcher *parentUploadFetcher; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m new file mode 100644 index 0000000..8da9796 --- /dev/null +++ b/saraWhatsUp/Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m @@ -0,0 +1,2001 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionUploadFetcher.h" + +#if TARGET_OS_OSX && GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH +// To reconnect background sessions on Mac outside +load requires importing and linking +// AppKit to access the NSApplicationDidFinishLaunching symbol. +#import +#endif + +static NSString *const kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey = @"_upChunk"; +static NSString *const kGTMSessionIdentifierUploadFileURLMetadataKey = @"_upFileURL"; +static NSString *const kGTMSessionIdentifierUploadFileLengthMetadataKey = @"_upFileLen"; +static NSString *const kGTMSessionIdentifierUploadLocationURLMetadataKey = @"_upLocURL"; +static NSString *const kGTMSessionIdentifierUploadMIMETypeMetadataKey = @"_uploadMIME"; +static NSString *const kGTMSessionIdentifierUploadChunkSizeMetadataKey = @"_upChSize"; +static NSString *const kGTMSessionIdentifierUploadCurrentOffsetMetadataKey = @"_upOffset"; +static NSString *const kGTMSessionIdentifierUploadAllowsCellularAccess = @"_upAllowsCellularAccess"; + +static NSString *const kGTMSessionHeaderXGoogUploadChunkGranularity = + @"X-Goog-Upload-Chunk-Granularity"; +static NSString *const kGTMSessionHeaderXGoogUploadCommand = @"X-Goog-Upload-Command"; +static NSString *const kGTMSessionHeaderXGoogUploadContentLength = @"X-Goog-Upload-Content-Length"; +static NSString *const kGTMSessionHeaderXGoogUploadContentType = @"X-Goog-Upload-Content-Type"; +static NSString *const kGTMSessionHeaderXGoogUploadOffset = @"X-Goog-Upload-Offset"; +static NSString *const kGTMSessionHeaderXGoogUploadProtocol = @"X-Goog-Upload-Protocol"; +static NSString *const kGTMSessionXGoogUploadProtocolResumable = @"resumable"; +static NSString *const kGTMSessionHeaderXGoogUploadSizeReceived = @"X-Goog-Upload-Size-Received"; +static NSString *const kGTMSessionHeaderXGoogUploadStatus = @"X-Goog-Upload-Status"; +static NSString *const kGTMSessionHeaderXGoogUploadURL = @"X-Goog-Upload-URL"; + +// Property of chunk fetchers identifying the parent upload fetcher. Non-retained NSValue. +static NSString *const kGTMSessionUploadFetcherChunkParentKey = @"_uploadFetcherChunkParent"; + +int64_t const kGTMSessionUploadFetcherUnknownFileSize = -1; + +int64_t const kGTMSessionUploadFetcherStandardChunkSize = (int64_t)LLONG_MAX; + +#if TARGET_OS_IPHONE +int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = + 10 * 1024 * 1024; // 10 MB for iOS, watchOS, tvOS +#else +int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = + 100 * 1024 * 1024; // 100 MB for macOS +#endif + +typedef NS_ENUM(NSUInteger, GTMSessionUploadFetcherStatus) { + kStatusUnknown, + kStatusActive, + kStatusFinal, + kStatusCancelled, +}; + +NSString *const kGTMSessionFetcherUploadLocationObtainedNotification = + @"kGTMSessionFetcherUploadLocationObtainedNotification"; + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (ProtectedMethods) + +// Access to non-public method on the parent fetcher class. +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks; +- (void)createSessionIdentifierWithMetadata:(NSDictionary *)metadata; +- (GTMSessionFetcherCompletionHandler)completionHandlerWithTarget:(id)target + didFinishSelector:(SEL)finishedSelector; +- (void)invokeOnCallbackQueue:(dispatch_queue_t)callbackQueue + afterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block; +- (NSTimer *)retryTimer; +- (void)beginFetchForRetry; + +@property(readwrite, strong) NSData *downloadedData; +- (void)releaseCallbacks; + +- (NSInteger)statusCodeUnsynchronized; + +- (BOOL)userStoppedFetching; + +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionUploadFetcher () + +// Changing readonly to readwrite. +@property(atomic, strong, readwrite) NSURLRequest *lastChunkRequest; +@property(atomic, readwrite, assign) int64_t currentOffset; + +// Internal properties. +@property(strong, atomic, nullable) GTMSessionFetcher *fetcherInFlight; // Synchronized on self. + +@property(assign, atomic, getter=isSubdataGenerating) BOOL subdataGenerating; +@property(assign, atomic) BOOL shouldInitiateOffsetQuery; +@property(assign, atomic) int64_t uploadGranularity; +@property(assign, atomic) BOOL allowsCellularAccess; + +@end + +@implementation GTMSessionUploadFetcher { + GTMSessionFetcher *_chunkFetcher; + + // We'll call through to the delegate's completion handler. + GTMSessionFetcherCompletionHandler _delegateCompletionHandler; + dispatch_queue_t _delegateCallbackQueue; + + // The initial fetch's body length and bytes actually sent are + // needed for calculating progress during subsequent chunk uploads + int64_t _initialBodyLength; + int64_t _initialBodySent; + + // The upload server address for the chunks of this upload session. + NSURL *_uploadLocationURL; + + // _uploadData, _uploadDataProvider, or _uploadFileHandle may be set, but only one. + NSData *_uploadData; + NSFileHandle *_uploadFileHandle; + GTMSessionUploadFetcherDataProvider _uploadDataProvider; + NSURL *_uploadFileURL; + int64_t _uploadFileLength; + NSString *_uploadMIMEType; + int64_t _chunkSize; + int64_t _uploadGranularity; + BOOL _isPaused; + BOOL _isRestartedUpload; + BOOL _shouldInitiateOffsetQuery; + + // Tied to useBackgroundSession property, since this property is applicable to chunk fetchers. + BOOL _useBackgroundSessionOnChunkFetchers; + + // We keep the latest offset into the upload data just for progress reporting. + int64_t _currentOffset; + + NSDictionary *_recentChunkReponseHeaders; + NSInteger _recentChunkStatusCode; + + // For waiting, we need to know the fetcher in flight, if any, and if subdata generation + // is in progress. + GTMSessionFetcher *_fetcherInFlight; + BOOL _isSubdataGenerating; + BOOL _isCancelInFlight; + + GTMSessionUploadFetcherCancellationHandler _cancellationHandler; +} + ++ (void)load { +#if GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH && TARGET_OS_IPHONE + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(reconnectFetchersForBackgroundSessionsOnAppLaunch:) + name:UIApplicationDidFinishLaunchingNotification + object:nil]; +#elif GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH && TARGET_OS_OSX + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(reconnectFetchersForBackgroundSessionsOnAppLaunch:) + name:NSApplicationDidFinishLaunchingNotification + object:nil]; +#else + [self uploadFetchersForBackgroundSessions]; +#endif +} + ++ (void)reconnectFetchersForBackgroundSessionsOnAppLaunch:(NSNotification *)notification { + // Give all other app-did-launch handlers a chance to complete before + // reconnecting the fetchers. Not doing this may lead to reconnecting + // before the app delegate has a chance to run. + dispatch_async(dispatch_get_main_queue(), ^{ + [self uploadFetchersForBackgroundSessions]; + }); +} + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTMSessionFetcherService *)fetcherService { + GTMSessionUploadFetcher *fetcher = [self uploadFetcherWithRequest:request + fetcherService:fetcherService]; + [fetcher setLocationURL:nil + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize + allowsCellularAccess:request.allowsCellularAccess]; + return fetcher; +} + ++ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil { + return [self uploadFetcherWithLocation:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize + allowsCellularAccess:YES + fetcherService:fetcherServiceOrNil]; +} + ++ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + allowsCellularAccess:(BOOL)allowsCellularAccess + fetcherService:(GTMSessionFetcherService *)fetcherService { + GTMSessionUploadFetcher *fetcher = [self uploadFetcherWithRequest:nil + fetcherService:fetcherService]; + [fetcher setLocationURL:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize + allowsCellularAccess:allowsCellularAccess]; + return fetcher; +} + ++ (instancetype)uploadFetcherForSessionIdentifierMetadata:(NSDictionary *)metadata { + GTMSESSION_ASSERT_DEBUG( + [metadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] boolValue], + @"Session identifier metadata is not for an upload fetcher: %@", metadata); + + NSNumber *uploadFileLengthNum = metadata[kGTMSessionIdentifierUploadFileLengthMetadataKey]; + GTMSESSION_ASSERT_DEBUG(uploadFileLengthNum != nil, + @"Session metadata missing an UploadFileSize"); + if (uploadFileLengthNum == nil) return nil; + + int64_t uploadFileLength = [uploadFileLengthNum longLongValue]; + GTMSESSION_ASSERT_DEBUG(uploadFileLength >= 0, @"Session metadata UploadFileSize is unknown"); + + NSString *uploadFileURLString = metadata[kGTMSessionIdentifierUploadFileURLMetadataKey]; + GTMSESSION_ASSERT_DEBUG(uploadFileURLString, @"Session metadata missing an UploadFileURL"); + if (uploadFileURLString == nil) return nil; + + NSURL *uploadFileURL = [NSURL URLWithString:uploadFileURLString]; + // There used to be a call here to NSURL checkResourceIsReachableAndReturnError: to check for the + // existence of the file (also tried NSFileManager fileExistsAtPath:). We've determined + // empirically that the check can fail at startup even when the upload file does in fact exist. + // For now, we'll go ahead and restore the background upload fetcher. If the file doesn't exist, + // it will fail later. + + NSString *uploadLocationURLString = metadata[kGTMSessionIdentifierUploadLocationURLMetadataKey]; + NSURL *uploadLocationURL = + uploadLocationURLString ? [NSURL URLWithString:uploadLocationURLString] : nil; + + NSString *uploadMIMEType = metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey]; + int64_t uploadChunkSize = + [metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] longLongValue]; + if (uploadChunkSize <= 0) { + uploadChunkSize = kGTMSessionUploadFetcherStandardChunkSize; + } + int64_t currentOffset = + [metadata[kGTMSessionIdentifierUploadCurrentOffsetMetadataKey] longLongValue]; + + BOOL allowsCellularAccess = YES; + if (metadata[kGTMSessionIdentifierUploadAllowsCellularAccess]) { + allowsCellularAccess = [metadata[kGTMSessionIdentifierUploadAllowsCellularAccess] boolValue]; + } + + GTMSESSION_ASSERT_DEBUG(currentOffset <= uploadFileLength, + @"CurrentOffset (%lld) exceeds UploadFileSize (%lld)", currentOffset, + uploadFileLength); + if (currentOffset > uploadFileLength) return nil; + + GTMSessionUploadFetcher *uploadFetcher = [self uploadFetcherWithLocation:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:uploadChunkSize + allowsCellularAccess:allowsCellularAccess + fetcherService:nil]; + // Set the upload file length before setting the upload file URL tries to determine the length. + [uploadFetcher setUploadFileLength:uploadFileLength]; + + uploadFetcher.uploadFileURL = uploadFileURL; + uploadFetcher.sessionUserInfo = metadata; + uploadFetcher.useBackgroundSession = YES; + uploadFetcher.currentOffset = currentOffset; + uploadFetcher.delegateCallbackQueue = uploadFetcher.callbackQueue; + uploadFetcher.allowedInsecureSchemes = @[ @"http" ]; // Allowed on restored upload fetcher. + return uploadFetcher; +} + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + fetcherService:(GTMSessionFetcherService *)fetcherService { + // Internal utility method for instantiating fetchers + GTMSessionUploadFetcher *fetcher; + if ([fetcherService isKindOfClass:[GTMSessionFetcherService class]]) { + fetcher = [fetcherService fetcherWithRequest:request fetcherClass:self]; + } else { + fetcher = [self fetcherWithRequest:request]; + } + fetcher.useBackgroundSession = YES; + return fetcher; +} + ++ (NSPointerArray *)uploadFetcherPointerArrayForBackgroundSessions { + static NSPointerArray *gUploadFetcherPointerArrayForBackgroundSessions = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gUploadFetcherPointerArrayForBackgroundSessions = [NSPointerArray weakObjectsPointerArray]; + }); + return gUploadFetcherPointerArrayForBackgroundSessions; +} + ++ (instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + NSArray *uploadFetchersForBackgroundSessions = [self uploadFetchersForBackgroundSessions]; + for (GTMSessionUploadFetcher *uploadFetcher in uploadFetchersForBackgroundSessions) { + if ([uploadFetcher.chunkFetcher.sessionIdentifier isEqual:sessionIdentifier]) { + return uploadFetcher; + } + } + return nil; +} + ++ (NSArray *)uploadFetchersForBackgroundSessions { + NSMutableSet *restoredSessionIdentifiers = [[NSMutableSet alloc] init]; + NSMutableArray *uploadFetchers = [[NSMutableArray alloc] init]; + NSPointerArray *uploadFetcherPointerArray = [self uploadFetcherPointerArrayForBackgroundSessions]; + + // Collect the background session upload fetchers that are still in memory. + @synchronized(uploadFetcherPointerArray) { + [uploadFetcherPointerArray compact]; + for (GTMSessionUploadFetcher *uploadFetcher in uploadFetcherPointerArray) { + NSString *sessionIdentifier = uploadFetcher.chunkFetcher.sessionIdentifier; + if (sessionIdentifier) { + [restoredSessionIdentifiers addObject:sessionIdentifier]; + [uploadFetchers addObject:uploadFetcher]; + } + } + } // @synchronized(uploadFetcherPointerArray) + + // The system may have other ongoing background upload sessions. Restore upload fetchers for those + // too. + NSArray *fetchers = [GTMSessionFetcher fetchersForBackgroundSessions]; + for (GTMSessionFetcher *fetcher in fetchers) { + NSString *sessionIdentifier = fetcher.sessionIdentifier; + if (!sessionIdentifier || [restoredSessionIdentifiers containsObject:sessionIdentifier]) { + continue; + } + NSDictionary *sessionIdentifierMetadata = [fetcher sessionIdentifierMetadata]; + if (sessionIdentifierMetadata == nil) { + continue; + } + if (![sessionIdentifierMetadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] + boolValue]) { + continue; + } + GTMSessionUploadFetcher *uploadFetcher = + [self uploadFetcherForSessionIdentifierMetadata:sessionIdentifierMetadata]; + if (uploadFetcher == nil) { + // Something went wrong with this upload fetcher, so kill the restored chunk fetcher. + [fetcher stopFetching]; + continue; + } + [uploadFetchers addObject:uploadFetcher]; + uploadFetcher->_chunkFetcher = fetcher; + uploadFetcher->_fetcherInFlight = fetcher; + [uploadFetcher attachSendProgressBlockToChunkFetcher:fetcher]; + fetcher.completionHandler = + [fetcher completionHandlerWithTarget:uploadFetcher + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; + + GTMSESSION_LOG_DEBUG(@"%@ restoring upload fetcher %@ for chunk fetcher %@", [self class], + uploadFetcher, fetcher); + } + return uploadFetchers; +} + +- (void)setUploadData:(NSData *)data { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadData != data) { + _uploadData = data; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSData *)uploadData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadData; + } +} + +- (void)setUploadFileHandle:(NSFileHandle *)fh { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileHandle != fh) { + _uploadFileHandle = fh; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSFileHandle *)uploadFileHandle { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadFileHandle; + } +} + +- (void)setUploadFileURL:(NSURL *)uploadURL { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileURL != uploadURL) { + _uploadFileURL = uploadURL; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSURL *)uploadFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadFileURL; + } +} + +- (void)setUploadFileLength:(int64_t)fullLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileLength == kGTMSessionUploadFetcherUnknownFileSize && + fullLength != kGTMSessionUploadFetcherUnknownFileSize) { + _uploadFileLength = fullLength; + } + } +} + +- (void)setUploadDataLength:(int64_t)fullLength + provider:(GTMSessionUploadFetcherDataProvider)block { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadDataProvider = [block copy]; + _uploadFileLength = fullLength; + } + [self setupRequestHeaders]; +} + +- (GTMSessionUploadFetcherDataProvider)uploadDataProvider { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadDataProvider; + } +} + +- (void)setUploadMIMEType:(NSString *)uploadMIMEType { + GTMSESSION_ASSERT_DEBUG(0, @"TODO: disallow setUploadMIMEType by making declaration readonly"); + // (and uploadMIMEType, chunksize, currentOffset) + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadMIMEType = uploadMIMEType; + } +} + +- (NSString *)uploadMIMEType { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadMIMEType; + } +} + +- (int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _chunkSize; + } +} + +- (void)setupRequestHeaders { + GTMSessionCheckNotSynchronized(self); + +#if DEBUG + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + int hasData = (_uploadData != nil) ? 1 : 0; + int hasFileHandle = (_uploadFileHandle != nil) ? 1 : 0; + int hasFileURL = (_uploadFileURL != nil) ? 1 : 0; + int hasUploadDataProvider = (_uploadDataProvider != nil) ? 1 : 0; + int numberOfSources = hasData + hasFileHandle + hasFileURL + hasUploadDataProvider; +#pragma unused(numberOfSources) + GTMSESSION_ASSERT_DEBUG(numberOfSources == 1, @"Need just one upload source (%d)", + numberOfSources); + } // @synchronized(self) +#endif + + // Add our custom headers to the initial request indicating the data + // type and total size to be delivered later in the chunk requests. + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + + GTMSESSION_ASSERT_DEBUG((mutableRequest == nil) != (_uploadLocationURL == nil), + @"Request and location are mutually exclusive"); + if (!mutableRequest) return; + + [mutableRequest setValue:kGTMSessionXGoogUploadProtocolResumable + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadProtocol]; + [mutableRequest setValue:@"start" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + [mutableRequest setValue:_uploadMIMEType + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentType]; + [mutableRequest setValue:@([self fullUploadLength]).stringValue + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentLength]; + + NSString *method = mutableRequest.HTTPMethod; + if (method == nil || [method caseInsensitiveCompare:@"GET"] == NSOrderedSame) { + [mutableRequest setHTTPMethod:@"POST"]; + } + + // Ensure the user agent header identifies this to the upload server as a + // GTMSessionUploadFetcher client. The /1 can be incremented in the unlikely circumstance + // we need to make a bug fix in the client that the server can recognize. + NSString *const kUserAgentStub = @"(GTMSUF/1)"; + NSString *userAgent = [mutableRequest valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent == nil || [userAgent rangeOfString:kUserAgentStub].location == NSNotFound) { + if (userAgent.length == 0) { + userAgent = GTMFetcherStandardUserAgentString(nil); + } + userAgent = [userAgent stringByAppendingFormat:@" %@", kUserAgentStub]; + [mutableRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + [self setRequest:mutableRequest]; +} + +- (void)setLocationURL:(nullable NSURL *)location + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + allowsCellularAccess:(BOOL)allowsCellularAccess { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(chunkSize > 0, @"chunk size is zero"); + + _allowsCellularAccess = allowsCellularAccess; + + // When resuming an upload, set the known upload target URL. + _uploadLocationURL = location; + + _uploadMIMEType = uploadMIMEType; + _chunkSize = chunkSize; + + // Indicate that we've not yet determined the file handle's length + _uploadFileLength = kGTMSessionUploadFetcherUnknownFileSize; + + // Indicate that we've not yet determined the upload fetcher status + _recentChunkStatusCode = -1; + + // If this is restarting an upload begun by another fetcher, + // the location is specified but the request is nil + _isRestartedUpload = (location != nil); + } // @synchronized(self) +} + +- (int64_t)fullUploadLength { + int64_t result; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadData) { + result = (int64_t)_uploadData.length; + } else { + if (_uploadFileLength == kGTMSessionUploadFetcherUnknownFileSize) { + if (_uploadFileHandle) { + // First time through, seek to end to determine file length + _uploadFileLength = (int64_t)[_uploadFileHandle seekToEndOfFile]; + } else if (_uploadDataProvider) { + // _uploadFileLength is set when the _uploadDataProvider is set. + GTMSESSION_ASSERT_DEBUG(_uploadFileLength >= 0, @"No uploadDataProvider length set"); + } else { + NSNumber *filesizeNum; + NSError *valueError; + if ([_uploadFileURL getResourceValue:&filesizeNum + forKey:NSURLFileSizeKey + error:&valueError]) { + _uploadFileLength = filesizeNum.longLongValue; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Cannot get file size: %@\n %@", valueError, + _uploadFileURL.path); + _uploadFileLength = 0; + } + } + } + result = _uploadFileLength; + } + } // @synchronized(self) + return result; +} + +// Make a subdata of the upload data. +- (void)generateChunkSubdataWithOffset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + GTMSessionUploadFetcherDataProvider uploadDataProvider = self.uploadDataProvider; + if (uploadDataProvider) { + uploadDataProvider(offset, length, response); + return; + } + + NSData *uploadData = self.uploadData; + if (uploadData) { + // NSData provided. + NSData *resultData; + if (offset == 0 && length == (int64_t)uploadData.length) { + resultData = uploadData; + } else { + int64_t dataLength = (int64_t)uploadData.length; + // Ensure our range is valid. b/18007814 + if (offset + length > dataLength) { + NSString *errorMessage = [NSString + stringWithFormat: + @"Range invalid for upload data. offset: %lld\tlength: %lld\tdataLength: %lld", + offset, length, dataLength]; + GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage); + response(nil, kGTMSessionUploadFetcherUnknownFileSize, + [self uploadChunkUnavailableErrorWithDescription:errorMessage]); + return; + } + NSRange range = NSMakeRange((NSUInteger)offset, (NSUInteger)length); + + @try { + resultData = [uploadData subdataWithRange:range]; + } @catch (NSException *exception) { + NSString *errorMessage = exception.description; + GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage); + response(nil, kGTMSessionUploadFetcherUnknownFileSize, + [self uploadChunkUnavailableErrorWithDescription:errorMessage]); + return; + } + } + response(resultData, kGTMSessionUploadFetcherUnknownFileSize, nil); + return; + } + NSURL *uploadFileURL = self.uploadFileURL; + if (uploadFileURL) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self generateChunkSubdataFromFileURL:uploadFileURL + offset:offset + length:length + response:response]; + }); + return; + } + GTMSESSION_ASSERT_DEBUG(_uploadFileHandle, @"Unexpectedly missing upload data package"); + NSFileHandle *uploadFileHandle = self.uploadFileHandle; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self generateChunkSubdataFromFileHandle:uploadFileHandle + offset:offset + length:length + response:response]; + }); +} + +- (void)generateChunkSubdataFromFileHandle:(NSFileHandle *)fileHandle + offset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + NSData *resultData; + NSError *error; + @try { + [fileHandle seekToFileOffset:(unsigned long long)offset]; + resultData = [fileHandle readDataOfLength:(NSUInteger)length]; + } @catch (NSException *exception) { + GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileHandle failed to read, %@", exception); + error = [self uploadChunkUnavailableErrorWithDescription:exception.description]; + } + // The response always re-dispatches to the main thread, so we skip doing that here. + response(resultData, kGTMSessionUploadFetcherUnknownFileSize, error); +} + +- (void)generateChunkSubdataFromFileURL:(NSURL *)fileURL + offset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + GTMSessionCheckNotSynchronized(self); + + NSData *resultData; + NSError *error; + int64_t fullUploadLength = [self fullUploadLength]; + NSData *mappedData = + [NSData dataWithContentsOfURL:fileURL + options:NSDataReadingMappedAlways + NSDataReadingUncached + error:&error]; + if (!mappedData) { + // We could not create an NSData by memory-mapping the file. +#if TARGET_IPHONE_SIMULATOR + // NSTemporaryDirectory() can differ in the simulator between app restarts, + // yet the contents for the new path remains unchanged, so try the latest temp path. + if ([error.domain isEqual:NSCocoaErrorDomain] && (error.code == NSFileReadNoSuchFileError)) { + NSString *filename = [fileURL lastPathComponent]; + NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + NSURL *newFileURL = [NSURL fileURLWithPath:filePath]; + if (![newFileURL isEqual:fileURL]) { + [self generateChunkSubdataFromFileURL:newFileURL + offset:offset + length:length + response:response]; + return; + } + } +#endif + + // If the file is just too large to create an NSData for, or if for some other reason we can't + // map it, create an NSFileHandle instead to read a subset into an NSData. +#if DEBUG + NSNumber *fileSizeNum; + BOOL hasFileSize = [fileURL getResourceValue:&fileSizeNum forKey:NSURLFileSizeKey error:NULL]; + GTMSESSION_LOG_DEBUG(@"Note: uploadFileURL is falling back to creating upload chunks by reading" + @" an NSFileHandle since uploadFileURL failed to map the upload file," + @" file size %@, %@", + hasFileSize ? fileSizeNum : @"unknown", error); +#endif + + NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:fileURL error:&error]; + if (fileHandle != nil) { + [self generateChunkSubdataFromFileHandle:fileHandle + offset:offset + length:length + response:response]; + return; + } + GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileURL failed to read, %@", error); + // Fall through with the error. + } else { + // Successfully created an NSData by memory-mapping the file. + if ((NSUInteger)(offset + length) > mappedData.length) { + NSString *errorMessage = [NSString + stringWithFormat:@"Range invalid for upload data. offset: %lld\tlength: " + @"%lld\tdataLength: %lld\texpected UploadLength: %lld", + offset, length, (long long)mappedData.length, fullUploadLength]; + GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage); + response(nil, kGTMSessionUploadFetcherUnknownFileSize, + [self uploadChunkUnavailableErrorWithDescription:errorMessage]); + return; + } + if (offset > 0 || length < fullUploadLength) { + NSRange range = NSMakeRange((NSUInteger)offset, (NSUInteger)length); + resultData = [mappedData subdataWithRange:range]; + } else { + resultData = mappedData; + } + } + // The response always re-dispatches to the main thread, so we skip re-dispatching here. + response(resultData, kGTMSessionUploadFetcherUnknownFileSize, error); +} + +- (NSError *)uploadChunkUnavailableErrorWithDescription:(NSString *)description { + // The description in the userInfo is intended as a clue to programmers, not + // for client code to examine or rely on. + NSDictionary *userInfo = @{@"description" : description}; + return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorUploadChunkUnavailable + userInfo:userInfo]; +} + +- (NSError *)prematureFailureErrorWithUserInfo:(NSDictionary *)userInfo { + // An error for if we get an unexpected status from the upload server or + // otherwise cannot continue. This is an issue beyond the upload protocol; + // there's no way the client can do anything useful except give up. + NSError *error = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:501 // Not implemented + userInfo:userInfo]; + return error; +} + ++ (GTMSessionUploadFetcherStatus)uploadStatusFromResponseHeaders:(NSDictionary *)responseHeaders { + NSString *statusString = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus]; + if ([statusString isEqual:@"active"]) { + return kStatusActive; + } + if ([statusString isEqual:@"final"]) { + return kStatusFinal; + } + if ([statusString isEqual:@"cancelled"]) { + return kStatusCancelled; + } + return kStatusUnknown; +} + +#pragma mark Method overrides affecting the initial fetch only + +- (void)setCompletionHandler:(GTMSessionFetcherCompletionHandler)handler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCompletionHandler = handler; + } +} + +- (void)setDelegateCallbackQueue:(nullable dispatch_queue_t)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCallbackQueue = queue; + } +} + +- (nullable dispatch_queue_t)delegateCallbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateCallbackQueue; + } +} + +- (BOOL)isRestartedUpload { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isRestartedUpload; + } +} + +- (nullable GTMSessionFetcher *)chunkFetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _chunkFetcher; + } +} + +- (void)setChunkFetcher:(nullable GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _chunkFetcher = fetcher; + } +} + +- (void)setFetcherInFlight:(nullable GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _fetcherInFlight = fetcher; + } +} + +- (nullable GTMSessionFetcher *)fetcherInFlight { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _fetcherInFlight; + } +} + +- (void)setCancellationHandler: + (nullable GTMSessionUploadFetcherCancellationHandler)cancellationHandler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _cancellationHandler = cancellationHandler; + } +} + +- (nullable GTMSessionUploadFetcherCancellationHandler)cancellationHandler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _cancellationHandler; + } +} + +- (void)beginFetchForRetry { + GTMSessionCheckNotSynchronized(self); + + // Override the superclass to reset the initial body length and fetcher-in-flight, + // then call the superclass implementation. + [self setInitialBodyLength:[self bodyLength]]; + + GTMSESSION_ASSERT_DEBUG(self.fetcherInFlight == nil, @"unexpected fetcher in flight: %@", + self.fetcherInFlight); + self.fetcherInFlight = self; + [super beginFetchForRetry]; +} + +- (void)beginFetchWithCompletionHandler:(GTMSessionFetcherCompletionHandler)handler { + GTMSessionCheckNotSynchronized(self); + + [self setInitialBodyLength:[self bodyLength]]; + + // We'll hold onto the superclass's callback queue so we can invoke the handler + // even after the superclass has released the queue and its callback handler, as + // happens during auth failure. + [self setDelegateCallbackQueue:self.callbackQueue]; + self.completionHandler = handler; + + if ([self isRestartedUpload]) { + // When restarting an upload, we know the destination location for chunk fetches, + // but we need to query to find the initial offset. + if (![self isPaused]) { + [self sendQueryForUploadOffsetWithFetcherProperties:self.properties]; + } + return; + } + // We don't want to call into the client's completion block immediately + // after the finish of the initial connection (the delegate is called only + // when uploading finishes), so we substitute our own completion block to be + // called when the initial connection finishes + GTMSESSION_ASSERT_DEBUG(self.fetcherInFlight == nil, @"unexpected fetcher in flight: %@", + self.fetcherInFlight); + + self.fetcherInFlight = self; + [super beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + self.fetcherInFlight = nil; + // callback + + BOOL hasTestBlock = (self.testBlock != nil); + if (![self isRestartedUpload] && !hasTestBlock) { + if (error == nil) { + [self beginChunkFetches]; + } else { + if ([self retryTimer] == nil) { + [self invokeFinalCallbackWithData:nil error:error shouldInvalidateLocation:YES]; + } + } + } else { + // If there was no initial request, then this fetch is resuming some + // other uploadFetcher's initial request, and the superclass's connection + // is never used, so at this point we call the user's actual completion + // block. + if (!hasTestBlock) { + [self invokeFinalCallbackWithData:data error:error shouldInvalidateLocation:YES]; + } else { + // There was a test block, so we won't do chunk fetches, but we simulate obtaining + // the data to be uploaded from the upload data provider block or the file handle, + // and then call back. + [self generateChunkSubdataWithOffset:0 + length:[self fullUploadLength] + response:^(NSData *generateData, int64_t fullUploadLength, + NSError *generateError) { + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + }]; + } + } + }]; +} + +- (void)beginChunkFetches { + GTMSessionCheckNotSynchronized(self); + +#if DEBUG + // The initial response of the resumable upload protocol should have an + // empty body + // + // This assert typically happens because the upload create/edit link URL was + // not supplied with the request, and the server is thus expecting a non- + // resumable request/response. + if (self.downloadedData.length > 0) { + NSData *downloadedData = self.downloadedData; + NSString *str = [[NSString alloc] initWithData:downloadedData encoding:NSUTF8StringEncoding]; +#pragma unused(str) + GTMSESSION_ASSERT_DEBUG(NO, @"unexpected response data (uploading to the wrong URL?)\n%@", str); + } +#endif + + // We need to get the upload URL from the location header to continue. + NSDictionary *responseHeaders = [self responseHeaders]; + + [self retrieveUploadChunkGranularityFromResponseHeaders:responseHeaders]; + + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown, + @"beginChunkFetches has unexpected upload status for headers %@", + responseHeaders); + + BOOL isPrematureStop = (uploadStatus == kStatusFinal) || (uploadStatus == kStatusCancelled); + + NSString *uploadLocationURLStr = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadURL]; + BOOL hasUploadLocation = (uploadLocationURLStr.length > 0); + + if (isPrematureStop || !hasUploadLocation) { + GTMSESSION_ASSERT_DEBUG(NO, @"Premature failure: upload-status:\"%@\" location:%@", + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], + uploadLocationURLStr); + // We cannot continue since we do not know the location to use + // as our upload destination. + NSDictionary *userInfo = nil; + NSData *downloadedData = self.downloadedData; + if (downloadedData.length > 0) { + userInfo = @{kGTMSessionFetcherStatusDataKey : downloadedData}; + } + NSError *failureError = [self prematureFailureErrorWithUserInfo:userInfo]; + [self invokeFinalCallbackWithData:nil error:failureError shouldInvalidateLocation:YES]; + return; + } + + self.uploadLocationURL = [NSURL URLWithString:uploadLocationURLStr]; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherUploadLocationObtainedNotification object:self]; + + // we've now sent all of the initial post body data, so we need to include + // its size in future progress indicator callbacks + [self setInitialBodySent:[self initialBodyLength]]; + + // just in case the user paused us during the initial fetch... + if (![self isPaused]) { + [self uploadNextChunkWithOffset:0]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + // Overrides the superclass. + [self invokeDelegateWithDidSendBytes:bytesSent + totalBytesSent:totalBytesSent + totalBytesExpectedToSend:totalBytesExpectedToSend + [self fullUploadLength]]; +} + +- (BOOL)shouldReleaseCallbacksUponCompletion { + // Overrides the superclass. + + // We don't want the superclass to release the delegate and callback + // blocks once the initial fetch has finished + // + // This is invoked for only successful completion of the connection; + // an error always will invoke and release the callbacks + return NO; +} + +- (void)invokeFinalCallbackWithData:(NSData *)data + error:(NSError *)error + shouldInvalidateLocation:(BOOL)shouldInvalidateLocation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (shouldInvalidateLocation) { + _uploadLocationURL = nil; + } + + dispatch_queue_t queue = _delegateCallbackQueue; + GTMSessionFetcherCompletionHandler handler = _delegateCompletionHandler; + if (queue && handler) { + [self invokeOnCallbackQueue:queue + afterUserStopped:NO + block:^{ + handler(data, error); + }]; + } + } // @synchronized(self) + + [self releaseUploadAndBaseCallbacks:!self.userStoppedFetching]; +} + +- (void)releaseUploadAndBaseCallbacks:(BOOL)shouldReleaseCancellation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCallbackQueue = nil; + _delegateCompletionHandler = nil; + _uploadDataProvider = nil; + if (shouldReleaseCancellation) { + _cancellationHandler = nil; + } + } + + // Release the base class's callbacks, too, if needed. + [self releaseCallbacks]; +} + +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks { + GTMSessionCheckNotSynchronized(self); + + // Clear _fetcherInFlight when stopped. Moved from stopFetching, since that's a public method, + // where this method does the work. Fixes issue clearing value when retryBlock included. + GTMSessionFetcher *fetcherInFlight = self.fetcherInFlight; + if (fetcherInFlight == self) { + self.fetcherInFlight = nil; + } + + [super stopFetchReleasingCallbacks:shouldReleaseCallbacks]; + + if (shouldReleaseCallbacks) { + [self releaseUploadAndBaseCallbacks:NO]; + } +} + +#pragma mark Chunk fetching methods + +- (void)uploadNextChunkWithOffset:(int64_t)offset { + // use the properties in each chunk fetcher + NSDictionary *props = [self properties]; + + [self uploadNextChunkWithOffset:offset fetcherProperties:props]; +} + +- (void)sendQueryForUploadOffsetWithFetcherProperties:(NSDictionary *)props { + GTMSessionFetcher *queryFetcher = [self uploadFetcherWithProperties:props isQueryFetch:YES]; + queryFetcher.bodyData = [NSData data]; + + NSString *originalComment = self.comment; + [queryFetcher + setCommentWithFormat:@"%@ (query offset)", originalComment ? originalComment : @"upload"]; + + [queryFetcher setRequestValue:@"query" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + + self.fetcherInFlight = queryFetcher; + [queryFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(queryFetcher:finishedWithData:error:)]; +} + +- (void)queryFetcher:(GTMSessionFetcher *)queryFetcher + finishedWithData:(NSData *)data + error:(NSError *)error { + self.fetcherInFlight = nil; + + NSDictionary *responseHeaders = [queryFetcher responseHeaders]; + NSString *sizeReceivedHeader; + + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown || error != nil, + @"query fetcher completion has unexpected upload status for headers %@", + responseHeaders); + + if (error == nil) { + sizeReceivedHeader = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadSizeReceived]; + + if (uploadStatus == kStatusCancelled || + (uploadStatus == kStatusActive && sizeReceivedHeader == nil)) { + NSDictionary *userInfo = nil; + if (data.length > 0) { + userInfo = @{kGTMSessionFetcherStatusDataKey : data}; + } + error = [self prematureFailureErrorWithUserInfo:userInfo]; + } + } + + if (error == nil) { + int64_t offset = [sizeReceivedHeader longLongValue]; + int64_t fullUploadLength = [self fullUploadLength]; + if (uploadStatus == kStatusFinal || + (offset >= fullUploadLength && + fullUploadLength != kGTMSessionUploadFetcherUnknownFileSize)) { + // Handle we're done + [self chunkFetcher:queryFetcher finishedWithData:data error:nil]; + } else { + [self retrieveUploadChunkGranularityFromResponseHeaders:responseHeaders]; + [self uploadNextChunkWithOffset:offset]; + } + } else { + // Handle query error + [self chunkFetcher:queryFetcher finishedWithData:data error:error]; + } +} + +- (void)sendCancelUploadWithFetcherProperties:(NSDictionary *)props { + @synchronized(self) { + _isCancelInFlight = YES; + } + GTMSessionFetcher *cancelFetcher = [self uploadFetcherWithProperties:props isQueryFetch:YES]; + cancelFetcher.bodyData = [NSData data]; + + NSString *originalComment = self.comment; + [cancelFetcher + setCommentWithFormat:@"%@ (cancel)", originalComment ? originalComment : @"upload"]; + + [cancelFetcher setRequestValue:@"cancel" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + + self.fetcherInFlight = cancelFetcher; + [cancelFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + self.fetcherInFlight = nil; + if (![self triggerCancellationHandlerForFetch:cancelFetcher data:data error:error]) { + if (error) { + GTMSESSION_LOG_DEBUG(@"cancelFetcher %@", error); + } + } + @synchronized(self) { + self->_isCancelInFlight = NO; + } + }]; +} + +- (void)uploadNextChunkWithOffset:(int64_t)offset fetcherProperties:(NSDictionary *)props { + GTMSessionCheckNotSynchronized(self); + + // Example chunk headers: + // X-Goog-Upload-Command: upload, finalize + // X-Goog-Upload-Offset: 0 + // Content-Length: 2000000 + // Content-Type: image/jpeg + // + // {bytes 0-1999999} + + // The chunk upload URL requires no authentication header. + GTMSessionFetcher *chunkFetcher = [self uploadFetcherWithProperties:props isQueryFetch:NO]; + [self attachSendProgressBlockToChunkFetcher:chunkFetcher]; + int64_t chunkSize = [self updateChunkFetcher:chunkFetcher forChunkAtOffset:offset]; + BOOL isUploadingFileURL = (self.uploadFileURL != nil); + int64_t fullUploadLength = [self fullUploadLength]; + + // The chunk size may have changed, so determine again if we're uploading the full file. + BOOL isUploadingFullFile = + (offset == 0 && fullUploadLength != kGTMSessionUploadFetcherUnknownFileSize && + chunkSize >= fullUploadLength); + if (isUploadingFullFile && isUploadingFileURL) { + // The data is the full upload file URL. + chunkFetcher.bodyFileURL = self.uploadFileURL; + [self beginChunkFetcher:chunkFetcher offset:offset]; + } else { + // Make an NSData for the subset for this upload chunk. + self.subdataGenerating = YES; + [self generateChunkSubdataWithOffset:offset + length:chunkSize + response:^(NSData *chunkData, int64_t uploadFileLength, + NSError *chunkError) { + // The subdata methods may leave us on a background thread. + dispatch_async(dispatch_get_main_queue(), ^{ + self.subdataGenerating = NO; + + // dont allow the updating of fileLength for uploads not using a + // data provider as they should know the file length before the + // upload starts. + if (self->_uploadDataProvider != nil && uploadFileLength > 0) { + [self setUploadFileLength:uploadFileLength]; + // Update the command and content-length headers if this is + // the last chunk to be sent. + if (offset + chunkSize >= uploadFileLength) { + int64_t updatedChunkSize = + [self updateChunkFetcher:chunkFetcher + forChunkAtOffset:offset]; + if (updatedChunkSize == 0) { + // Calling beginChunkFetcher early when there is no more + // data to send allows us to properly handle nil chunkData + // below without having to account for the case where we + // are just finalizing the file. + chunkFetcher.bodyData = [[NSData alloc] init]; + [self beginChunkFetcher:chunkFetcher offset:offset]; + return; + } + } + } + + if (chunkData == nil) { + NSError *responseError = chunkError; + if (!responseError) { + responseError = + [self uploadChunkUnavailableErrorWithDescription: + @"chunkData is nil"]; + } + [self invokeFinalCallbackWithData:nil + error:responseError + shouldInvalidateLocation:YES]; + return; + } + + BOOL didWriteFile = NO; + if (isUploadingFileURL) { + // Make a temporary file with the data subset. + NSString *tempName = + [NSString stringWithFormat:@"GTMUpload_temp_%@", + [[NSUUID UUID] UUIDString]]; + NSString *tempPath = [NSTemporaryDirectory() + stringByAppendingPathComponent:tempName]; + NSError *writeError; + didWriteFile = [chunkData writeToFile:tempPath + options:NSDataWritingAtomic + error:&writeError]; + if (didWriteFile) { + chunkFetcher.bodyFileURL = [NSURL fileURLWithPath:tempPath]; + } else { + GTMSESSION_LOG_DEBUG(@"writeToFile failed: %@\n%@", + writeError, tempPath); + } + } + if (!didWriteFile) { + chunkFetcher.bodyData = [chunkData copy]; + } + [self beginChunkFetcher:chunkFetcher offset:offset]; + }); + }]; + } +} + +- (void)beginChunkFetcher:(GTMSessionFetcher *)chunkFetcher offset:(int64_t)offset { + // Track the current offset for progress reporting + self.currentOffset = offset; + + // Hang on to the fetcher in case we need to cancel it. We set these before beginning the + // chunk fetch so the observers notified of chunk fetches can inspect the upload fetcher to + // match to the chunk. + self.chunkFetcher = chunkFetcher; + self.fetcherInFlight = chunkFetcher; + + // Update the last chunk request, including any request headers. + self.lastChunkRequest = chunkFetcher.request; + + [chunkFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; +} + +- (void)attachSendProgressBlockToChunkFetcher:(GTMSessionFetcher *)chunkFetcher { + chunkFetcher.sendProgressBlock = + ^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) { + // The total bytes expected include the initial body and the full chunked + // data, independent of how big this fetcher's chunk is. + int64_t initialBodySent = [self bodyLength]; // TODO(grobbins) use [self initialBodySent] + int64_t totalSent = initialBodySent + self.currentOffset + totalBytesSent; + int64_t totalExpected = initialBodySent + [self fullUploadLength]; + + [self invokeDelegateWithDidSendBytes:bytesSent + totalBytesSent:totalSent + totalBytesExpectedToSend:totalExpected]; + }; +} + +- (NSDictionary *)uploadSessionIdentifierMetadata { + NSMutableDictionary *metadata = [NSMutableDictionary dictionary]; + metadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] = @YES; + GTMSESSION_ASSERT_DEBUG(self.uploadFileURL, + @"Invalid upload fetcher to create session identifier for metadata"); + metadata[kGTMSessionIdentifierUploadFileURLMetadataKey] = [self.uploadFileURL absoluteString]; + metadata[kGTMSessionIdentifierUploadFileLengthMetadataKey] = @([self fullUploadLength]); + + if (self.uploadLocationURL) { + metadata[kGTMSessionIdentifierUploadLocationURLMetadataKey] = + [self.uploadLocationURL absoluteString]; + } + if (self.uploadMIMEType) { + metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey] = self.uploadMIMEType; + } + metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] = @(self.chunkSize); + metadata[kGTMSessionIdentifierUploadCurrentOffsetMetadataKey] = @(self.currentOffset); + metadata[kGTMSessionIdentifierUploadAllowsCellularAccess] = @(self.request.allowsCellularAccess); + + return metadata; +} + +- (GTMSessionFetcher *)uploadFetcherWithProperties:(NSDictionary *)properties + isQueryFetch:(BOOL)isQueryFetch { + GTMSessionCheckNotSynchronized(self); + + // Common code to make a request for a query command or for a chunk upload. + NSURL *uploadLocationURL = self.uploadLocationURL; + NSMutableURLRequest *chunkRequest = [NSMutableURLRequest requestWithURL:uploadLocationURL]; + [chunkRequest setHTTPMethod:@"PUT"]; + + // copy the user-agent from the original connection + // n.b. that self.request is nil for upload fetchers created with an existing upload location + // URL. + NSURLRequest *origRequest = self.request; + + chunkRequest.allowsCellularAccess = origRequest.allowsCellularAccess; + if (!origRequest) { + chunkRequest.allowsCellularAccess = _allowsCellularAccess; + } + NSString *userAgent = [origRequest valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent.length > 0) { + [chunkRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + + [chunkRequest setValue:kGTMSessionXGoogUploadProtocolResumable + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadProtocol]; + + // To avoid timeouts when debugging, copy the timeout of the initial fetcher. + NSTimeInterval origTimeout = [origRequest timeoutInterval]; + [chunkRequest setTimeoutInterval:origTimeout]; + + // + // Make a new chunk fetcher. + // + GTMSessionFetcher *chunkFetcher = [GTMSessionFetcher fetcherWithRequest:chunkRequest]; + chunkFetcher.callbackQueue = self.callbackQueue; + chunkFetcher.sessionUserInfo = self.sessionUserInfo; + chunkFetcher.configurationBlock = self.configurationBlock; + chunkFetcher.allowedInsecureSchemes = self.allowedInsecureSchemes; + chunkFetcher.allowLocalhostRequest = self.allowLocalhostRequest; + chunkFetcher.allowInvalidServerCertificates = self.allowInvalidServerCertificates; + chunkFetcher.useUploadTask = !isQueryFetch; + + if (self.uploadFileURL && !isQueryFetch && self.useBackgroundSession) { + [chunkFetcher createSessionIdentifierWithMetadata:[self uploadSessionIdentifierMetadata]]; + } + + // Give the chunk fetcher the same properties as the previous chunk fetcher + chunkFetcher.properties = [properties mutableCopy]; + [chunkFetcher setProperty:[NSValue valueWithNonretainedObject:self] + forKey:kGTMSessionUploadFetcherChunkParentKey]; + + // copy other fetcher settings to the new fetcher + chunkFetcher.retryEnabled = self.retryEnabled; + chunkFetcher.maxRetryInterval = self.maxRetryInterval; + + if ([self isRetryEnabled]) { + // We interpose our own retry method both so we can change the request to ask the server to + // tell us where to resume the chunk. + chunkFetcher.retryBlock = + ^(BOOL suggestedWillRetry, NSError *chunkError, GTMSessionFetcherRetryResponse response) { + void (^finish)(BOOL) = ^(BOOL shouldRetry) { + // We'll retry by sending an offset query. + if (shouldRetry) { + self.shouldInitiateOffsetQuery = !isQueryFetch; + + // We don't know what our actual offset is anymore, but the server will tell us. + self.currentOffset = 0; + } + // We don't actually want to retry this specific fetcher. + response(NO); + }; + + GTMSessionFetcherRetryBlock retryBlock = self.retryBlock; + if (retryBlock) { + // Ask the client, then call the finish block above. + retryBlock(suggestedWillRetry, chunkError, finish); + } else { + finish(suggestedWillRetry); + } + }; + } + + return chunkFetcher; +} + +- (void)chunkFetcher:(GTMSessionFetcher *)chunkFetcher + finishedWithData:(NSData *)data + error:(NSError *)error { + BOOL hasDestroyedOldChunkFetcher = NO; + self.fetcherInFlight = nil; + + NSDictionary *responseHeaders = [chunkFetcher responseHeaders]; + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG( + uploadStatus != kStatusUnknown || error != nil || self.wasCreatedFromBackgroundSession, + @"chunk fetcher completion has kStatusUnknown upload status for headers %@ fetcher %@", + responseHeaders, self); + BOOL isUploadStatusStopped = (uploadStatus == kStatusFinal || uploadStatus == kStatusCancelled); + + // Check if the fetcher was actually querying. If it failed, do not retry, + // as it would enter an infinite retry loop. + NSString *uploadCommand = + chunkFetcher.request.allHTTPHeaderFields[kGTMSessionHeaderXGoogUploadCommand]; + BOOL isQueryFetch = [uploadCommand isEqual:@"query"]; + + // TODO + // Maybe here we can check to see if the request had x goog content length set. (the file length + // one). + NSString *previousContentLengthValue = + [chunkFetcher.request valueForHTTPHeaderField:@"Content-Length"]; + // The Content-Length header may not be present if the chunk fetcher was recreated from + // a background session. + BOOL hasKnownChunkSize = (previousContentLengthValue != nil); + int64_t previousContentLength = [previousContentLengthValue longLongValue]; + + BOOL needsQuery = (!hasKnownChunkSize && !isUploadStatusStopped); + + if (error || (needsQuery && !isQueryFetch)) { + NSInteger status = error.code; + + // Status 4xx indicates a bad offset in the Google upload protocol. However, do not retry status + // 404 per spec, nor if the upload size appears to have been zero (since the server will just + // keep asking us to retry.) + if (self.shouldInitiateOffsetQuery || (needsQuery && !isQueryFetch) || + ([error.domain isEqual:kGTMSessionFetcherStatusDomain] && status >= 400 && status <= 499 && + status != 404 && uploadStatus == kStatusActive && previousContentLength > 0)) { + self.shouldInitiateOffsetQuery = NO; + [self destroyChunkFetcher]; + hasDestroyedOldChunkFetcher = YES; + [self sendQueryForUploadOffsetWithFetcherProperties:chunkFetcher.properties]; + } else { + // Some unexpected status has occurred; handle it as we would a regular + // object fetcher failure. + [self invokeFinalCallbackWithData:data error:error shouldInvalidateLocation:NO]; + } + } else { + // The chunk has uploaded successfully. + int64_t newOffset = self.currentOffset + previousContentLength; +#if DEBUG + // Verify that if we think all of the uploading data has been sent, the server responded with + // the "final" upload status. + BOOL hasUploadAllData = (newOffset == [self fullUploadLength]); + BOOL isFinalStatus = (uploadStatus == kStatusFinal); +#pragma unused(hasUploadAllData, isFinalStatus) + GTMSESSION_ASSERT_DEBUG(hasUploadAllData == isFinalStatus || !hasKnownChunkSize, + @"uploadStatus:%@ newOffset:%lld (%lld + %lld) fullUploadLength:%lld" + @" chunkFetcher:%@ requestHeaders:%@ responseHeaders:%@", + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], + newOffset, self.currentOffset, previousContentLength, + [self fullUploadLength], chunkFetcher, + chunkFetcher.request.allHTTPHeaderFields, responseHeaders); +#endif + if (isUploadStatusStopped || (!_uploadData && _uploadFileLength == 0) || + (_currentOffset > _uploadFileLength && _uploadFileLength > 0)) { + // This was the last chunk. + if (error == nil && uploadStatus == kStatusCancelled) { + // Report cancelled status as an error. + NSDictionary *userInfo = nil; + if (data.length > 0) { + userInfo = @{kGTMSessionFetcherStatusDataKey : data}; + } + data = nil; + error = [self prematureFailureErrorWithUserInfo:userInfo]; + } else { + // The upload is in final status. + // + // Take the chunk fetcher's data as the superclass data. + self.downloadedData = data; + self.statusCode = chunkFetcher.statusCode; + } + + // we're done + [self invokeFinalCallbackWithData:data error:error shouldInvalidateLocation:YES]; + } else { + // Start the next chunk. + self.currentOffset = newOffset; + + // We want to destroy this chunk fetcher before creating the next one, but + // we want to pass on its properties + NSDictionary *props = [chunkFetcher properties]; + + // We no longer need to be able to cancel this chunkFetcher. Destroy it + // before we create a new chunk fetcher. + [self destroyChunkFetcher]; + hasDestroyedOldChunkFetcher = YES; + + [self uploadNextChunkWithOffset:newOffset fetcherProperties:props]; + } + } + if (!hasDestroyedOldChunkFetcher) { + [self destroyChunkFetcher]; + } +} + +- (void)destroyChunkFetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_fetcherInFlight == _chunkFetcher) { + _fetcherInFlight = nil; + } + + [_chunkFetcher stopFetching]; + + NSURL *chunkFileURL = _chunkFetcher.bodyFileURL; + BOOL wasTemporaryUploadFile = ![chunkFileURL isEqual:_uploadFileURL]; + if (wasTemporaryUploadFile) { + NSError *error; + [[NSFileManager defaultManager] removeItemAtURL:chunkFileURL error:&error]; + if (error) { + GTMSESSION_LOG_DEBUG(@"removingItemAtURL failed: %@\n%@", error, chunkFileURL); + } + } + + _recentChunkReponseHeaders = _chunkFetcher.responseHeaders; + + // To avoid retain cycles, remove all properties except the parent identifier. + _chunkFetcher.properties = + @{kGTMSessionUploadFetcherChunkParentKey : [NSValue valueWithNonretainedObject:self]}; + + _chunkFetcher.retryBlock = nil; + _chunkFetcher.sendProgressBlock = nil; + _chunkFetcher = nil; + } // @synchronized(self) +} + +// This method calculates the proper values to pass to the client's send progress block. +// +// The actual total bytes sent include the initial body sent, plus the +// offset into the batched data prior to the current chunk fetcher + +- (void)invokeDelegateWithDidSendBytes:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpected { + GTMSessionCheckNotSynchronized(self); + + // Ensure the chunk fetcher survives the callback in case the user pauses the upload process. + __block GTMSessionFetcher *holdFetcher = self.chunkFetcher; + + [self invokeOnCallbackQueue:self.delegateCallbackQueue + afterUserStopped:NO + block:^{ + GTMSessionFetcherSendProgressBlock sendProgressBlock = + self.sendProgressBlock; + if (sendProgressBlock) { + sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpected); + } + holdFetcher = nil; + }]; +} + +- (void)retrieveUploadChunkGranularityFromResponseHeaders:(NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + + // Standard granularity for Google uploads is 256K. + NSString *chunkGranularityHeader = + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadChunkGranularity]; + self.uploadGranularity = chunkGranularityHeader.longLongValue; +} + +#pragma mark - + +- (BOOL)isPaused { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isPaused; + } // @synchronized(self) +} + +- (void)pauseFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _isPaused = YES; + } // @synchronized(self) + + // Pausing just means stopping the current chunk from uploading; + // when we resume, we will send a query request to the server to + // figure out what bytes to resume sending. + // + // We won't try to cancel the initial data upload, but rather will check + // for being paused in beginChunkFetches. + [self destroyChunkFetcher]; +} + +- (void)resumeFetching { + BOOL wasPaused; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + wasPaused = _isPaused; + _isPaused = NO; + } // @synchronized(self) + + if (wasPaused) { + [self sendQueryForUploadOffsetWithFetcherProperties:self.properties]; + } +} + +- (void)stopFetching { + // Overrides the superclass + [self destroyChunkFetcher]; + + // If we think the server is waiting for more data, then tell it there won't be more. + if (self.uploadLocationURL) { + [self sendCancelUploadWithFetcherProperties:[self properties]]; + self.uploadLocationURL = nil; + } else { + [self invokeOnCallbackQueue:self.callbackQueue + afterUserStopped:YES + block:^{ + // Repeated calls to stopFetching may cause this path to be reached + // despite having sent a real cancel request, check here to ensure that + // the cancellation handler invocation which fires will definitely be + // for the real request sent previously. + @synchronized(self) { + if (self->_isCancelInFlight) { + return; + } + } + [self triggerCancellationHandlerForFetch:nil data:nil error:nil]; + }]; + } + + [super stopFetching]; +} + +// Fires the cancellation handler, returning whether there was a handler to be fired. +- (BOOL)triggerCancellationHandlerForFetch:(GTMSessionFetcher *)fetcher + data:(NSData *)data + error:(NSError *)error { + GTMSessionUploadFetcherCancellationHandler handler = self.cancellationHandler; + if (handler) { + handler(fetcher, data, error); + self.cancellationHandler = nil; + return YES; + } + return NO; +} + +#pragma mark - + +- (int64_t)updateChunkFetcher:(GTMSessionFetcher *)chunkFetcher forChunkAtOffset:(int64_t)offset { + BOOL isUploadingFileURL = (self.uploadFileURL != nil); + + // Upload another chunk, meeting server-required granularity. + int64_t chunkSize = self.chunkSize; + + int64_t fullUploadLength = [self fullUploadLength]; + BOOL isFileLengthKnown = fullUploadLength >= 0; + + BOOL isUploadingFullFile = (offset == 0 && isFileLengthKnown && chunkSize >= fullUploadLength); + if (!isUploadingFileURL || !isUploadingFullFile) { + // We're not uploading the entire file and given the file URL. Since we'll be + // allocating a subdata block for a chunk, we need to bound it to something that + // won't blow the process's memory. + if (chunkSize > kGTMSessionUploadFetcherMaximumDemandBufferSize) { + chunkSize = kGTMSessionUploadFetcherMaximumDemandBufferSize; + } + } + + int64_t granularity = self.uploadGranularity; + if (granularity > 0) { + if (chunkSize < granularity) { + chunkSize = granularity; + } else { + chunkSize = chunkSize - (chunkSize % granularity); + } + } + + GTMSESSION_ASSERT_DEBUG(offset < fullUploadLength || fullUploadLength == 0, + @"offset %lld exceeds data length %lld", offset, fullUploadLength); + + if (granularity > 0) { + offset = offset - (offset % granularity); + } + + // If the chunk size is bigger than the remaining data, or else + // it's close enough in size to the remaining data that we'd rather + // avoid having a whole extra http fetch for the leftover bit, then make + // this chunk size exactly match the remaining data size + NSString *command; + int64_t thisChunkSize = chunkSize; + + BOOL isChunkTooBig = (thisChunkSize >= (fullUploadLength - offset)); + BOOL isChunkAlmostBigEnough = (fullUploadLength - offset - 2500 < thisChunkSize); + BOOL isFinalChunk = (isChunkTooBig || isChunkAlmostBigEnough) && isFileLengthKnown; + if (isFinalChunk) { + thisChunkSize = fullUploadLength - offset; + if (thisChunkSize > 0) { + command = @"upload, finalize"; + } else { + command = @"finalize"; + } + } else { + command = @"upload"; + } + NSString *lengthStr = @(thisChunkSize).stringValue; + NSString *offsetStr = @(offset).stringValue; + + [chunkFetcher setRequestValue:command forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + [chunkFetcher setRequestValue:lengthStr forHTTPHeaderField:@"Content-Length"]; + [chunkFetcher setRequestValue:offsetStr forHTTPHeaderField:kGTMSessionHeaderXGoogUploadOffset]; + if (_uploadFileLength != kGTMSessionUploadFetcherUnknownFileSize) { + [chunkFetcher setRequestValue:@([self fullUploadLength]).stringValue + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentLength]; + } + + // Append the range of bytes in this chunk to the fetcher comment. + NSString *baseComment = self.comment; + [chunkFetcher setCommentWithFormat:@"%@ (%lld-%lld)", baseComment ? baseComment : @"upload", + offset, MAX(0, offset + thisChunkSize - 1)]; + + return thisChunkSize; +} + +// Public properties. +// clang-format off +@synthesize currentOffset = _currentOffset, + allowsCellularAccess = _allowsCellularAccess, + delegateCompletionHandler = _delegateCompletionHandler, + chunkFetcher = _chunkFetcher, + lastChunkRequest = _lastChunkRequest, + subdataGenerating = _subdataGenerating, + shouldInitiateOffsetQuery = _shouldInitiateOffsetQuery, + uploadGranularity = _uploadGranularity; +// clang-format on + +// Internal properties. +@dynamic fetcherInFlight; +@dynamic activeFetcher; +@dynamic statusCode; +@dynamic delegateCallbackQueue; + ++ (void)removePointer:(void *)pointer fromPointerArray:(NSPointerArray *)pointerArray { + for (NSUInteger index = 0, count = pointerArray.count; index < count; ++index) { + void *pointerAtIndex = [pointerArray pointerAtIndex:index]; + if (pointerAtIndex == pointer) { + [pointerArray removePointerAtIndex:index]; + return; + } + } +} + +- (BOOL)useBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _useBackgroundSessionOnChunkFetchers; + } // @synchronized(self +} + +- (void)setUseBackgroundSession:(BOOL)useBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_useBackgroundSessionOnChunkFetchers != useBackgroundSession) { + _useBackgroundSessionOnChunkFetchers = useBackgroundSession; + NSPointerArray *uploadFetcherPointerArrayForBackgroundSessions = + [[self class] uploadFetcherPointerArrayForBackgroundSessions]; + @synchronized(uploadFetcherPointerArrayForBackgroundSessions) { + if (_useBackgroundSessionOnChunkFetchers) { + [uploadFetcherPointerArrayForBackgroundSessions addPointer:(__bridge void *)self]; + } else { + [[self class] removePointer:(__bridge void *)self + fromPointerArray:uploadFetcherPointerArrayForBackgroundSessions]; + } + } // @synchronized(uploadFetcherPointerArrayForBackgroundSessions) + } + } // @synchronized(self) +} + +- (BOOL)canFetchWithBackgroundSession { + // The initial upload fetcher is always a foreground session; the + // useBackgroundSession property will apply only to chunk fetchers, + // not to queries. + return NO; +} + +- (NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + // Overrides the superclass + + // If asked for the fetcher's response, use the most recent chunk fetcher's response, + // since the original request's response lacks useful information like the actual + // Content-Type. + NSDictionary *dict = self.chunkFetcher.responseHeaders; + if (dict) { + return dict; + } + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_recentChunkReponseHeaders) { + return _recentChunkReponseHeaders; + } + } // @synchronized(self + + // No chunk fetcher yet completed, so return whatever we have from the initial fetch. + return [super responseHeaders]; +} + +- (NSInteger)statusCodeUnsynchronized { + GTMSessionCheckSynchronized(self); + + if (_recentChunkStatusCode != -1) { + // Overrides the superclass to indicate status appropriate to the initial + // or latest chunk fetch + return _recentChunkStatusCode; + } else { + return [super statusCodeUnsynchronized]; + } +} + +- (void)setStatusCode:(NSInteger)val { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _recentChunkStatusCode = val; + } +} + +- (int64_t)initialBodyLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _initialBodyLength; + } +} + +- (void)setInitialBodyLength:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _initialBodyLength = length; + } +} + +- (int64_t)initialBodySent { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _initialBodySent; + } +} + +- (void)setInitialBodySent:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _initialBodySent = length; + } +} + +- (NSURL *)uploadLocationURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadLocationURL; + } +} + +- (void)setUploadLocationURL:(NSURL *)locationURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadLocationURL = locationURL; + } +} + +- (GTMSessionFetcher *)activeFetcher { + GTMSessionFetcher *result = self.fetcherInFlight; + if (result) return result; + + return self; +} + +- (BOOL)isFetching { + // If there is an active chunk fetcher, then the upload fetcher is considered + // to still be fetching. + if (self.fetcherInFlight != nil) return YES; + + return [super isFetching]; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds { + NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + + while (self.fetcherInFlight || self.subdataGenerating) { + if ([timeoutDate timeIntervalSinceNow] < 0) return NO; + + if (self.subdataGenerating) { + // Allow time for subdata generation. + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:0.001]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + // Wait for any chunk or query fetchers that still have pending callbacks or + // notifications. + BOOL timedOut; + + if (self.fetcherInFlight == self) { + timedOut = ![super waitForCompletionWithTimeout:timeoutInSeconds]; + } else { + timedOut = ![self.fetcherInFlight waitForCompletionWithTimeout:timeoutInSeconds]; + } + if (timedOut) return NO; + } + } + return YES; +} +#pragma clang diagnostic pop + +@end + +@implementation GTMSessionFetcher (GTMSessionUploadFetcherMethods) + +- (GTMSessionUploadFetcher *)parentUploadFetcher { + NSValue *property = [self propertyForKey:kGTMSessionUploadFetcherChunkParentKey]; + if (!property) return nil; + + GTMSessionUploadFetcher *uploadFetcher = property.nonretainedObjectValue; + + GTMSESSION_ASSERT_DEBUG([uploadFetcher isKindOfClass:[GTMSessionUploadFetcher class]], + @"Unexpected parent upload fetcher class: %@", [uploadFetcher class]); + return uploadFetcher; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m new file mode 100644 index 0000000..11d849e --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m @@ -0,0 +1,95 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h" + +#import + +@implementation GDTCCTCompressionHelper + ++ (nullable NSData *)gzippedData:(NSData *)data { +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (data.length > UINT_MAX) { + return nil; + } +#endif + + enum { kChunkSize = 1024 }; + + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + + int level = Z_DEFAULT_COMPRESSION; + if (!bytes || !length) { + return nil; + } + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + int memLevel = 8; // Default. + int windowBits = 15 + 16; // Enable gzip header instead of zlib header. + + int retCode; + if (deflateInit2(&strm, level, Z_DEFLATED, windowBits, memLevel, Z_DEFAULT_STRATEGY) != Z_OK) { + return nil; + } + + // Hint the size at 1/4 the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length / 4)]; + unsigned char output[kChunkSize]; + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + // Collect the data. + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = deflate(&strm, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + deflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // If the loop exits, it used all input and the stream ended. + NSAssert(strm.avail_in == 0, + @"Should have finished deflating without using all input, %u bytes left", strm.avail_in); + NSAssert(retCode == Z_STREAM_END, + @"thought we finished deflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + deflateEnd(&strm); + + return result; +} + ++ (BOOL)isGzipped:(NSData *)data { + const UInt8 *bytes = (const UInt8 *)data.bytes; + return (data.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b); +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m new file mode 100644 index 0000000..ece3bae --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m @@ -0,0 +1,270 @@ +/* + * 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 "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h" + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#elif TARGET_OS_OSX +#import +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import +#import +#import + +#import "GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h" + +#pragma mark - General purpose encoders + +pb_bytes_array_t *GDTCCTEncodeString(NSString *string) { + NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding]; + return GDTCCTEncodeData(stringBytes); +} + +pb_bytes_array_t *GDTCCTEncodeData(NSData *data) { + pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + if (pbBytesArray != NULL) { + [data getBytes:pbBytesArray->bytes length:data.length]; + pbBytesArray->size = (pb_size_t)data.length; + } + return pbBytesArray; +} + +#pragma mark - CCT object constructors + +NSData *_Nullable GDTCCTEncodeBatchedLogRequest(gdt_cct_BatchedLogRequest *batchedLogRequest) { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + // Encode 1 time to determine the size. + if (!pb_encode(&sizestream, gdt_cct_BatchedLogRequest_fields, batchedLogRequest)) { + GDTCORLogError(GDTCORMCEGeneralError, @"Error in nanopb encoding for size: %s", + PB_GET_ERROR(&sizestream)); + } + + // Encode a 2nd time to actually get the bytes from it. + size_t bufferSize = sizestream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + CFDataSetLength(dataRef, bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, gdt_cct_BatchedLogRequest_fields, batchedLogRequest)) { + GDTCORLogError(GDTCORMCEGeneralError, @"Error in nanopb encoding for bytes: %s", + PB_GET_ERROR(&ostream)); + } + + return CFBridgingRelease(dataRef); +} + +gdt_cct_BatchedLogRequest GDTCCTConstructBatchedLogRequest( + NSDictionary *> *logMappingIDToLogSet) { + gdt_cct_BatchedLogRequest batchedLogRequest = gdt_cct_BatchedLogRequest_init_default; + NSUInteger numberOfLogRequests = logMappingIDToLogSet.count; + gdt_cct_LogRequest *logRequests = calloc(numberOfLogRequests, sizeof(gdt_cct_LogRequest)); + if (logRequests == NULL) { + return batchedLogRequest; + } + + __block int i = 0; + [logMappingIDToLogSet enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull logMappingID, + NSSet *_Nonnull logSet, + BOOL *_Nonnull stop) { + int32_t logSource = [logMappingID intValue]; + gdt_cct_LogRequest logRequest = GDTCCTConstructLogRequest(logSource, logSet); + logRequests[i] = logRequest; + i++; + }]; + + batchedLogRequest.log_request = logRequests; + batchedLogRequest.log_request_count = (pb_size_t)numberOfLogRequests; + return batchedLogRequest; +} + +gdt_cct_LogRequest GDTCCTConstructLogRequest(int32_t logSource, + NSSet *_Nonnull logSet) { + if (logSet.count == 0) { + GDTCORLogError(GDTCORMCEGeneralError, @"%@", + @"An empty event set can't be serialized to proto."); + gdt_cct_LogRequest logRequest = gdt_cct_LogRequest_init_default; + return logRequest; + } + gdt_cct_LogRequest logRequest = gdt_cct_LogRequest_init_default; + logRequest.log_source = logSource; + logRequest.has_log_source = 1; + logRequest.client_info = GDTCCTConstructClientInfo(); + logRequest.has_client_info = 1; + logRequest.log_event = calloc(logSet.count, sizeof(gdt_cct_LogEvent)); + if (logRequest.log_event == NULL) { + return logRequest; + } + int i = 0; + for (GDTCOREvent *log in logSet) { + gdt_cct_LogEvent logEvent = GDTCCTConstructLogEvent(log); + logRequest.log_event[i] = logEvent; + i++; + } + logRequest.log_event_count = (pb_size_t)logSet.count; + + GDTCORClock *currentTime = [GDTCORClock snapshot]; + logRequest.request_time_ms = currentTime.timeMillis; + logRequest.has_request_time_ms = 1; + logRequest.request_uptime_ms = [currentTime uptimeMilliseconds]; + logRequest.has_request_uptime_ms = 1; + + return logRequest; +} + +gdt_cct_LogEvent GDTCCTConstructLogEvent(GDTCOREvent *event) { + gdt_cct_LogEvent logEvent = gdt_cct_LogEvent_init_default; + logEvent.event_time_ms = event.clockSnapshot.timeMillis; + logEvent.has_event_time_ms = 1; + logEvent.event_uptime_ms = [event.clockSnapshot uptimeMilliseconds]; + logEvent.has_event_uptime_ms = 1; + logEvent.timezone_offset_seconds = event.clockSnapshot.timezoneOffsetSeconds; + logEvent.has_timezone_offset_seconds = 1; + if (event.customBytes) { + NSData *networkConnectionInfoData = event.networkConnectionInfoData; + if (networkConnectionInfoData) { + [networkConnectionInfoData getBytes:&logEvent.network_connection_info + length:networkConnectionInfoData.length]; + logEvent.has_network_connection_info = 1; + } + NSNumber *eventCode = event.eventCode; + if (eventCode != nil) { + logEvent.has_event_code = 1; + logEvent.event_code = [eventCode intValue]; + } + } + NSError *error; + NSData *extensionBytes; + extensionBytes = event.serializedDataObjectBytes; + if (error) { + GDTCORLogWarning(GDTCORMCWFileReadError, + @"There was an error reading extension bytes from disk: %@", error); + return logEvent; + } + logEvent.source_extension = GDTCCTEncodeData(extensionBytes); // read bytes from the file. + return logEvent; +} + +gdt_cct_ClientInfo GDTCCTConstructClientInfo() { + gdt_cct_ClientInfo clientInfo = gdt_cct_ClientInfo_init_default; + clientInfo.client_type = gdt_cct_ClientInfo_ClientType_IOS_FIREBASE; + clientInfo.has_client_type = 1; +#if TARGET_OS_IOS || TARGET_OS_TV + clientInfo.ios_client_info = GDTCCTConstructiOSClientInfo(); + clientInfo.has_ios_client_info = 1; +#elif TARGET_OS_OSX + // TODO(mikehaney24): Expand the proto to include macOS client info. +#endif + return clientInfo; +} + +gdt_cct_IosClientInfo GDTCCTConstructiOSClientInfo() { + gdt_cct_IosClientInfo iOSClientInfo = gdt_cct_IosClientInfo_init_default; +#if TARGET_OS_IOS || TARGET_OS_TV + UIDevice *device = [UIDevice currentDevice]; + NSBundle *bundle = [NSBundle mainBundle]; + NSLocale *locale = [NSLocale currentLocale]; + iOSClientInfo.os_full_version = GDTCCTEncodeString(device.systemVersion); + NSArray *versionComponents = [device.systemVersion componentsSeparatedByString:@"."]; + iOSClientInfo.os_major_version = GDTCCTEncodeString(versionComponents[0]); + NSString *version = [bundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; + if (version) { + iOSClientInfo.application_build = GDTCCTEncodeString(version); + } + NSString *countryCode = [locale objectForKey:NSLocaleCountryCode]; + if (countryCode) { + iOSClientInfo.country = GDTCCTEncodeString([locale objectForKey:NSLocaleCountryCode]); + } + iOSClientInfo.model = GDTCCTEncodeString(GDTCORDeviceModel()); + NSString *languageCode = bundle.preferredLocalizations.firstObject; + iOSClientInfo.language_code = + languageCode ? GDTCCTEncodeString(languageCode) : GDTCCTEncodeString(@"en"); + iOSClientInfo.application_bundle_id = GDTCCTEncodeString(bundle.bundleIdentifier); +#endif + return iOSClientInfo; +} + +NSData *GDTCCTConstructNetworkConnectionInfoData() { + gdt_cct_NetworkConnectionInfo networkConnectionInfo = gdt_cct_NetworkConnectionInfo_init_default; + NSInteger currentNetworkType = GDTCORNetworkTypeMessage(); + if (currentNetworkType) { + networkConnectionInfo.has_network_type = 1; + if (currentNetworkType == GDTCORNetworkTypeMobile) { + networkConnectionInfo.network_type = gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE; + networkConnectionInfo.mobile_subtype = GDTCCTNetworkConnectionInfoNetworkMobileSubtype(); + if (networkConnectionInfo.mobile_subtype != + gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE) { + networkConnectionInfo.has_mobile_subtype = 1; + } + } else { + networkConnectionInfo.network_type = gdt_cct_NetworkConnectionInfo_NetworkType_WIFI; + } + } + NSData *networkConnectionInfoData = [NSData dataWithBytes:&networkConnectionInfo + length:sizeof(networkConnectionInfo)]; + return networkConnectionInfoData; +} + +gdt_cct_NetworkConnectionInfo_MobileSubtype GDTCCTNetworkConnectionInfoNetworkMobileSubtype() { + NSNumber *networkMobileSubtypeMessage = @(GDTCORNetworkMobileSubTypeMessage()); + if (!networkMobileSubtypeMessage.intValue) { + return gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE; + } + static NSDictionary *MessageToNetworkSubTypeMessage; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + MessageToNetworkSubTypeMessage = @{ + @(GDTCORNetworkMobileSubtypeGPRS) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_GPRS), + @(GDTCORNetworkMobileSubtypeEdge) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EDGE), + @(GDTCORNetworkMobileSubtypeWCDMA) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE), + @(GDTCORNetworkMobileSubtypeHSDPA) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_HSDPA), + @(GDTCORNetworkMobileSubtypeHSUPA) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_HSUPA), + @(GDTCORNetworkMobileSubtypeCDMA1x) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_CDMA), + @(GDTCORNetworkMobileSubtypeCDMAEVDORev0) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_0), + @(GDTCORNetworkMobileSubtypeCDMAEVDORevA) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_A), + @(GDTCORNetworkMobileSubtypeCDMAEVDORevB) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_B), + @(GDTCORNetworkMobileSubtypeHRPD) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EHRPD), + @(GDTCORNetworkMobileSubtypeLTE) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE), + }; + }); + NSNumber *networkMobileSubtype = MessageToNetworkSubTypeMessage[networkMobileSubtypeMessage]; + return networkMobileSubtype.intValue; +} + +#pragma mark - CCT Object decoders + +gdt_cct_LogResponse GDTCCTDecodeLogResponse(NSData *data, NSError **error) { + gdt_cct_LogResponse response = gdt_cct_LogResponse_init_default; + pb_istream_t istream = pb_istream_from_buffer([data bytes], [data length]); + if (!pb_decode(&istream, gdt_cct_LogResponse_fields, &response)) { + NSString *nanopb_error = [NSString stringWithFormat:@"%s", PB_GET_ERROR(&istream)]; + NSDictionary *userInfo = @{@"nanopb error:" : nanopb_error}; + if (error != NULL) { + *error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:userInfo]; + } + response = (gdt_cct_LogResponse)gdt_cct_LogResponse_init_default; + } + return response; +} diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m new file mode 100644 index 0000000..f3887df --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m @@ -0,0 +1,573 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import +#import +#import + +#import +#import +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h" +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h" + +NS_ASSUME_NONNULL_BEGIN + +#ifdef GDTCOR_VERSION +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x +static NSString *const kGDTCCTSupportSDKVersion = @STR(GDTCOR_VERSION); +#else +static NSString *const kGDTCCTSupportSDKVersion = @"UNKNOWN"; +#endif // GDTCOR_VERSION + +typedef void (^GDTCCTUploaderURLTaskCompletion)(NSNumber *batchID, + NSSet *_Nullable events, + NSData *_Nullable data, + NSURLResponse *_Nullable response, + NSError *_Nullable error); + +typedef void (^GDTCCTUploaderEventBatchBlock)(NSNumber *_Nullable batchID, + NSSet *_Nullable events); + +@interface GDTCCTUploadOperation () + +/// The properties to store parameters passed in the initializer. See the initialized docs for +/// details. +@property(nonatomic, readonly) GDTCORTarget target; +@property(nonatomic, readonly) GDTCORUploadConditions conditions; +@property(nonatomic, readonly) NSURL *uploadURL; +@property(nonatomic, readonly) id storage; +@property(nonatomic, readonly) id metadataProvider; + +/** The URL session that will attempt upload. */ +@property(nonatomic) NSURLSession *uploaderSession; + +/// NSOperation state properties implementation. +@property(nonatomic, readwrite, getter=isExecuting) BOOL executing; +@property(nonatomic, readwrite, getter=isFinished) BOOL finished; + +@property(nonatomic, readwrite) BOOL uploadAttempted; + +@end + +@implementation GDTCCTUploadOperation + +- (instancetype)initWithTarget:(GDTCORTarget)target + conditions:(GDTCORUploadConditions)conditions + uploadURL:(NSURL *)uploadURL + queue:(dispatch_queue_t)queue + storage:(id)storage + metadataProvider:(id)metadataProvider { + self = [super init]; + if (self) { + _uploaderQueue = queue; + _target = target; + _conditions = conditions; + _uploadURL = uploadURL; + _storage = storage; + _metadataProvider = metadataProvider; + } + return self; +} + +- (NSURLSession *)uploaderSessionCreateIfNeeded { + if (_uploaderSession == nil) { + NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; + _uploaderSession = [NSURLSession sessionWithConfiguration:config + delegate:self + delegateQueue:nil]; + } + return _uploaderSession; +} + +- (void)uploadTarget:(GDTCORTarget)target withConditions:(GDTCORUploadConditions)conditions { + __block GDTCORBackgroundIdentifier backgroundTaskID = GDTCORBackgroundIdentifierInvalid; + + dispatch_block_t backgroundTaskCompletion = ^{ + // End the background task if there was one. + if (backgroundTaskID != GDTCORBackgroundIdentifierInvalid) { + [[GDTCORApplication sharedApplication] endBackgroundTask:backgroundTaskID]; + backgroundTaskID = GDTCORBackgroundIdentifierInvalid; + } + }; + + backgroundTaskID = [[GDTCORApplication sharedApplication] + beginBackgroundTaskWithName:@"GDTCCTUploader-upload" + expirationHandler:^{ + if (backgroundTaskID != GDTCORBackgroundIdentifierInvalid) { + // Cancel the upload and complete delivery. + [self.currentTask cancel]; + + // End the background task. + backgroundTaskCompletion(); + } + }]; + + id storage = self.storage; + + // 1. Check if the conditions for the target are suitable. + [self isReadyToUploadTarget:target conditions:conditions] + .thenOn(self.uploaderQueue, + ^id(id result) { + // 2. Remove previously attempted batches + return [storage removeAllBatchesForTarget:target deleteEvents:NO]; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(id result) { + // There may be a big amount of events stored, so creating a batch may be an + // expensive operation. + + // 3. Do a lightweight check if there are any events for the target first to + // finish early if there are no. + return [storage hasEventsForTarget:target]; + }) + .validateOn(self.uploaderQueue, + ^BOOL(NSNumber *hasEvents) { + // Stop operation if there are no events to upload. + return hasEvents.boolValue; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(id result) { + if (self.isCancelled) { + return nil; + } + + // 4. Fetch events to upload. + GDTCORStorageEventSelector *eventSelector = [self eventSelectorTarget:target + withConditions:conditions]; + return [storage batchWithEventSelector:eventSelector + batchExpiration:[NSDate dateWithTimeIntervalSinceNow:600]]; + }) + .validateOn(self.uploaderQueue, + ^BOOL(GDTCORUploadBatch *batch) { + // 5. Validate batch. + return batch.batchID != nil && batch.events.count > 0; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(GDTCORUploadBatch *batch) { + // A non-empty batch has been created, consider it as an upload attempt. + self.uploadAttempted = YES; + + // 6. Perform upload URL request. + return [self sendURLRequestWithBatch:batch target:target storage:storage]; + }) + .thenOn(self.uploaderQueue, + ^id(id result) { + // 7. Finish operation. + [self finishOperation]; + backgroundTaskCompletion(); + return nil; + }) + .catchOn(self.uploaderQueue, ^(NSError *error) { + // TODO: Maybe report the error to the client. + [self finishOperation]; + backgroundTaskCompletion(); + }); +} + +#pragma mark - Upload implementation details + +/** Sends URL request to upload the provided batch and handle the response. */ +- (FBLPromise *)sendURLRequestWithBatch:(GDTCORUploadBatch *)batch + target:(GDTCORTarget)target + storage:(id)storage { + NSNumber *batchID = batch.batchID; + + // 1. Send URL request. + return [self sendURLRequestWithBatch:batch target:target] + .thenOn( + self.uploaderQueue, + ^FBLPromise *(GULURLSessionDataResponse *response) { + // 2. Parse response and update the next upload time if can. + [self updateNextUploadTimeWithResponse:response forTarget:target]; + + // 3. Cleanup batch. + + // Only retry if one of these codes is returned: + // 429 - Too many requests; + // 5xx - Server errors. + NSInteger statusCode = response.HTTPResponse.statusCode; + if (statusCode == 429 || (statusCode >= 500 && statusCode < 600)) { + // Move the events back to the main storage to be uploaded on the next attempt. + return [storage removeBatchWithID:batchID deleteEvents:NO]; + } else { + if (statusCode >= 200 && statusCode <= 300) { + GDTCORLogDebug(@"CCT: batch %@ delivered", batchID); + } else { + GDTCORLogDebug( + @"CCT: batch %@ was rejected by the server and will be deleted with all events", + batchID); + } + + // The events are either delivered or unrecoverable broken, so remove the batch with + // events. + return [storage removeBatchWithID:batch.batchID deleteEvents:YES]; + } + }) + .recoverOn(self.uploaderQueue, ^id(NSError *error) { + // In the case of a network error move the events back to the main storage to be uploaded on + // the next attempt. + return [storage removeBatchWithID:batchID deleteEvents:NO]; + }); +} + +/** Composes and sends URL request. */ +- (FBLPromise *)sendURLRequestWithBatch:(GDTCORUploadBatch *)batch + target:(GDTCORTarget)target { + return [FBLPromise + onQueue:self.uploaderQueue + do:^NSURLRequest * { + // 1. Prepare URL request. + NSData *requestProtoData = [self constructRequestProtoWithEvents:batch.events]; + NSData *gzippedData = [GDTCCTCompressionHelper gzippedData:requestProtoData]; + BOOL usingGzipData = + gzippedData != nil && gzippedData.length < requestProtoData.length; + NSData *dataToSend = usingGzipData ? gzippedData : requestProtoData; + NSURLRequest *request = [self constructRequestWithURL:self.uploadURL + forTarget:target + data:dataToSend]; + GDTCORLogDebug(@"CTT: request containing %lu events for batch: %@ for target: " + @"%ld created: %@", + (unsigned long)batch.events.count, batch.batchID, (long)target, + request); + return request; + }] + .thenOn(self.uploaderQueue, + ^FBLPromise *(NSURLRequest *request) { + // 2. Send URL request. + return + [[self uploaderSessionCreateIfNeeded] gul_dataTaskPromiseWithRequest:request]; + }) + .thenOn(self.uploaderQueue, + ^GULURLSessionDataResponse *(GULURLSessionDataResponse *response) { + // Invalidate session to release the delegate (which is `self`) to break the retain + // cycle. + [self.uploaderSession finishTasksAndInvalidate]; + return response; + }) + .recoverOn(self.uploaderQueue, ^id(NSError *error) { + // Invalidate session to release the delegate (which is `self`) to break the retain cycle. + [self.uploaderSession finishTasksAndInvalidate]; + // Re-throw the error. + return error; + }); +} + +/** Parses server response and update next upload time for the specified target based on it. */ +- (void)updateNextUploadTimeWithResponse:(GULURLSessionDataResponse *)response + forTarget:(GDTCORTarget)target { + GDTCORClock *futureUploadTime; + if (response.HTTPBody) { + NSError *decodingError; + gdt_cct_LogResponse logResponse = GDTCCTDecodeLogResponse(response.HTTPBody, &decodingError); + if (!decodingError && logResponse.has_next_request_wait_millis) { + GDTCORLogDebug(@"CCT: The backend responded asking to not upload for %lld millis from now.", + logResponse.next_request_wait_millis); + futureUploadTime = + [GDTCORClock clockSnapshotInTheFuture:logResponse.next_request_wait_millis]; + } else if (decodingError) { + GDTCORLogDebug(@"There was a response decoding error: %@", decodingError); + } + pb_release(gdt_cct_LogResponse_fields, &logResponse); + } + + // If no futureUploadTime was parsed from the response body, then check + // [Retry-After](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header. + if (!futureUploadTime) { + NSString *retryAfterHeader = response.HTTPResponse.allHeaderFields[@"Retry-After"]; + if (retryAfterHeader.length > 0) { + NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + NSNumber *retryAfterSeconds = [formatter numberFromString:retryAfterHeader]; + if (retryAfterSeconds != nil) { + uint64_t retryAfterMillis = retryAfterSeconds.unsignedIntegerValue * 1000u; + futureUploadTime = [GDTCORClock clockSnapshotInTheFuture:retryAfterMillis]; + } + } + } + + if (!futureUploadTime) { + GDTCORLogDebug(@"%@", @"CCT: The backend response failed to parse, so the next request " + @"won't occur until 15 minutes from now"); + // 15 minutes from now. + futureUploadTime = [GDTCORClock clockSnapshotInTheFuture:15 * 60 * 1000]; + } + + [self.metadataProvider setNextUploadTime:futureUploadTime forTarget:target]; +} + +#pragma mark - Private helper methods + +/** @return A resolved promise if is ready and a rejected promise if not. */ +- (FBLPromise *)isReadyToUploadTarget:(GDTCORTarget)target + conditions:(GDTCORUploadConditions)conditions { + FBLPromise *promise = [FBLPromise pendingPromise]; + if ([self readyToUploadTarget:target conditions:conditions]) { + [promise fulfill:[NSNull null]]; + } else { + NSString *reason = + [NSString stringWithFormat:@"Target %ld is not ready to upload with condition: %ld", + (long)target, (long)conditions]; + [promise reject:[self genericRejectedPromiseErrorWithReason:reason]]; + } + return promise; +} + +// TODO: Move to a separate class/extension/file when needed in other files. +/** Returns an error object with the specified failure reason. */ +- (NSError *)genericRejectedPromiseErrorWithReason:(NSString *)reason { + return [NSError errorWithDomain:@"GDTCCTUploader" + code:-1 + userInfo:@{NSLocalizedFailureReasonErrorKey : reason}]; +} + +/** Returns if the specified target is ready to be uploaded based on the specified conditions. */ +- (BOOL)readyToUploadTarget:(GDTCORTarget)target conditions:(GDTCORUploadConditions)conditions { + // Not ready to upload with no network connection. + // TODO: Reconsider using reachability to prevent an upload attempt. + // See https://developer.apple.com/videos/play/wwdc2019/712/ (49:40) for more details. + if (conditions & GDTCORUploadConditionNoNetwork) { + GDTCORLogDebug(@"%@", @"CCT: Not ready to upload without a network connection."); + return NO; + } + + // Upload events with no additional conditions if high priority. + if ((conditions & GDTCORUploadConditionHighPriority) == GDTCORUploadConditionHighPriority) { + GDTCORLogDebug(@"%@", @"CCT: a high priority event is allowing an upload"); + return YES; + } + + // Check next upload time for the target. + BOOL isAfterNextUploadTime = YES; + GDTCORClock *nextUploadTime = [self.metadataProvider nextUploadTimeForTarget:target]; + if (nextUploadTime) { + isAfterNextUploadTime = [[GDTCORClock snapshot] isAfter:nextUploadTime]; + } + + if (isAfterNextUploadTime) { + GDTCORLogDebug(@"CCT: can upload to target %ld because the request wait time has transpired", + (long)target); + } else { + GDTCORLogDebug(@"CCT: can't upload to target %ld because the backend asked to wait", + (long)target); + } + + return isAfterNextUploadTime; +} + +/** Constructs data given an upload package. + * + * @param events The events used to construct the request proto bytes. + * @return Proto bytes representing a gdt_cct_LogRequest object. + */ +- (nonnull NSData *)constructRequestProtoWithEvents:(NSSet *)events { + // Segment the log events by log type. + NSMutableDictionary *> *logMappingIDToLogSet = + [[NSMutableDictionary alloc] init]; + [events enumerateObjectsUsingBlock:^(GDTCOREvent *_Nonnull event, BOOL *_Nonnull stop) { + NSMutableSet *logSet = logMappingIDToLogSet[event.mappingID]; + logSet = logSet ? logSet : [[NSMutableSet alloc] init]; + [logSet addObject:event]; + logMappingIDToLogSet[event.mappingID] = logSet; + }]; + + gdt_cct_BatchedLogRequest batchedLogRequest = + GDTCCTConstructBatchedLogRequest(logMappingIDToLogSet); + + NSData *data = GDTCCTEncodeBatchedLogRequest(&batchedLogRequest); + pb_release(gdt_cct_BatchedLogRequest_fields, &batchedLogRequest); + return data ? data : [[NSData alloc] init]; +} + +/** Constructs a request to the given URL and target with the specified request body data. + * + * @param target The target backend to send the request to. + * @param data The request body data. + * @return A new NSURLRequest ready to be sent to FLL. + */ +- (nullable NSURLRequest *)constructRequestWithURL:(NSURL *)URL + forTarget:(GDTCORTarget)target + data:(NSData *)data { + if (data == nil || data.length == 0) { + GDTCORLogDebug(@"There was no data to construct a request for target %ld.", (long)target); + return nil; + } + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + NSString *targetString; + switch (target) { + case kGDTCORTargetCCT: + targetString = @"cct"; + break; + + case kGDTCORTargetFLL: + targetString = @"fll"; + break; + + case kGDTCORTargetCSH: + targetString = @"csh"; + break; + case kGDTCORTargetINT: + targetString = @"int"; + break; + + default: + targetString = @"unknown"; + break; + } + NSString *userAgent = + [NSString stringWithFormat:@"datatransport/%@ %@support/%@ apple/", kGDTCORVersion, + targetString, kGDTCCTSupportSDKVersion]; + + [request setValue:[self.metadataProvider APIKeyForTarget:target] + forHTTPHeaderField:@"X-Goog-Api-Key"]; + + if ([GDTCCTCompressionHelper isGzipped:data]) { + [request setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"]; + } + [request setValue:@"application/x-protobuf" forHTTPHeaderField:@"Content-Type"]; + [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; + [request setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + request.HTTPMethod = @"POST"; + [request setHTTPBody:data]; + return request; +} + +/** Creates and returns a storage event selector for the specified target and conditions. */ +- (GDTCORStorageEventSelector *)eventSelectorTarget:(GDTCORTarget)target + withConditions:(GDTCORUploadConditions)conditions { + if ((conditions & GDTCORUploadConditionHighPriority) == GDTCORUploadConditionHighPriority) { + return [GDTCORStorageEventSelector eventSelectorForTarget:target]; + } + NSMutableSet *qosTiers = [[NSMutableSet alloc] init]; + if (conditions & GDTCORUploadConditionWifiData) { + [qosTiers addObjectsFromArray:@[ + @(GDTCOREventQoSFast), @(GDTCOREventQoSWifiOnly), @(GDTCOREventQosDefault), + @(GDTCOREventQoSTelemetry), @(GDTCOREventQoSUnknown) + ]]; + } + if (conditions & GDTCORUploadConditionMobileData) { + [qosTiers addObjectsFromArray:@[ @(GDTCOREventQoSFast), @(GDTCOREventQosDefault) ]]; + } + + return [[GDTCORStorageEventSelector alloc] initWithTarget:target + eventIDs:nil + mappingIDs:nil + qosTiers:qosTiers]; +} + +#pragma mark - NSURLSessionDelegate + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *_Nullable))completionHandler { + if (!completionHandler) { + return; + } + if (response.statusCode == 302 || response.statusCode == 301) { + NSURLRequest *newRequest = [self constructRequestWithURL:request.URL + forTarget:kGDTCORTargetCCT + data:task.originalRequest.HTTPBody]; + completionHandler(newRequest); + } else { + completionHandler(request); + } +} + +#pragma mark - NSOperation methods + +@synthesize executing = _executing; +@synthesize finished = _finished; + +- (BOOL)isFinished { + @synchronized(self) { + return _finished; + } +} + +- (BOOL)isExecuting { + @synchronized(self) { + return _executing; + } +} + +- (BOOL)isAsynchronous { + return YES; +} + +- (void)startOperation { + @synchronized(self) { + [self willChangeValueForKey:@"isExecuting"]; + [self willChangeValueForKey:@"isFinished"]; + self->_executing = YES; + self->_finished = NO; + [self didChangeValueForKey:@"isExecuting"]; + [self didChangeValueForKey:@"isFinished"]; + } +} + +- (void)finishOperation { + @synchronized(self) { + [self willChangeValueForKey:@"isExecuting"]; + [self willChangeValueForKey:@"isFinished"]; + self->_executing = NO; + self->_finished = YES; + [self didChangeValueForKey:@"isExecuting"]; + [self didChangeValueForKey:@"isFinished"]; + } +} + +- (void)start { + [self startOperation]; + + GDTCORLogDebug(@"Upload operation started: %@", self); + [self uploadTarget:self.target withConditions:self.conditions]; +} + +- (void)cancel { + @synchronized(self) { + [super cancel]; + + // If the operation hasn't been started we can set `isFinished = YES` straight away. + if (!_executing) { + _executing = NO; + _finished = YES; + } + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m new file mode 100644 index 0000000..d25dc54 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m @@ -0,0 +1,210 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCCTUploader () + +@property(nonatomic, readonly) NSOperationQueue *uploadOperationQueue; +@property(nonatomic, readonly) dispatch_queue_t uploadQueue; + +@property(nonatomic, readonly) + NSMutableDictionary *nextUploadTimeByTarget; + +@end + +@implementation GDTCCTUploader + +static NSURL *_testServerURL = nil; + ++ (void)load { + GDTCCTUploader *uploader = [GDTCCTUploader sharedInstance]; + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetCCT]; + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetFLL]; + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetCSH]; + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetINT]; +} + ++ (instancetype)sharedInstance { + static GDTCCTUploader *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCCTUploader alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _uploadQueue = dispatch_queue_create("com.google.GDTCCTUploader", DISPATCH_QUEUE_SERIAL); + _uploadOperationQueue = [[NSOperationQueue alloc] init]; + _uploadOperationQueue.maxConcurrentOperationCount = 1; + _nextUploadTimeByTarget = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)uploadTarget:(GDTCORTarget)target withConditions:(GDTCORUploadConditions)conditions { + // Current GDTCCTUploader expected behaviour: + // 1. Accept multiple upload request + // 2. Verify if there are events eligible for upload and start upload for the first suitable + // target + // 3. Ignore other requests while an upload is in-progress. + + // TODO: Revisit expected behaviour. + // Potentially better option: + // 1. Accept and enqueue all upload requests + // 2. Notify the client of upload stages + // 3. Allow the client cancelling upload requests as needed. + + id storage = GDTCORStoragePromiseInstanceForTarget(target); + if (storage == nil) { + GDTCORLogError(GDTCORMCEGeneralError, + @"Failed to upload target: %ld - could not find corresponding storage instance.", + (long)target); + return; + } + + GDTCCTUploadOperation *uploadOperation = + [[GDTCCTUploadOperation alloc] initWithTarget:target + conditions:conditions + uploadURL:[[self class] serverURLForTarget:target] + queue:self.uploadQueue + storage:storage + metadataProvider:self]; + + GDTCORLogDebug(@"Upload operation created: %@, target: %@", uploadOperation, @(target)); + + __weak __auto_type weakSelf = self; + __weak GDTCCTUploadOperation *weakOperation = uploadOperation; + uploadOperation.completionBlock = ^{ + __auto_type strongSelf = weakSelf; + GDTCCTUploadOperation *strongOperation = weakOperation; + if (strongSelf == nil || strongOperation == nil) { + GDTCORLogDebug(@"Internal inconsistency: GDTCCTUploader was deallocated during upload.", nil); + return; + } + + GDTCORLogDebug(@"Upload operation finished: %@, uploadAttempted: %@", strongOperation, + @(strongOperation.uploadAttempted)); + + if (strongOperation.uploadAttempted) { + // Ignore all upload requests received when the upload was in progress. + [strongSelf.uploadOperationQueue cancelAllOperations]; + } + }; + + [self.uploadOperationQueue addOperation:uploadOperation]; + GDTCORLogDebug(@"Upload operation scheduled: %@, operation count: %@", uploadOperation, + @(self.uploadOperationQueue.operationCount)); +} + +#pragma mark - URLs + ++ (void)setTestServerURL:(NSURL *_Nullable)serverURL { + _testServerURL = serverURL; +} + ++ (NSURL *_Nullable)testServerURL { + return _testServerURL; +} + ++ (nullable NSURL *)serverURLForTarget:(GDTCORTarget)target { +#if !NDEBUG + if (_testServerURL) { + return _testServerURL; + } +#endif // !NDEBUG + + return [GDTCOREndpoints uploadURLForTarget:target]; +} + +- (NSString *)FLLAndCSHAndINTAPIKey { + static NSString *defaultServerKey; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // These strings should be interleaved to construct the real key. + const char *p1 = "AzSBG0honD6A-PxV5nBc"; + const char *p2 = "Iay44Iwtu2vV0AOrz1C"; + const char defaultKey[40] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], + p1[4], p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], + p1[8], p2[8], p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], + p1[12], p2[12], p1[13], p2[13], p1[14], p2[14], p1[15], p2[15], + p1[16], p2[16], p1[17], p2[17], p1[18], p2[18], p1[19], '\0'}; + defaultServerKey = [NSString stringWithUTF8String:defaultKey]; + }); + return defaultServerKey; +} + +#pragma mark - GDTCCTUploadMetadataProvider + +- (nullable GDTCORClock *)nextUploadTimeForTarget:(GDTCORTarget)target { + @synchronized(self.nextUploadTimeByTarget) { + return self.nextUploadTimeByTarget[@(target)]; + } +} + +- (void)setNextUploadTime:(nullable GDTCORClock *)time forTarget:(GDTCORTarget)target { + @synchronized(self.nextUploadTimeByTarget) { + self.nextUploadTimeByTarget[@(target)] = time; + } +} + +- (nullable NSString *)APIKeyForTarget:(GDTCORTarget)target { + if (target == kGDTCORTargetFLL || target == kGDTCORTargetCSH) { + return [self FLLAndCSHAndINTAPIKey]; + } + + if (target == kGDTCORTargetINT) { + return [self FLLAndCSHAndINTAPIKey]; + } + + return nil; +} + +#if !NDEBUG + +- (BOOL)waitForUploadFinishedWithTimeout:(NSTimeInterval)timeout { + NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:timeout]; + while ([expirationDate compare:[NSDate date]] == NSOrderedDescending) { + if (self.uploadOperationQueue.operationCount == 0) { + return YES; + } else { + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + } + } + + GDTCORLogDebug(@"Uploader wait for finish timeout exceeded. Operations still in queue: %@", + self.uploadOperationQueue.operations); + return NO; +} + +#endif // !NDEBUG + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m new file mode 100644 index 0000000..1c77b4c --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m @@ -0,0 +1,240 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +NSString *const GDTCCTNeedsNetworkConnectionInfo = @"needs_network_connection_info"; + +NSString *const GDTCCTNetworkConnectionInfo = @"network_connection_info"; + +NSString *const GDTCCTEventCodeInfo = @"event_code_info"; + +@implementation GDTCOREvent (GDTCCTSupport) + +- (void)setNeedsNetworkConnectionInfoPopulated:(BOOL)needsNetworkConnectionInfoPopulated { + if (!needsNetworkConnectionInfoPopulated) { + if (!self.customBytes) { + return; + } + + // Make sure we don't destroy the eventCode data, if any is present. + @try { + NSError *error; + NSMutableDictionary *bytesDict = + [[NSJSONSerialization JSONObjectWithData:self.customBytes options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + NSNumber *eventCode = bytesDict[GDTCCTEventCodeInfo]; + if (eventCode != nil) { + self.customBytes = + [NSJSONSerialization dataWithJSONObject:@{GDTCCTEventCodeInfo : eventCode} + options:0 + error:&error]; + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when setting the event for needs_network_connection_info: %@", + exception); + } + } else { + @try { + NSError *error; + NSMutableDictionary *bytesDict; + if (self.customBytes) { + bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an even'ts event_code: %@", error); + return; + } + } else { + bytesDict = [[NSMutableDictionary alloc] init]; + } + [bytesDict setObject:@YES forKey:GDTCCTNeedsNetworkConnectionInfo]; + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when setting the event for needs_network_connection_info: %@", + exception); + } + } +} + +- (BOOL)needsNetworkConnectionInfoPopulated { + if (self.customBytes) { + @try { + NSError *error; + NSDictionary *bytesDict = [NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error]; + return bytesDict && !error && [bytesDict[GDTCCTNeedsNetworkConnectionInfo] boolValue]; + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when checking the event for needs_network_connection_info: %@", + exception); + } + } + return NO; +} + +- (void)setNetworkConnectionInfoData:(NSData *)networkConnectionInfoData { + @try { + NSError *error; + NSString *dataString = [networkConnectionInfoData base64EncodedStringWithOptions:0]; + if (dataString != nil) { + NSMutableDictionary *bytesDict; + if (self.customBytes) { + bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an even'ts event_code: %@", error); + return; + } + } else { + bytesDict = [[NSMutableDictionary alloc] init]; + } + [bytesDict setObject:dataString forKey:GDTCCTNetworkConnectionInfo]; + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + if (error) { + self.customBytes = nil; + GDTCORLogDebug(@"Error when setting an event's network_connection_info: %@", error); + } + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when setting an event's network_connection_info: %@", exception); + } +} + +- (nullable NSData *)networkConnectionInfoData { + if (self.customBytes) { + @try { + NSError *error; + NSDictionary *bytesDict = [NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error]; + NSString *base64Data = bytesDict[GDTCCTNetworkConnectionInfo]; + if (base64Data == nil) { + return nil; + } + + NSData *networkConnectionInfoData = [[NSData alloc] initWithBase64EncodedString:base64Data + options:0]; + if (error) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", error); + return nil; + } else { + return networkConnectionInfoData; + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", exception); + } + } + return nil; +} + +- (NSNumber *)eventCode { + if (self.customBytes) { + @try { + NSError *error; + NSDictionary *bytesDict = [NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error]; + NSString *eventCodeString = bytesDict[GDTCCTEventCodeInfo]; + + if (!eventCodeString) { + return nil; + } + + NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + NSNumber *eventCode = [formatter numberFromString:eventCodeString]; + + if (error) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", error); + return nil; + } else { + return eventCode; + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when getting an event's event_code: %@", exception); + } + } + return nil; +} + +- (void)setEventCode:(NSNumber *)eventCode { + if (eventCode == nil) { + if (!self.customBytes) { + return; + } + + NSError *error; + NSMutableDictionary *bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + + [bytesDict removeObjectForKey:GDTCCTEventCodeInfo]; + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + if (error) { + self.customBytes = nil; + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + return; + } + + @try { + NSMutableDictionary *bytesDict; + NSError *error; + if (self.customBytes) { + bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + } else { + bytesDict = [[NSMutableDictionary alloc] init]; + } + + NSString *eventCodeString = [eventCode stringValue]; + if (eventCodeString == nil) { + return; + } + + [bytesDict setObject:eventCodeString forKey:GDTCCTEventCodeInfo]; + + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + if (error) { + self.customBytes = nil; + GDTCORLogDebug(@"Error when setting an event's network_connection_info: %@", error); + return; + } + + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", exception); + } +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h new file mode 100644 index 0000000..b53dd5f --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** A class with methods to help with gzipped data. */ +@interface GDTCCTCompressionHelper : NSObject + +/** Compresses the given data and returns a new data object. + * + * @note Reduced version from GULNSData+zlib.m of GoogleUtilities. + * @return Compressed data, or nil if there was an error. + */ ++ (nullable NSData *)gzippedData:(NSData *)data; + +/** Returns YES if the data looks like it was gzip compressed by checking for the gzip magic number. + * + * @note: From https://en.wikipedia.org/wiki/Gzip, gzip's magic number is 1f 8b. + * @return YES if the data appears gzipped, NO otherwise. + */ ++ (BOOL)isGzipped:(NSData *)data; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h new file mode 100644 index 0000000..8372cf9 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h @@ -0,0 +1,128 @@ +/* + * 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 + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h" + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - General purpose encoders + +/** Converts an NSString* to a pb_bytes_array_t*. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * + * @param string The string to convert. + * @return A newly allocated array of bytes representing the UTF8 encoding of the string. + */ +pb_bytes_array_t *GDTCCTEncodeString(NSString *string); + +/** Converts an NSData to a pb_bytes_array_t*. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * + * @param data The data to convert. + * @return A newly allocated array of bytes with [data bytes] copied into it. + */ +pb_bytes_array_t *GDTCCTEncodeData(NSData *data); + +#pragma mark - CCT object constructors + +/** Encodes a batched log request. + * + * @note Ensure that pb_release is called on the batchedLogRequest param. + * + * @param batchedLogRequest A pointer to the log batch to encode to bytes. + * @return An NSData object representing the bytes of the log request batch. + */ +FOUNDATION_EXPORT +NSData *GDTCCTEncodeBatchedLogRequest(gdt_cct_BatchedLogRequest *batchedLogRequest); + +/** Constructs a gdt_cct_BatchedLogRequest given sets of events segemented by mapping ID. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * + * @param logMappingIDToLogSet A map of mapping IDs to sets of events to convert into a batch. + * @return A newly created gdt_cct_BatchedLogRequest. + */ +FOUNDATION_EXPORT +gdt_cct_BatchedLogRequest GDTCCTConstructBatchedLogRequest( + NSDictionary *> *logMappingIDToLogSet); + +/** Constructs a log request given a log source and a set of events. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * @param logSource The CCT log source to put into the log request. + * @param logSet The set of events to send in this log request. + */ +FOUNDATION_EXPORT +gdt_cct_LogRequest GDTCCTConstructLogRequest(int32_t logSource, NSSet *logSet); + +/** Constructs a gdt_cct_LogEvent given a GDTCOREvent*. + * + * @param event The GDTCOREvent to convert. + * @return The new gdt_cct_LogEvent object. + */ +FOUNDATION_EXPORT +gdt_cct_LogEvent GDTCCTConstructLogEvent(GDTCOREvent *event); + +/** Constructs a gdt_cct_ClientInfo representing the client device. + * + * @return The new gdt_cct_ClientInfo object. + */ +FOUNDATION_EXPORT +gdt_cct_ClientInfo GDTCCTConstructClientInfo(void); + +/** Constructs a gdt_cct_IosClientInfo representing the client device. + * + * @return The new gdt_cct_IosClientInfo object. + */ +FOUNDATION_EXPORT +gdt_cct_IosClientInfo GDTCCTConstructiOSClientInfo(void); + +/** Constructs the data of a gdt_cct_NetworkConnectionInfo representing the client nework connection + * information. + * + * @return The data of a gdt_cct_NetworkConnectionInfo object. + */ +FOUNDATION_EXPORT +NSData *GDTCCTConstructNetworkConnectionInfoData(void); + +/** Return a gdt_cct_NetworkConnectionInfo_MobileSubtype representing the client + * + * @return The gdt_cct_NetworkConnectionInfo_MobileSubtype. + */ +FOUNDATION_EXPORT +gdt_cct_NetworkConnectionInfo_MobileSubtype GDTCCTNetworkConnectionInfoNetworkMobileSubtype(void); + +#pragma mark - CCT object decoders + +/** Decodes a gdt_cct_LogResponse given proto bytes. + * + * @note calloc is called in this method. Ensure that pb_release is called on the return value. + * + * @param data The proto bytes of the gdt_cct_LogResponse. + * @param error An error that will be populated if something went wrong during decoding. + * @return A newly allocated gdt_cct_LogResponse from the data, if the bytes decoded properly. + */ +FOUNDATION_EXPORT +gdt_cct_LogResponse GDTCCTDecodeLogResponse(NSData *data, NSError **error); + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h new file mode 100644 index 0000000..3f63644 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h" + +@protocol GDTCORStoragePromiseProtocol; + +NS_ASSUME_NONNULL_BEGIN + +/// The protocol defines methods to retrieve/update data shared between different upload operations. +@protocol GDTCCTUploadMetadataProvider + +/** Returns a GDTCORClock object representing time after which a next upload attempt is allowed for + * the specified target. Upload is allowed now if `nil`. */ +- (nullable GDTCORClock *)nextUploadTimeForTarget:(GDTCORTarget)target; + +/** Stores or resets time after which a next upload attempt is allowed for the specified target. */ +- (void)setNextUploadTime:(nullable GDTCORClock *)time forTarget:(GDTCORTarget)target; + +/** Returns an API key for the specified target. */ +- (nullable NSString *)APIKeyForTarget:(GDTCORTarget)target; + +@end + +/** Class capable of uploading events to the CCT backend. */ +@interface GDTCCTUploadOperation : NSOperation + +- (instancetype)init NS_UNAVAILABLE; + +/** The designated initializer. + * @param target The events target to upload. + * @param conditions A set of upload conditions. The conditions affect the set of events to be + * uploaded, e.g. events with some QoS are not uploaded on a cellular network, etc. + * @param uploadURL The backend URL to upload the events. + * @param queue A queue to dispatch async upload steps. + * @param storage A storage object to fetch events for upload. + * @param metadataProvider An object to retrieve/update data shared between different upload + * operations. + * @return An instance of GDTCCTUploadOperation ready to be added to an NSOperationQueue. + */ +- (instancetype)initWithTarget:(GDTCORTarget)target + conditions:(GDTCORUploadConditions)conditions + uploadURL:(NSURL *)uploadURL + queue:(dispatch_queue_t)queue + storage:(id)storage + metadataProvider:(id)metadataProvider + NS_DESIGNATED_INITIALIZER; + +/** YES if a batch upload attempt was performed. NO otherwise. If NO for the finished operation, + * then there were no events suitable for upload. */ +@property(nonatomic, readonly) BOOL uploadAttempted; + +/** The queue on which all CCT uploading will occur. */ +@property(nonatomic, readonly) dispatch_queue_t uploaderQueue; + +/** The current upload task. */ +@property(nullable, nonatomic, readonly) NSURLSessionUploadTask *currentTask; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h new file mode 100644 index 0000000..876fbe1 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h @@ -0,0 +1,45 @@ +/* + * 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 + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Class capable of uploading events to the CCT backend. */ +@interface GDTCCTUploader : NSObject + +/** Creates and/or returns the singleton instance of this class. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +#if !NDEBUG +/** An upload URL used across all targets. For testing only. */ +@property(class, nullable, nonatomic) NSURL *testServerURL; + +/** Spins runloop until upload finishes or timeout. + * @return YES if upload finishes, NO in the case of timeout. + */ +- (BOOL)waitForUploadFinishedWithTimeout:(NSTimeInterval)timeout; + +#endif // !NDEBUG + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c new file mode 100644 index 0000000..2f5327e --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c @@ -0,0 +1,128 @@ +/* + * 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. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.7 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +const gdt_cct_NetworkConnectionInfo_NetworkType gdt_cct_NetworkConnectionInfo_network_type_default = gdt_cct_NetworkConnectionInfo_NetworkType_NONE; +const gdt_cct_NetworkConnectionInfo_MobileSubtype gdt_cct_NetworkConnectionInfo_mobile_subtype_default = gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE; +const gdt_cct_QosTierConfiguration_QosTier gdt_cct_LogRequest_qos_tier_default = gdt_cct_QosTierConfiguration_QosTier_DEFAULT; +const int32_t gdt_cct_QosTierConfiguration_log_source_default = 0; + + +const pb_field_t gdt_cct_LogEvent_fields[7] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, gdt_cct_LogEvent, event_time_ms, event_time_ms, 0), + PB_FIELD( 6, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_LogEvent, source_extension, event_time_ms, 0), + PB_FIELD( 11, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, event_code, source_extension, 0), + PB_FIELD( 15, SINT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, timezone_offset_seconds, event_code, 0), + PB_FIELD( 17, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, event_uptime_ms, timezone_offset_seconds, 0), + PB_FIELD( 23, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, network_connection_info, event_uptime_ms, &gdt_cct_NetworkConnectionInfo_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_NetworkConnectionInfo_fields[3] = { + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, gdt_cct_NetworkConnectionInfo, network_type, network_type, &gdt_cct_NetworkConnectionInfo_network_type_default), + PB_FIELD( 2, UENUM , OPTIONAL, STATIC , OTHER, gdt_cct_NetworkConnectionInfo, mobile_subtype, network_type, &gdt_cct_NetworkConnectionInfo_mobile_subtype_default), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_IosClientInfo_fields[8] = { + PB_FIELD( 3, BYTES , OPTIONAL, POINTER , FIRST, gdt_cct_IosClientInfo, os_major_version, os_major_version, 0), + PB_FIELD( 4, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, os_full_version, os_major_version, 0), + PB_FIELD( 5, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, application_build, os_full_version, 0), + PB_FIELD( 6, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, country, application_build, 0), + PB_FIELD( 7, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, model, country, 0), + PB_FIELD( 8, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, language_code, model, 0), + PB_FIELD( 11, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, application_bundle_id, language_code, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_ClientInfo_fields[3] = { + PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, gdt_cct_ClientInfo, client_type, client_type, 0), + PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_ClientInfo, ios_client_info, client_type, &gdt_cct_IosClientInfo_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_BatchedLogRequest_fields[2] = { + PB_FIELD( 1, MESSAGE , REPEATED, POINTER , FIRST, gdt_cct_BatchedLogRequest, log_request, log_request, &gdt_cct_LogRequest_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_LogRequest_fields[7] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, gdt_cct_LogRequest, client_info, client_info, &gdt_cct_ClientInfo_fields), + PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, log_source, client_info, 0), + PB_FIELD( 3, MESSAGE , REPEATED, POINTER , OTHER, gdt_cct_LogRequest, log_event, log_source, &gdt_cct_LogEvent_fields), + PB_FIELD( 4, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, request_time_ms, log_event, 0), + PB_FIELD( 8, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, request_uptime_ms, request_time_ms, 0), + PB_FIELD( 9, UENUM , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, qos_tier, request_uptime_ms, &gdt_cct_LogRequest_qos_tier_default), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_QosTierConfiguration_fields[3] = { + PB_FIELD( 2, UENUM , OPTIONAL, STATIC , FIRST, gdt_cct_QosTierConfiguration, qos_tier, qos_tier, 0), + PB_FIELD( 3, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_QosTierConfiguration, log_source, qos_tier, &gdt_cct_QosTierConfiguration_log_source_default), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_QosTiersOverride_fields[3] = { + PB_FIELD( 1, MESSAGE , REPEATED, POINTER , FIRST, gdt_cct_QosTiersOverride, qos_tier_configuration, qos_tier_configuration, &gdt_cct_QosTierConfiguration_fields), + PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_QosTiersOverride, qos_tier_fingerprint, qos_tier_configuration, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_LogResponse_fields[3] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, gdt_cct_LogResponse, next_request_wait_millis, next_request_wait_millis, 0), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_LogResponse, qos_tier, next_request_wait_millis, &gdt_cct_QosTiersOverride_fields), + PB_LAST_FIELD +}; + + + + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_cct_LogEvent, network_connection_info) < 65536 && pb_membersize(gdt_cct_ClientInfo, ios_client_info) < 65536 && pb_membersize(gdt_cct_LogRequest, client_info) < 65536 && pb_membersize(gdt_cct_LogResponse, qos_tier) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_gdt_cct_LogEvent_gdt_cct_NetworkConnectionInfo_gdt_cct_IosClientInfo_gdt_cct_ClientInfo_gdt_cct_BatchedLogRequest_gdt_cct_LogRequest_gdt_cct_QosTierConfiguration_gdt_cct_QosTiersOverride_gdt_cct_LogResponse) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_cct_LogEvent, network_connection_info) < 256 && pb_membersize(gdt_cct_ClientInfo, ios_client_info) < 256 && pb_membersize(gdt_cct_LogRequest, client_info) < 256 && pb_membersize(gdt_cct_LogResponse, qos_tier) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_gdt_cct_LogEvent_gdt_cct_NetworkConnectionInfo_gdt_cct_IosClientInfo_gdt_cct_ClientInfo_gdt_cct_BatchedLogRequest_gdt_cct_LogRequest_gdt_cct_QosTierConfiguration_gdt_cct_QosTiersOverride_gdt_cct_LogResponse) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h new file mode 100644 index 0000000..05bdf58 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h @@ -0,0 +1,281 @@ +/* + * 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. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.7 */ + +#ifndef PB_GDT_CCT_CCT_NANOPB_H_INCLUDED +#define PB_GDT_CCT_CCT_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _gdt_cct_NetworkConnectionInfo_NetworkType { + gdt_cct_NetworkConnectionInfo_NetworkType_NONE = -1, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE = 0, + gdt_cct_NetworkConnectionInfo_NetworkType_WIFI = 1, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_MMS = 2, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_SUPL = 3, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_DUN = 4, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_HIPRI = 5, + gdt_cct_NetworkConnectionInfo_NetworkType_WIMAX = 6, + gdt_cct_NetworkConnectionInfo_NetworkType_BLUETOOTH = 7, + gdt_cct_NetworkConnectionInfo_NetworkType_DUMMY = 8, + gdt_cct_NetworkConnectionInfo_NetworkType_ETHERNET = 9, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_FOTA = 10, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_IMS = 11, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_CBS = 12, + gdt_cct_NetworkConnectionInfo_NetworkType_WIFI_P2P = 13, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_IA = 14, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_EMERGENCY = 15, + gdt_cct_NetworkConnectionInfo_NetworkType_PROXY = 16, + gdt_cct_NetworkConnectionInfo_NetworkType_VPN = 17 +} gdt_cct_NetworkConnectionInfo_NetworkType; +#define _gdt_cct_NetworkConnectionInfo_NetworkType_MIN gdt_cct_NetworkConnectionInfo_NetworkType_NONE +#define _gdt_cct_NetworkConnectionInfo_NetworkType_MAX gdt_cct_NetworkConnectionInfo_NetworkType_VPN +#define _gdt_cct_NetworkConnectionInfo_NetworkType_ARRAYSIZE ((gdt_cct_NetworkConnectionInfo_NetworkType)(gdt_cct_NetworkConnectionInfo_NetworkType_VPN+1)) + +typedef enum _gdt_cct_NetworkConnectionInfo_MobileSubtype { + gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE = 0, + gdt_cct_NetworkConnectionInfo_MobileSubtype_GPRS = 1, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EDGE = 2, + gdt_cct_NetworkConnectionInfo_MobileSubtype_UMTS = 3, + gdt_cct_NetworkConnectionInfo_MobileSubtype_CDMA = 4, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_0 = 5, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_A = 6, + gdt_cct_NetworkConnectionInfo_MobileSubtype_RTT = 7, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSDPA = 8, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSUPA = 9, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSPA = 10, + gdt_cct_NetworkConnectionInfo_MobileSubtype_IDEN = 11, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_B = 12, + gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE = 13, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EHRPD = 14, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSPAP = 15, + gdt_cct_NetworkConnectionInfo_MobileSubtype_GSM = 16, + gdt_cct_NetworkConnectionInfo_MobileSubtype_TD_SCDMA = 17, + gdt_cct_NetworkConnectionInfo_MobileSubtype_IWLAN = 18, + gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE_CA = 19, + gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED = 100 +} gdt_cct_NetworkConnectionInfo_MobileSubtype; +#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_MIN gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE +#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_MAX gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED +#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_ARRAYSIZE ((gdt_cct_NetworkConnectionInfo_MobileSubtype)(gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED+1)) + +typedef enum _gdt_cct_ClientInfo_ClientType { + gdt_cct_ClientInfo_ClientType_CLIENT_UNKNOWN = 0, + gdt_cct_ClientInfo_ClientType_IOS_FIREBASE = 15 +} gdt_cct_ClientInfo_ClientType; +#define _gdt_cct_ClientInfo_ClientType_MIN gdt_cct_ClientInfo_ClientType_CLIENT_UNKNOWN +#define _gdt_cct_ClientInfo_ClientType_MAX gdt_cct_ClientInfo_ClientType_IOS_FIREBASE +#define _gdt_cct_ClientInfo_ClientType_ARRAYSIZE ((gdt_cct_ClientInfo_ClientType)(gdt_cct_ClientInfo_ClientType_IOS_FIREBASE+1)) + +typedef enum _gdt_cct_QosTierConfiguration_QosTier { + gdt_cct_QosTierConfiguration_QosTier_DEFAULT = 0, + gdt_cct_QosTierConfiguration_QosTier_UNMETERED_ONLY = 1, + gdt_cct_QosTierConfiguration_QosTier_UNMETERED_OR_DAILY = 2, + gdt_cct_QosTierConfiguration_QosTier_FAST_IF_RADIO_AWAKE = 3, + gdt_cct_QosTierConfiguration_QosTier_NEVER = 4 +} gdt_cct_QosTierConfiguration_QosTier; +#define _gdt_cct_QosTierConfiguration_QosTier_MIN gdt_cct_QosTierConfiguration_QosTier_DEFAULT +#define _gdt_cct_QosTierConfiguration_QosTier_MAX gdt_cct_QosTierConfiguration_QosTier_NEVER +#define _gdt_cct_QosTierConfiguration_QosTier_ARRAYSIZE ((gdt_cct_QosTierConfiguration_QosTier)(gdt_cct_QosTierConfiguration_QosTier_NEVER+1)) + +/* Struct definitions */ +typedef struct _gdt_cct_BatchedLogRequest { + pb_size_t log_request_count; + struct _gdt_cct_LogRequest *log_request; +/* @@protoc_insertion_point(struct:gdt_cct_BatchedLogRequest) */ +} gdt_cct_BatchedLogRequest; + +typedef struct _gdt_cct_IosClientInfo { + pb_bytes_array_t *os_major_version; + pb_bytes_array_t *os_full_version; + pb_bytes_array_t *application_build; + pb_bytes_array_t *country; + pb_bytes_array_t *model; + pb_bytes_array_t *language_code; + pb_bytes_array_t *application_bundle_id; +/* @@protoc_insertion_point(struct:gdt_cct_IosClientInfo) */ +} gdt_cct_IosClientInfo; + +typedef struct _gdt_cct_ClientInfo { + bool has_client_type; + gdt_cct_ClientInfo_ClientType client_type; + bool has_ios_client_info; + gdt_cct_IosClientInfo ios_client_info; +/* @@protoc_insertion_point(struct:gdt_cct_ClientInfo) */ +} gdt_cct_ClientInfo; + +typedef struct _gdt_cct_NetworkConnectionInfo { + bool has_network_type; + gdt_cct_NetworkConnectionInfo_NetworkType network_type; + bool has_mobile_subtype; + gdt_cct_NetworkConnectionInfo_MobileSubtype mobile_subtype; +/* @@protoc_insertion_point(struct:gdt_cct_NetworkConnectionInfo) */ +} gdt_cct_NetworkConnectionInfo; + +typedef struct _gdt_cct_QosTierConfiguration { + bool has_qos_tier; + gdt_cct_QosTierConfiguration_QosTier qos_tier; + bool has_log_source; + int32_t log_source; +/* @@protoc_insertion_point(struct:gdt_cct_QosTierConfiguration) */ +} gdt_cct_QosTierConfiguration; + +typedef struct _gdt_cct_QosTiersOverride { + pb_size_t qos_tier_configuration_count; + struct _gdt_cct_QosTierConfiguration *qos_tier_configuration; + bool has_qos_tier_fingerprint; + int64_t qos_tier_fingerprint; +/* @@protoc_insertion_point(struct:gdt_cct_QosTiersOverride) */ +} gdt_cct_QosTiersOverride; + +typedef struct _gdt_cct_LogEvent { + bool has_event_time_ms; + int64_t event_time_ms; + pb_bytes_array_t *source_extension; + bool has_event_code; + int32_t event_code; + bool has_timezone_offset_seconds; + int64_t timezone_offset_seconds; + bool has_event_uptime_ms; + int64_t event_uptime_ms; + bool has_network_connection_info; + gdt_cct_NetworkConnectionInfo network_connection_info; +/* @@protoc_insertion_point(struct:gdt_cct_LogEvent) */ +} gdt_cct_LogEvent; + +typedef struct _gdt_cct_LogRequest { + bool has_client_info; + gdt_cct_ClientInfo client_info; + bool has_log_source; + int32_t log_source; + pb_size_t log_event_count; + struct _gdt_cct_LogEvent *log_event; + bool has_request_time_ms; + int64_t request_time_ms; + bool has_request_uptime_ms; + int64_t request_uptime_ms; + bool has_qos_tier; + gdt_cct_QosTierConfiguration_QosTier qos_tier; +/* @@protoc_insertion_point(struct:gdt_cct_LogRequest) */ +} gdt_cct_LogRequest; + +typedef struct _gdt_cct_LogResponse { + bool has_next_request_wait_millis; + int64_t next_request_wait_millis; + bool has_qos_tier; + gdt_cct_QosTiersOverride qos_tier; +/* @@protoc_insertion_point(struct:gdt_cct_LogResponse) */ +} gdt_cct_LogResponse; + +/* Default values for struct fields */ +extern const gdt_cct_NetworkConnectionInfo_NetworkType gdt_cct_NetworkConnectionInfo_network_type_default; +extern const gdt_cct_NetworkConnectionInfo_MobileSubtype gdt_cct_NetworkConnectionInfo_mobile_subtype_default; +extern const gdt_cct_QosTierConfiguration_QosTier gdt_cct_LogRequest_qos_tier_default; +extern const int32_t gdt_cct_QosTierConfiguration_log_source_default; + +/* Initializer values for message structs */ +#define gdt_cct_LogEvent_init_default {false, 0, NULL, false, 0, false, 0, false, 0, false, gdt_cct_NetworkConnectionInfo_init_default} +#define gdt_cct_NetworkConnectionInfo_init_default {false, gdt_cct_NetworkConnectionInfo_NetworkType_NONE, false, gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE} +#define gdt_cct_IosClientInfo_init_default {NULL, NULL, NULL, NULL, NULL, NULL, NULL} +#define gdt_cct_ClientInfo_init_default {false, _gdt_cct_ClientInfo_ClientType_MIN, false, gdt_cct_IosClientInfo_init_default} +#define gdt_cct_BatchedLogRequest_init_default {0, NULL} +#define gdt_cct_LogRequest_init_default {false, gdt_cct_ClientInfo_init_default, false, 0, 0, NULL, false, 0, false, 0, false, gdt_cct_QosTierConfiguration_QosTier_DEFAULT} +#define gdt_cct_QosTierConfiguration_init_default {false, _gdt_cct_QosTierConfiguration_QosTier_MIN, false, 0} +#define gdt_cct_QosTiersOverride_init_default {0, NULL, false, 0} +#define gdt_cct_LogResponse_init_default {false, 0, false, gdt_cct_QosTiersOverride_init_default} +#define gdt_cct_LogEvent_init_zero {false, 0, NULL, false, 0, false, 0, false, 0, false, gdt_cct_NetworkConnectionInfo_init_zero} +#define gdt_cct_NetworkConnectionInfo_init_zero {false, _gdt_cct_NetworkConnectionInfo_NetworkType_MIN, false, _gdt_cct_NetworkConnectionInfo_MobileSubtype_MIN} +#define gdt_cct_IosClientInfo_init_zero {NULL, NULL, NULL, NULL, NULL, NULL, NULL} +#define gdt_cct_ClientInfo_init_zero {false, _gdt_cct_ClientInfo_ClientType_MIN, false, gdt_cct_IosClientInfo_init_zero} +#define gdt_cct_BatchedLogRequest_init_zero {0, NULL} +#define gdt_cct_LogRequest_init_zero {false, gdt_cct_ClientInfo_init_zero, false, 0, 0, NULL, false, 0, false, 0, false, _gdt_cct_QosTierConfiguration_QosTier_MIN} +#define gdt_cct_QosTierConfiguration_init_zero {false, _gdt_cct_QosTierConfiguration_QosTier_MIN, false, 0} +#define gdt_cct_QosTiersOverride_init_zero {0, NULL, false, 0} +#define gdt_cct_LogResponse_init_zero {false, 0, false, gdt_cct_QosTiersOverride_init_zero} + +/* Field tags (for use in manual encoding/decoding) */ +#define gdt_cct_BatchedLogRequest_log_request_tag 1 +#define gdt_cct_IosClientInfo_os_major_version_tag 3 +#define gdt_cct_IosClientInfo_os_full_version_tag 4 +#define gdt_cct_IosClientInfo_application_build_tag 5 +#define gdt_cct_IosClientInfo_country_tag 6 +#define gdt_cct_IosClientInfo_model_tag 7 +#define gdt_cct_IosClientInfo_language_code_tag 8 +#define gdt_cct_IosClientInfo_application_bundle_id_tag 11 +#define gdt_cct_ClientInfo_client_type_tag 1 +#define gdt_cct_ClientInfo_ios_client_info_tag 4 +#define gdt_cct_NetworkConnectionInfo_network_type_tag 1 +#define gdt_cct_NetworkConnectionInfo_mobile_subtype_tag 2 +#define gdt_cct_QosTierConfiguration_qos_tier_tag 2 +#define gdt_cct_QosTierConfiguration_log_source_tag 3 +#define gdt_cct_QosTiersOverride_qos_tier_configuration_tag 1 +#define gdt_cct_QosTiersOverride_qos_tier_fingerprint_tag 2 +#define gdt_cct_LogEvent_event_time_ms_tag 1 +#define gdt_cct_LogEvent_event_code_tag 11 +#define gdt_cct_LogEvent_event_uptime_ms_tag 17 +#define gdt_cct_LogEvent_source_extension_tag 6 +#define gdt_cct_LogEvent_timezone_offset_seconds_tag 15 +#define gdt_cct_LogEvent_network_connection_info_tag 23 +#define gdt_cct_LogRequest_request_time_ms_tag 4 +#define gdt_cct_LogRequest_request_uptime_ms_tag 8 +#define gdt_cct_LogRequest_client_info_tag 1 +#define gdt_cct_LogRequest_log_source_tag 2 +#define gdt_cct_LogRequest_log_event_tag 3 +#define gdt_cct_LogRequest_qos_tier_tag 9 +#define gdt_cct_LogResponse_next_request_wait_millis_tag 1 +#define gdt_cct_LogResponse_qos_tier_tag 3 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t gdt_cct_LogEvent_fields[7]; +extern const pb_field_t gdt_cct_NetworkConnectionInfo_fields[3]; +extern const pb_field_t gdt_cct_IosClientInfo_fields[8]; +extern const pb_field_t gdt_cct_ClientInfo_fields[3]; +extern const pb_field_t gdt_cct_BatchedLogRequest_fields[2]; +extern const pb_field_t gdt_cct_LogRequest_fields[7]; +extern const pb_field_t gdt_cct_QosTierConfiguration_fields[3]; +extern const pb_field_t gdt_cct_QosTiersOverride_fields[3]; +extern const pb_field_t gdt_cct_LogResponse_fields[3]; + +/* Maximum encoded size of messages (where known) */ +/* gdt_cct_LogEvent_size depends on runtime parameters */ +#define gdt_cct_NetworkConnectionInfo_size 13 +/* gdt_cct_IosClientInfo_size depends on runtime parameters */ +/* gdt_cct_ClientInfo_size depends on runtime parameters */ +/* gdt_cct_BatchedLogRequest_size depends on runtime parameters */ +/* gdt_cct_LogRequest_size depends on runtime parameters */ +#define gdt_cct_QosTierConfiguration_size 13 +/* gdt_cct_QosTiersOverride_size depends on runtime parameters */ +/* gdt_cct_LogResponse_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define CCT_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h new file mode 100644 index 0000000..295e6f8 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A string sets in customBytes as a key paired to @YES if current event needs to + * populate network connection info data, @NO otherwise. + */ +FOUNDATION_EXPORT NSString *const GDTCCTNeedsNetworkConnectionInfo; + +/** A string sets in customBytes as a key paired to the network connection info data + * of current event. + */ +FOUNDATION_EXPORT NSString *const GDTCCTNetworkConnectionInfo; + +/** A category that uses the customBytes property of a GDTCOREvent to store network connection info. + */ +@interface GDTCOREvent (GDTCCTSupport) + +/** If YES, needs the network connection info field set during prioritization. + * @note Uses the GDTCOREvent customBytes property. + */ +@property(nonatomic) BOOL needsNetworkConnectionInfoPopulated; + +/** The network connection info as collected at the time of the event. + * @note Uses the GDTCOREvent customBytes property. + */ +@property(nullable, nonatomic) NSData *networkConnectionInfoData; + +/** Code that identifies the event to be sent to the CCT backend. + */ +@property(nullable, nonatomic) NSNumber *eventCode; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m new file mode 100644 index 0000000..14462ae --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m @@ -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 "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" + +GDTCORAssertionBlock GDTCORAssertionBlockToRunInstead(void) { + // This class is only compiled in by unit tests, and this should fail quickly in optimized builds. + Class GDTCORAssertClass = NSClassFromString(@"GDTCORAssertHelper"); + if (__builtin_expect(!!GDTCORAssertClass, 0)) { + SEL assertionBlockSEL = NSSelectorFromString(@"assertionBlock"); + if (assertionBlockSEL) { + IMP assertionBlockIMP = [GDTCORAssertClass methodForSelector:assertionBlockSEL]; + if (assertionBlockIMP) { + GDTCORAssertionBlock assertionBlock = ((GDTCORAssertionBlock(*)(id, SEL))assertionBlockIMP)( + GDTCORAssertClass, assertionBlockSEL); + if (assertionBlock) { + return assertionBlock; + } + } + } + } + return NULL; +} diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORClock.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORClock.m new file mode 100644 index 0000000..85afeba --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORClock.m @@ -0,0 +1,178 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" + +#import + +// Using a monotonic clock is necessary because CFAbsoluteTimeGetCurrent(), NSDate, and related all +// are subject to drift. That it to say, multiple consecutive calls do not always result in a +// time that is in the future. Clocks may be adjusted by the user, NTP, or any number of external +// factors. This class attempts to determine the wall-clock time at the time of the event by +// capturing the kernel start and time since boot to determine a wallclock time in UTC. +// +// Timezone offsets at the time of a snapshot are also captured in order to provide local-time +// details. Other classes in this library depend on comparing times at some time in the future to +// a time captured in the past, and this class needs to provide a mechanism to do that. +// +// TL;DR: This class attempts to accomplish two things: 1. Provide accurate event times. 2. Provide +// a monotonic clock mechanism to accurately check if some clock snapshot was before or after +// by using a shared reference point (kernel boot time). +// +// Note: Much of the mach time stuff doesn't work properly in the simulator. So this class can be +// difficult to unit test. + +/** Returns the kernel boottime property from sysctl. + * + * Inspired by https://stackoverflow.com/a/40497811 + * + * @return The KERN_BOOTTIME property from sysctl, in nanoseconds. + */ +static int64_t KernelBootTimeInNanoseconds() { + // Caching the result is not possible because clock drift would not be accounted for. + struct timeval boottime; + int mib[2] = {CTL_KERN, KERN_BOOTTIME}; + size_t size = sizeof(boottime); + int rc = sysctl(mib, 2, &boottime, &size, NULL, 0); + if (rc != 0) { + return 0; + } + return (int64_t)boottime.tv_sec * NSEC_PER_SEC + (int64_t)boottime.tv_usec * NSEC_PER_USEC; +} + +/** Returns value of gettimeofday, in nanoseconds. + * + * Inspired by https://stackoverflow.com/a/40497811 + * + * @return The value of gettimeofday, in nanoseconds. + */ +static int64_t UptimeInNanoseconds() { + int64_t before_now_nsec; + int64_t after_now_nsec; + struct timeval now; + + before_now_nsec = KernelBootTimeInNanoseconds(); + // Addresses a race condition in which the system time has updated, but the boottime has not. + do { + gettimeofday(&now, NULL); + after_now_nsec = KernelBootTimeInNanoseconds(); + } while (after_now_nsec != before_now_nsec); + return (int64_t)now.tv_sec * NSEC_PER_SEC + (int64_t)now.tv_usec * NSEC_PER_USEC - + before_now_nsec; +} + +// TODO: Consider adding a 'trustedTime' property that can be populated by the response from a BE. +@implementation GDTCORClock + +- (instancetype)init { + self = [super init]; + if (self) { + _kernelBootTimeNanoseconds = KernelBootTimeInNanoseconds(); + _uptimeNanoseconds = UptimeInNanoseconds(); + _timeMillis = + (int64_t)((CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) * NSEC_PER_USEC); + _timezoneOffsetSeconds = [[NSTimeZone systemTimeZone] secondsFromGMT]; + } + return self; +} + ++ (GDTCORClock *)snapshot { + return [[GDTCORClock alloc] init]; +} + ++ (instancetype)clockSnapshotInTheFuture:(uint64_t)millisInTheFuture { + GDTCORClock *snapshot = [self snapshot]; + snapshot->_timeMillis += millisInTheFuture; + return snapshot; +} + +- (BOOL)isAfter:(GDTCORClock *)otherClock { + // These clocks are trivially comparable when they share a kernel boot time. + if (_kernelBootTimeNanoseconds == otherClock->_kernelBootTimeNanoseconds) { + int64_t timeDiff = (_timeMillis + _timezoneOffsetSeconds) - + (otherClock->_timeMillis + otherClock->_timezoneOffsetSeconds); + return timeDiff > 0; + } else { + int64_t kernelBootTimeDiff = + otherClock->_kernelBootTimeNanoseconds - _kernelBootTimeNanoseconds; + // This isn't a great solution, but essentially, if the other clock's boot time is 'later', NO + // is returned. This can be altered by changing the system time and rebooting. + return kernelBootTimeDiff < 0 ? YES : NO; + } +} + +- (int64_t)uptimeMilliseconds { + return self.uptimeNanoseconds / NSEC_PER_MSEC; +} + +- (NSUInteger)hash { + return [@(_kernelBootTimeNanoseconds) hash] ^ [@(_uptimeNanoseconds) hash] ^ + [@(_timeMillis) hash] ^ [@(_timezoneOffsetSeconds) hash]; +} + +- (BOOL)isEqual:(id)object { + return [self hash] == [object hash]; +} + +#pragma mark - NSSecureCoding + +/** NSKeyedCoder key for timeMillis property. */ +static NSString *const kGDTCORClockTimeMillisKey = @"GDTCORClockTimeMillis"; + +/** NSKeyedCoder key for timezoneOffsetMillis property. */ +static NSString *const kGDTCORClockTimezoneOffsetSeconds = @"GDTCORClockTimezoneOffsetSeconds"; + +/** NSKeyedCoder key for _kernelBootTime ivar. */ +static NSString *const kGDTCORClockKernelBootTime = @"GDTCORClockKernelBootTime"; + +/** NSKeyedCoder key for _uptimeNanoseconds ivar. */ +static NSString *const kGDTCORClockUptime = @"GDTCORClockUptime"; + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [super init]; + if (self) { + // TODO: If the kernelBootTimeNanoseconds is more recent, we need to change the kernel boot time + // and uptimeMillis ivars + _timeMillis = [aDecoder decodeInt64ForKey:kGDTCORClockTimeMillisKey]; + _timezoneOffsetSeconds = [aDecoder decodeInt64ForKey:kGDTCORClockTimezoneOffsetSeconds]; + _kernelBootTimeNanoseconds = [aDecoder decodeInt64ForKey:kGDTCORClockKernelBootTime]; + _uptimeNanoseconds = [aDecoder decodeInt64ForKey:kGDTCORClockUptime]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeInt64:_timeMillis forKey:kGDTCORClockTimeMillisKey]; + [aCoder encodeInt64:_timezoneOffsetSeconds forKey:kGDTCORClockTimezoneOffsetSeconds]; + [aCoder encodeInt64:_kernelBootTimeNanoseconds forKey:kGDTCORClockKernelBootTime]; + [aCoder encodeInt64:_uptimeNanoseconds forKey:kGDTCORClockUptime]; +} + +#pragma mark - Deprecated properties + +- (int64_t)kernelBootTime { + return self.kernelBootTimeNanoseconds; +} + +- (int64_t)uptime { + return self.uptimeNanoseconds; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m new file mode 100644 index 0000000..5eaee92 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m @@ -0,0 +1,55 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +volatile NSInteger GDTCORConsoleLoggerLoggingLevel = GDTCORLoggingLevelErrors; + +/** The console logger prefix. */ +static NSString *kGDTCORConsoleLogger = @"[GoogleDataTransport]"; + +NSString *GDTCORMessageCodeEnumToString(GDTCORMessageCode code) { + return [[NSString alloc] initWithFormat:@"I-GDTCOR%06ld", (long)code]; +} + +void GDTCORLog(GDTCORMessageCode code, GDTCORLoggingLevel logLevel, NSString *format, ...) { +// Don't log anything in not debug builds. +#if !NDEBUG + if (logLevel >= GDTCORConsoleLoggerLoggingLevel) { + NSString *logFormat = [NSString stringWithFormat:@"%@[%@] %@", kGDTCORConsoleLogger, + GDTCORMessageCodeEnumToString(code), format]; + va_list args; + va_start(args, format); + NSLogv(logFormat, args); + va_end(args); + } +#endif // !NDEBUG +} + +void GDTCORLogAssert( + BOOL wasFatal, NSString *_Nonnull file, NSInteger line, NSString *_Nullable format, ...) { +// Don't log anything in not debug builds. +#if !NDEBUG + GDTCORMessageCode code = wasFatal ? GDTCORMCEFatalAssertion : GDTCORMCEGeneralError; + NSString *logFormat = + [NSString stringWithFormat:@"%@[%@] (%@:%ld) : %@", kGDTCORConsoleLogger, + GDTCORMessageCodeEnumToString(code), file, (long)line, format]; + va_list args; + va_start(args, format); + NSLogv(logFormat, args); + va_end(args); +#endif // !NDEBUG +} diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m new file mode 100644 index 0000000..0bc8515 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m @@ -0,0 +1,101 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h" + +@interface GDTCORDirectorySizeTracker () + +/** The observed directory path. */ +@property(nonatomic, readonly) NSString *directoryPath; + +/** The cached content size of the observed directory. */ +@property(nonatomic, nullable) NSNumber *cachedSizeBytes; + +@end + +@implementation GDTCORDirectorySizeTracker + +- (instancetype)initWithDirectoryPath:(NSString *)path { + self = [super init]; + if (self) { + _directoryPath = path; + } + return self; +} + +- (GDTCORStorageSizeBytes)directoryContentSize { + if (self.cachedSizeBytes == nil) { + self.cachedSizeBytes = @([self calculateDirectoryContentSize]); + } + + return self.cachedSizeBytes.unsignedLongLongValue; +} + +- (void)fileWasAddedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize { + if (![path hasPrefix:self.directoryPath]) { + // Ignore because the file is not inside the directory. + return; + } + + self.cachedSizeBytes = @([self directoryContentSize] + fileSize); +} + +- (void)fileWasRemovedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize { + if (![path hasPrefix:self.directoryPath]) { + // Ignore because the file is not inside the directory. + return; + } + + self.cachedSizeBytes = @([self directoryContentSize] - fileSize); +} + +- (void)resetCachedSize { + self.cachedSizeBytes = nil; +} + +- (GDTCORStorageSizeBytes)calculateDirectoryContentSize { + NSArray *prefetchedProperties = @[ NSURLIsRegularFileKey, NSURLFileSizeKey ]; + uint64_t totalBytes = 0; + NSURL *directoryURL = [NSURL fileURLWithPath:self.directoryPath]; + + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] + enumeratorAtURL:directoryURL + includingPropertiesForKeys:prefetchedProperties + options:NSDirectoryEnumerationSkipsHiddenFiles + errorHandler:^BOOL(NSURL *_Nonnull url, NSError *_Nonnull error) { + return YES; + }]; + + for (NSURL *fileURL in enumerator) { + @autoreleasepool { + NSNumber *isRegularFile; + [fileURL getResourceValue:&isRegularFile forKey:NSURLIsRegularFileKey error:nil]; + if (isRegularFile.boolValue) { + totalBytes += [self fileSizeAtURL:fileURL]; + } + } + } + + return totalBytes; +} + +- (GDTCORStorageSizeBytes)fileSizeAtURL:(NSURL *)fileURL { + NSNumber *fileSize; + [fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:nil]; + return fileSize.unsignedLongLongValue; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m new file mode 100644 index 0000000..eacc7b4 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m @@ -0,0 +1,92 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h" + +static NSString *const kINTServerURL = + @"https://dummyapiverylong-dummy.dummy.com/dummy/api/very/long"; + +@implementation GDTCOREndpoints + ++ (NSDictionary *)uploadURLs { + // These strings should be interleaved to construct the real URL. This is just to (hopefully) + // fool github URL scanning bots. + static NSURL *CCTServerURL; + static dispatch_once_t CCTOnceToken; + dispatch_once(&CCTOnceToken, ^{ + const char *p1 = "hts/frbslgiggolai.o/0clgbth"; + const char *p2 = "tp:/ieaeogn.ogepscmvc/o/ac"; + const char URL[54] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4], + p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8], + p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13], + p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17], + p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22], + p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], '\0'}; + CCTServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]]; + }); + + static NSURL *FLLServerURL; + static dispatch_once_t FLLOnceToken; + dispatch_once(&FLLOnceToken, ^{ + const char *p1 = "hts/frbslgigp.ogepscmv/ieo/eaybtho"; + const char *p2 = "tp:/ieaeogn-agolai.o/1frlglgc/aclg"; + const char URL[69] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4], + p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8], + p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13], + p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17], + p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22], + p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], p2[26], + p1[27], p2[27], p1[28], p2[28], p1[29], p2[29], p1[30], p2[30], p1[31], + p2[31], p1[32], p2[32], p1[33], p2[33], '\0'}; + FLLServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]]; + }); + + static NSURL *CSHServerURL; + static dispatch_once_t CSHOnceToken; + dispatch_once(&CSHOnceToken, ^{ + // These strings should be interleaved to construct the real URL. This is just to (hopefully) + // fool github URL scanning bots. + const char *p1 = "hts/cahyiseot-agolai.o/1frlglgc/aclg"; + const char *p2 = "tp:/rsltcrprsp.ogepscmv/ieo/eaybtho"; + const char URL[72] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4], + p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8], + p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13], + p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17], + p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22], + p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], p2[26], + p1[27], p2[27], p1[28], p2[28], p1[29], p2[29], p1[30], p2[30], p1[31], + p2[31], p1[32], p2[32], p1[33], p2[33], p1[34], p2[34], p1[35], '\0'}; + CSHServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]]; + }); + static NSDictionary *uploadURLs; + static dispatch_once_t URLOnceToken; + dispatch_once(&URLOnceToken, ^{ + uploadURLs = @{ + @(kGDTCORTargetCCT) : CCTServerURL, + @(kGDTCORTargetFLL) : FLLServerURL, + @(kGDTCORTargetCSH) : CSHServerURL, + @(kGDTCORTargetINT) : [NSURL URLWithString:kINTServerURL] + }; + }); + return uploadURLs; +} + ++ (nullable NSURL *)uploadURLForTarget:(GDTCORTarget)target { + NSDictionary *URLs = [self uploadURLs]; + return [URLs objectForKey:@(target)]; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m new file mode 100644 index 0000000..5a8d324 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m @@ -0,0 +1,153 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h" + +@implementation GDTCOREvent + ++ (NSString *)nextEventID { + // Replace special non-alphanumeric characters to avoid potential conflicts with storage logic. + return [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""]; +} + +- (nullable instancetype)initWithMappingID:(NSString *)mappingID target:(GDTCORTarget)target { + GDTCORAssert(mappingID.length > 0, @"Please give a valid mapping ID"); + GDTCORAssert(target > 0, @"A target cannot be negative or 0"); + if (mappingID.length == 0 || target <= 0) { + return nil; + } + self = [super init]; + if (self) { + _eventID = [GDTCOREvent nextEventID]; + _mappingID = mappingID; + _target = target; + _qosTier = GDTCOREventQosDefault; + _expirationDate = [NSDate dateWithTimeIntervalSinceNow:604800]; // 7 days. + + GDTCORLogDebug(@"Event %@ created. ID:%@ mappingID: %@ target:%ld", self, _eventID, mappingID, + (long)target); + } + + return self; +} + +- (instancetype)copy { + GDTCOREvent *copy = [[GDTCOREvent alloc] initWithMappingID:_mappingID target:_target]; + copy->_eventID = _eventID; + copy.dataObject = _dataObject; + copy.qosTier = _qosTier; + copy.clockSnapshot = _clockSnapshot; + copy.customBytes = _customBytes; + GDTCORLogDebug(@"Copying event %@ to event %@", self, copy); + return copy; +} + +- (NSUInteger)hash { + // This loses some precision, but it's probably fine. + NSUInteger eventIDHash = [_eventID hash]; + NSUInteger mappingIDHash = [_mappingID hash]; + NSUInteger timeHash = [_clockSnapshot hash]; + NSInteger serializedBytesHash = [_serializedDataObjectBytes hash]; + + return eventIDHash ^ mappingIDHash ^ _target ^ _qosTier ^ timeHash ^ serializedBytesHash; +} + +- (BOOL)isEqual:(id)object { + return [self hash] == [object hash]; +} + +#pragma mark - Property overrides + +- (void)setDataObject:(id)dataObject { + // If you're looking here because of a performance issue in -transportBytes slowing the assignment + // of -dataObject, one way to address this is to add a queue to this class, + // dispatch_(barrier_ if concurrent)async here, and implement the getter with a dispatch_sync. + if (dataObject != _dataObject) { + _dataObject = dataObject; + } + self->_serializedDataObjectBytes = [dataObject transportBytes]; +} + +#pragma mark - NSSecureCoding and NSCoding Protocols + +/** NSCoding key for eventID property. */ +static NSString *kEventIDKey = @"GDTCOREventEventIDKey"; + +/** NSCoding key for mappingID property. */ +static NSString *kMappingIDKey = @"GDTCOREventMappingIDKey"; + +/** NSCoding key for target property. */ +static NSString *kTargetKey = @"GDTCOREventTargetKey"; + +/** NSCoding key for qosTier property. */ +static NSString *kQoSTierKey = @"GDTCOREventQoSTierKey"; + +/** NSCoding key for clockSnapshot property. */ +static NSString *kClockSnapshotKey = @"GDTCOREventClockSnapshotKey"; + +/** NSCoding key for expirationDate property. */ +static NSString *kExpirationDateKey = @"GDTCOREventExpirationDateKey"; + +/** NSCoding key for serializedDataObjectBytes property. */ +static NSString *kSerializedDataObjectBytes = @"GDTCOREventSerializedDataObjectBytesKey"; + +/** NSCoding key for customData property. */ +static NSString *kCustomDataKey = @"GDTCOREventCustomDataKey"; + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (self) { + _mappingID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kMappingIDKey]; + _target = [aDecoder decodeIntegerForKey:kTargetKey]; + _eventID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kEventIDKey] + ?: [GDTCOREvent nextEventID]; + _qosTier = [aDecoder decodeIntegerForKey:kQoSTierKey]; + _clockSnapshot = [aDecoder decodeObjectOfClass:[GDTCORClock class] forKey:kClockSnapshotKey]; + _customBytes = [aDecoder decodeObjectOfClass:[NSData class] forKey:kCustomDataKey]; + _expirationDate = [aDecoder decodeObjectOfClass:[NSDate class] forKey:kExpirationDateKey]; + _serializedDataObjectBytes = [aDecoder decodeObjectOfClass:[NSData class] + forKey:kSerializedDataObjectBytes]; + if (!_serializedDataObjectBytes) { + return nil; + } + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_eventID forKey:kEventIDKey]; + [aCoder encodeObject:_mappingID forKey:kMappingIDKey]; + [aCoder encodeInteger:_target forKey:kTargetKey]; + [aCoder encodeInteger:_qosTier forKey:kQoSTierKey]; + [aCoder encodeObject:_clockSnapshot forKey:kClockSnapshotKey]; + [aCoder encodeObject:_customBytes forKey:kCustomDataKey]; + [aCoder encodeObject:_expirationDate forKey:kExpirationDateKey]; + [aCoder encodeObject:self.serializedDataObjectBytes forKey:kSerializedDataObjectBytes]; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m new file mode 100644 index 0000000..c3a22a8 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m @@ -0,0 +1,104 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h" + +@implementation GDTCORFlatFileStorage (Promises) + +- (FBLPromise *> *)batchIDsForTarget:(GDTCORTarget)target { + return [FBLPromise onQueue:self.storageQueue + wrapObjectCompletion:^(FBLPromiseObjectCompletion _Nonnull handler) { + [self batchIDsForTarget:target onComplete:handler]; + }]; +} + +- (FBLPromise *)removeBatchWithID:(NSNumber *)batchID deleteEvents:(BOOL)deleteEvents { + return [FBLPromise onQueue:self.storageQueue + wrapCompletion:^(FBLPromiseCompletion _Nonnull handler) { + [self removeBatchWithID:batchID deleteEvents:deleteEvents onComplete:handler]; + }]; +} + +- (FBLPromise *)removeBatchesWithIDs:(NSSet *)batchIDs + deleteEvents:(BOOL)deleteEvents { + NSMutableArray *removeBatchPromises = + [NSMutableArray arrayWithCapacity:batchIDs.count]; + for (NSNumber *batchID in batchIDs) { + [removeBatchPromises addObject:[self removeBatchWithID:batchID deleteEvents:deleteEvents]]; + } + + return [FBLPromise onQueue:self.storageQueue all:[removeBatchPromises copy]].thenOn( + self.storageQueue, ^id(id result) { + return [FBLPromise resolvedWith:[NSNull null]]; + }); +} + +- (FBLPromise *)removeAllBatchesForTarget:(GDTCORTarget)target + deleteEvents:(BOOL)deleteEvents { + return + [self batchIDsForTarget:target].thenOn(self.storageQueue, ^id(NSSet *batchIDs) { + if (batchIDs.count == 0) { + return [FBLPromise resolvedWith:[NSNull null]]; + } else { + return [self removeBatchesWithIDs:batchIDs deleteEvents:NO]; + } + }); +} + +- (FBLPromise *)hasEventsForTarget:(GDTCORTarget)target { + return [FBLPromise onQueue:self.storageQueue + wrapBoolCompletion:^(FBLPromiseBoolCompletion _Nonnull handler) { + [self hasEventsForTarget:target onComplete:handler]; + }]; +} + +- (FBLPromise *)batchWithEventSelector: + (GDTCORStorageEventSelector *)eventSelector + batchExpiration:(NSDate *)expiration { + return [FBLPromise + onQueue:self.storageQueue + async:^(FBLPromiseFulfillBlock _Nonnull fulfill, FBLPromiseRejectBlock _Nonnull reject) { + [self batchWithEventSelector:eventSelector + batchExpiration:expiration + onComplete:^(NSNumber *_Nullable newBatchID, + NSSet *_Nullable batchEvents) { + if (newBatchID == nil || batchEvents == nil) { + reject([self genericRejectedPromiseErrorWithReason: + @"There are no events for the selector."]); + } else { + fulfill([[GDTCORUploadBatch alloc] initWithBatchID:newBatchID + events:batchEvents]); + } + }]; + }]; +} + +// TODO: Move to a separate class/extension when needed in more places. +- (NSError *)genericRejectedPromiseErrorWithReason:(NSString *)reason { + return [NSError errorWithDomain:@"GDTCORFlatFileStorage" + code:-1 + userInfo:@{NSLocalizedFailureReasonErrorKey : reason}]; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m new file mode 100644 index 0000000..6e326d8 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m @@ -0,0 +1,826 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A library data key this class uses to track batchIDs. */ +static NSString *const gBatchIDCounterKey = @"GDTCORFlatFileStorageBatchIDCounter"; + +/** The separator used between metadata elements in filenames. */ +static NSString *const kMetadataSeparator = @"-"; + +NSString *const kGDTCOREventComponentsEventIDKey = @"GDTCOREventComponentsEventIDKey"; + +NSString *const kGDTCOREventComponentsQoSTierKey = @"GDTCOREventComponentsQoSTierKey"; + +NSString *const kGDTCOREventComponentsMappingIDKey = @"GDTCOREventComponentsMappingIDKey"; + +NSString *const kGDTCOREventComponentsExpirationKey = @"GDTCOREventComponentsExpirationKey"; + +NSString *const kGDTCORBatchComponentsTargetKey = @"GDTCORBatchComponentsTargetKey"; + +NSString *const kGDTCORBatchComponentsBatchIDKey = @"GDTCORBatchComponentsBatchIDKey"; + +NSString *const kGDTCORBatchComponentsExpirationKey = @"GDTCORBatchComponentsExpirationKey"; + +NSString *const GDTCORFlatFileStorageErrorDomain = @"GDTCORFlatFileStorage"; + +const uint64_t kGDTCORFlatFileStorageSizeLimit = 20 * 1000 * 1000; // 20 MB. + +@interface GDTCORFlatFileStorage () + +/** An instance of the size tracker to keep track of the disk space consumed by the storage. */ +@property(nonatomic, readonly) GDTCORDirectorySizeTracker *sizeTracker; + +@end + +@implementation GDTCORFlatFileStorage + +@synthesize sizeTracker = _sizeTracker; + ++ (void)load { +#if !NDEBUG + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetTest]; +#endif // !NDEBUG + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetCCT]; + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetFLL]; + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetCSH]; + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetINT]; +} + ++ (instancetype)sharedInstance { + static GDTCORFlatFileStorage *sharedStorage; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedStorage = [[GDTCORFlatFileStorage alloc] init]; + }); + return sharedStorage; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _storageQueue = + dispatch_queue_create("com.google.GDTCORFlatFileStorage", DISPATCH_QUEUE_SERIAL); + _uploadCoordinator = [GDTCORUploadCoordinator sharedInstance]; + } + return self; +} + +- (GDTCORDirectorySizeTracker *)sizeTracker { + if (_sizeTracker == nil) { + _sizeTracker = + [[GDTCORDirectorySizeTracker alloc] initWithDirectoryPath:GDTCORRootDirectory().path]; + } + return _sizeTracker; +} + +#pragma mark - GDTCORStorageProtocol + +- (void)storeEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + GDTCORLogDebug(@"Saving event: %@", event); + if (event == nil || event.serializedDataObjectBytes == nil) { + GDTCORLogDebug(@"%@", @"The event was nil, so it was not saved."); + if (completion) { + completion(NO, [NSError errorWithDomain:NSInternalInconsistencyException + code:-1 + userInfo:nil]); + } + return; + } + if (!completion) { + completion = ^(BOOL wasWritten, NSError *_Nullable error) { + GDTCORLogDebug(@"event %@ stored. success:%@ error:%@", event, wasWritten ? @"YES" : @"NO", + error); + }; + } + + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; + bgID = [[GDTCORApplication sharedApplication] + beginBackgroundTaskWithName:@"GDTStorage" + expirationHandler:^{ + // End the background task if it's still valid. + [[GDTCORApplication sharedApplication] endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }]; + + dispatch_async(_storageQueue, ^{ + // Check that a backend implementation is available for this target. + GDTCORTarget target = event.target; + NSString *filePath = [GDTCORFlatFileStorage pathForTarget:target + eventID:event.eventID + qosTier:@(event.qosTier) + expirationDate:event.expirationDate + mappingID:event.mappingID]; + NSError *error; + NSData *encodedEvent = GDTCOREncodeArchive(event, nil, &error); + if (error) { + completion(NO, error); + return; + } + + // Check storage size limit before storing the event. + uint64_t resultingStorageSize = self.sizeTracker.directoryContentSize + encodedEvent.length; + if (resultingStorageSize > kGDTCORFlatFileStorageSizeLimit) { + NSError *error = [NSError + errorWithDomain:GDTCORFlatFileStorageErrorDomain + code:GDTCORFlatFileStorageErrorSizeLimitReached + userInfo:@{ + NSLocalizedFailureReasonErrorKey : @"Storage size limit has been reached." + }]; + completion(NO, error); + return; + } + + // Write the encoded event to the file. + BOOL writeResult = GDTCORWriteDataToFile(encodedEvent, filePath, &error); + if (writeResult == NO || error) { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@ error:%@", filePath, error); + completion(NO, error); + return; + } else { + GDTCORLogDebug(@"Writing archive succeeded: %@", filePath); + completion(YES, nil); + } + + // Notify size tracker. + [self.sizeTracker fileWasAddedAtPath:filePath withSize:encodedEvent.length]; + + // Check the QoS, if it's high priority, notify the target that it has a high priority event. + if (event.qosTier == GDTCOREventQoSFast) { + // TODO: Remove a direct dependency on the upload coordinator. + [self.uploadCoordinator forceUploadForTarget:target]; + } + + // Cancel or end the associated background task if it's still valid. + [[GDTCORApplication sharedApplication] endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }); +} + +- (void)batchWithEventSelector:(nonnull GDTCORStorageEventSelector *)eventSelector + batchExpiration:(nonnull NSDate *)expiration + onComplete: + (nonnull void (^)(NSNumber *_Nullable batchID, + NSSet *_Nullable events))onComplete { + dispatch_queue_t queue = _storageQueue; + void (^onPathsForTargetComplete)(NSNumber *, NSSet *_Nonnull) = ^( + NSNumber *batchID, NSSet *_Nonnull paths) { + dispatch_async(queue, ^{ + NSMutableSet *events = [[NSMutableSet alloc] init]; + for (NSString *eventPath in paths) { + NSError *error; + GDTCOREvent *event = + (GDTCOREvent *)GDTCORDecodeArchive([GDTCOREvent class], eventPath, nil, &error); + if (event == nil || error) { + GDTCORLogDebug(@"Error deserializing event: %@", error); + [[NSFileManager defaultManager] removeItemAtPath:eventPath error:nil]; + continue; + } else { + NSString *fileName = [eventPath lastPathComponent]; + NSString *batchPath = + [GDTCORFlatFileStorage batchPathForTarget:eventSelector.selectedTarget + batchID:batchID + expirationDate:expiration]; + [[NSFileManager defaultManager] createDirectoryAtPath:batchPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSString *destinationPath = [batchPath stringByAppendingPathComponent:fileName]; + error = nil; + [[NSFileManager defaultManager] moveItemAtPath:eventPath + toPath:destinationPath + error:&error]; + if (error) { + GDTCORLogDebug(@"An event file wasn't moveable into the batch directory: %@", error); + } + [events addObject:event]; + } + } + if (onComplete) { + if (events.count == 0) { + onComplete(nil, nil); + } else { + onComplete(batchID, events); + } + } + }); + }; + + void (^onBatchIDFetchComplete)(NSNumber *) = ^(NSNumber *batchID) { + dispatch_async(queue, ^{ + if (batchID == nil) { + if (onComplete) { + onComplete(nil, nil); + return; + } + } + [self pathsForTarget:eventSelector.selectedTarget + eventIDs:eventSelector.selectedEventIDs + qosTiers:eventSelector.selectedQosTiers + mappingIDs:eventSelector.selectedMappingIDs + onComplete:^(NSSet *_Nonnull paths) { + onPathsForTargetComplete(batchID, paths); + }]; + }); + }; + + [self nextBatchID:^(NSNumber *_Nullable batchID) { + if (batchID == nil) { + if (onComplete) { + onComplete(nil, nil); + } + } else { + onBatchIDFetchComplete(batchID); + } + }]; +} + +- (void)removeBatchWithID:(nonnull NSNumber *)batchID + deleteEvents:(BOOL)deleteEvents + onComplete:(void (^_Nullable)(void))onComplete { + dispatch_async(_storageQueue, ^{ + [self syncThreadUnsafeRemoveBatchWithID:batchID deleteEvents:deleteEvents]; + + if (onComplete) { + onComplete(); + } + }); +} + +- (void)batchIDsForTarget:(GDTCORTarget)target + onComplete:(nonnull void (^)(NSSet *_Nullable))onComplete { + dispatch_async(_storageQueue, ^{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error; + NSArray *batchPaths = + [fileManager contentsOfDirectoryAtPath:[GDTCORFlatFileStorage batchDataStoragePath] + error:&error]; + if (error || batchPaths.count == 0) { + if (onComplete) { + onComplete(nil); + } + return; + } + NSMutableSet *batchIDs = [[NSMutableSet alloc] init]; + for (NSString *path in batchPaths) { + NSDictionary *components = [self batchComponentsFromFilename:path]; + NSNumber *targetNumber = components[kGDTCORBatchComponentsTargetKey]; + NSNumber *batchID = components[kGDTCORBatchComponentsBatchIDKey]; + if (batchID != nil && targetNumber.intValue == target) { + [batchIDs addObject:batchID]; + } + } + if (onComplete) { + onComplete(batchIDs); + } + }); +} + +- (void)libraryDataForKey:(nonnull NSString *)key + onFetchComplete:(nonnull void (^)(NSData *_Nullable, NSError *_Nullable))onFetchComplete + setNewValue:(NSData *_Nullable (^_Nullable)(void))setValueBlock { + dispatch_async(_storageQueue, ^{ + NSString *dataPath = [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:key]; + NSError *error; + NSData *data = [NSData dataWithContentsOfFile:dataPath options:0 error:&error]; + if (onFetchComplete) { + onFetchComplete(data, error); + } + if (setValueBlock) { + NSData *newValue = setValueBlock(); + // The -isKindOfClass check is necessary because without an explicit 'return nil' in the block + // the implicit return value will be the block itself. The compiler doesn't detect this. + if (newValue != nil && [newValue isKindOfClass:[NSData class]] && newValue.length) { + NSError *newValueError; + if ([newValue writeToFile:dataPath options:NSDataWritingAtomic error:&newValueError]) { + // Update storage size. + [self.sizeTracker fileWasRemovedAtPath:dataPath withSize:data.length]; + [self.sizeTracker fileWasAddedAtPath:dataPath withSize:newValue.length]; + } else { + GDTCORLogDebug(@"Error writing new value in libraryDataForKey: %@", newValueError); + } + } + } + }); +} + +- (void)storeLibraryData:(NSData *)data + forKey:(nonnull NSString *)key + onComplete:(nullable void (^)(NSError *_Nullable error))onComplete { + if (!data || data.length <= 0) { + if (onComplete) { + onComplete([NSError errorWithDomain:NSInternalInconsistencyException code:-1 userInfo:nil]); + } + return; + } + dispatch_async(_storageQueue, ^{ + NSError *error; + NSString *dataPath = [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:key]; + if ([data writeToFile:dataPath options:NSDataWritingAtomic error:&error]) { + [self.sizeTracker fileWasAddedAtPath:dataPath withSize:data.length]; + } + if (onComplete) { + onComplete(error); + } + }); +} + +- (void)removeLibraryDataForKey:(nonnull NSString *)key + onComplete:(nonnull void (^)(NSError *_Nullable error))onComplete { + dispatch_async(_storageQueue, ^{ + NSError *error; + NSString *dataPath = [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:key]; + GDTCORStorageSizeBytes fileSize = + [self.sizeTracker fileSizeAtURL:[NSURL fileURLWithPath:dataPath]]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) { + if ([[NSFileManager defaultManager] removeItemAtPath:dataPath error:&error]) { + [self.sizeTracker fileWasRemovedAtPath:dataPath withSize:fileSize]; + } + if (onComplete) { + onComplete(error); + } + } + }); +} + +- (void)hasEventsForTarget:(GDTCORTarget)target onComplete:(void (^)(BOOL hasEvents))onComplete { + dispatch_async(_storageQueue, ^{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *targetPath = [NSString + stringWithFormat:@"%@/%ld", [GDTCORFlatFileStorage eventDataStoragePath], (long)target]; + [fileManager createDirectoryAtPath:targetPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:targetPath]; + BOOL hasEventAtLeastOneEvent = [enumerator nextObject] != nil; + if (onComplete) { + onComplete(hasEventAtLeastOneEvent); + } + }); +} + +- (void)checkForExpirations { + dispatch_async(_storageQueue, ^{ + GDTCORLogDebug(@"%@", @"Checking for expired events and batches"); + NSTimeInterval now = [NSDate date].timeIntervalSince1970; + NSFileManager *fileManager = [NSFileManager defaultManager]; + + // TODO: Storage may not have enough context to remove batches because a batch may be being + // uploaded but the storage has not context of it. + + // Find expired batches and move their events back to the main storage. + // If a batch contains expired events they are expected to be removed further in the method + // together with other expired events in the main storage. + NSString *batchDataPath = [GDTCORFlatFileStorage batchDataStoragePath]; + NSArray *batchDataPaths = [fileManager contentsOfDirectoryAtPath:batchDataPath + error:nil]; + for (NSString *path in batchDataPaths) { + @autoreleasepool { + NSString *fileName = [path lastPathComponent]; + NSDictionary *batchComponents = [self batchComponentsFromFilename:fileName]; + NSDate *expirationDate = batchComponents[kGDTCORBatchComponentsExpirationKey]; + NSNumber *batchID = batchComponents[kGDTCORBatchComponentsBatchIDKey]; + if (expirationDate != nil && expirationDate.timeIntervalSince1970 < now && batchID != nil) { + NSNumber *batchID = batchComponents[kGDTCORBatchComponentsBatchIDKey]; + // Move all events from the expired batch back to the main storage. + [self syncThreadUnsafeRemoveBatchWithID:batchID deleteEvents:NO]; + } + } + } + + // Find expired events and remove them from the storage. + NSString *eventDataPath = [GDTCORFlatFileStorage eventDataStoragePath]; + NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:eventDataPath]; + NSString *path; + + while (YES) { + @autoreleasepool { + // Call `[enumerator nextObject]` under autorelease pool to make sure all autoreleased + // objects created under the hood are released on each iteration end to avoid unnecessary + // memory growth. + path = [enumerator nextObject]; + if (path == nil) { + break; + } + + NSString *fileName = [path lastPathComponent]; + NSDictionary *eventComponents = [self eventComponentsFromFilename:fileName]; + NSDate *expirationDate = eventComponents[kGDTCOREventComponentsExpirationKey]; + if (expirationDate != nil && expirationDate.timeIntervalSince1970 < now) { + NSString *pathToDelete = [eventDataPath stringByAppendingPathComponent:path]; + NSError *error; + [fileManager removeItemAtPath:pathToDelete error:&error]; + if (error != nil) { + GDTCORLogDebug(@"There was an error deleting an expired item: %@", error); + } else { + GDTCORLogDebug(@"Item deleted because it expired: %@", pathToDelete); + } + } + } + } + + [self.sizeTracker resetCachedSize]; + }); +} + +- (void)storageSizeWithCallback:(void (^)(uint64_t storageSize))onComplete { + if (!onComplete) { + return; + } + + dispatch_async(_storageQueue, ^{ + onComplete([self.sizeTracker directoryContentSize]); + }); +} + +#pragma mark - Private not thread safe methods +/** Looks for directory paths containing events for a batch with the specified ID. + * @param batchID A batch ID. + * @param outError A pointer to `NSError *` to assign as possible error to. + * @return An array of an array of paths to directories for event batches with a specified batch ID + * or `nil` in the case of an error. Usually returns a single path but potentially return more in + * cases when the app is terminated while uploading a batch. + */ +- (nullable NSArray *)batchDirPathsForBatchID:(NSNumber *)batchID + error:(NSError **_Nonnull)outError { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error; + NSArray *batches = + [fileManager contentsOfDirectoryAtPath:[GDTCORFlatFileStorage batchDataStoragePath] + error:&error]; + if (batches == nil) { + *outError = error; + GDTCORLogDebug(@"Failed to find event file paths for batchID: %@, error: %@", batchID, error); + return nil; + } + + NSMutableArray *batchDirPaths = [NSMutableArray array]; + for (NSString *path in batches) { + NSDictionary *components = [self batchComponentsFromFilename:path]; + NSNumber *pathBatchID = components[kGDTCORBatchComponentsBatchIDKey]; + if ([pathBatchID isEqual:batchID]) { + NSString *batchDirPath = + [[GDTCORFlatFileStorage batchDataStoragePath] stringByAppendingPathComponent:path]; + [batchDirPaths addObject:batchDirPath]; + } + } + + return [batchDirPaths copy]; +} + +/** Makes a copy of the contents of a directory to a directory at the specified path.*/ +- (BOOL)moveContentsOfDirectoryAtPath:(NSString *)sourcePath + to:(NSString *)destinationPath + error:(NSError **_Nonnull)outError { + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSError *error; + NSArray *contentsPaths = [fileManager contentsOfDirectoryAtPath:sourcePath + error:&error]; + if (contentsPaths == nil) { + *outError = error; + return NO; + } + + NSMutableArray *errors = [NSMutableArray array]; + for (NSString *path in contentsPaths) { + NSString *contentDestinationPath = [destinationPath stringByAppendingPathComponent:path]; + NSString *contentSourcePath = [sourcePath stringByAppendingPathComponent:path]; + + NSError *moveError; + if (![fileManager moveItemAtPath:contentSourcePath + toPath:contentDestinationPath + error:&moveError] && + moveError) { + [errors addObject:moveError]; + } + } + + if (errors.count == 0) { + return YES; + } else { + NSError *combinedError = [NSError errorWithDomain:@"GDTCORFlatFileStorage" + code:-1 + userInfo:@{NSUnderlyingErrorKey : errors}]; + *outError = combinedError; + return NO; + } +} + +- (void)syncThreadUnsafeRemoveBatchWithID:(nonnull NSNumber *)batchID + deleteEvents:(BOOL)deleteEvents { + NSError *error; + NSArray *batchDirPaths = [self batchDirPathsForBatchID:batchID error:&error]; + + if (batchDirPaths == nil) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + + void (^removeBatchDir)(NSString *batchDirPath) = ^(NSString *batchDirPath) { + NSError *error; + if ([fileManager removeItemAtPath:batchDirPath error:&error]) { + GDTCORLogDebug(@"Batch removed at path: %@", batchDirPath); + } else { + GDTCORLogDebug(@"Failed to remove batch at path: %@", batchDirPath); + } + }; + + for (NSString *batchDirPath in batchDirPaths) { + @autoreleasepool { + if (deleteEvents) { + removeBatchDir(batchDirPath); + } else { + NSString *batchDirName = [batchDirPath lastPathComponent]; + NSDictionary *components = [self batchComponentsFromFilename:batchDirName]; + NSString *targetValue = [components[kGDTCORBatchComponentsTargetKey] stringValue]; + NSString *destinationPath; + if (targetValue) { + destinationPath = [[GDTCORFlatFileStorage eventDataStoragePath] + stringByAppendingPathComponent:targetValue]; + } + + // `- [NSFileManager moveItemAtPath:toPath:error:]` method fails if an item by the + // destination path already exists (which usually is the case for the current method). Move + // the events one by one instead. + if (destinationPath && [self moveContentsOfDirectoryAtPath:batchDirPath + to:destinationPath + error:&error]) { + GDTCORLogDebug(@"Batched events at path: %@ moved back to the storage: %@", batchDirPath, + destinationPath); + } else { + GDTCORLogDebug(@"Error encountered whilst moving events back: %@", error); + } + + // Even if not all events where moved back to the storage, there is not much can be done at + // this point, so cleanup batch directory now to avoid cluttering. + removeBatchDir(batchDirPath); + } + } + } + + [self.sizeTracker resetCachedSize]; +} + +#pragma mark - Private helper methods + ++ (NSString *)eventDataStoragePath { + static NSString *eventDataPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + eventDataPath = [NSString stringWithFormat:@"%@/%@/gdt_event_data", GDTCORRootDirectory().path, + NSStringFromClass([self class])]; + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:eventDataPath + withIntermediateDirectories:YES + attributes:0 + error:&error]; + GDTCORAssert(error == nil, @"Creating the library data path failed: %@", error); + return eventDataPath; +} + ++ (NSString *)batchDataStoragePath { + static NSString *batchDataPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + batchDataPath = [NSString stringWithFormat:@"%@/%@/gdt_batch_data", GDTCORRootDirectory().path, + NSStringFromClass([self class])]; + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:batchDataPath + withIntermediateDirectories:YES + attributes:0 + error:&error]; + GDTCORAssert(error == nil, @"Creating the batch data path failed: %@", error); + return batchDataPath; +} + ++ (NSString *)libraryDataStoragePath { + static NSString *libraryDataPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + libraryDataPath = + [NSString stringWithFormat:@"%@/%@/gdt_library_data", GDTCORRootDirectory().path, + NSStringFromClass([self class])]; + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:libraryDataPath + withIntermediateDirectories:YES + attributes:0 + error:&error]; + GDTCORAssert(error == nil, @"Creating the library data path failed: %@", error); + return libraryDataPath; +} + ++ (NSString *)batchPathForTarget:(GDTCORTarget)target + batchID:(NSNumber *)batchID + expirationDate:(NSDate *)expirationDate { + return + [NSString stringWithFormat:@"%@/%ld%@%@%@%llu", [GDTCORFlatFileStorage batchDataStoragePath], + (long)target, kMetadataSeparator, batchID, kMetadataSeparator, + ((uint64_t)expirationDate.timeIntervalSince1970)]; +} + ++ (NSString *)pathForTarget:(GDTCORTarget)target + eventID:(NSString *)eventID + qosTier:(NSNumber *)qosTier + expirationDate:(NSDate *)expirationDate + mappingID:(NSString *)mappingID { + NSMutableCharacterSet *allowedChars = [[NSCharacterSet alphanumericCharacterSet] mutableCopy]; + [allowedChars addCharactersInString:kMetadataSeparator]; + mappingID = [mappingID stringByAddingPercentEncodingWithAllowedCharacters:allowedChars]; + return [NSString stringWithFormat:@"%@/%ld/%@%@%@%@%llu%@%@", + [GDTCORFlatFileStorage eventDataStoragePath], (long)target, + eventID, kMetadataSeparator, qosTier, kMetadataSeparator, + ((uint64_t)expirationDate.timeIntervalSince1970), + kMetadataSeparator, mappingID]; +} + +- (void)pathsForTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + qosTiers:(nullable NSSet *)qosTiers + mappingIDs:(nullable NSSet *)mappingIDs + onComplete:(void (^)(NSSet *paths))onComplete { + void (^completion)(NSSet *) = onComplete == nil ? ^(NSSet *paths){} : onComplete; + dispatch_async(_storageQueue, ^{ + NSMutableSet *paths = [[NSMutableSet alloc] init]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *targetPath = [NSString + stringWithFormat:@"%@/%ld", [GDTCORFlatFileStorage eventDataStoragePath], (long)target]; + [fileManager createDirectoryAtPath:targetPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSError *error; + NSArray *dirPaths = [fileManager contentsOfDirectoryAtPath:targetPath error:&error]; + if (error) { + GDTCORLogDebug(@"There was an error reading the contents of the target path: %@", error); + completion(paths); + return; + } + BOOL checkingIDs = eventIDs.count > 0; + BOOL checkingQosTiers = qosTiers.count > 0; + BOOL checkingMappingIDs = mappingIDs.count > 0; + BOOL checkingAnything = checkingIDs == NO && checkingQosTiers == NO && checkingMappingIDs == NO; + for (NSString *path in dirPaths) { + // Skip hidden files that are created as part of atomic file creation. + if ([path hasPrefix:@"."]) { + continue; + } + NSString *filePath = [targetPath stringByAppendingPathComponent:path]; + if (checkingAnything) { + [paths addObject:filePath]; + continue; + } + NSString *filename = [path lastPathComponent]; + NSDictionary *eventComponents = [self eventComponentsFromFilename:filename]; + if (!eventComponents) { + GDTCORLogDebug(@"There was an error reading the filename components: %@", eventComponents); + continue; + } + NSString *eventID = eventComponents[kGDTCOREventComponentsEventIDKey]; + NSNumber *qosTier = eventComponents[kGDTCOREventComponentsQoSTierKey]; + NSString *mappingID = eventComponents[kGDTCOREventComponentsMappingIDKey]; + + NSNumber *eventIDMatch = checkingIDs ? @([eventIDs containsObject:eventID]) : nil; + NSNumber *qosTierMatch = checkingQosTiers ? @([qosTiers containsObject:qosTier]) : nil; + NSNumber *mappingIDMatch = + checkingMappingIDs + ? @([mappingIDs containsObject:[mappingID stringByRemovingPercentEncoding]]) + : nil; + if ((eventIDMatch == nil || eventIDMatch.boolValue) && + (qosTierMatch == nil || qosTierMatch.boolValue) && + (mappingIDMatch == nil || mappingIDMatch.boolValue)) { + [paths addObject:filePath]; + } + } + completion(paths); + }); +} + +- (void)nextBatchID:(void (^)(NSNumber *_Nullable batchID))nextBatchID { + __block int32_t lastBatchID = -1; + [self libraryDataForKey:gBatchIDCounterKey + onFetchComplete:^(NSData *_Nullable data, NSError *_Nullable getValueError) { + if (!getValueError) { + [data getBytes:(void *)&lastBatchID length:sizeof(int32_t)]; + } + if (data == nil) { + lastBatchID = 0; + } + if (nextBatchID) { + nextBatchID(@(lastBatchID)); + } + } + setNewValue:^NSData *_Nullable(void) { + if (lastBatchID != -1) { + int32_t incrementedValue = lastBatchID + 1; + return [NSData dataWithBytes:&incrementedValue length:sizeof(int32_t)]; + } + return nil; + }]; +} + +- (nullable NSDictionary *)eventComponentsFromFilename:(NSString *)fileName { + NSArray *components = [fileName componentsSeparatedByString:kMetadataSeparator]; + if (components.count >= 4) { + NSString *eventID = components[0]; + NSNumber *qosTier = @(components[1].integerValue); + NSDate *expirationDate = [NSDate dateWithTimeIntervalSince1970:components[2].longLongValue]; + NSString *mappingID = [[components subarrayWithRange:NSMakeRange(3, components.count - 3)] + componentsJoinedByString:kMetadataSeparator]; + if (eventID == nil || qosTier == nil || mappingID == nil || expirationDate == nil) { + GDTCORLogDebug(@"There was an error parsing the event filename components: %@", components); + return nil; + } + return @{ + kGDTCOREventComponentsEventIDKey : eventID, + kGDTCOREventComponentsQoSTierKey : qosTier, + kGDTCOREventComponentsExpirationKey : expirationDate, + kGDTCOREventComponentsMappingIDKey : mappingID + }; + } + GDTCORLogDebug(@"The event filename could not be split: %@", fileName); + return nil; +} + +- (nullable NSDictionary *)batchComponentsFromFilename:(NSString *)fileName { + NSArray *components = [fileName componentsSeparatedByString:kMetadataSeparator]; + if (components.count == 3) { + NSNumber *target = @(components[0].integerValue); + NSNumber *batchID = @(components[1].integerValue); + NSDate *expirationDate = [NSDate dateWithTimeIntervalSince1970:components[2].doubleValue]; + if (target == nil || batchID == nil || expirationDate == nil) { + GDTCORLogDebug(@"There was an error parsing the batch filename components: %@", components); + return nil; + } + return @{ + kGDTCORBatchComponentsTargetKey : target, + kGDTCORBatchComponentsBatchIDKey : batchID, + kGDTCORBatchComponentsExpirationKey : expirationDate + }; + } + GDTCORLogDebug(@"The batch filename could not be split: %@", fileName); + return nil; +} + +#pragma mark - GDTCORLifecycleProtocol + +- (void)appWillBackground:(GDTCORApplication *)app { + dispatch_async(_storageQueue, ^{ + // Immediately request a background task to run until the end of the current queue of work, + // and cancel it once the work is done. + __block GDTCORBackgroundIdentifier bgID = + [app beginBackgroundTaskWithName:@"GDTStorage" + expirationHandler:^{ + [app endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }]; + // End the background task if it's still valid. + [app endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }); +} + +- (void)appWillTerminate:(GDTCORApplication *)application { + dispatch_sync(_storageQueue, ^{ + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m new file mode 100644 index 0000000..89da75d --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m @@ -0,0 +1,119 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h" + +@implementation GDTCORLifecycle + ++ (void)load { + [self sharedInstance]; +} + +/** Creates/returns the singleton instance of this class. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance { + static GDTCORLifecycle *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCORLifecycle alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(applicationDidEnterBackground:) + name:kGDTCORApplicationDidEnterBackgroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(applicationWillEnterForeground:) + name:kGDTCORApplicationWillEnterForegroundNotification + object:nil]; + + NSString *name = kGDTCORApplicationWillTerminateNotification; + [notificationCenter addObserver:self + selector:@selector(applicationWillTerminate:) + name:name + object:nil]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)applicationDidEnterBackground:(NSNotification *)notification { + GDTCORApplication *application = [GDTCORApplication sharedApplication]; + if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillBackground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORTransformer that the app is backgrounding."); + [[GDTCORTransformer sharedInstance] appWillBackground:application]; + } + if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillBackground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORUploadCoordinator that the app is backgrounding."); + [[GDTCORUploadCoordinator sharedInstance] appWillBackground:application]; + } + if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillBackground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORRegistrar that the app is backgrounding."); + [[GDTCORRegistrar sharedInstance] appWillBackground:application]; + } +} + +- (void)applicationWillEnterForeground:(NSNotification *)notification { + GDTCORApplication *application = [GDTCORApplication sharedApplication]; + if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillForeground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORTransformer that the app is foregrounding."); + [[GDTCORTransformer sharedInstance] appWillForeground:application]; + } + if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillForeground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORUploadCoordinator that the app is foregrounding."); + [[GDTCORUploadCoordinator sharedInstance] appWillForeground:application]; + } + if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillForeground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORRegistrar that the app is foregrounding."); + [[GDTCORRegistrar sharedInstance] appWillForeground:application]; + } +} + +- (void)applicationWillTerminate:(NSNotification *)notification { + GDTCORApplication *application = [GDTCORApplication sharedApplication]; + if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORTransformer that the app is terminating."); + [[GDTCORTransformer sharedInstance] appWillTerminate:application]; + } + if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORUploadCoordinator that the app is terminating."); + [[GDTCORUploadCoordinator sharedInstance] appWillTerminate:application]; + } + if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORRegistrar that the app is terminating."); + [[GDTCORRegistrar sharedInstance] appWillTerminate:application]; + } +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m new file mode 100644 index 0000000..a6207ec --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m @@ -0,0 +1,604 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +#ifdef GDTCOR_VERSION +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x +NSString *const kGDTCORVersion = @STR(GDTCOR_VERSION); +#else +NSString *const kGDTCORVersion = @"Unknown"; +#endif // GDTCOR_VERSION + +const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid = 0; + +NSString *const kGDTCORApplicationDidEnterBackgroundNotification = + @"GDTCORApplicationDidEnterBackgroundNotification"; + +NSString *const kGDTCORApplicationWillEnterForegroundNotification = + @"GDTCORApplicationWillEnterForegroundNotification"; + +NSString *const kGDTCORApplicationWillTerminateNotification = + @"GDTCORApplicationWillTerminateNotification"; + +NSURL *GDTCORRootDirectory(void) { + static NSURL *GDTPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *cachePath = + NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; + GDTPath = + [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/google-sdks-events", cachePath]]; + GDTCORLogDebug(@"GDT's state will be saved to: %@", GDTPath); + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:GDTPath.path + withIntermediateDirectories:YES + attributes:nil + error:&error]; + GDTCORAssert(error == nil, @"There was an error creating GDT's path"); + return GDTPath; +} + +BOOL GDTCORReachabilityFlagsReachable(GDTCORNetworkReachabilityFlags flags) { +#if !TARGET_OS_WATCH + BOOL reachable = + (flags & kSCNetworkReachabilityFlagsReachable) == kSCNetworkReachabilityFlagsReachable; + BOOL connectionRequired = (flags & kSCNetworkReachabilityFlagsConnectionRequired) == + kSCNetworkReachabilityFlagsConnectionRequired; + return reachable && !connectionRequired; +#else + return (flags & kGDTCORNetworkReachabilityFlagsReachable) == + kGDTCORNetworkReachabilityFlagsReachable; +#endif +} + +BOOL GDTCORReachabilityFlagsContainWWAN(GDTCORNetworkReachabilityFlags flags) { +#if TARGET_OS_IOS + return (flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN; +#else + // Assume network connection not WWAN on macOS, tvOS, watchOS. + return NO; +#endif // TARGET_OS_IOS +} + +GDTCORNetworkType GDTCORNetworkTypeMessage() { +#if !TARGET_OS_WATCH + SCNetworkReachabilityFlags reachabilityFlags = [GDTCORReachability currentFlags]; + if ((reachabilityFlags & kSCNetworkReachabilityFlagsReachable) == + kSCNetworkReachabilityFlagsReachable) { + if (GDTCORReachabilityFlagsContainWWAN(reachabilityFlags)) { + return GDTCORNetworkTypeMobile; + } else { + return GDTCORNetworkTypeWIFI; + } + } +#endif + return GDTCORNetworkTypeUNKNOWN; +} + +GDTCORNetworkMobileSubtype GDTCORNetworkMobileSubTypeMessage() { +#if TARGET_OS_IOS + static NSDictionary *CTRadioAccessTechnologyToNetworkSubTypeMessage; + static CTTelephonyNetworkInfo *networkInfo; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + CTRadioAccessTechnologyToNetworkSubTypeMessage = @{ + CTRadioAccessTechnologyGPRS : @(GDTCORNetworkMobileSubtypeGPRS), + CTRadioAccessTechnologyEdge : @(GDTCORNetworkMobileSubtypeEdge), + CTRadioAccessTechnologyWCDMA : @(GDTCORNetworkMobileSubtypeWCDMA), + CTRadioAccessTechnologyHSDPA : @(GDTCORNetworkMobileSubtypeHSDPA), + CTRadioAccessTechnologyHSUPA : @(GDTCORNetworkMobileSubtypeHSUPA), + CTRadioAccessTechnologyCDMA1x : @(GDTCORNetworkMobileSubtypeCDMA1x), + CTRadioAccessTechnologyCDMAEVDORev0 : @(GDTCORNetworkMobileSubtypeCDMAEVDORev0), + CTRadioAccessTechnologyCDMAEVDORevA : @(GDTCORNetworkMobileSubtypeCDMAEVDORevA), + CTRadioAccessTechnologyCDMAEVDORevB : @(GDTCORNetworkMobileSubtypeCDMAEVDORevB), + CTRadioAccessTechnologyeHRPD : @(GDTCORNetworkMobileSubtypeHRPD), + CTRadioAccessTechnologyLTE : @(GDTCORNetworkMobileSubtypeLTE), + }; + networkInfo = [[CTTelephonyNetworkInfo alloc] init]; + }); + NSString *networkCurrentRadioAccessTechnology; +#if TARGET_OS_MACCATALYST + NSDictionary *networkCurrentRadioAccessTechnologyDict = + networkInfo.serviceCurrentRadioAccessTechnology; + if (networkCurrentRadioAccessTechnologyDict.count) { + networkCurrentRadioAccessTechnology = networkCurrentRadioAccessTechnologyDict.allValues[0]; + } +#else // TARGET_OS_MACCATALYST + if (@available(iOS 12.0, *)) { + NSDictionary *networkCurrentRadioAccessTechnologyDict = + networkInfo.serviceCurrentRadioAccessTechnology; + if (networkCurrentRadioAccessTechnologyDict.count) { + // In iOS 12, multiple radio technologies can be captured. We prefer not particular radio + // tech to another, so we'll just return the first value in the dictionary. + networkCurrentRadioAccessTechnology = networkCurrentRadioAccessTechnologyDict.allValues[0]; + } + } else { +#if TARGET_OS_IOS && __IPHONE_OS_VERSION_MIN_REQUIRED < 120000 + networkCurrentRadioAccessTechnology = networkInfo.currentRadioAccessTechnology; +#endif // TARGET_OS_IOS && __IPHONE_OS_VERSION_MIN_REQUIRED < 120000 + } +#endif // TARGET_OS_MACCATALYST + if (networkCurrentRadioAccessTechnology) { + NSNumber *networkMobileSubtype = + CTRadioAccessTechnologyToNetworkSubTypeMessage[networkCurrentRadioAccessTechnology]; + return networkMobileSubtype.intValue; + } else { + return GDTCORNetworkMobileSubtypeUNKNOWN; + } +#else // TARGET_OS_IOS + return GDTCORNetworkMobileSubtypeUNKNOWN; +#endif // TARGET_OS_IOS +} + +NSString *_Nonnull GDTCORDeviceModel() { + static NSString *deviceModel = @"Unknown"; + +#if TARGET_OS_IOS || TARGET_OS_TV + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + size_t size; + char *keyToExtract = "hw.machine"; + sysctlbyname(keyToExtract, NULL, &size, NULL, 0); + if (size > 0) { + char *machine = calloc(1, size); + sysctlbyname(keyToExtract, machine, &size, NULL, 0); + deviceModel = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding]; + free(machine); + } else { + deviceModel = [UIDevice currentDevice].model; + } + }); +#endif + + return deviceModel; +} + +NSData *_Nullable GDTCOREncodeArchive(id obj, + NSString *filePath, + NSError *_Nullable *error) { + BOOL result = NO; + if (filePath.length > 0) { + result = [[NSFileManager defaultManager] + createDirectoryAtPath:[filePath stringByDeletingLastPathComponent] + withIntermediateDirectories:YES + attributes:nil + error:error]; + if (result == NO || *error) { + GDTCORLogDebug(@"Attempt to create directory failed: path:%@ error:%@", filePath, *error); + return nil; + } + } + NSData *resultData; + if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4, *)) { + resultData = [NSKeyedArchiver archivedDataWithRootObject:obj + requiringSecureCoding:YES + error:error]; + if (resultData == nil || (error != NULL && *error != nil)) { + GDTCORLogDebug(@"Encoding an object failed: %@", *error); + return nil; + } + if (filePath.length > 0) { + result = [resultData writeToFile:filePath options:NSDataWritingAtomic error:error]; + if (result == NO || *error) { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@ error:%@", filePath, *error); + } else { + GDTCORLogDebug(@"Writing archive succeeded: %@", filePath); + } + } + } else { + @try { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + resultData = [NSKeyedArchiver archivedDataWithRootObject:obj]; +#pragma clang diagnostic pop + if (filePath.length > 0) { + result = [resultData writeToFile:filePath options:NSDataWritingAtomic error:error]; + if (result == NO || *error) { + GDTCORLogDebug(@"Attempt to write archive failed: URL:%@ error:%@", filePath, *error); + } else { + GDTCORLogDebug(@"Writing archive succeeded: %@", filePath); + } + } + } @catch (NSException *exception) { + NSString *errorString = + [NSString stringWithFormat:@"An exception was thrown during encoding: %@", exception]; + *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:-1 + userInfo:@{NSLocalizedFailureReasonErrorKey : errorString}]; + } + if (filePath.length > 0) { + GDTCORLogDebug(@"Attempt to write archive. successful:%@ URL:%@ error:%@", + result ? @"YES" : @"NO", filePath, *error); + } + } + return resultData; +} + +id _Nullable GDTCORDecodeArchive(Class archiveClass, + NSString *_Nullable archivePath, + NSData *_Nullable archiveData, + NSError *_Nullable *error) { + id unarchivedObject = nil; + if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4, *)) { + NSData *data = archiveData ? archiveData : [NSData dataWithContentsOfFile:archivePath]; + if (data) { + unarchivedObject = [NSKeyedUnarchiver unarchivedObjectOfClass:archiveClass + fromData:data + error:error]; + } + } else { + @try { + NSData *archivedData = + archiveData ? archiveData : [NSData dataWithContentsOfFile:archivePath]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + unarchivedObject = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData]; +#pragma clang diagnostic pop + } @catch (NSException *exception) { + NSString *errorString = + [NSString stringWithFormat:@"An exception was thrown during encoding: %@", exception]; + *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:-1 + userInfo:@{NSLocalizedFailureReasonErrorKey : errorString}]; + } + } + return unarchivedObject; +} + +BOOL GDTCORWriteDataToFile(NSData *data, NSString *filePath, NSError *_Nullable *outError) { + BOOL result = NO; + if (filePath.length > 0) { + result = [[NSFileManager defaultManager] + createDirectoryAtPath:[filePath stringByDeletingLastPathComponent] + withIntermediateDirectories:YES + attributes:nil + error:outError]; + if (result == NO || *outError) { + GDTCORLogDebug(@"Attempt to create directory failed: path:%@ error:%@", filePath, *outError); + return result; + } + } + + if (filePath.length > 0) { + result = [data writeToFile:filePath options:NSDataWritingAtomic error:outError]; + if (result == NO || *outError) { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@ error:%@", filePath, *outError); + } else { + GDTCORLogDebug(@"Writing archive succeeded: %@", filePath); + } + } + + return result; +} + +@interface GDTCORApplication () +/** + Private flag to match the existing `readonly` public flag. This will be accurate for all platforms, + since we handle each platform's lifecycle notifications separately. + */ +@property(atomic, readwrite) BOOL isRunningInBackground; + +@end + +@implementation GDTCORApplication + +#if TARGET_OS_WATCH +/** A dispatch queue on which all task semaphores will populate and remove from + * gBackgroundIdentifierToSemaphoreMap. + */ +static dispatch_queue_t gSemaphoreQueue; + +/** For mapping backgroundIdentifier to task semaphore. */ +static NSMutableDictionary *gBackgroundIdentifierToSemaphoreMap; +#endif + ++ (void)load { + GDTCORLogDebug( + @"%@", @"GDT is initializing. Please note that if you quit the app via the " + "debugger and not through a lifecycle event, event data will remain on disk but " + "storage won't have a reference to them since the singleton wasn't saved to disk."); +#if TARGET_OS_IOS || TARGET_OS_TV + // If this asserts, please file a bug at https://github.com/firebase/firebase-ios-sdk/issues. + GDTCORFatalAssert( + GDTCORBackgroundIdentifierInvalid == UIBackgroundTaskInvalid, + @"GDTCORBackgroundIdentifierInvalid and UIBackgroundTaskInvalid should be the same."); +#endif + [self sharedApplication]; +} + ++ (void)initialize { +#if TARGET_OS_WATCH + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gSemaphoreQueue = dispatch_queue_create("com.google.GDTCORApplication", DISPATCH_QUEUE_SERIAL); + GDTCORLogDebug( + @"%@", + @"GDTCORApplication is initializing on watchOS, gSemaphoreQueue has been initialized."); + gBackgroundIdentifierToSemaphoreMap = [[NSMutableDictionary alloc] init]; + GDTCORLogDebug(@"%@", @"GDTCORApplication is initializing on watchOS, " + @"gBackgroundIdentifierToSemaphoreMap has been initialized."); + }); +#endif +} + ++ (nullable GDTCORApplication *)sharedApplication { + static GDTCORApplication *application; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + application = [[GDTCORApplication alloc] init]; + }); + return application; +} + +- (instancetype)init { + self = [super init]; + if (self) { + // This class will be instantiated in the foreground. + _isRunningInBackground = NO; + +#if TARGET_OS_IOS || TARGET_OS_TV + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + + NSString *name = UIApplicationWillTerminateNotification; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillTerminate:) + name:name + object:nil]; + +#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 + if (@available(iOS 13, tvOS 13.0, *)) { + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:UISceneWillEnterForegroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:UISceneWillDeactivateNotification + object:nil]; + } +#endif // defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 + +#elif TARGET_OS_OSX + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(macOSApplicationWillTerminate:) + name:NSApplicationWillTerminateNotification + object:nil]; + +#elif TARGET_OS_WATCH + // TODO: Notification on watchOS platform is currently posted by strings which are frangible. + // TODO: Needs improvements here. + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:@"UIApplicationDidEnterBackgroundNotification" + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:@"UIApplicationWillEnterForegroundNotification" + object:nil]; + + // Adds observers for app extension on watchOS platform + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:NSExtensionHostDidEnterBackgroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:NSExtensionHostWillEnterForegroundNotification + object:nil]; +#endif + } + return self; +} + +#if TARGET_OS_WATCH +/** Generates and maps a unique background identifier to the given semaphore. + * + * @param semaphore The semaphore to map. + * @return A unique GDTCORBackgroundIdentifier mapped to the given semaphore. + */ ++ (GDTCORBackgroundIdentifier)createAndMapBackgroundIdentifierToSemaphore: + (dispatch_semaphore_t)semaphore { + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; + dispatch_queue_t queue = gSemaphoreQueue; + NSMutableDictionary *map = gBackgroundIdentifierToSemaphoreMap; + if (queue && map) { + dispatch_sync(queue, ^{ + bgID = arc4random(); + NSNumber *bgIDNumber = @(bgID); + while (bgID == GDTCORBackgroundIdentifierInvalid || map[bgIDNumber]) { + bgID = arc4random(); + bgIDNumber = @(bgID); + } + map[bgIDNumber] = semaphore; + }); + } + return bgID; +} + +/** Returns the semaphore mapped to given bgID and removes the value from the map. + * + * @param bgID The unique NSUInteger as GDTCORBackgroundIdentifier. + * @return The semaphore mapped by given bgID. + */ ++ (dispatch_semaphore_t)semaphoreForBackgroundIdentifier:(GDTCORBackgroundIdentifier)bgID { + __block dispatch_semaphore_t semaphore; + dispatch_queue_t queue = gSemaphoreQueue; + NSMutableDictionary *map = gBackgroundIdentifierToSemaphoreMap; + NSNumber *bgIDNumber = @(bgID); + if (queue && map) { + dispatch_sync(queue, ^{ + semaphore = map[bgIDNumber]; + [map removeObjectForKey:bgIDNumber]; + }); + } + return semaphore; +} +#endif + +- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name + expirationHandler:(void (^)(void))handler { + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; +#if !TARGET_OS_WATCH + bgID = [[self sharedApplicationForBackgroundTask] beginBackgroundTaskWithName:name + expirationHandler:handler]; +#if !NDEBUG + if (bgID != GDTCORBackgroundIdentifierInvalid) { + GDTCORLogDebug(@"Creating background task with name:%@ bgID:%ld", name, (long)bgID); + } +#endif // !NDEBUG +#elif TARGET_OS_WATCH + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + bgID = [GDTCORApplication createAndMapBackgroundIdentifierToSemaphore:semaphore]; + if (bgID != GDTCORBackgroundIdentifierInvalid) { + GDTCORLogDebug(@"Creating activity with name:%@ bgID:%ld on watchOS.", name, (long)bgID); + } + [[self sharedNSProcessInfoForBackgroundTask] + performExpiringActivityWithReason:name + usingBlock:^(BOOL expired) { + if (expired) { + if (handler) { + handler(); + } + dispatch_semaphore_signal(semaphore); + GDTCORLogDebug( + @"Activity with name:%@ bgID:%ld on watchOS is expiring.", + name, (long)bgID); + } else { + dispatch_semaphore_wait( + semaphore, + dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC)); + } + }]; +#endif + return bgID; +} + +- (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID { +#if !TARGET_OS_WATCH + if (bgID != GDTCORBackgroundIdentifierInvalid) { + GDTCORLogDebug(@"Ending background task with ID:%ld was successful", (long)bgID); + [[self sharedApplicationForBackgroundTask] endBackgroundTask:bgID]; + return; + } +#elif TARGET_OS_WATCH + if (bgID != GDTCORBackgroundIdentifierInvalid) { + dispatch_semaphore_t semaphore = [GDTCORApplication semaphoreForBackgroundIdentifier:bgID]; + GDTCORLogDebug(@"Ending activity with bgID:%ld on watchOS.", (long)bgID); + if (semaphore) { + dispatch_semaphore_signal(semaphore); + GDTCORLogDebug(@"Signaling semaphore with bgID:%ld on watchOS.", (long)bgID); + } else { + GDTCORLogDebug(@"Semaphore with bgID:%ld is nil on watchOS.", (long)bgID); + } + } +#endif // !TARGET_OS_WATCH +} + +#pragma mark - App environment helpers + +- (BOOL)isAppExtension { + BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + return appExtension; +} + +/** Returns a UIApplication or NSProcessInfo instance if on the appropriate platform. + * + * @return The shared UIApplication or NSProcessInfo if on the appropriate platform. + */ +#if TARGET_OS_IOS || TARGET_OS_TV +- (nullable UIApplication *)sharedApplicationForBackgroundTask { +#elif TARGET_OS_WATCH +- (nullable NSProcessInfo *)sharedNSProcessInfoForBackgroundTask { +#else +- (nullable id)sharedApplicationForBackgroundTask { +#endif + id sharedInstance = nil; +#if TARGET_OS_IOS || TARGET_OS_TV + if (![self isAppExtension]) { + Class uiApplicationClass = NSClassFromString(@"UIApplication"); + if (uiApplicationClass && + [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) { + sharedInstance = [uiApplicationClass sharedApplication]; + } + } +#elif TARGET_OS_WATCH + sharedInstance = [NSProcessInfo processInfo]; +#endif + return sharedInstance; +} + +#pragma mark - UIApplicationDelegate and WKExtensionDelegate + +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH +- (void)iOSApplicationDidEnterBackground:(NSNotification *)notif { + _isRunningInBackground = YES; + + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is backgrounding."); + [notifCenter postNotificationName:kGDTCORApplicationDidEnterBackgroundNotification object:nil]; +} + +- (void)iOSApplicationWillEnterForeground:(NSNotification *)notif { + _isRunningInBackground = NO; + + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is foregrounding."); + [notifCenter postNotificationName:kGDTCORApplicationWillEnterForegroundNotification object:nil]; +} +#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + +#pragma mark - UIApplicationDelegate + +#if TARGET_OS_IOS || TARGET_OS_TV +- (void)iOSApplicationWillTerminate:(NSNotification *)notif { + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is terminating."); + [notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil]; +} +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#pragma mark - NSApplicationDelegate + +#if TARGET_OS_OSX +- (void)macOSApplicationWillTerminate:(NSNotification *)notif { + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is terminating."); + [notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil]; +} +#endif // TARGET_OS_OSX + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m new file mode 100644 index 0000000..43811e6 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m @@ -0,0 +1,125 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import + +/** Sets the _callbackFlag ivar whenever the network changes. + * + * @param reachability The reachability object calling back. + * @param flags The new flag values. + * @param info Any data that might be passed in by the callback. + */ +static void GDTCORReachabilityCallback(GDTCORNetworkReachabilityRef reachability, + GDTCORNetworkReachabilityFlags flags, + void *info); + +@implementation GDTCORReachability { + /** The reachability object. */ + GDTCORNetworkReachabilityRef _reachabilityRef; + + /** The queue on which callbacks and all work will occur. */ + dispatch_queue_t _reachabilityQueue; + + /** Flags specified by reachability callbacks. */ + GDTCORNetworkReachabilityFlags _callbackFlags; +} + ++ (void)initialize { + [self sharedInstance]; +} + ++ (instancetype)sharedInstance { + static GDTCORReachability *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCORReachability alloc] init]; + }); + return sharedInstance; +} + ++ (GDTCORNetworkReachabilityFlags)currentFlags { + __block GDTCORNetworkReachabilityFlags currentFlags; +#if !TARGET_OS_WATCH + dispatch_sync([GDTCORReachability sharedInstance] -> _reachabilityQueue, ^{ + GDTCORReachability *reachability = [GDTCORReachability sharedInstance]; + currentFlags = + reachability->_callbackFlags ? reachability->_callbackFlags : reachability->_flags; + GDTCORLogDebug(@"Initial reachability flags determined: %d", currentFlags); + }); +#else + currentFlags = kGDTCORNetworkReachabilityFlagsReachable; +#endif + return currentFlags; +} + +- (instancetype)init { + self = [super init]; +#if !TARGET_OS_WATCH + if (self) { + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + + _reachabilityQueue = + dispatch_queue_create("com.google.GDTCORReachability", DISPATCH_QUEUE_SERIAL); + _reachabilityRef = SCNetworkReachabilityCreateWithAddress( + kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress); + Boolean success = SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, _reachabilityQueue); + if (!success) { + GDTCORLogWarning(GDTCORMCWReachabilityFailed, @"%@", @"The reachability queue wasn't set."); + } + success = SCNetworkReachabilitySetCallback(_reachabilityRef, GDTCORReachabilityCallback, NULL); + if (!success) { + GDTCORLogWarning(GDTCORMCWReachabilityFailed, @"%@", + @"The reachability callback wasn't set."); + } + + // Get the initial set of flags. + dispatch_async(_reachabilityQueue, ^{ + Boolean valid = SCNetworkReachabilityGetFlags(self->_reachabilityRef, &self->_flags); + if (!valid) { + GDTCORLogDebug(@"%@", @"Determining reachability failed."); + self->_flags = 0; + } + }); + } +#endif + return self; +} + +- (void)setCallbackFlags:(GDTCORNetworkReachabilityFlags)flags { + if (_callbackFlags != flags) { + self->_callbackFlags = flags; + } +} + +@end + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +static void GDTCORReachabilityCallback(GDTCORNetworkReachabilityRef reachability, + GDTCORNetworkReachabilityFlags flags, + void *info) { +#pragma clang diagnostic pop + GDTCORLogDebug(@"Reachability changed, new flags: %d", flags); + [[GDTCORReachability sharedInstance] setCallbackFlags:flags]; +} diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m new file mode 100644 index 0000000..d7e9b09 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m @@ -0,0 +1,157 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +id _Nullable GDTCORStorageInstanceForTarget(GDTCORTarget target) { + return [GDTCORRegistrar sharedInstance].targetToStorage[@(target)]; +} + +FOUNDATION_EXPORT +id _Nullable GDTCORStoragePromiseInstanceForTarget( + GDTCORTarget target) { + id storage = [GDTCORRegistrar sharedInstance].targetToStorage[@(target)]; + if ([storage conformsToProtocol:@protocol(GDTCORStoragePromiseProtocol)]) { + return storage; + } else { + return nil; + } +} + +@implementation GDTCORRegistrar { + /** Backing ivar for targetToUploader property. */ + NSMutableDictionary> *_targetToUploader; + + /** Backing ivar for targetToStorage property. */ + NSMutableDictionary> *_targetToStorage; +} + ++ (instancetype)sharedInstance { + static GDTCORRegistrar *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCORRegistrar alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _registrarQueue = dispatch_queue_create("com.google.GDTCORRegistrar", DISPATCH_QUEUE_SERIAL); + _targetToUploader = [[NSMutableDictionary alloc] init]; + _targetToStorage = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)registerUploader:(id)backend target:(GDTCORTarget)target { + __weak GDTCORRegistrar *weakSelf = self; + dispatch_async(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + GDTCORLogDebug(@"Registered an uploader: %@ for target:%ld", backend, (long)target); + strongSelf->_targetToUploader[@(target)] = backend; + } + }); +} + +- (void)registerStorage:(id)storage target:(GDTCORTarget)target { + __weak GDTCORRegistrar *weakSelf = self; + dispatch_async(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + GDTCORLogDebug(@"Registered storage: %@ for target:%ld", storage, (long)target); + strongSelf->_targetToStorage[@(target)] = storage; + } + }); +} + +- (NSMutableDictionary> *)targetToUploader { + __block NSMutableDictionary> *targetToUploader; + __weak GDTCORRegistrar *weakSelf = self; + dispatch_sync(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + targetToUploader = strongSelf->_targetToUploader; + } + }); + return targetToUploader; +} + +- (NSMutableDictionary> *)targetToStorage { + __block NSMutableDictionary> *targetToStorage; + __weak GDTCORRegistrar *weakSelf = self; + dispatch_sync(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + targetToStorage = strongSelf->_targetToStorage; + } + }); + return targetToStorage; +} + +#pragma mark - GDTCORLifecycleProtocol + +- (void)appWillBackground:(nonnull GDTCORApplication *)app { + NSArray> *uploaders = [self.targetToUploader allValues]; + for (id uploader in uploaders) { + if ([uploader respondsToSelector:@selector(appWillBackground:)]) { + [uploader appWillBackground:app]; + } + } + NSArray> *storages = [self.targetToStorage allValues]; + for (id storage in storages) { + if ([storage respondsToSelector:@selector(appWillBackground:)]) { + [storage appWillBackground:app]; + } + } +} + +- (void)appWillForeground:(nonnull GDTCORApplication *)app { + NSArray> *uploaders = [self.targetToUploader allValues]; + for (id uploader in uploaders) { + if ([uploader respondsToSelector:@selector(appWillForeground:)]) { + [uploader appWillForeground:app]; + } + } + NSArray> *storages = [self.targetToStorage allValues]; + for (id storage in storages) { + if ([storage respondsToSelector:@selector(appWillForeground:)]) { + [storage appWillForeground:app]; + } + } +} + +- (void)appWillTerminate:(nonnull GDTCORApplication *)app { + NSArray> *uploaders = [self.targetToUploader allValues]; + for (id uploader in uploaders) { + if ([uploader respondsToSelector:@selector(appWillTerminate:)]) { + [uploader appWillTerminate:app]; + } + } + NSArray> *storages = [self.targetToStorage allValues]; + for (id storage in storages) { + if ([storage respondsToSelector:@selector(appWillTerminate:)]) { + [storage appWillTerminate:app]; + } + } +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m new file mode 100644 index 0000000..30915da --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" + +@implementation GDTCORStorageEventSelector + ++ (instancetype)eventSelectorForTarget:(GDTCORTarget)target { + return [[self alloc] initWithTarget:target eventIDs:nil mappingIDs:nil qosTiers:nil]; +} + +- (instancetype)initWithTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + mappingIDs:(nullable NSSet *)mappingIDs + qosTiers:(nullable NSSet *)qosTiers { + self = [super init]; + if (self) { + _selectedTarget = target; + _selectedEventIDs = eventIDs; + _selectedMappingIDs = mappingIDs; + _selectedQosTiers = qosTiers; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m new file mode 100644 index 0000000..b6d0249 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m @@ -0,0 +1,111 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +@implementation GDTCORTransformer + ++ (instancetype)sharedInstance { + static GDTCORTransformer *eventTransformer; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + eventTransformer = [[self alloc] init]; + }); + return eventTransformer; +} + +- (instancetype)init { + return [self initWithApplication:[GDTCORApplication sharedApplication]]; +} + +- (instancetype)initWithApplication:(id)application { + self = [super init]; + if (self) { + _eventWritingQueue = + dispatch_queue_create("com.google.GDTCORTransformer", DISPATCH_QUEUE_SERIAL); + _application = application; + } + return self; +} + +- (void)transformEvent:(GDTCOREvent *)event + withTransformers:(NSArray> *)transformers + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + GDTCORAssert(event, @"You can't write a nil event"); + + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; + __auto_type __weak weakApplication = self.application; + bgID = [self.application beginBackgroundTaskWithName:@"GDTTransformer" + expirationHandler:^{ + [weakApplication endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }]; + + __auto_type completionWrapper = ^(BOOL wasWritten, NSError *_Nullable error) { + if (completion) { + completion(wasWritten, error); + } + + // The work is done, cancel the background task if it's valid. + [weakApplication endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }; + + dispatch_async(_eventWritingQueue, ^{ + GDTCOREvent *transformedEvent = event; + for (id transformer in transformers) { + if ([transformer respondsToSelector:@selector(transformGDTEvent:)]) { + GDTCORLogDebug(@"Applying a transformer to event %@", event); + transformedEvent = [transformer transformGDTEvent:event]; + if (!transformedEvent) { + completionWrapper(NO, nil); + return; + } + } else { + GDTCORLogError(GDTCORMCETransformerDoesntImplementTransform, + @"Transformer doesn't implement transformGDTEvent: %@", transformer); + completionWrapper(NO, nil); + return; + } + } + + id storage = + [GDTCORRegistrar sharedInstance].targetToStorage[@(event.target)]; + + [storage storeEvent:transformedEvent onComplete:completionWrapper]; + }); +} + +#pragma mark - GDTCORLifecycleProtocol + +- (void)appWillTerminate:(GDTCORApplication *)application { + // Flush the queue immediately. + dispatch_sync(_eventWritingQueue, ^{ + }); +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m new file mode 100644 index 0000000..1db4d52 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m @@ -0,0 +1,92 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h" + +@implementation GDTCORTransport + +- (nullable instancetype)initWithMappingID:(NSString *)mappingID + transformers: + (nullable NSArray> *)transformers + target:(GDTCORTarget)target { + GDTCORAssert(mappingID.length > 0, @"A mapping ID cannot be nil or empty"); + GDTCORAssert(target > 0, @"A target cannot be negative or 0"); + if (mappingID == nil || mappingID.length == 0 || target <= 0) { + return nil; + } + self = [super init]; + if (self) { + _mappingID = mappingID; + _transformers = transformers; + _target = target; + _transformerInstance = [GDTCORTransformer sharedInstance]; + } + GDTCORLogDebug(@"Transport object created. mappingID:%@ transformers:%@ target:%ld", mappingID, + transformers, (long)target); + return self; +} + +- (void)sendTelemetryEvent:(GDTCOREvent *)event + onComplete: + (void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + event.qosTier = GDTCOREventQoSTelemetry; + [self sendEvent:event onComplete:completion]; +} + +- (void)sendDataEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + GDTCORAssert(event.qosTier != GDTCOREventQoSTelemetry, @"Use -sendTelemetryEvent, please."); + [self sendEvent:event onComplete:completion]; +} + +- (void)sendTelemetryEvent:(GDTCOREvent *)event { + [self sendTelemetryEvent:event onComplete:nil]; +} + +- (void)sendDataEvent:(GDTCOREvent *)event { + [self sendDataEvent:event onComplete:nil]; +} + +- (GDTCOREvent *)eventForTransport { + return [[GDTCOREvent alloc] initWithMappingID:_mappingID target:_target]; +} + +#pragma mark - Private helper methods + +/** Sends the given event through the transport pipeline. + * + * @param event The event to send. + * @param completion A block that will be called when the event has been written or dropped. + */ +- (void)sendEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + // TODO: Determine if sending an event before registration is allowed. + GDTCORAssert(event, @"You can't send a nil event"); + GDTCOREvent *copiedEvent = [event copy]; + copiedEvent.clockSnapshot = [GDTCORClock snapshot]; + [self.transformerInstance transformEvent:copiedEvent + withTransformers:_transformers + onComplete:completion]; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m new file mode 100644 index 0000000..7d2abe2 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h" + +@implementation GDTCORUploadBatch + +- (instancetype)initWithBatchID:(NSNumber *)batchID events:(NSSet *)events { + self = [super init]; + if (self) { + _batchID = batchID; + _events = events; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m new file mode 100644 index 0000000..3357fbe --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m @@ -0,0 +1,176 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +@implementation GDTCORUploadCoordinator + ++ (instancetype)sharedInstance { + static GDTCORUploadCoordinator *sharedUploader; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedUploader = [[GDTCORUploadCoordinator alloc] init]; + [sharedUploader startTimer]; + }); + return sharedUploader; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _coordinationQueue = + dispatch_queue_create("com.google.GDTCORUploadCoordinator", DISPATCH_QUEUE_SERIAL); + _registrar = [GDTCORRegistrar sharedInstance]; + _timerInterval = 30 * NSEC_PER_SEC; + _timerLeeway = 5 * NSEC_PER_SEC; + } + return self; +} + +- (void)forceUploadForTarget:(GDTCORTarget)target { + dispatch_async(_coordinationQueue, ^{ + GDTCORLogDebug(@"Forcing an upload of target %ld", (long)target); + GDTCORUploadConditions conditions = [self uploadConditions]; + conditions |= GDTCORUploadConditionHighPriority; + [self uploadTargets:@[ @(target) ] conditions:conditions]; + }); +} + +#pragma mark - Private helper methods + +/** Starts a timer that checks whether or not events can be uploaded at regular intervals. It will + * check the next-upload clocks of all targets to determine if an upload attempt can be made. + */ +- (void)startTimer { + dispatch_async(_coordinationQueue, ^{ + if (self->_timer) { + // The timer has been already started. + return; + } + + // Delay the timer slightly so it doesn't run while +load calls are still running. + dispatch_time_t deadline = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC / 2); + + self->_timer = + dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self->_coordinationQueue); + dispatch_source_set_timer(self->_timer, deadline, self->_timerInterval, self->_timerLeeway); + + dispatch_source_set_event_handler(self->_timer, ^{ + if (![[GDTCORApplication sharedApplication] isRunningInBackground]) { + GDTCORUploadConditions conditions = [self uploadConditions]; + GDTCORLogDebug(@"%@", @"Upload timer fired"); + [self uploadTargets:[self.registrar.targetToUploader allKeys] conditions:conditions]; + } + }); + GDTCORLogDebug(@"%@", @"Upload timer started"); + dispatch_resume(self->_timer); + }); +} + +/** Stops the currently running timer. */ +- (void)stopTimer { + if (_timer) { + dispatch_source_cancel(_timer); + _timer = nil; + } +} + +/** Triggers the uploader implementations for the given targets to upload. + * + * @param targets An array of targets to trigger. + * @param conditions The set of upload conditions. + */ +- (void)uploadTargets:(NSArray *)targets conditions:(GDTCORUploadConditions)conditions { + dispatch_async(_coordinationQueue, ^{ + // TODO: The reachability signal may be not reliable enough to prevent an upload attempt. + // See https://developer.apple.com/videos/play/wwdc2019/712/ (49:40) for more details. + if ((conditions & GDTCORUploadConditionNoNetwork) == GDTCORUploadConditionNoNetwork) { + return; + } + for (NSNumber *target in targets) { + id uploader = self->_registrar.targetToUploader[target]; + [uploader uploadTarget:target.intValue withConditions:conditions]; + } + }); +} + +- (void)signalToStoragesToCheckExpirations { + // The same storage may be associated with several targets. Make sure to check for expirations + // only once per storage. + NSSet> *storages = + [NSSet setWithArray:[_registrar.targetToStorage allValues]]; + for (id storage in storages) { + [storage checkForExpirations]; + } +} + +/** Returns the registered storage for the given NSNumber wrapped GDTCORTarget. + * + * @param target The NSNumber wrapping of a GDTCORTarget to find the storage instance of. + * @return The storage instance for the given target. + */ +- (nullable id)storageForTarget:(NSNumber *)target { + id storage = [GDTCORRegistrar sharedInstance].targetToStorage[target]; + GDTCORAssert(storage, @"A storage must be registered for target %@", target); + return storage; +} + +/** Returns the current upload conditions after making determinations about the network connection. + * + * @return The current upload conditions. + */ +- (GDTCORUploadConditions)uploadConditions { + GDTCORNetworkReachabilityFlags currentFlags = [GDTCORReachability currentFlags]; + BOOL networkConnected = GDTCORReachabilityFlagsReachable(currentFlags); + if (!networkConnected) { + return GDTCORUploadConditionNoNetwork; + } + BOOL isWWAN = GDTCORReachabilityFlagsContainWWAN(currentFlags); + if (isWWAN) { + return GDTCORUploadConditionMobileData; + } else { + return GDTCORUploadConditionWifiData; + } +} + +#pragma mark - GDTCORLifecycleProtocol + +- (void)appWillForeground:(GDTCORApplication *)app { + // -startTimer is thread-safe. + [self startTimer]; + [self signalToStoragesToCheckExpirations]; +} + +- (void)appWillBackground:(GDTCORApplication *)app { + dispatch_async(_coordinationQueue, ^{ + [self stopTimer]; + }); +} + +- (void)appWillTerminate:(GDTCORApplication *)application { + dispatch_sync(_coordinationQueue, ^{ + [self stopTimer]; + }); +} + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h new file mode 100644 index 0000000..e158a5a --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h @@ -0,0 +1,95 @@ +/* + * 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 + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A block type that could be run instead of normal assertion logging. No return type, no params. + */ +typedef void (^GDTCORAssertionBlock)(void); + +/** Returns the result of executing a soft-linked method present in unit tests that allows a block + * to be run instead of normal assertion logging. This helps ameliorate issues with catching + * exceptions that occur on a dispatch_queue. + * + * @return A block that can be run instead of normal assert printing. + */ +FOUNDATION_EXPORT GDTCORAssertionBlock _Nullable GDTCORAssertionBlockToRunInstead(void); + +#if defined(NS_BLOCK_ASSERTIONS) + +#define GDTCORAssert(condition, ...) \ + do { \ + } while (0); + +#define GDTCORFatalAssert(condition, ...) \ + do { \ + } while (0); + +#else // defined(NS_BLOCK_ASSERTIONS) + +/** Asserts using a console log, unless a block was specified to be run instead. + * + * @param condition The condition you'd expect to be YES. + */ +#define GDTCORAssert(condition, format, ...) \ + do { \ + __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ + if (__builtin_expect(!(condition), 0)) { \ + GDTCORAssertionBlock assertionBlock = GDTCORAssertionBlockToRunInstead(); \ + if (assertionBlock) { \ + assertionBlock(); \ + } else { \ + NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \ + __assert_file__ = __assert_file__ ? __assert_file__ : @""; \ + GDTCORLogAssert(NO, __assert_file__, __LINE__, format, ##__VA_ARGS__); \ + __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ + } \ + } \ + } while (0); + +/** Asserts by logging to the console and throwing an exception if NS_BLOCK_ASSERTIONS is not + * defined. + * + * @param condition The condition you'd expect to be YES. + */ +#define GDTCORFatalAssert(condition, format, ...) \ + do { \ + __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ + if (__builtin_expect(!(condition), 0)) { \ + GDTCORAssertionBlock assertionBlock = GDTCORAssertionBlockToRunInstead(); \ + if (assertionBlock) { \ + assertionBlock(); \ + } else { \ + NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \ + __assert_file__ = __assert_file__ ? __assert_file__ : @""; \ + GDTCORLogAssert(YES, __assert_file__, __LINE__, format, ##__VA_ARGS__); \ + [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \ + object:self \ + file:__assert_file__ \ + lineNumber:__LINE__ \ + description:format, ##__VA_ARGS__]; \ + __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ + } \ + } \ + } while (0); + +#endif // defined(NS_BLOCK_ASSERTIONS) + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h new file mode 100644 index 0000000..a6fa8a3 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The class calculates and caches the specified directory content size and uses add/remove signals + * from client the client to keep the size up to date without accessing file system. + * This is an internal class designed to be used by `GDTCORFlatFileStorage`. + * NOTE: The class is not thread-safe. The client must take care of synchronization. + */ +@interface GDTCORDirectorySizeTracker : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes the object with a directory path. + * @param path The directory path to track content size. + */ +- (instancetype)initWithDirectoryPath:(NSString *)path; + +/** Returns a cached or calculates (if there is no cached) directory content size. + * @return The directory content size in bytes calculated based on `NSURLFileSizeKey`. + */ +- (GDTCORStorageSizeBytes)directoryContentSize; + +/** The client must call this method or `resetCachedSize` method each time a file or directory is + * added to the tracked directory. + * @param path The path to the added file. If the path is outside the tracked directory then the + * @param fileSize The size of the added file. + * method is no-op. + */ +- (void)fileWasAddedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize; + +/** The client must call this method or `resetCachedSize` method each time a file or directory is + * removed from the tracked directory. + * @param path The path to the removed file. If the path is outside the tracked directory then the + * @param fileSize The size of the removed file. + * method is no-op. + */ +- (void)fileWasRemovedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize; + +/** Invalidates cached directory size. */ +- (void)resetCachedSize; + +/** Returns URL resource value for `NSURLFileSizeKey` key for the specified URL. */ +- (GDTCORStorageSizeBytes)fileSizeAtURL:(NSURL *)fileURL; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h new file mode 100644 index 0000000..3d77970 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h @@ -0,0 +1,63 @@ +/* + * 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 + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/** A protocol defining the lifecycle events objects in the library must respond to immediately. */ +@protocol GDTCORLifecycleProtocol + +@optional + +/** Indicates an imminent app termination in the rare occurrence when -applicationWillTerminate: has + * been called. + * + * @param app The GDTCORApplication instance. + */ +- (void)appWillTerminate:(GDTCORApplication *)app; + +/** Indicates that the app is moving to background and eventual suspension or the current UIScene is + * deactivating. + * + * @param app The GDTCORApplication instance. + */ +- (void)appWillBackground:(GDTCORApplication *)app; + +/** Indicates that the app is resuming operation or a UIScene is activating. + * + * @param app The GDTCORApplication instance. + */ +- (void)appWillForeground:(GDTCORApplication *)app; + +@end + +/** This class manages the library's response to app lifecycle events. + * + * When backgrounding, the library doesn't stop processing events, it's just that several background + * tasks will end up being created for every event that's sent, and the stateful objects of the + * library (GDTCORStorage and GDTCORUploadCoordinator instances) will deserialize themselves from + * and to disk before and after every operation, respectively. + */ +@interface GDTCORLifecycle : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h new file mode 100644 index 0000000..44252ab --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h @@ -0,0 +1,225 @@ +/* + * 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 + +#if !TARGET_OS_WATCH +#import +#endif + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#elif TARGET_OS_OSX +#import +#elif TARGET_OS_WATCH +#import +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_IOS +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** The GoogleDataTransport library version. */ +FOUNDATION_EXPORT NSString *const kGDTCORVersion; + +/** A notification sent out if the app is backgrounding. */ +FOUNDATION_EXPORT NSString *const kGDTCORApplicationDidEnterBackgroundNotification; + +/** A notification sent out if the app is foregrounding. */ +FOUNDATION_EXPORT NSString *const kGDTCORApplicationWillEnterForegroundNotification; + +/** A notification sent out if the app is terminating. */ +FOUNDATION_EXPORT NSString *const kGDTCORApplicationWillTerminateNotification; + +/** The different possible network connection type. */ +typedef NS_ENUM(NSInteger, GDTCORNetworkType) { + GDTCORNetworkTypeUNKNOWN = 0, + GDTCORNetworkTypeWIFI = 1, + GDTCORNetworkTypeMobile = 2, +}; + +/** The different possible network connection mobile subtype. */ +typedef NS_ENUM(NSInteger, GDTCORNetworkMobileSubtype) { + GDTCORNetworkMobileSubtypeUNKNOWN = 0, + GDTCORNetworkMobileSubtypeGPRS = 1, + GDTCORNetworkMobileSubtypeEdge = 2, + GDTCORNetworkMobileSubtypeWCDMA = 3, + GDTCORNetworkMobileSubtypeHSDPA = 4, + GDTCORNetworkMobileSubtypeHSUPA = 5, + GDTCORNetworkMobileSubtypeCDMA1x = 6, + GDTCORNetworkMobileSubtypeCDMAEVDORev0 = 7, + GDTCORNetworkMobileSubtypeCDMAEVDORevA = 8, + GDTCORNetworkMobileSubtypeCDMAEVDORevB = 9, + GDTCORNetworkMobileSubtypeHRPD = 10, + GDTCORNetworkMobileSubtypeLTE = 11, +}; + +#if !TARGET_OS_WATCH +/** Define SCNetworkReachabilityFlags as GDTCORNetworkReachabilityFlags on non-watchOS. */ +typedef SCNetworkReachabilityFlags GDTCORNetworkReachabilityFlags; + +/** Define SCNetworkReachabilityRef as GDTCORNetworkReachabilityRef on non-watchOS. */ +typedef SCNetworkReachabilityRef GDTCORNetworkReachabilityRef; + +#else +/** The different possible reachabilityFlags option on watchOS. */ +typedef NS_OPTIONS(uint32_t, GDTCORNetworkReachabilityFlags) { + kGDTCORNetworkReachabilityFlagsReachable = 1 << 1, + // TODO(doudounan): Add more options on watchOS if watchOS network connection information relative + // APIs available in the future. +}; + +/** Define a struct as GDTCORNetworkReachabilityRef on watchOS to store network connection + * information. */ +typedef struct { + // TODO(doudounan): Store network connection information on watchOS if watchOS network connection + // information relative APIs available in the future. +} GDTCORNetworkReachabilityRef; +#endif + +/** Returns a URL to the root directory under which all GDT-associated data must be saved. + * + * @return A URL to the root directory under which all GDT-associated data must be saved. + */ +NSURL *GDTCORRootDirectory(void); + +/** Compares flags with the reachable flag (on non-watchos with both reachable and + * connectionRequired flags), if available, and returns YES if network reachable. + * + * @param flags The set of reachability flags. + * @return YES if the network is reachable, NO otherwise. + */ +BOOL GDTCORReachabilityFlagsReachable(GDTCORNetworkReachabilityFlags flags); + +/** Compares flags with the WWAN reachability flag, if available, and returns YES if present. + * + * @param flags The set of reachability flags. + * @return YES if the WWAN flag is set, NO otherwise. + */ +BOOL GDTCORReachabilityFlagsContainWWAN(GDTCORNetworkReachabilityFlags flags); + +/** Generates an enum message GDTCORNetworkType representing network connection type. + * + * @return A GDTCORNetworkType representing network connection type. + */ +GDTCORNetworkType GDTCORNetworkTypeMessage(void); + +/** Generates an enum message GDTCORNetworkMobileSubtype representing network connection mobile + * subtype. + * + * @return A GDTCORNetworkMobileSubtype representing network connection mobile subtype. + */ +GDTCORNetworkMobileSubtype GDTCORNetworkMobileSubTypeMessage(void); + +/** Identifies the model of the device on which the library is currently working on. + * + * @return A NSString representing the device model. + */ +NSString *_Nonnull GDTCORDeviceModel(void); + +/** Writes the given object to the given fileURL and populates the given error if it fails. + * + * @param obj The object to encode. + * @param filePath The path to write the object to. Can be nil if you just need the data. + * @param error The error to populate if something goes wrong. + * @return The data of the archive. If error is nil, it's been written to disk. + */ +NSData *_Nullable GDTCOREncodeArchive(id obj, + NSString *_Nullable filePath, + NSError *_Nullable *error); + +/** Decodes an object of the given class from the given archive path or data and populates the given + * error if it fails. + * + * @param archiveClass The class of the archive's root object. + * @param archivePath The path to the archived data. Don't use with the archiveData param. + * @param archiveData The data to decode. Don't use with the archivePath param. + * @param error The error to populate if something goes wrong. + */ +id _Nullable GDTCORDecodeArchive(Class archiveClass, + NSString *_Nullable archivePath, + NSData *_Nullable archiveData, + NSError *_Nullable *error); + +/** Writes the provided data to a file at the provided path. Intermediate directories will be + * created as needed. + * @param data The file content. + * @param filePath The path to the file to write the provided data. + * @param outError The error to populate if something goes wrong. + * @return `YES` in the case of success, `NO` otherwise. + */ +BOOL GDTCORWriteDataToFile(NSData *data, NSString *filePath, NSError *_Nullable *outError); + +/** A typedef identify background identifiers. */ +typedef volatile NSUInteger GDTCORBackgroundIdentifier; + +/** A background task's invalid sentinel value. */ +FOUNDATION_EXPORT const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid; + +#if TARGET_OS_IOS || TARGET_OS_TV +/** A protocol that wraps UIApplicationDelegate, WKExtensionDelegate or NSObject protocol, depending + * on the platform. + */ +@protocol GDTCORApplicationDelegate +#elif TARGET_OS_OSX +@protocol GDTCORApplicationDelegate +#elif TARGET_OS_WATCH +@protocol GDTCORApplicationDelegate +#else +@protocol GDTCORApplicationDelegate +#endif // TARGET_OS_IOS || TARGET_OS_TV + +@end + +@protocol GDTCORApplicationProtocol + +@required + +/** Flag to determine if the application is running in the background. */ +@property(atomic, readonly) BOOL isRunningInBackground; + +/** Creates a background task with the returned identifier if on a suitable platform. + * + * @name name The name of the task, useful for debugging which background tasks are running. + * @param handler The handler block that is called if the background task expires. + * @return An identifier for the background task, or GDTCORBackgroundIdentifierInvalid if one + * couldn't be created. + */ +- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name + expirationHandler:(void (^__nullable)(void))handler; + +/** Ends the background task if the identifier is valid. + * + * @param bgID The background task to end. + */ +- (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID; + +@end + +/** A cross-platform application class. */ +@interface GDTCORApplication : NSObject + +/** Creates and/or returns the shared application instance. + * + * @return The shared application instance. + */ ++ (nullable GDTCORApplication *)sharedApplication; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h new file mode 100644 index 0000000..eb89832 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h @@ -0,0 +1,31 @@ +/* + * 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 + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class helps determine upload conditions by determining connectivity. */ +@interface GDTCORReachability : NSObject + +/** The current set flags indicating network conditions */ ++ (GDTCORNetworkReachabilityFlags)currentFlags; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h new file mode 100644 index 0000000..3ea521b --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.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 + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Manages the registration of targets with the transport SDK. */ +@interface GDTCORRegistrar : NSObject + +/** Creates and/or returns the singleton instance. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +/** Registers a backend implementation with the GoogleDataTransport infrastructure. + * + * @param backend The backend object to register. + * @param target The target this backend object will be responsible for. + */ +- (void)registerUploader:(id)backend target:(GDTCORTarget)target; + +/** Registers a storage implementation with the GoogleDataTransport infrastructure. + * + * @param storage The storage instance to be associated with this uploader and target. + * @param target The target this backend object will be responsible for. + */ +- (void)registerStorage:(id)storage target:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h new file mode 100644 index 0000000..7662d8b --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class enables the finding of events by matching events with the properties of this class. + */ +@interface GDTCORStorageEventSelector : NSObject + +/** The target to find events for. Required. */ +@property(readonly, nonatomic) GDTCORTarget selectedTarget; + +/** Finds a specific event. */ +@property(nullable, readonly, nonatomic) NSSet *selectedEventIDs; + +/** Finds all events of a mappingID. */ +@property(nullable, readonly, nonatomic) NSSet *selectedMappingIDs; + +/** Finds all events matching the qosTiers in this list. */ +@property(nullable, readonly, nonatomic) NSSet *selectedQosTiers; + +/** Initializes an event selector that will find all events for the given target. + * + * @param target The selected target. + * @return An immutable event selector instance. + */ ++ (instancetype)eventSelectorForTarget:(GDTCORTarget)target; + +/** Instantiates an event selector. + * + * @param target The selected target. + * @param eventIDs Optional param to find an event matching this eventID. + * @param mappingIDs Optional param to find events matching this mappingID. + * @param qosTiers Optional param to find events matching the given QoS tiers. + * @return An immutable event selector instance. + */ +- (instancetype)initWithTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + mappingIDs:(nullable NSSet *)mappingIDs + qosTiers:(nullable NSSet *)qosTiers; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h new file mode 100644 index 0000000..ffccfdb --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h @@ -0,0 +1,171 @@ +/* + * 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. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +@class GDTCOREvent; +@class GDTCORClock; +@class GDTCORUploadBatch; + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/** The data type to represent storage size. */ +typedef uint64_t GDTCORStorageSizeBytes; + +typedef void (^GDTCORStorageBatchBlock)(NSNumber *_Nullable newBatchID, + NSSet *_Nullable batchEvents); + +/** Defines the interface a storage subsystem is expected to implement. */ +@protocol GDTCORStorageProtocol + +@required + +/** Stores an event and calls onComplete with a non-nil error if anything went wrong. + * + * @param event The event to store + * @param completion The completion block to call after an attempt to store the event has been made. + */ +- (void)storeEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +/** Returns YES if some events have been stored for the given target, NO otherwise. + * + * @param onComplete The completion block to invoke when determining if there are events is done. + */ +- (void)hasEventsForTarget:(GDTCORTarget)target onComplete:(void (^)(BOOL hasEvents))onComplete; + +/** Constructs an event batch with the given event selector. Events in this batch will not be + * returned in any queries or other batches until the batch is removed. + * + * @param eventSelector The event selector used to find the events. + * @param expiration The expiration time of the batch. If removeBatchWithID:deleteEvents:onComplete: + * is not called within this time frame, the batch will be removed with its events deleted. + * @param onComplete The completion handler to be called when the events have been fetched. + */ +- (void)batchWithEventSelector:(nonnull GDTCORStorageEventSelector *)eventSelector + batchExpiration:(nonnull NSDate *)expiration + onComplete:(nonnull GDTCORStorageBatchBlock)onComplete; + +/** Removes the event batch. + * + * @param batchID The batchID to remove. + * @param deleteEvents If YES, the events in this batch are deleted. + * @param onComplete The completion handler to call when the batch removal process has completed. + */ +- (void)removeBatchWithID:(NSNumber *)batchID + deleteEvents:(BOOL)deleteEvents + onComplete:(void (^_Nullable)(void))onComplete; + +/** Finds the batchIDs for the given target and calls the callback block. + * + * @param target The target. + * @param onComplete The block to invoke with the set of current batchIDs. + */ +- (void)batchIDsForTarget:(GDTCORTarget)target + onComplete:(void (^)(NSSet *_Nullable batchIDs))onComplete; + +/** Checks the storage for expired events and batches, deletes them if they're expired. */ +- (void)checkForExpirations; + +/** Persists the given data with the given key. + * + * @param data The data to store. + * @param key The unique key to store it to. + * @param onComplete An block to be run when storage of the data is complete. + */ +- (void)storeLibraryData:(NSData *)data + forKey:(NSString *)key + onComplete:(nullable void (^)(NSError *_Nullable error))onComplete; + +/** Retrieves the stored data for the given key and optionally sets a new value. + * + * @param key The key corresponding to the desired data. + * @param onFetchComplete The callback to invoke with the data once it's retrieved. + * @param setValueBlock This optional block can provide a new value to set. + */ +- (void)libraryDataForKey:(nonnull NSString *)key + onFetchComplete:(nonnull void (^)(NSData *_Nullable data, + NSError *_Nullable error))onFetchComplete + setNewValue:(NSData *_Nullable (^_Nullable)(void))setValueBlock; + +/** Removes data from storage and calls the callback when complete. + * + * @param key The key of the data to remove. + * @param onComplete The callback that will be invoked when removing the data is complete. + */ +- (void)removeLibraryDataForKey:(NSString *)key + onComplete:(void (^)(NSError *_Nullable error))onComplete; + +/** Calculates and returns the total disk size that this storage consumes. + * + * @param onComplete The callback that will be invoked once storage size calculation is complete. + */ +- (void)storageSizeWithCallback:(void (^)(GDTCORStorageSizeBytes storageSize))onComplete; + +@end + +// TODO: Consider complete replacing block based API by promise API. + +/** Promise based version of API defined in GDTCORStorageProtocol. See API docs for corresponding + * methods in GDTCORStorageProtocol. */ +@protocol GDTCORStoragePromiseProtocol + +- (FBLPromise *> *)batchIDsForTarget:(GDTCORTarget)target; + +- (FBLPromise *)removeBatchWithID:(NSNumber *)batchID deleteEvents:(BOOL)deleteEvents; + +- (FBLPromise *)removeBatchesWithIDs:(NSSet *)batchIDs + deleteEvents:(BOOL)deleteEvents; + +- (FBLPromise *)removeAllBatchesForTarget:(GDTCORTarget)target + deleteEvents:(BOOL)deleteEvents; + +/** See `hasEventsForTarget:onComplete:`. + * @return A promise object that is resolved with @YES if there are events for the specified target + * and @NO otherwise. + */ +- (FBLPromise *)hasEventsForTarget:(GDTCORTarget)target; + +/** See `batchWithEventSelector:batchExpiration:onComplete:` + * The promise is rejected when there are no events for the specified selector. + */ +- (FBLPromise *)batchWithEventSelector: + (GDTCORStorageEventSelector *)eventSelector + batchExpiration:(NSDate *)expiration; + +@end + +/** Retrieves the storage instance for the given target. + * + * @param target The target. + * * @return The storage instance registered for the target, or nil if there is none. + */ +FOUNDATION_EXPORT +id _Nullable GDTCORStorageInstanceForTarget(GDTCORTarget target); + +// TODO: Ideally we should remove completion-based API and use promise-based one. Need to double +// check if it's ok. +FOUNDATION_EXPORT +id _Nullable GDTCORStoragePromiseInstanceForTarget( + GDTCORTarget target); + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h new file mode 100644 index 0000000..9b5343d --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h @@ -0,0 +1,59 @@ +/* + * 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 + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Options that define a set of upload conditions. This is used to help minimize end user data + * consumption impact. + */ +typedef NS_OPTIONS(NSInteger, GDTCORUploadConditions) { + + /** An upload shouldn't be attempted, because there's no network. */ + GDTCORUploadConditionNoNetwork = 1 << 0, + + /** An upload would likely use mobile data. */ + GDTCORUploadConditionMobileData = 1 << 1, + + /** An upload would likely use wifi data. */ + GDTCORUploadConditionWifiData = 1 << 2, + + /** An upload uses some sort of network connection, but it's unclear which. */ + GDTCORUploadConditionUnclearConnection = 1 << 3, + + /** A high priority event has occurred. */ + GDTCORUploadConditionHighPriority = 1 << 4, +}; + +/** This protocol defines the common interface for uploader implementations. */ +@protocol GDTCORUploader + +@required + +/** Uploads events to the backend using this specific backend's chosen format. + * + * @param conditions The conditions that the upload attempt is likely to occur under. + */ +- (void)uploadTarget:(GDTCORTarget)target withConditions:(GDTCORUploadConditions)conditions; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h new file mode 100644 index 0000000..4b1a903 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h" + +@interface GDTCOREndpoints () + +/** Returns the list of all the upload URLs used by the transport library. + * + * @return Map of the transport target and the URL used for uploading the events for that target. + */ ++ (NSDictionary *)uploadURLs; + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h new file mode 100644 index 0000000..e97eb31 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h @@ -0,0 +1,33 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCOREvent () + +/** The unique ID of the event. This property is for testing only. */ +@property(nonatomic, readwrite) NSString *eventID; + +/** Generates a unique event ID. */ ++ (NSString *)nextEventID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h new file mode 100644 index 0000000..66ea857 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h" + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/// The category extends `GDTCORFlatFileStorage` API with `GDTCORStoragePromiseProtocol` methods. +@interface GDTCORFlatFileStorage (Promises) + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h new file mode 100644 index 0000000..09f1dae --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h @@ -0,0 +1,158 @@ +/* + * 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 + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" + +@class GDTCOREvent; +@class GDTCORUploadCoordinator; + +NS_ASSUME_NONNULL_BEGIN + +/** The event components eventID dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsEventIDKey; + +/** The event components qosTier dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsQoSTierKey; + +/** The event components mappingID dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsMappingIDKey; + +/** The event components expirationDate dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsExpirationKey; + +/** The batch components target dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCORBatchComponentsTargetKey; + +/** The batch components batchID dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCORBatchComponentsBatchIDKey; + +/** The batch components expiration dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCORBatchComponentsExpirationKey; + +/** The maximum allowed disk space taken by the stored data. */ +FOUNDATION_EXPORT const uint64_t kGDTCORFlatFileStorageSizeLimit; + +FOUNDATION_EXPORT NSString *const GDTCORFlatFileStorageErrorDomain; + +typedef NS_ENUM(NSInteger, GDTCORFlatFileStorageError) { + GDTCORFlatFileStorageErrorSizeLimitReached = 0 +}; + +/** Manages the storage of events. This class is thread-safe. + * + * Event files will be stored as follows: + * /google-sdk-events//gdt_event_data//.. + * + * Library data will be stored as follows: + * /google-sdk-events//gdt_library_data/ + * + * Batch data will be stored as follows: + * /google-sdk-events//gdt_batch_data/./.. + */ +@interface GDTCORFlatFileStorage : NSObject + +/** The queue on which all storage work will occur. */ +@property(nonatomic) dispatch_queue_t storageQueue; + +/** The upload coordinator instance used by this storage instance. */ +@property(nonatomic) GDTCORUploadCoordinator *uploadCoordinator; + +/** Creates and/or returns the storage singleton. + * + * @return The storage singleton. + */ ++ (instancetype)sharedInstance; + +/** Returns the base directory under which all events will be stored. + * + * @return The base directory under which all events will be stored. + */ ++ (NSString *)eventDataStoragePath; + +/** Returns the base directory under which all library data will be stored. + * + * @return The base directory under which all library data will be stored. + */ ++ (NSString *)libraryDataStoragePath; + +/** Returns the base directory under which all batch data will be stored. + * + * @return The base directory under which all batch data will be stored. + */ ++ (NSString *)batchDataStoragePath; + +/** */ ++ (NSString *)batchPathForTarget:(GDTCORTarget)target + batchID:(NSNumber *)batchID + expirationDate:(NSDate *)expirationDate; + +/** Returns a constructed storage path based on the given values. This path may not exist. + * + * @param target The target, which is necessary to be given a path. + * @param eventID The eventID. + * @param qosTier The qosTier. + * @param expirationDate The expirationDate as a 1970-relative time interval. + * @param mappingID The mappingID. + * @return The path representing the combination of the given parameters. + */ ++ (NSString *)pathForTarget:(GDTCORTarget)target + eventID:(NSString *)eventID + qosTier:(NSNumber *)qosTier + expirationDate:(NSDate *)expirationDate + mappingID:(NSString *)mappingID; + +/** Returns extant paths that match all of the given parameters. + * + * @param eventIDs The list of eventIDs to look for, or nil for any. + * @param qosTiers The list of qosTiers to look for, or nil for any. + * @param mappingIDs The list of mappingIDs to look for, or nil for any. + * @param onComplete The completion to call once the paths have been discovered. + */ +- (void)pathsForTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + qosTiers:(nullable NSSet *)qosTiers + mappingIDs:(nullable NSSet *)mappingIDs + onComplete:(void (^)(NSSet *paths))onComplete; + +/** Fetches the current batchID counter value from library storage, increments it, and sets the new + * value. Returns nil if a batchID was not able to be created for some reason. + * + * @param onComplete A block to execute when creating the next batchID is complete. + */ +- (void)nextBatchID:(void (^)(NSNumber *_Nullable batchID))onComplete; + +/** Constructs a dictionary of event filename components. + * + * @param fileName The event filename to split. + * @return The dictionary of event component keys to their values. + */ +- (nullable NSDictionary *)eventComponentsFromFilename:(NSString *)fileName; + +/** Constructs a dictionary of batch filename components. + * + * @param fileName The batch folder name to split. + * @return The dictionary of batch component keys to their values. + */ +- (nullable NSDictionary *)batchComponentsFromFilename:(NSString *)fileName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h new file mode 100644 index 0000000..06b1f67 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h @@ -0,0 +1,30 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" + +@interface GDTCORReachability () + +/** Allows manually setting the flags for testing purposes. */ +@property(nonatomic, readwrite) GDTCORNetworkReachabilityFlags flags; + +/** Creates/returns the singleton instance of this class. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +@end diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h new file mode 100644 index 0000000..2679611 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h @@ -0,0 +1,35 @@ +/* + * 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 "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" + +@interface GDTCORRegistrar () + +NS_ASSUME_NONNULL_BEGIN + +/** The concurrent queue on which all registration occurs. */ +@property(nonatomic, readonly) dispatch_queue_t registrarQueue; + +/** A map of targets to backend implementations. */ +@property(atomic, readonly) NSMutableDictionary> *targetToUploader; + +/** A map of targets to storage instances. */ +@property(atomic, readonly) + NSMutableDictionary> *targetToStorage; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h new file mode 100644 index 0000000..ccca628 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h @@ -0,0 +1,57 @@ +/* + * 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 + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" + +@class GDTCOREvent; + +@protocol GDTCOREventTransformer; + +NS_ASSUME_NONNULL_BEGIN + +/** Manages the transforming of events. It's desirable for this to be its own class + * because running all events through a single instance ensures that transformers are thread-safe. + * Having a per-transport queue to run on isn't sufficient because transformer objects could + * maintain state (or at least, there's nothing to stop them from doing that) and the same instances + * may be used across multiple instances. + */ +@interface GDTCORTransformer : NSObject + +/** Instantiates or returns the event transformer singleton. + * + * @return The singleton instance of the event transformer. + */ ++ (instancetype)sharedInstance; + +/** Writes the result of applying the given transformers' `transformGDTEvent:` method on the given + * event. + * + * @note If the app is suspended, a background task will be created to complete work in-progress, + * but this method will not send any further events until the app is resumed. + * + * @param event The event to apply transformers on. + * @param transformers The list of transformers to apply. + * @param completion A block to run when an event was written to disk or dropped. + */ +- (void)transformEvent:(GDTCOREvent *)event + withTransformers:(nullable NSArray> *)transformers + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h new file mode 100644 index 0000000..bb86407 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h" + +@protocol GDTCORApplicationProtocol; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORTransformer () + +/** The queue on which all work will occur. */ +@property(nonatomic) dispatch_queue_t eventWritingQueue; + +/** The application instance that is used to begin/end background tasks. */ +@property(nonatomic, readonly) id application; + +/** The internal initializer. Should be used in tests only to create an instance with a + * particular(fake) application instance. */ +- (instancetype)initWithApplication:(id)application; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h new file mode 100644 index 0000000..41a1224 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.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 "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h" + +@class GDTCORTransformer; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORTransport () + +/** The mapping identifier that the target backend will use to map the transport bytes to proto. */ +@property(nonatomic) NSString *mappingID; + +/** The transformers that will operate on events sent by this transport. */ +@property(nonatomic) NSArray> *transformers; + +/** The target backend of this transport. */ +@property(nonatomic) NSInteger target; + +/** The transformer instance to used to transform events. Allows injecting a fake during testing. */ +@property(nonatomic) GDTCORTransformer *transformerInstance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h new file mode 100644 index 0000000..8d1fd11 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#import + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/// A data object representing a batch of events scheduled for upload. +@interface GDTCORUploadBatch : NSObject + +/// An ID used to identify the batch in the storage. +@property(nonatomic, readonly) NSNumber *batchID; + +/// The collection of the events in the batch. +@property(nonatomic, readonly) NSSet *events; + +/// The default initializer. See also docs for the corresponding properties. +- (instancetype)initWithBatchID:(NSNumber *)batchID events:(NSSet *)events; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h new file mode 100644 index 0000000..bdac3f3 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h @@ -0,0 +1,68 @@ +/* + * 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 + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" + +@class GDTCORClock; + +NS_ASSUME_NONNULL_BEGIN + +/** This class connects storage and uploader implementations, providing events to an uploader + * and informing the storage what events were successfully uploaded or not. + */ +@interface GDTCORUploadCoordinator : NSObject + +/** The queue on which all upload coordination will occur. Also used by a dispatch timer. */ +/** Creates and/or returrns the singleton. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +/** The queue on which all upload coordination will occur. */ +@property(nonatomic, readonly) dispatch_queue_t coordinationQueue; + +/** A timer that will causes regular checks for events to upload. */ +@property(nonatomic, readonly, nullable) dispatch_source_t timer; + +/** The interval the timer will fire. */ +@property(nonatomic, readonly) uint64_t timerInterval; + +/** Some leeway given to libdispatch for the timer interval event. */ +@property(nonatomic, readonly) uint64_t timerLeeway; + +/** The registrar object the coordinator will use. Generally used for testing. */ +@property(nonatomic) GDTCORRegistrar *registrar; + +/** Forces the backend specified by the target to upload the provided set of events. This should + * only ever happen when the QoS tier of an event requires it. + * + * @param target The target that should force an upload. + */ +- (void)forceUploadForTarget:(GDTCORTarget)target; + +/** Starts the upload timer. */ +- (void)startTimer; + +/** Stops the upload timer from running. */ +- (void)stopTimer; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h new file mode 100644 index 0000000..8c75b50 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.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 + +NS_ASSUME_NONNULL_BEGIN + +/** This class manages the device clock and produces snapshots of the current time. */ +@interface GDTCORClock : NSObject + +/** The wallclock time, UTC, in milliseconds. */ +@property(nonatomic, readonly) int64_t timeMillis; + +/** The offset from UTC in seconds. */ +@property(nonatomic, readonly) int64_t timezoneOffsetSeconds; + +/** The kernel boot time when this clock was created in nanoseconds. */ +@property(nonatomic, readonly) int64_t kernelBootTimeNanoseconds; + +/** The device uptime when this clock was created in nanoseconds. */ +@property(nonatomic, readonly) int64_t uptimeNanoseconds; + +@property(nonatomic, readonly) int64_t kernelBootTime DEPRECATED_MSG_ATTRIBUTE( + "Please use `kernelBootTimeNanoseconds` instead"); + +@property(nonatomic, readonly) + int64_t uptime DEPRECATED_MSG_ATTRIBUTE("Please use `uptimeNanoseconds` instead"); + +/** Creates a GDTCORClock object using the current time and offsets. + * + * @return A new GDTCORClock object representing the current time state. + */ ++ (instancetype)snapshot; + +/** Creates a GDTCORClock object representing a time in the future, relative to now. + * + * @param millisInTheFuture The millis in the future from now this clock should represent. + * @return An instance representing a future time. + */ ++ (instancetype)clockSnapshotInTheFuture:(uint64_t)millisInTheFuture; + +/** Compares one clock with another, returns YES if the caller is after the parameter. + * + * @return YES if the calling clock's time is after the given clock's time. + */ +- (BOOL)isAfter:(GDTCORClock *)otherClock; + +/** Returns value of `uptime` property in milliseconds. */ +- (int64_t)uptimeMilliseconds; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h new file mode 100644 index 0000000..1fdf732 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h @@ -0,0 +1,144 @@ +/* + * 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 + +/** The current logging level. This value and higher will be printed. Declared as volatile to make + * getting and setting atomic. + */ +FOUNDATION_EXPORT volatile NSInteger GDTCORConsoleLoggerLoggingLevel; + +/** A list of logging levels that GDT supports. */ +typedef NS_ENUM(NSInteger, GDTCORLoggingLevel) { + + /** Causes all logs to be printed. */ + GDTCORLoggingLevelDebug = 1, + + /** Causes all non-debug logs to be printed. */ + GDTCORLoggingLevelVerbose = 2, + + /** Causes warnings and errors to be printed. */ + GDTCORLoggingLevelWarnings = 3, + + /** Causes errors to be printed. This is the default value. */ + GDTCORLoggingLevelErrors = 4 +}; + +/** A list of message codes to print in the logger that help to correspond printed messages with + * code locations. + * + * Prefixes: + * - MCD => MessageCodeDebug + * - MCW => MessageCodeWarning + * - MCE => MessageCodeError + */ +typedef NS_ENUM(NSInteger, GDTCORMessageCode) { + + /** For debug logs. */ + GDTCORMCDDebugLog = 0, + + /** For warning messages concerning transportBytes: not being implemented by a data object. */ + GDTCORMCWDataObjectMissingBytesImpl = 1, + + /** For warning messages concerning a failed event upload. */ + GDTCORMCWUploadFailed = 2, + + /** For warning messages concerning a forced event upload. */ + GDTCORMCWForcedUpload = 3, + + /** For warning messages concerning a failed reachability call. */ + GDTCORMCWReachabilityFailed = 4, + + /** For warning messages concerning a database warning. */ + GDTCORMCWDatabaseWarning = 5, + + /** For warning messages concerning the reading of a event file. */ + GDTCORMCWFileReadError = 6, + + /** For error messages concerning transformGDTEvent: not being implemented by an event + transformer. */ + GDTCORMCETransformerDoesntImplementTransform = 1000, + + /** For error messages concerning the creation of a directory failing. */ + GDTCORMCEDirectoryCreationError = 1001, + + /** For error messages concerning the writing of a event file. */ + GDTCORMCEFileWriteError = 1002, + + /** For error messages concerning the lack of a prioritizer for a given backend. */ + GDTCORMCEPrioritizerError = 1003, + + /** For error messages concerning a package delivery API violation. */ + GDTCORMCEDeliverTwice = 1004, + + /** For error messages concerning an error in an implementation of -transportBytes. */ + GDTCORMCETransportBytesError = 1005, + + /** For general purpose error messages in a dependency. */ + GDTCORMCEGeneralError = 1006, + + /** For fatal errors. Please go to https://github.com/firebase/firebase-ios-sdk/issues and open + * an issue if you encounter an error with this code. + */ + GDTCORMCEFatalAssertion = 1007, + + /** For error messages concerning the reading of a event file. */ + GDTCORMCEFileReadError = 1008, + + /** For errors related to running sqlite. */ + GDTCORMCEDatabaseError = 1009, +}; + +/** Prints the given code and format string to the console. + * + * @param code The message code describing the nature of the log. + * @param logLevel The log level of this log. + * @param format The format string. + */ +FOUNDATION_EXPORT +void GDTCORLog(GDTCORMessageCode code, GDTCORLoggingLevel logLevel, NSString *_Nonnull format, ...) + NS_FORMAT_FUNCTION(3, 4); + +/** Prints an assert log to the console. + * + * @param wasFatal Send YES if the assertion should be fatal, NO otherwise. + * @param file The file in which the failure occurred. + * @param line The line number of the failure. + * @param format The format string. + */ +FOUNDATION_EXPORT void GDTCORLogAssert(BOOL wasFatal, + NSString *_Nonnull file, + NSInteger line, + NSString *_Nullable format, + ...) NS_FORMAT_FUNCTION(4, 5); + +/** Returns the string that represents some message code. + * + * @param code The code to convert to a string. + * @return The string representing the message code. + */ +FOUNDATION_EXPORT NSString *_Nonnull GDTCORMessageCodeEnumToString(GDTCORMessageCode code); + +#define GDTCORLogDebug(MESSAGE_FORMAT, ...) \ + GDTCORLog(GDTCORMCDDebugLog, GDTCORLoggingLevelDebug, MESSAGE_FORMAT, __VA_ARGS__); + +// A define to wrap GULLogWarning with slightly more convenient usage. +#define GDTCORLogWarning(MESSAGE_CODE, MESSAGE_FORMAT, ...) \ + GDTCORLog(MESSAGE_CODE, GDTCORLoggingLevelWarnings, MESSAGE_FORMAT, __VA_ARGS__); + +// A define to wrap GULLogError with slightly more convenient usage and a failing assert. +#define GDTCORLogError(MESSAGE_CODE, MESSAGE_FORMAT, ...) \ + GDTCORLog(MESSAGE_CODE, GDTCORLoggingLevelErrors, MESSAGE_FORMAT, __VA_ARGS__); diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h new file mode 100644 index 0000000..836a454 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/* Class that manages the endpoints used by Google data transport library. */ +@interface GDTCOREndpoints : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Returns the upload URL for a target specified. If the target is not available, returns nil. + * + * @param target GoogleDataTransport target for which the upload URL is being looked up for. + * @return URL that will be used for uploading the events for the provided target. + */ ++ (nullable NSURL *)uploadURLForTarget:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h new file mode 100644 index 0000000..52c2384 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h @@ -0,0 +1,87 @@ +/* + * 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 + +#import "GDTCOREventDataObject.h" +#import "GDTCORTargets.h" + +@class GDTCORClock; + +NS_ASSUME_NONNULL_BEGIN + +/** The different possible quality of service specifiers. High values indicate high priority. */ +typedef NS_ENUM(NSInteger, GDTCOREventQoS) { + /** The QoS tier wasn't set, and won't ever be sent. */ + GDTCOREventQoSUnknown = 0, + + /** This event is internal telemetry data that should not be sent on its own if possible. */ + GDTCOREventQoSTelemetry = 1, + + /** This event should be sent, but in a batch only roughly once per day. */ + GDTCOREventQoSDaily = 2, + + /** This event should be sent when requested by the uploader. */ + GDTCOREventQosDefault = 3, + + /** This event should be sent immediately along with any other data that can be batched. */ + GDTCOREventQoSFast = 4, + + /** This event should only be uploaded on wifi. */ + GDTCOREventQoSWifiOnly = 5, +}; + +@interface GDTCOREvent : NSObject + +/** The unique ID of the event. */ +@property(readonly, nonatomic) NSString *eventID; + +/** The mapping identifier, to allow backends to map the transport bytes to a proto. */ +@property(nullable, readonly, nonatomic) NSString *mappingID; + +/** The identifier for the backend this event will eventually be sent to. */ +@property(readonly, nonatomic) GDTCORTarget target; + +/** The data object encapsulated in the transport of your choice, as long as it implements + * the GDTCOREventDataObject protocol. */ +@property(nullable, nonatomic) id dataObject; + +/** The serialized bytes from calling [dataObject transportBytes]. */ +@property(nullable, readonly, nonatomic) NSData *serializedDataObjectBytes; + +/** The quality of service tier this event belongs to. */ +@property(nonatomic) GDTCOREventQoS qosTier; + +/** The clock snapshot at the time of the event. */ +@property(nonatomic) GDTCORClock *clockSnapshot; + +/** The expiration date of the event. Default is 604800 seconds (7 days) from creation. */ +@property(nonatomic) NSDate *expirationDate; + +/** Bytes that can be used by an uploader later on. */ +@property(nullable, nonatomic) NSData *customBytes; + +/** Initializes an instance using the given mappingID. + * + * @param mappingID The mapping identifier. + * @param target The event's target identifier. + * @return An instance of this class. + */ +- (nullable instancetype)initWithMappingID:(NSString *)mappingID target:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h new file mode 100644 index 0000000..34ef624 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h @@ -0,0 +1,36 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** This protocol defines the common interface that event protos should implement regardless of the + * underlying transport technology (protobuf, nanopb, etc). + */ +@protocol GDTCOREventDataObject + +@required + +/** Returns the serialized proto bytes of the implementing event proto. + * + * @return the serialized proto bytes of the implementing event proto. + */ +- (NSData *)transportBytes; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h new file mode 100644 index 0000000..80dee7d --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h @@ -0,0 +1,38 @@ +/* + * 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 + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/** Defines the API that event transformers must adopt. */ +@protocol GDTCOREventTransformer + +@required + +/** Transforms an event by applying some logic to it. Events returned can be nil, for example, in + * instances where the event should be sampled. + * + * @param event The event to transform. + * @return A transformed event, or nil if the transformation dropped the event. + */ +- (nullable GDTCOREvent *)transformGDTEvent:(GDTCOREvent *)event; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h new file mode 100644 index 0000000..0b83ab9 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h @@ -0,0 +1,40 @@ +/* + * 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 + +/** The list of targets supported by the shared transport infrastructure. If adding a new target, + * please use the previous value +1. + */ +typedef NS_ENUM(NSInteger, GDTCORTarget) { + + /** A target only used in testing. */ + kGDTCORTargetTest = 999, + + /** The CCT target. */ + kGDTCORTargetCCT = 1000, + + /** The FLL target. */ + kGDTCORTargetFLL = 1001, + + /** The CSH target. The CSH target is a special-purpose backend. Please do not use it without + * permission. + */ + kGDTCORTargetCSH = 1002, + + /** The INT target. */ + kGDTCORTargetINT = 1003, +}; diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h new file mode 100644 index 0000000..e58248d --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h @@ -0,0 +1,92 @@ +/* + * 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 + +#import "GDTCOREventTransformer.h" +#import "GDTCORTargets.h" + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORTransport : NSObject + +// Please use the designated initializer. +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes a new transport that will send events to the given target backend. + * + * @param mappingID The mapping identifier used by the backend to map the data object transport + * bytes to a proto. + * @param transformers A list of transformers to be applied to events that are sent. + * @param target The target backend of this transport. + * @return A transport that will send events. + */ +- (nullable instancetype)initWithMappingID:(NSString *)mappingID + transformers: + (nullable NSArray> *)transformers + target:(GDTCORTarget)target NS_DESIGNATED_INITIALIZER; + +/** Copies and sends an internal telemetry event. Events sent using this API are lower in priority, + * and sometimes won't be sent on their own. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + * @param completion A block that will be called when the event has been written or dropped. + */ +- (void)sendTelemetryEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +/** Copies and sends an internal telemetry event. Events sent using this API are lower in priority, + * and sometimes won't be sent on their own. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + */ +- (void)sendTelemetryEvent:(GDTCOREvent *)event; + +/** Copies and sends an SDK service data event. Events send using this API are higher in priority, + * and will cause a network request at some point in the relative near future. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + * @param completion A block that will be called when the event has been written or dropped. + */ +- (void)sendDataEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +/** Copies and sends an SDK service data event. Events send using this API are higher in priority, + * and will cause a network request at some point in the relative near future. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + */ +- (void)sendDataEvent:(GDTCOREvent *)event; + +/** Creates an event for use by this transport. + * + * @return An event that is suited for use by this transport. + */ +- (GDTCOREvent *)eventForTransport; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h new file mode 100644 index 0000000..0bd39dc --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h @@ -0,0 +1,24 @@ +/* + * 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 "GDTCORClock.h" +#import "GDTCORConsoleLogger.h" +#import "GDTCOREndpoints.h" +#import "GDTCOREvent.h" +#import "GDTCOREventDataObject.h" +#import "GDTCOREventTransformer.h" +#import "GDTCORTargets.h" +#import "GDTCORTransport.h" diff --git a/saraWhatsUp/Pods/GoogleDataTransport/LICENSE b/saraWhatsUp/Pods/GoogleDataTransport/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/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/saraWhatsUp/Pods/GoogleDataTransport/README.md b/saraWhatsUp/Pods/GoogleDataTransport/README.md new file mode 100644 index 0000000..2633a79 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleDataTransport/README.md @@ -0,0 +1,231 @@ +[![Version](https://img.shields.io/cocoapods/v/GoogleDataTransport.svg?style=flat)](https://cocoapods.org/pods/GoogleDataTransport) +[![License](https://img.shields.io/cocoapods/l/GoogleDataTransport.svg?style=flat)](https://cocoapods.org/pods/GoogleDataTransport) +[![Platform](https://img.shields.io/cocoapods/p/GoogleDataTransport.svg?style=flat)](https://cocoapods.org/pods/GoogleDataTransport) + +[![Actions Status][gh-datatransport-badge]][gh-actions] + +# GoogleDataTransport + +This library is for internal Google use only. It allows the logging of data and +telemetry from Google SDKs. + +## Integration Testing +These instructions apply to minor and patch version updates. Major versions need +a customized adaptation. + +After the CI is green: +* Determine the next version for release by checking the + [tagged releases](https://github.com/google/GoogleDataTransport/tags). + Ensure that the next release version keeps the Swift PM and CocoaPods versions in sync. +* Verify that the releasing version is the latest entry in the [CHANGELOG.md](CHANGELOG.md), + updating it if necessary. +* Update the version in the podspec to match the latest entry in the [CHANGELOG.md](CHANGELOG.md) +* Checkout the `main` branch and ensure it is up to date. + ```console + git checkout main + git pull + ``` +* Add the CocoaPods tag (`{version}` will be the latest version in the [podspec](GoogleDataTransport.podspec#L3)) + ```console + git tag CocoaPods-{version} + git push origin CocoaPods-{version} + ``` +* Push the podspec to the designated repo + * If this version of GDT is intended to launch **before or with** the next Firebase release: +

+ Push to SpecsStaging + + ```console + pod repo push --skip-tests staging GoogleDataTransport.podspec + ``` + + If the command fails with `Unable to find the 'staging' repo.`, add the staging repo with: + ```console + pod repo add staging git@github.com:firebase/SpecsStaging.git + ``` +
+ * Otherwise: +
+ Push to SpecsDev + + ```console + pod repo push --skip-tests dev GoogleDataTransport.podspec + ``` + + If the command fails with `Unable to find the 'dev' repo.`, add the dev repo with: + ```console + pod repo add dev git@github.com:firebase/SpecsDev.git + ``` +
+* Run Firebase CI by waiting until next nightly or adding a PR that touches `Gemfile`. +* On google3, create a workspace and new CL. Then copybara and run a global TAP. +
+  /google/data/ro/teams/copybara/copybara third_party/firebase/ios/Releases/GoogleDataTransport/copy.bara.sky \
+  --piper-description-behavior=OVERWRITE \
+  --destination-cl=YOUR_CL gdt
+  
+ +## Publishing +The release process is as follows: +1. [Tag and release for Swift PM](#swift-package-manager) +2. [Publish to CocoaPods](#cocoapods) +3. [Create GitHub Release](#create-github-release) +4. [Perform post release cleanup](#post-release-cleanup) + +### Swift Package Manager + By creating and [pushing a tag](https://github.com/google/GoogleDataTransport/tags) + for Swift PM, the newly tagged version will be immediately released for public use. + Given this, please verify the intended time of release for Swift PM. + * Add a version tag for Swift PM + ```console + git tag {version} + git push origin {version} + ``` + *Note: Ensure that any inflight PRs that depend on the new `GoogleDataTransport` version are updated to point to the + newly tagged version rather than a checksum.* + +### CocoaPods +* Publish the newly versioned pod to CocoaPods + + It's recommended to point to the `GoogleDataTransport.podspec` in `staging` to make sure the correct spec is being published. + ```console + pod trunk push ~/.cocoapods/repos/staging/GoogleDataTransport/{version}/GoogleDataTransport.podspec --skip-tests + ``` + + The pod push was successful if the above command logs: `🚀 GoogleDataTransport ({version}) successfully published`. + In addition, a new commit that publishes the new version (co-authored by [CocoaPodsAtGoogle](https://github.com/CocoaPodsAtGoogle)) + should appear in the [CocoaPods specs repo](https://github.com/CocoaPods/Specs). Last, the latest version should be displayed + on [GoogleDataTransport's CocoaPods page](https://cocoapods.org/pods/GoogleDataTransport). + +### [Create GitHub Release](https://github.com/google/GoogleDataTransport/releases/new/) + Update the [release template](https://github.com/google/GoogleDataTransport/releases/new/)'s **Tag version** and **Release title** + fields with the latest version. In addition, reference the [Release Notes](./CHANGELOG.md) in the release's description. + + See [this release](https://github.com/google/GoogleDataTransport/releases/edit/9.0.1) for an example. + + *Don't forget to perform the [post release cleanup](#post-release-cleanup)!* + +### Post Release Cleanup +
+ Clean up SpecsStaging + + ```console + pwd=$(pwd) + mkdir -p /tmp/release-cleanup && cd $_ + git clone git@github.com:firebase/SpecsStaging.git + cd SpecsStaging/ + git rm -rf GoogleDataTransport/ + git commit -m "Post publish cleanup" + git push origin master + rm -rf /tmp/release-cleanup + cd $pwd + ``` +
+ +## Set logging level + +### Swift + +- Import `GoogleDataTransport` module: + ```swift + import GoogleDataTransport + ``` +- Set logging level global variable to the desired value before calling `FirebaseApp.configure()`: + ```swift + GDTCORConsoleLoggerLoggingLevel = GDTCORLoggingLevel.debug.rawValue + ``` +### Objective-C + +- Import `GoogleDataTransport`: + ```objective-c + #import + ``` +- Set logging level global variable to the desired value before calling `-[FIRApp configure]`: + ```objective-c + GDTCORConsoleLoggerLoggingLevel = GDTCORLoggingLevelDebug; + ``` + +## Prereqs + +- `gem install --user cocoapods cocoapods-generate` +- `brew install protobuf nanopb-generator` +- `easy_install --user protobuf` + +## To develop + +- Run `./GoogleDataTransport/generate_project.sh` after installing the prereqs + +## When adding new logging endpoint + +- Use commands similar to: + - `python -c "line='https://www.firebase.com'; print line[0::2]" ` + - `python -c "line='https://www.firebase.com'; print line[1::2]" ` + +## When adding internal code that shouldn't be easily usable on github + +- Consider using go/copybara-library/scrubbing#cc_scrub + +## Development + +Ensure that you have at least the following software: + + * Xcode 12.0 (or later) + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen GoogleDataTransport.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. + +### Development for Catalyst +* `pod gen GoogleDataTransport.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 + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@13 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +## 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). + +[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions +[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m new file mode 100644 index 0000000..88ea069 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m @@ -0,0 +1,1070 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h" +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Common/GULLoggerCodes.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +#import +#import + +// Implementations need to be typed before calling the implementation directly to cast the +// arguments and the return types correctly. Otherwise, it will crash the app. +typedef BOOL (*GULRealOpenURLSourceApplicationAnnotationIMP)( + id, SEL, GULApplication *, NSURL *, NSString *, id); + +typedef BOOL (*GULRealOpenURLOptionsIMP)( + id, SEL, GULApplication *, NSURL *, NSDictionary *); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-prototypes" +typedef void (*GULRealHandleEventsForBackgroundURLSessionIMP)( + id, SEL, GULApplication *, NSString *, void (^)()); +#pragma clang diagnostic pop + +typedef BOOL (*GULRealContinueUserActivityIMP)( + id, SEL, GULApplication *, NSUserActivity *, void (^)(NSArray *restorableObjects)); + +typedef void (*GULRealDidRegisterForRemoteNotificationsIMP)(id, SEL, GULApplication *, NSData *); + +typedef void (*GULRealDidFailToRegisterForRemoteNotificationsIMP)(id, + SEL, + GULApplication *, + NSError *); + +typedef void (*GULRealDidReceiveRemoteNotificationIMP)(id, SEL, GULApplication *, NSDictionary *); + +#if !TARGET_OS_WATCH && !TARGET_OS_OSX +typedef void (*GULRealDidReceiveRemoteNotificationWithCompletionIMP)( + id, SEL, GULApplication *, NSDictionary *, void (^)(UIBackgroundFetchResult)); +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX + +typedef void (^GULAppDelegateInterceptorCallback)(id); + +// The strings below are the keys for associated objects. +static char const *const kGULRealIMPBySelectorKey = "GUL_realIMPBySelector"; +static char const *const kGULRealClassKey = "GUL_realClass"; + +static NSString *const kGULAppDelegateKeyPath = @"delegate"; + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/AppDelegateSwizzler]"; + +// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change +// we disable App Delegate proxying when either of these two flags are set to NO. + +/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */ +static NSString *const kGULFirebaseAppDelegateProxyEnabledPlistKey = + @"FirebaseAppDelegateProxyEnabled"; + +/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying. + */ +static NSString *const kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey = + @"GoogleUtilitiesAppDelegateProxyEnabled"; + +/** The prefix of the App Delegate. */ +static NSString *const kGULAppDelegatePrefix = @"GUL_"; + +/** The original instance of App Delegate. */ +static id gOriginalAppDelegate; + +/** The original App Delegate class */ +static Class gOriginalAppDelegateClass; + +/** The subclass of the original App Delegate. */ +static Class gAppDelegateSubclass; + +/** Remote notification methods selectors + * + * We have to opt out of referencing APNS related App Delegate methods directly to prevent + * an Apple review warning email about missing Push Notification Entitlement + * (like here: https://github.com/firebase/firebase-ios-sdk/issues/2807). From our experience, the + * warning is triggered when any of the symbols is present in the application sent to review, even + * if the code is never executed. Because GULAppDelegateSwizzler may be used by applications that + * are not using APNS we have to refer to the methods indirectly using selector constructed from + * string. + * + * NOTE: None of the methods is proxied unless it is explicitly requested by calling the method + * +[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods] + */ +static NSString *const kGULDidRegisterForRemoteNotificationsSEL = + @"application:didRegisterForRemoteNotificationsWithDeviceToken:"; +static NSString *const kGULDidFailToRegisterForRemoteNotificationsSEL = + @"application:didFailToRegisterForRemoteNotificationsWithError:"; +static NSString *const kGULDidReceiveRemoteNotificationSEL = + @"application:didReceiveRemoteNotification:"; +static NSString *const kGULDidReceiveRemoteNotificationWithCompletionSEL = + @"application:didReceiveRemoteNotification:fetchCompletionHandler:"; + +/** + * This class is necessary to store the delegates in an NSArray without retaining them. + * [NSValue valueWithNonRetainedObject] also provides this functionality, but does not provide a + * zeroing pointer. This will cause EXC_BAD_ACCESS when trying to access the object after it is + * dealloced. Instead, this container stores a weak, zeroing reference to the object, which + * automatically is set to nil by the runtime when the object is dealloced. + */ +@interface GULZeroingWeakContainer : NSObject + +/** Stores a weak object. */ +@property(nonatomic, weak) id object; + +@end + +@implementation GULZeroingWeakContainer +@end + +@interface GULAppDelegateObserver : NSObject +@end + +@implementation GULAppDelegateObserver { + BOOL _isObserving; +} + ++ (GULAppDelegateObserver *)sharedInstance { + static GULAppDelegateObserver *instance; + static dispatch_once_t once; + dispatch_once(&once, ^{ + instance = [[GULAppDelegateObserver alloc] init]; + }); + return instance; +} + +- (void)observeUIApplication { + if (_isObserving) { + return; + } + [[GULAppDelegateSwizzler sharedApplication] + addObserver:self + forKeyPath:kGULAppDelegateKeyPath + options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld + context:nil]; + _isObserving = YES; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if ([keyPath isEqual:kGULAppDelegateKeyPath]) { + id newValue = change[NSKeyValueChangeNewKey]; + id oldValue = change[NSKeyValueChangeOldKey]; + if ([newValue isEqual:oldValue]) { + return; + } + // Free the stored app delegate instance because it has been changed to a different instance to + // avoid keeping it alive forever. + if ([oldValue isEqual:gOriginalAppDelegate]) { + gOriginalAppDelegate = nil; + // Remove the observer. Parse it to NSObject to avoid warning. + [[GULAppDelegateSwizzler sharedApplication] removeObserver:self + forKeyPath:kGULAppDelegateKeyPath]; + _isObserving = NO; + } + } +} + +@end + +@implementation GULAppDelegateSwizzler + +static dispatch_once_t sProxyAppDelegateOnceToken; +static dispatch_once_t sProxyAppDelegateRemoteNotificationOnceToken; + +#pragma mark - Public methods + ++ (BOOL)isAppDelegateProxyEnabled { + NSDictionary *infoDictionary = [NSBundle mainBundle].infoDictionary; + + id isFirebaseProxyEnabledPlistValue = infoDictionary[kGULFirebaseAppDelegateProxyEnabledPlistKey]; + id isGoogleProxyEnabledPlistValue = + infoDictionary[kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey]; + + // Enabled by default. + BOOL isFirebaseAppDelegateProxyEnabled = YES; + BOOL isGoogleUtilitiesAppDelegateProxyEnabled = YES; + + if ([isFirebaseProxyEnabledPlistValue isKindOfClass:[NSNumber class]]) { + isFirebaseAppDelegateProxyEnabled = [isFirebaseProxyEnabledPlistValue boolValue]; + } + + if ([isGoogleProxyEnabledPlistValue isKindOfClass:[NSNumber class]]) { + isGoogleUtilitiesAppDelegateProxyEnabled = [isGoogleProxyEnabledPlistValue boolValue]; + } + + // Only deactivate the proxy if it is explicitly disabled by app developers using either one of + // the plist flags. + return isFirebaseAppDelegateProxyEnabled && isGoogleUtilitiesAppDelegateProxyEnabled; +} + ++ (GULAppDelegateInterceptorID)registerAppDelegateInterceptor: + (id)interceptor { + NSAssert(interceptor, @"AppDelegateProxy cannot add nil interceptor"); + NSAssert([interceptor conformsToProtocol:@protocol(GULApplicationDelegate)], + @"AppDelegateProxy interceptor does not conform to UIApplicationDelegate"); + + if (!interceptor) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling000], + @"AppDelegateProxy cannot add nil interceptor."); + return nil; + } + if (![interceptor conformsToProtocol:@protocol(GULApplicationDelegate)]) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling001], + @"AppDelegateProxy interceptor does not conform to UIApplicationDelegate"); + return nil; + } + + // The ID should be the same given the same interceptor object. + NSString *interceptorID = [NSString stringWithFormat:@"%@%p", kGULAppDelegatePrefix, interceptor]; + if (!interceptorID.length) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling002], + @"AppDelegateProxy cannot create Interceptor ID."); + return nil; + } + GULZeroingWeakContainer *weakObject = [[GULZeroingWeakContainer alloc] init]; + weakObject.object = interceptor; + [GULAppDelegateSwizzler interceptors][interceptorID] = weakObject; + return interceptorID; +} + ++ (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID { + NSAssert(interceptorID, @"AppDelegateProxy cannot unregister nil interceptor ID."); + NSAssert(((NSString *)interceptorID).length != 0, + @"AppDelegateProxy cannot unregister empty interceptor ID."); + + if (!interceptorID) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling003], + @"AppDelegateProxy cannot unregister empty interceptor ID."); + return; + } + + GULZeroingWeakContainer *weakContainer = [GULAppDelegateSwizzler interceptors][interceptorID]; + if (!weakContainer.object) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling004], + @"AppDelegateProxy cannot unregister interceptor that was not registered. " + "Interceptor ID %@", + interceptorID); + return; + } + + [[GULAppDelegateSwizzler interceptors] removeObjectForKey:interceptorID]; +} + ++ (void)proxyOriginalDelegate { + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + dispatch_once(&sProxyAppDelegateOnceToken, ^{ + id originalDelegate = + [GULAppDelegateSwizzler sharedApplication].delegate; + [GULAppDelegateSwizzler proxyAppDelegate:originalDelegate]; + }); +} + ++ (void)proxyOriginalDelegateIncludingAPNSMethods { + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + [self proxyOriginalDelegate]; + + dispatch_once(&sProxyAppDelegateRemoteNotificationOnceToken, ^{ + id appDelegate = [GULAppDelegateSwizzler sharedApplication].delegate; + + NSMutableDictionary *realImplementationsBySelector = + [objc_getAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey) mutableCopy]; + + [self proxyRemoteNotificationsMethodsWithAppDelegateSubClass:gAppDelegateSubclass + realClass:gOriginalAppDelegateClass + appDelegate:appDelegate + realImplementationsBySelector:realImplementationsBySelector]; + + objc_setAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN); + [self reassignAppDelegate]; + }); +} + +#pragma mark - Create proxy + ++ (GULApplication *)sharedApplication { + if ([GULAppEnvironmentUtil isAppExtension]) { + return nil; + } + id sharedApplication = nil; + Class uiApplicationClass = NSClassFromString(kGULApplicationClassName); + if (uiApplicationClass && + [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) { + sharedApplication = [uiApplicationClass sharedApplication]; + } + return sharedApplication; +} + +#pragma mark - Override default methods + +/** Creates a new subclass of the class of the given object and sets the isa value of the given + * object to the new subclass. Additionally this copies methods to that new subclass that allow us + * to intercept UIApplicationDelegate methods. This is better known as isa swizzling. + * + * @param appDelegate The object to which you want to isa swizzle. This has to conform to the + * UIApplicationDelegate subclass. + * @return Returns the new subclass. + */ ++ (nullable Class)createSubclassWithObject:(id)appDelegate { + Class realClass = [appDelegate class]; + + // Create GUL__ + NSString *classNameWithPrefix = + [kGULAppDelegatePrefix stringByAppendingString:NSStringFromClass(realClass)]; + NSString *newClassName = + [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString]; + + if (NSClassFromString(newClassName)) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling005], + @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: " + @"%@, subclass: %@", + NSStringFromClass(realClass), newClassName); + return nil; + } + + // Register the new class as subclass of the real one. Do not allocate more than the real class + // size. + Class appDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0); + if (appDelegateSubClass == Nil) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling006], + @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: " + @"%@, subclass: Nil", + NSStringFromClass(realClass)); + return nil; + } + + NSMutableDictionary *realImplementationsBySelector = + [[NSMutableDictionary alloc] init]; + + // For application:continueUserActivity:restorationHandler: + SEL continueUserActivitySEL = @selector(application:continueUserActivity:restorationHandler:); + [self proxyDestinationSelector:continueUserActivitySEL + implementationsFromSourceSelector:continueUserActivitySEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + +#if TARGET_OS_IOS || TARGET_OS_TV + // Add the following methods from GULAppDelegate class, and store the real implementation so it + // can forward to the real one. + // For application:openURL:options: + SEL applicationOpenURLOptionsSEL = @selector(application:openURL:options:); + if ([appDelegate respondsToSelector:applicationOpenURLOptionsSEL]) { + // Only add the application:openURL:options: method if the original AppDelegate implements it. + // This fixes a bug if an app only implements application:openURL:sourceApplication:annotation: + // (if we add the `options` method, iOS sees that one exists and does not call the + // `sourceApplication` method, which in this case is the only one the app implements). + + [self proxyDestinationSelector:applicationOpenURLOptionsSEL + implementationsFromSourceSelector:applicationOpenURLOptionsSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + } + + // For application:handleEventsForBackgroundURLSession:completionHandler: + SEL handleEventsForBackgroundURLSessionSEL = @selector(application: + handleEventsForBackgroundURLSession:completionHandler:); + [self proxyDestinationSelector:handleEventsForBackgroundURLSessionSEL + implementationsFromSourceSelector:handleEventsForBackgroundURLSessionSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_IOS + // For application:openURL:sourceApplication:annotation: + SEL openURLSourceApplicationAnnotationSEL = @selector(application: + openURL:sourceApplication:annotation:); + + [self proxyDestinationSelector:openURLSourceApplicationAnnotationSEL + implementationsFromSourceSelector:openURLSourceApplicationAnnotationSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; +#endif // TARGET_OS_IOS + + // Override the description too so the custom class name will not show up. + [GULAppDelegateSwizzler addInstanceMethodWithDestinationSelector:@selector(description) + withImplementationFromSourceSelector:@selector(fakeDescription) + fromClass:[self class] + toClass:appDelegateSubClass]; + + // Store original implementations to a fake property of the original delegate. + objc_setAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(appDelegate, &kGULRealClassKey, realClass, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + // The subclass size has to be exactly the same size with the original class size. The subclass + // cannot have more ivars/properties than its superclass since it will cause an offset in memory + // that can lead to overwriting the isa of an object in the next frame. + if (class_getInstanceSize(realClass) != class_getInstanceSize(appDelegateSubClass)) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling007], + @"Cannot create subclass of App Delegate, because the created subclass is not the " + @"same size. %@", + NSStringFromClass(realClass)); + NSAssert(NO, @"Classes must be the same size to swizzle isa"); + return nil; + } + + // Make the newly created class to be the subclass of the real App Delegate class. + objc_registerClassPair(appDelegateSubClass); + if (object_setClass(appDelegate, appDelegateSubClass)) { + GULLogDebug(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling008], + @"Successfully created App Delegate Proxy automatically. To disable the " + @"proxy, set the flag %@ to NO (Boolean) in the Info.plist", + [GULAppDelegateSwizzler correctAppDelegateProxyKey]); + } + + return appDelegateSubClass; +} + ++ (void)proxyRemoteNotificationsMethodsWithAppDelegateSubClass:(Class)appDelegateSubClass + realClass:(Class)realClass + appDelegate:(id)appDelegate + realImplementationsBySelector: + (NSMutableDictionary *)realImplementationsBySelector { + if (realClass == nil || appDelegateSubClass == nil || appDelegate == nil || + realImplementationsBySelector == nil) { + // The App Delegate has not been swizzled. + return; + } + + // For application:didRegisterForRemoteNotificationsWithDeviceToken: + SEL didRegisterForRemoteNotificationsSEL = + NSSelectorFromString(kGULDidRegisterForRemoteNotificationsSEL); + SEL didRegisterForRemoteNotificationsDonorSEL = @selector(application: + donor_didRegisterForRemoteNotificationsWithDeviceToken:); + + [self proxyDestinationSelector:didRegisterForRemoteNotificationsSEL + implementationsFromSourceSelector:didRegisterForRemoteNotificationsDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // For application:didFailToRegisterForRemoteNotificationsWithError: + SEL didFailToRegisterForRemoteNotificationsSEL = + NSSelectorFromString(kGULDidFailToRegisterForRemoteNotificationsSEL); + SEL didFailToRegisterForRemoteNotificationsDonorSEL = @selector(application: + donor_didFailToRegisterForRemoteNotificationsWithError:); + + [self proxyDestinationSelector:didFailToRegisterForRemoteNotificationsSEL + implementationsFromSourceSelector:didFailToRegisterForRemoteNotificationsDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // For application:didReceiveRemoteNotification: + SEL didReceiveRemoteNotificationSEL = NSSelectorFromString(kGULDidReceiveRemoteNotificationSEL); + SEL didReceiveRemoteNotificationDonotSEL = @selector(application: + donor_didReceiveRemoteNotification:); + + [self proxyDestinationSelector:didReceiveRemoteNotificationSEL + implementationsFromSourceSelector:didReceiveRemoteNotificationDonotSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // For application:didReceiveRemoteNotification:fetchCompletionHandler: +#if !TARGET_OS_WATCH && !TARGET_OS_OSX + SEL didReceiveRemoteNotificationWithCompletionSEL = + NSSelectorFromString(kGULDidReceiveRemoteNotificationWithCompletionSEL); + SEL didReceiveRemoteNotificationWithCompletionDonorSEL = + @selector(application:donor_didReceiveRemoteNotification:fetchCompletionHandler:); + if ([appDelegate respondsToSelector:didReceiveRemoteNotificationWithCompletionSEL]) { + // Only add the application:didReceiveRemoteNotification:fetchCompletionHandler: method if + // the original AppDelegate implements it. + // This fixes a bug if an app only implements application:didReceiveRemoteNotification: + // (if we add the method with completion, iOS sees that one exists and does not call + // the method without the completion, which in this case is the only one the app implements). + + [self proxyDestinationSelector:didReceiveRemoteNotificationWithCompletionSEL + implementationsFromSourceSelector:didReceiveRemoteNotificationWithCompletionDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + } +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX +} + +/// We have to do this to invalidate the cache that caches the original respondsToSelector of +/// openURL handlers. Without this, it won't call the default implementations because the system +/// checks and caches them. +/// Register KVO only once. Otherwise, the observing method will be called as many times as +/// being registered. ++ (void)reassignAppDelegate { +#if !TARGET_OS_WATCH + id delegate = [self sharedApplication].delegate; + [self sharedApplication].delegate = nil; + [self sharedApplication].delegate = delegate; + gOriginalAppDelegate = delegate; + [[GULAppDelegateObserver sharedInstance] observeUIApplication]; +#endif +} + +#pragma mark - Helper methods + ++ (GULMutableDictionary *)interceptors { + static dispatch_once_t onceToken; + static GULMutableDictionary *sInterceptors; + dispatch_once(&onceToken, ^{ + sInterceptors = [[GULMutableDictionary alloc] init]; + }); + return sInterceptors; +} + ++ (nullable NSValue *)originalImplementationForSelector:(SEL)selector object:(id)object { + NSDictionary *realImplementationBySelector = + objc_getAssociatedObject(object, &kGULRealIMPBySelectorKey); + return realImplementationBySelector[NSStringFromSelector(selector)]; +} + ++ (void)proxyDestinationSelector:(SEL)destinationSelector + implementationsFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)sourceClass + toClass:(Class)destinationClass + realClass:(Class)realClass + storeDestinationImplementationTo: + (NSMutableDictionary *)destinationImplementationsBySelector { + [self addInstanceMethodWithDestinationSelector:destinationSelector + withImplementationFromSourceSelector:sourceSelector + fromClass:sourceClass + toClass:destinationClass]; + IMP sourceImplementation = + [GULAppDelegateSwizzler implementationOfMethodSelector:destinationSelector + fromClass:realClass]; + NSValue *sourceImplementationPointer = [NSValue valueWithPointer:sourceImplementation]; + + NSString *destinationSelectorString = NSStringFromSelector(destinationSelector); + destinationImplementationsBySelector[destinationSelectorString] = sourceImplementationPointer; +} + +/** Copies a method identified by the methodSelector from one class to the other. After this method + * is called, performing [toClassInstance methodSelector] will be similar to calling + * [fromClassInstance methodSelector]. This method does nothing if toClass already has a method + * identified by methodSelector. + * + * @param methodSelector The SEL that identifies both the method on the fromClass as well as the + * one on the toClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithSelector:(SEL)methodSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + [self addInstanceMethodWithDestinationSelector:methodSelector + withImplementationFromSourceSelector:methodSelector + fromClass:fromClass + toClass:toClass]; +} + +/** Copies a method identified by the sourceSelector from the fromClass as a method for the + * destinationSelector on the toClass. After this method is called, performing + * [toClassInstance destinationSelector] will be similar to calling + * [fromClassInstance sourceSelector]. This method does nothing if toClass already has a method + * identified by destinationSelector. + * + * @param destinationSelector The SEL that identifies the method on the toClass. + * @param sourceSelector The SEL that identifies the method on the fromClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector + withImplementationFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + Method method = class_getInstanceMethod(fromClass, sourceSelector); + IMP methodIMP = method_getImplementation(method); + const char *types = method_getTypeEncoding(method); + if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) { + GULLogWarning(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling009], + @"Cannot copy method to destination selector %@ as it already exists", + NSStringFromSelector(destinationSelector)); + } +} + +/** Gets the IMP of the instance method on the class identified by the selector. + * + * @param selector The selector of which the IMP is to be fetched. + * @param aClass The class from which the IMP is to be fetched. + * @return The IMP of the instance method identified by selector and aClass. + */ ++ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass { + Method aMethod = class_getInstanceMethod(aClass, selector); + return method_getImplementation(aMethod); +} + +/** Enumerates through all the interceptors and if they respond to a given selector, executes a + * GULAppDelegateInterceptorCallback with the interceptor. + * + * @param methodSelector The SEL to check if an interceptor responds to. + * @param callback the GULAppDelegateInterceptorCallback. + */ ++ (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector + callback:(GULAppDelegateInterceptorCallback)callback { + if (!callback) { + return; + } + + NSDictionary *interceptors = [GULAppDelegateSwizzler interceptors].dictionary; + [interceptors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + GULZeroingWeakContainer *interceptorContainer = obj; + id interceptor = interceptorContainer.object; + if (!interceptor) { + GULLogWarning( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling010], + @"AppDelegateProxy cannot find interceptor with ID %@. Removing the interceptor.", key); + [[GULAppDelegateSwizzler interceptors] removeObjectForKey:key]; + return; + } + if ([interceptor respondsToSelector:methodSelector]) { + callback(interceptor); + } + }]; +} + +// The methods below are donor methods which are added to the dynamic subclass of the App Delegate. +// They are called within the scope of the real App Delegate so |self| does not refer to the +// GULAppDelegateSwizzler instance but the real App Delegate instance. + +#pragma mark - [Donor Methods] Overridden instance description method + +- (NSString *)fakeDescription { + Class realClass = objc_getAssociatedObject(self, &kGULRealClassKey); + return [NSString stringWithFormat:@"<%@: %p>", realClass, self]; +} + +#pragma mark - [Donor Methods] URL overridden handler methods +#if TARGET_OS_IOS || TARGET_OS_TV + +- (BOOL)application:(GULApplication *)application + openURL:(NSURL *)url + options:(NSDictionary *)options { + SEL methodSelector = @selector(application:openURL:options:); + // Call the real implementation if the real App Delegate has any. + NSValue *openURLIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealOpenURLOptionsIMP openURLOptionsIMP = [openURLIMPPointer pointerValue]; + + __block BOOL returnedValue = NO; + +// This is needed to for the library to be warning free on iOS versions < 9. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + returnedValue |= [interceptor application:application + openURL:url + options:options]; + }]; +#pragma clang diagnostic pop + if (openURLOptionsIMP) { + returnedValue |= openURLOptionsIMP(self, methodSelector, application, url, options); + } + return returnedValue; +} + +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_IOS + +- (BOOL)application:(GULApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation { + SEL methodSelector = @selector(application:openURL:sourceApplication:annotation:); + + // Call the real implementation if the real App Delegate has any. + NSValue *openURLSourceAppAnnotationIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealOpenURLSourceApplicationAnnotationIMP openURLSourceApplicationAnnotationIMP = + [openURLSourceAppAnnotationIMPPointer pointerValue]; + + __block BOOL returnedValue = NO; + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + returnedValue |= [interceptor application:application + openURL:url + sourceApplication:sourceApplication + annotation:annotation]; +#pragma clang diagnostic pop + }]; + if (openURLSourceApplicationAnnotationIMP) { + returnedValue |= openURLSourceApplicationAnnotationIMP(self, methodSelector, application, url, + sourceApplication, annotation); + } + return returnedValue; +} + +#endif // TARGET_OS_IOS + +#pragma mark - [Donor Methods] Network overridden handler methods + +#if TARGET_OS_IOS || TARGET_OS_TV + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-prototypes" +- (void)application:(GULApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(void (^)())completionHandler API_AVAILABLE(ios(7.0)) { +#pragma clang diagnostic pop + SEL methodSelector = @selector(application: + handleEventsForBackgroundURLSession:completionHandler:); + NSValue *handleBackgroundSessionPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealHandleEventsForBackgroundURLSessionIMP handleBackgroundSessionIMP = + [handleBackgroundSessionPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + [interceptor application:application + handleEventsForBackgroundURLSession:identifier + completionHandler:completionHandler]; + }]; + // Call the real implementation if the real App Delegate has any. + if (handleBackgroundSessionIMP) { + handleBackgroundSessionIMP(self, methodSelector, application, identifier, completionHandler); + } +} + +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#pragma mark - [Donor Methods] User Activities overridden handler methods + +- (BOOL)application:(GULApplication *)application + continueUserActivity:(NSUserActivity *)userActivity + restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { + SEL methodSelector = @selector(application:continueUserActivity:restorationHandler:); + NSValue *continueUserActivityIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealContinueUserActivityIMP continueUserActivityIMP = + continueUserActivityIMPPointer.pointerValue; + + __block BOOL returnedValue = NO; +#if !TARGET_OS_WATCH + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + returnedValue |= [interceptor application:application + continueUserActivity:userActivity + restorationHandler:restorationHandler]; + }]; +#endif + // Call the real implementation if the real App Delegate has any. + if (continueUserActivityIMP) { + returnedValue |= continueUserActivityIMP(self, methodSelector, application, userActivity, + restorationHandler); + } + return returnedValue; +} + +#pragma mark - [Donor Methods] Remote Notifications + +- (void)application:(GULApplication *)application + donor_didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + SEL methodSelector = NSSelectorFromString(kGULDidRegisterForRemoteNotificationsSEL); + + NSValue *didRegisterForRemoteNotificationsIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidRegisterForRemoteNotificationsIMP didRegisterForRemoteNotificationsIMP = + [didRegisterForRemoteNotificationsIMPPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&deviceToken) atIndex:3]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didRegisterForRemoteNotificationsIMP) { + didRegisterForRemoteNotificationsIMP(self, methodSelector, application, deviceToken); + } +} + +- (void)application:(GULApplication *)application + donor_didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { + SEL methodSelector = NSSelectorFromString(kGULDidFailToRegisterForRemoteNotificationsSEL); + NSValue *didFailToRegisterForRemoteNotificationsIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidFailToRegisterForRemoteNotificationsIMP didFailToRegisterForRemoteNotificationsIMP = + [didFailToRegisterForRemoteNotificationsIMPPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&error) atIndex:3]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didFailToRegisterForRemoteNotificationsIMP) { + didFailToRegisterForRemoteNotificationsIMP(self, methodSelector, application, error); + } +} + +#if !TARGET_OS_WATCH && !TARGET_OS_OSX +- (void)application:(GULApplication *)application + donor_didReceiveRemoteNotification:(NSDictionary *)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { + SEL methodSelector = NSSelectorFromString(kGULDidReceiveRemoteNotificationWithCompletionSEL); + NSValue *didReceiveRemoteNotificationWithCompletionIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidReceiveRemoteNotificationWithCompletionIMP + didReceiveRemoteNotificationWithCompletionIMP = + [didReceiveRemoteNotificationWithCompletionIMPPointer pointerValue]; + + dispatch_group_t __block callbackGroup = dispatch_group_create(); + NSMutableArray *__block fetchResults = [NSMutableArray array]; + + void (^localCompletionHandler)(UIBackgroundFetchResult) = + ^void(UIBackgroundFetchResult fetchResult) { + [fetchResults addObject:[NSNumber numberWithInt:(int)fetchResult]]; + dispatch_group_leave(callbackGroup); + }; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + dispatch_group_enter(callbackGroup); + + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&userInfo) atIndex:3]; + [invocation setArgument:(void *)(&localCompletionHandler) + atIndex:4]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didReceiveRemoteNotificationWithCompletionIMP) { + dispatch_group_enter(callbackGroup); + + didReceiveRemoteNotificationWithCompletionIMP(self, methodSelector, application, userInfo, + localCompletionHandler); + } + + dispatch_group_notify(callbackGroup, dispatch_get_main_queue(), ^() { + BOOL allFetchesFailed = YES; + BOOL anyFetchHasNewData = NO; + + for (NSNumber *oneResult in fetchResults) { + UIBackgroundFetchResult result = oneResult.intValue; + + switch (result) { + case UIBackgroundFetchResultNoData: + allFetchesFailed = NO; + break; + case UIBackgroundFetchResultNewData: + allFetchesFailed = NO; + anyFetchHasNewData = YES; + break; + case UIBackgroundFetchResultFailed: + + break; + } + } + + UIBackgroundFetchResult finalFetchResult = UIBackgroundFetchResultNoData; + + if (allFetchesFailed) { + finalFetchResult = UIBackgroundFetchResultFailed; + } else if (anyFetchHasNewData) { + finalFetchResult = UIBackgroundFetchResultNewData; + } else { + finalFetchResult = UIBackgroundFetchResultNoData; + } + + completionHandler(finalFetchResult); + }); +} +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX + +- (void)application:(GULApplication *)application + donor_didReceiveRemoteNotification:(NSDictionary *)userInfo { + SEL methodSelector = NSSelectorFromString(kGULDidReceiveRemoteNotificationSEL); + NSValue *didReceiveRemoteNotificationIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidReceiveRemoteNotificationIMP didReceiveRemoteNotificationIMP = + [didReceiveRemoteNotificationIMPPointer pointerValue]; + + // Notify interceptors. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&userInfo) atIndex:3]; + [invocation invoke]; + }]; +#pragma clang diagnostic pop + // Call the real implementation if the real App Delegate has any. + if (didReceiveRemoteNotificationIMP) { + didReceiveRemoteNotificationIMP(self, methodSelector, application, userInfo); + } +} + ++ (nullable NSInvocation *)appDelegateInvocationForSelector:(SEL)selector { + struct objc_method_description methodDescription = + protocol_getMethodDescription(@protocol(GULApplicationDelegate), selector, NO, YES); + if (methodDescription.types == NULL) { + return nil; + } + + NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:methodDescription.types]; + return [NSInvocation invocationWithMethodSignature:signature]; +} + ++ (void)proxyAppDelegate:(id)appDelegate { + if (![appDelegate conformsToProtocol:@protocol(GULApplicationDelegate)]) { + GULLogNotice( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate], + @"App Delegate does not conform to UIApplicationDelegate protocol. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + + id originalDelegate = appDelegate; + // Do not create a subclass if it is not enabled. + if (![GULAppDelegateSwizzler isAppDelegateProxyEnabled]) { + GULLogNotice(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling011], + @"App Delegate Proxy is disabled. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + // Do not accept nil delegate. + if (!originalDelegate) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling012], + @"Cannot create App Delegate Proxy because App Delegate instance is nil. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + + @try { + gOriginalAppDelegateClass = [originalDelegate class]; + gAppDelegateSubclass = [self createSubclassWithObject:originalDelegate]; + [self reassignAppDelegate]; + } @catch (NSException *exception) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling013], + @"Cannot create App Delegate Proxy. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } +} + +#pragma mark - Methods to print correct debug logs + ++ (NSString *)correctAppDelegateProxyKey { + return NSClassFromString(@"FIRCore") ? kGULFirebaseAppDelegateProxyEnabledPlistKey + : kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey; +} + ++ (NSString *)correctAlternativeWhenAppDelegateProxyNotCreated { + return NSClassFromString(@"FIRCore") + ? @"To log deep link campaigns manually, call the methods in " + @"FIRAnalytics+AppDelegate.h." + : @""; +} + +#pragma mark - Private Methods for Testing + ++ (void)clearInterceptors { + [[self interceptors] removeAllObjects]; +} + ++ (void)resetProxyOriginalDelegateOnceToken { + sProxyAppDelegateOnceToken = 0; + sProxyAppDelegateRemoteNotificationOnceToken = 0; +} + ++ (id)originalDelegate { + return gOriginalAppDelegate; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m new file mode 100644 index 0000000..36ba1ca --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m @@ -0,0 +1,439 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h" + +#import "GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h" +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Common/GULLoggerCodes.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +#import + +#if UISCENE_SUPPORTED +API_AVAILABLE(ios(13.0), tvos(13.0)) +typedef void (*GULOpenURLContextsIMP)(id, SEL, UIScene *, NSSet *); + +API_AVAILABLE(ios(13.0), tvos(13.0)) +typedef void (^GULSceneDelegateInterceptorCallback)(id); + +// The strings below are the keys for associated objects. +static char const *const kGULRealIMPBySelectorKey = "GUL_realIMPBySelector"; +static char const *const kGULRealClassKey = "GUL_realClass"; +#endif // UISCENE_SUPPORTED + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/SceneDelegateSwizzler]"; + +// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change +// we disable App Delegate proxying when either of these two flags are set to NO. + +/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */ +static NSString *const kGULFirebaseSceneDelegateProxyEnabledPlistKey = + @"FirebaseAppDelegateProxyEnabled"; + +/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying. + */ +static NSString *const kGULGoogleUtilitiesSceneDelegateProxyEnabledPlistKey = + @"GoogleUtilitiesAppDelegateProxyEnabled"; + +/** The prefix of the Scene Delegate. */ +static NSString *const kGULSceneDelegatePrefix = @"GUL_"; + +/** + * This class is necessary to store the delegates in an NSArray without retaining them. + * [NSValue valueWithNonRetainedObject] also provides this functionality, but does not provide a + * zeroing pointer. This will cause EXC_BAD_ACCESS when trying to access the object after it is + * dealloced. Instead, this container stores a weak, zeroing reference to the object, which + * automatically is set to nil by the runtime when the object is dealloced. + */ +@interface GULSceneZeroingWeakContainer : NSObject + +/** Stores a weak object. */ +@property(nonatomic, weak) id object; + +@end + +@implementation GULSceneZeroingWeakContainer +@end + +@implementation GULSceneDelegateSwizzler + +#pragma mark - Public methods + ++ (BOOL)isSceneDelegateProxyEnabled { + return [GULAppDelegateSwizzler isAppDelegateProxyEnabled]; +} + ++ (void)proxyOriginalSceneDelegate { +#if UISCENE_SUPPORTED + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (@available(iOS 13.0, tvOS 13.0, *)) { + if (![GULSceneDelegateSwizzler isSceneDelegateProxyEnabled]) { + return; + } + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(handleSceneWillConnectToNotification:) + name:UISceneWillConnectNotification + object:nil]; + } + }); +#endif // UISCENE_SUPPORTED +} + +#if UISCENE_SUPPORTED ++ (GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor:(id)interceptor { + NSAssert(interceptor, @"SceneDelegateProxy cannot add nil interceptor"); + NSAssert([interceptor conformsToProtocol:@protocol(UISceneDelegate)], + @"SceneDelegateProxy interceptor does not conform to UIApplicationDelegate"); + + if (!interceptor) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling000], + @"SceneDelegateProxy cannot add nil interceptor."); + return nil; + } + if (![interceptor conformsToProtocol:@protocol(UISceneDelegate)]) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling001], + @"SceneDelegateProxy interceptor does not conform to UIApplicationDelegate"); + return nil; + } + + // The ID should be the same given the same interceptor object. + NSString *interceptorID = + [NSString stringWithFormat:@"%@%p", kGULSceneDelegatePrefix, interceptor]; + if (!interceptorID.length) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling002], + @"SceneDelegateProxy cannot create Interceptor ID."); + return nil; + } + GULSceneZeroingWeakContainer *weakObject = [[GULSceneZeroingWeakContainer alloc] init]; + weakObject.object = interceptor; + [GULSceneDelegateSwizzler interceptors][interceptorID] = weakObject; + return interceptorID; +} + ++ (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID { + NSAssert(interceptorID, @"SceneDelegateProxy cannot unregister nil interceptor ID."); + NSAssert(((NSString *)interceptorID).length != 0, + @"SceneDelegateProxy cannot unregister empty interceptor ID."); + + if (!interceptorID) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling003], + @"SceneDelegateProxy cannot unregister empty interceptor ID."); + return; + } + + GULSceneZeroingWeakContainer *weakContainer = + [GULSceneDelegateSwizzler interceptors][interceptorID]; + if (!weakContainer.object) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling004], + @"SceneDelegateProxy cannot unregister interceptor that was not registered. " + "Interceptor ID %@", + interceptorID); + return; + } + + [[GULSceneDelegateSwizzler interceptors] removeObjectForKey:interceptorID]; +} + +#pragma mark - Helper methods + ++ (GULMutableDictionary *)interceptors { + static dispatch_once_t onceToken; + static GULMutableDictionary *sInterceptors; + dispatch_once(&onceToken, ^{ + sInterceptors = [[GULMutableDictionary alloc] init]; + }); + return sInterceptors; +} + ++ (void)clearInterceptors { + [[self interceptors] removeAllObjects]; +} + ++ (nullable NSValue *)originalImplementationForSelector:(SEL)selector object:(id)object { + NSDictionary *realImplementationBySelector = + objc_getAssociatedObject(object, &kGULRealIMPBySelectorKey); + return realImplementationBySelector[NSStringFromSelector(selector)]; +} + ++ (void)proxyDestinationSelector:(SEL)destinationSelector + implementationsFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)sourceClass + toClass:(Class)destinationClass + realClass:(Class)realClass + storeDestinationImplementationTo: + (NSMutableDictionary *)destinationImplementationsBySelector { + [self addInstanceMethodWithDestinationSelector:destinationSelector + withImplementationFromSourceSelector:sourceSelector + fromClass:sourceClass + toClass:destinationClass]; + IMP sourceImplementation = + [GULSceneDelegateSwizzler implementationOfMethodSelector:destinationSelector + fromClass:realClass]; + NSValue *sourceImplementationPointer = [NSValue valueWithPointer:sourceImplementation]; + + NSString *destinationSelectorString = NSStringFromSelector(destinationSelector); + destinationImplementationsBySelector[destinationSelectorString] = sourceImplementationPointer; +} + +/** Copies a method identified by the methodSelector from one class to the other. After this method + * is called, performing [toClassInstance methodSelector] will be similar to calling + * [fromClassInstance methodSelector]. This method does nothing if toClass already has a method + * identified by methodSelector. + * + * @param methodSelector The SEL that identifies both the method on the fromClass as well as the + * one on the toClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithSelector:(SEL)methodSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + [self addInstanceMethodWithDestinationSelector:methodSelector + withImplementationFromSourceSelector:methodSelector + fromClass:fromClass + toClass:toClass]; +} + +/** Copies a method identified by the sourceSelector from the fromClass as a method for the + * destinationSelector on the toClass. After this method is called, performing + * [toClassInstance destinationSelector] will be similar to calling + * [fromClassInstance sourceSelector]. This method does nothing if toClass already has a method + * identified by destinationSelector. + * + * @param destinationSelector The SEL that identifies the method on the toClass. + * @param sourceSelector The SEL that identifies the method on the fromClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector + withImplementationFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + Method method = class_getInstanceMethod(fromClass, sourceSelector); + IMP methodIMP = method_getImplementation(method); + const char *types = method_getTypeEncoding(method); + if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) { + GULLogWarning( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling009], + @"Cannot copy method to destination selector %@ as it already exists", + NSStringFromSelector(destinationSelector)); + } +} + +/** Gets the IMP of the instance method on the class identified by the selector. + * + * @param selector The selector of which the IMP is to be fetched. + * @param aClass The class from which the IMP is to be fetched. + * @return The IMP of the instance method identified by selector and aClass. + */ ++ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass { + Method aMethod = class_getInstanceMethod(aClass, selector); + return method_getImplementation(aMethod); +} + +/** Enumerates through all the interceptors and if they respond to a given selector, executes a + * GULSceneDelegateInterceptorCallback with the interceptor. + * + * @param methodSelector The SEL to check if an interceptor responds to. + * @param callback the GULSceneDelegateInterceptorCallback. + */ ++ (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector + callback:(GULSceneDelegateInterceptorCallback)callback + API_AVAILABLE(ios(13.0)) { + if (!callback) { + return; + } + + NSDictionary *interceptors = [GULSceneDelegateSwizzler interceptors].dictionary; + [interceptors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + GULSceneZeroingWeakContainer *interceptorContainer = obj; + id interceptor = interceptorContainer.object; + if (!interceptor) { + GULLogWarning( + kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling010], + @"SceneDelegateProxy cannot find interceptor with ID %@. Removing the interceptor.", key); + [[GULSceneDelegateSwizzler interceptors] removeObjectForKey:key]; + return; + } + if ([interceptor respondsToSelector:methodSelector]) { + callback(interceptor); + } + }]; +} + ++ (void)handleSceneWillConnectToNotification:(NSNotification *)notification { + if (@available(iOS 13.0, tvOS 13.0, *)) { + if ([notification.object isKindOfClass:[UIScene class]]) { + UIScene *scene = (UIScene *)notification.object; + [GULSceneDelegateSwizzler proxySceneDelegateIfNeeded:scene]; + } + } +} + +#pragma mark - [Donor Methods] UISceneDelegate URL handler + +- (void)scene:(UIScene *)scene + openURLContexts:(NSSet *)URLContexts API_AVAILABLE(ios(13.0), tvos(13.0)) { + if (@available(iOS 13.0, tvOS 13.0, *)) { + SEL methodSelector = @selector(scene:openURLContexts:); + // Call the real implementation if the real Scene Delegate has any. + NSValue *openURLContextsIMPPointer = + [GULSceneDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULOpenURLContextsIMP openURLContextsIMP = [openURLContextsIMPPointer pointerValue]; + + [GULSceneDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + if ([interceptor + conformsToProtocol:@protocol(UISceneDelegate)]) { + id sceneInterceptor = + (id)interceptor; + [sceneInterceptor scene:scene openURLContexts:URLContexts]; + } + }]; + + if (openURLContextsIMP) { + openURLContextsIMP(self, methodSelector, scene, URLContexts); + } + } +} + ++ (void)proxySceneDelegateIfNeeded:(UIScene *)scene { + Class realClass = [scene.delegate class]; + NSString *className = NSStringFromClass(realClass); + + // Skip proxying if failed to get the delegate class name for some reason (e.g. `delegate == nil`) + // or the class has a prefix of kGULAppDelegatePrefix, which means it has been proxied before. + if (className == nil || [className hasPrefix:kGULSceneDelegatePrefix]) { + return; + } + + NSString *classNameWithPrefix = [kGULSceneDelegatePrefix stringByAppendingString:className]; + NSString *newClassName = + [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString]; + + if (NSClassFromString(newClassName)) { + GULLogError( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class" + @": %@, subclass: %@", + className, newClassName); + return; + } + + // Register the new class as subclass of the real one. Do not allocate more than the real class + // size. + Class sceneDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0); + if (sceneDelegateSubClass == Nil) { + GULLogError( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class" + @": %@, subclass: Nil", + className); + return; + } + + NSMutableDictionary *realImplementationsBySelector = + [[NSMutableDictionary alloc] init]; + + // For scene:openURLContexts: + SEL openURLContextsSEL = @selector(scene:openURLContexts:); + [self proxyDestinationSelector:openURLContextsSEL + implementationsFromSourceSelector:openURLContextsSEL + fromClass:[GULSceneDelegateSwizzler class] + toClass:sceneDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // Store original implementations to a fake property of the original delegate. + objc_setAssociatedObject(scene.delegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(scene.delegate, &kGULRealClassKey, realClass, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + // The subclass size has to be exactly the same size with the original class size. The subclass + // cannot have more ivars/properties than its superclass since it will cause an offset in memory + // that can lead to overwriting the isa of an object in the next frame. + if (class_getInstanceSize(realClass) != class_getInstanceSize(sceneDelegateSubClass)) { + GULLogError( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create subclass of Scene Delegate, because the created subclass is not the " + @"same size. %@", + className); + NSAssert(NO, @"Classes must be the same size to swizzle isa"); + return; + } + + // Make the newly created class to be the subclass of the real Scene Delegate class. + objc_registerClassPair(sceneDelegateSubClass); + if (object_setClass(scene.delegate, sceneDelegateSubClass)) { + GULLogDebug( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Successfully created Scene Delegate Proxy automatically. To disable the " + @"proxy, set the flag %@ to NO (Boolean) in the Info.plist", + [GULSceneDelegateSwizzler correctSceneDelegateProxyKey]); + } +} + ++ (NSString *)correctSceneDelegateProxyKey { + return NSClassFromString(@"FIRCore") ? kGULFirebaseSceneDelegateProxyEnabledPlistKey + : kGULGoogleUtilitiesSceneDelegateProxyEnabledPlistKey; +} + +#endif // UISCENE_SUPPORTED + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h new file mode 100644 index 0000000..38e9315 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +@class GULApplication; + +NS_ASSUME_NONNULL_BEGIN + +@interface GULAppDelegateSwizzler () + +/** ISA Swizzles the given appDelegate as the original app delegate would be. + * + * @param appDelegate The object that needs to be isa swizzled. This should conform to the + * application delegate protocol. + */ ++ (void)proxyAppDelegate:(id)appDelegate; + +/** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer. + * + * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is + * the interceptorID. + */ ++ (GULMutableDictionary *)interceptors; + +/** Deletes all the registered interceptors. */ ++ (void)clearInterceptors; + +/** Resets the token that prevents the app delegate proxy from being isa swizzled multiple times. */ ++ (void)resetProxyOriginalDelegateOnceToken; + +/** Returns the original app delegate that was proxied. + * + * @return The original app delegate instance that was proxied. + */ ++ (id)originalDelegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h new file mode 100644 index 0000000..89896f7 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GULSceneDelegateSwizzler () + +#if UISCENE_SUPPORTED + +/** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer. + * + * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is + * the interceptorID. + */ ++ (GULMutableDictionary *)interceptors; + +/** Deletes all the registered interceptors. */ ++ (void)clearInterceptors; + +/** ISA Swizzles the given appDelegate as the original app delegate would be. + * + * @param scene The scene whose delegate needs to be isa swizzled. This should conform to the + * scene delegate protocol. + */ ++ (void)proxySceneDelegateIfNeeded:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0)); + +#endif // UISCENE_SUPPORTED + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h new file mode 100644 index 0000000..58dec49 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h @@ -0,0 +1,107 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULApplication.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NSString *const GULAppDelegateInterceptorID; + +/** This class contains methods that isa swizzle the app delegate. */ +@interface GULAppDelegateSwizzler : NSProxy + +/** Registers an app delegate interceptor whose methods will be invoked as they're invoked on the + * original app delegate. + * + * @param interceptor An instance of a class that conforms to the application delegate protocol. + * The interceptor is NOT retained. + * @return A unique GULAppDelegateInterceptorID if interceptor was successfully registered; nil + * if it fails. + */ ++ (nullable GULAppDelegateInterceptorID)registerAppDelegateInterceptor: + (id)interceptor; + +/** Unregisters an interceptor with the given ID if it exists. + * + * @param interceptorID The object that was generated when the interceptor was registered. + */ ++ (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID; + +/** This method ensures that the original app delegate has been proxied. Call this before + * registering your interceptor. This method is safe to call multiple times (but it only proxies + * the app delegate once). + * + * This method doesn't proxy APNS related methods: + * @code + * - application:didRegisterForRemoteNotificationsWithDeviceToken: + * - application:didFailToRegisterForRemoteNotificationsWithError: + * - application:didReceiveRemoteNotification:fetchCompletionHandler: + * - application:didReceiveRemoteNotification: + * @endcode + * + * To proxy these methods use +[GULAppDelegateSwizzler + * proxyOriginalDelegateIncludingAPNSMethods]. The methods have to be proxied separately to + * avoid potential warnings from Apple review about missing Push Notification Entitlement (e.g. + * https://github.com/firebase/firebase-ios-sdk/issues/2807) + * + * The method has no effect for extensions. + * + * @see proxyOriginalDelegateIncludingAPNSMethods + */ ++ (void)proxyOriginalDelegate; + +/** This method ensures that the original app delegate has been proxied including APNS related + * methods. Call this before registering your interceptor. This method is safe to call multiple + * times (but it only proxies the app delegate once) or + * after +[GULAppDelegateSwizzler proxyOriginalDelegate] + * + * This method calls +[GULAppDelegateSwizzler proxyOriginalDelegate] under the hood. + * After calling this method the following App Delegate methods will be proxied in addition to + * the methods proxied by proxyOriginalDelegate: + * @code + * - application:didRegisterForRemoteNotificationsWithDeviceToken: + * - application:didFailToRegisterForRemoteNotificationsWithError: + * - application:didReceiveRemoteNotification:fetchCompletionHandler: + * - application:didReceiveRemoteNotification: + * @endcode + * + * The method has no effect for extensions. + * + * @see proxyOriginalDelegate + */ ++ (void)proxyOriginalDelegateIncludingAPNSMethods; + +/** Indicates whether app delegate proxy is explicitly disabled or enabled. Enabled by default. + * + * @return YES if AppDelegateProxy is Enabled, NO otherwise. + */ ++ (BOOL)isAppDelegateProxyEnabled; + +/** Returns the current sharedApplication. + * + * @return the current application instance if in an app, or nil if in extension or if it doesn't + * exist. + */ ++ (nullable GULApplication *)sharedApplication; + +/** Do not initialize this class. */ +- (instancetype)init NS_UNAVAILABLE; + +NS_ASSUME_NONNULL_END + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h new file mode 100644 index 0000000..8067212 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#if TARGET_OS_IOS || TARGET_OS_TV + +#import + +#define GULApplication UIApplication +#define GULApplicationDelegate UIApplicationDelegate +#define GULUserActivityRestoring UIUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"UIApplication"; + +#elif TARGET_OS_OSX + +#import + +#define GULApplication NSApplication +#define GULApplicationDelegate NSApplicationDelegate +#define GULUserActivityRestoring NSUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"NSApplication"; + +#elif TARGET_OS_WATCH + +#import + +// We match the according watchOS API but swizzling should not work in watch +#define GULApplication WKExtension +#define GULApplicationDelegate WKExtensionDelegate +#define GULUserActivityRestoring NSUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"WKExtension"; + +#endif diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h new file mode 100644 index 0000000..ed080a3 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import + +#if !TARGET_OS_OSX +#import +#endif // !TARGET_OS_OSX + +#if ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000)) +#define UISCENE_SUPPORTED 1 +#endif + +NS_ASSUME_NONNULL_BEGIN + +typedef NSString *const GULSceneDelegateInterceptorID; + +/** This class contains methods that isa swizzle the scene delegate. */ +@interface GULSceneDelegateSwizzler : NSProxy + +#if UISCENE_SUPPORTED + +/** Registers a scene delegate interceptor whose methods will be invoked as they're invoked on the + * original scene delegate. + * + * @param interceptor An instance of a class that conforms to the application delegate protocol. + * The interceptor is NOT retained. + * @return A unique GULSceneDelegateInterceptorID if interceptor was successfully registered; nil + * if it fails. + */ ++ (nullable GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor: + (id)interceptor API_AVAILABLE(ios(13.0), tvos(13.0)); + +/** Unregisters an interceptor with the given ID if it exists. + * + * @param interceptorID The object that was generated when the interceptor was registered. + */ ++ (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID + API_AVAILABLE(ios(13.0), tvos(13.0)); + +/** Do not initialize this class. */ +- (instancetype)init NS_UNAVAILABLE; + +#endif // UISCENE_SUPPORTED + +/** This method ensures that the original scene delegate has been proxied. Call this before + * registering your interceptor. This method is safe to call multiple times (but it only proxies + * the scene delegate once). + * + * The method has no effect for extensions. + */ ++ (void)proxyOriginalSceneDelegate; + +/** Indicates whether scene delegate proxy is explicitly disabled or enabled. Enabled by default. + * + * @return YES if SceneDelegateProxy is Enabled, NO otherwise. + */ ++ (BOOL)isSceneDelegateProxyEnabled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h new file mode 100644 index 0000000..053ce84 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h @@ -0,0 +1,56 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +typedef NS_ENUM(NSInteger, GULSwizzlerMessageCode) { + // App Delegate Swizzling. + kGULSwizzlerMessageCodeAppDelegateSwizzling000 = 1000, // I-SWZ001000 + kGULSwizzlerMessageCodeAppDelegateSwizzling001 = 1001, // I-SWZ001001 + kGULSwizzlerMessageCodeAppDelegateSwizzling002 = 1002, // I-SWZ001002 + kGULSwizzlerMessageCodeAppDelegateSwizzling003 = 1003, // I-SWZ001003 + kGULSwizzlerMessageCodeAppDelegateSwizzling004 = 1004, // I-SWZ001004 + kGULSwizzlerMessageCodeAppDelegateSwizzling005 = 1005, // I-SWZ001005 + kGULSwizzlerMessageCodeAppDelegateSwizzling006 = 1006, // I-SWZ001006 + kGULSwizzlerMessageCodeAppDelegateSwizzling007 = 1007, // I-SWZ001007 + kGULSwizzlerMessageCodeAppDelegateSwizzling008 = 1008, // I-SWZ001008 + kGULSwizzlerMessageCodeAppDelegateSwizzling009 = 1009, // I-SWZ001009 + kGULSwizzlerMessageCodeAppDelegateSwizzling010 = 1010, // I-SWZ001010 + kGULSwizzlerMessageCodeAppDelegateSwizzling011 = 1011, // I-SWZ001011 + kGULSwizzlerMessageCodeAppDelegateSwizzling012 = 1012, // I-SWZ001012 + kGULSwizzlerMessageCodeAppDelegateSwizzling013 = 1013, // I-SWZ001013 + kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate = 1014, // I-SWZ001014 + + // Scene Delegate Swizzling. + kGULSwizzlerMessageCodeSceneDelegateSwizzling000 = 1100, // I-SWZ001100 + kGULSwizzlerMessageCodeSceneDelegateSwizzling001 = 1101, // I-SWZ001101 + kGULSwizzlerMessageCodeSceneDelegateSwizzling002 = 1102, // I-SWZ001102 + kGULSwizzlerMessageCodeSceneDelegateSwizzling003 = 1103, // I-SWZ001103 + kGULSwizzlerMessageCodeSceneDelegateSwizzling004 = 1104, // I-SWZ001104 + kGULSwizzlerMessageCodeSceneDelegateSwizzling005 = 1105, // I-SWZ001105 + kGULSwizzlerMessageCodeSceneDelegateSwizzling006 = 1106, // I-SWZ001106 + kGULSwizzlerMessageCodeSceneDelegateSwizzling007 = 1107, // I-SWZ001107 + kGULSwizzlerMessageCodeSceneDelegateSwizzling008 = 1108, // I-SWZ001108 + kGULSwizzlerMessageCodeSceneDelegateSwizzling009 = 1109, // I-SWZ001109 + kGULSwizzlerMessageCodeSceneDelegateSwizzling010 = 1110, // I-SWZ001110 + kGULSwizzlerMessageCodeSceneDelegateSwizzling011 = 1111, // I-SWZ001111 + kGULSwizzlerMessageCodeSceneDelegateSwizzling012 = 1112, // I-SWZ001112 + kGULSwizzlerMessageCodeSceneDelegateSwizzling013 = 1113, // I-SWZ001113 + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate = 1114, // I-SWZ001114 + + // Method Swizzling. + kGULSwizzlerMessageCodeMethodSwizzling000 = 2000, // I-SWZ002000 +}; diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m new file mode 100644 index 0000000..f1d8ddc --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m @@ -0,0 +1,153 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h" + +NSString *const kGULHeartbeatStorageDirectory = @"Google/FIRApp"; + +@interface GULHeartbeatDateStorage () + +/** The name of the file that stores heartbeat information. */ +@property(nonatomic, readonly) NSString *fileName; +@end + +@implementation GULHeartbeatDateStorage + +@synthesize fileURL = _fileURL; + +- (instancetype)initWithFileName:(NSString *)fileName { + if (fileName == nil) return nil; + + self = [super init]; + if (self) { + _fileName = fileName; + } + return self; +} + +/** Lazy getter for fileURL. + * @return fileURL where heartbeat information is stored. + */ +- (NSURL *)fileURL { + if (!_fileURL) { + NSURL *directoryURL = [self directoryPathURL]; + [self checkAndCreateDirectory:directoryURL]; + _fileURL = [directoryURL URLByAppendingPathComponent:_fileName]; + } + return _fileURL; +} + +/** Returns the URL path of the directory for heartbeat storage data. + * @return the URL path of the directory for heartbeat storage data. + */ +- (NSURL *)directoryPathURL { + NSArray *paths; +#if TARGET_OS_TV + paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); +#else + paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); +#endif // TARGET_OS_TV + NSString *rootPath = [paths lastObject]; + NSURL *rootURL = [NSURL fileURLWithPath:rootPath]; + NSURL *directoryURL = [rootURL URLByAppendingPathComponent:kGULHeartbeatStorageDirectory]; + return directoryURL; +} + +/** Check for the existence of the directory specified by the URL, and create it if it does not + * exist. + * @param directoryPathURL The path to the directory that needs to exist. + */ +- (void)checkAndCreateDirectory:(NSURL *)directoryPathURL { + NSError *error; + if (![directoryPathURL checkResourceIsReachableAndReturnError:&error]) { + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtURL:directoryPathURL + withIntermediateDirectories:YES + attributes:nil + error:&error]; + } +} + +- (nullable NSDate *)heartbeatDateForTag:(NSString *)tag { + @synchronized(self.class) { + NSDictionary *heartbeatDictionary = [self heartbeatDictionaryWithFileURL:self.fileURL]; + NSDate *heartbeatDate = heartbeatDictionary[tag]; + + // Validate the value type. If the storage file was corrupted or updated with a different format + // by a newer SDK version the value type may be different. + if (![heartbeatDate isKindOfClass:[NSDate class]]) { + heartbeatDate = nil; + } + + return heartbeatDate; + } +} + +- (BOOL)setHearbeatDate:(NSDate *)date forTag:(NSString *)tag { + // Synchronize on the class to ensure that the different instances of the class will not access + // the same file concurrently. + // TODO: Consider a different synchronization strategy here and in `-heartbeatDateForTag:` method. + // Currently no heartbeats can be read/written concurrently even if they are in different files. + @synchronized(self.class) { + NSMutableDictionary *heartbeatDictionary = + [[self heartbeatDictionaryWithFileURL:self.fileURL] mutableCopy]; + heartbeatDictionary[tag] = date; + NSError *error; + BOOL isSuccess = [self writeDictionary:[heartbeatDictionary copy] + forWritingURL:self.fileURL + error:&error]; + return isSuccess; + } +} + +- (NSDictionary *)heartbeatDictionaryWithFileURL:(NSURL *)readingFileURL { + NSDictionary *heartbeatDictionary; + + NSError *error; + NSData *objectData = [NSData dataWithContentsOfURL:readingFileURL options:0 error:&error]; + + if (objectData.length > 0 && error == nil) { + NSSet *objectClasses = + [NSSet setWithArray:@[ NSDictionary.class, NSDate.class, NSString.class ]]; + heartbeatDictionary = [GULSecureCoding unarchivedObjectOfClasses:objectClasses + fromData:objectData + error:&error]; + } + + if (heartbeatDictionary.count == 0 || error != nil) { + heartbeatDictionary = [NSDictionary dictionary]; + } + + return heartbeatDictionary; +} + +- (BOOL)writeDictionary:(NSDictionary *)dictionary + forWritingURL:(NSURL *)writingFileURL + error:(NSError **)outError { + // Archive a mutable copy `dictionary` for writing to disk. This is done for + // backwards compatibility. See Google Utilities issue #36 for more context. + // TODO: Remove usage of mutable copy in a future version of Google Utilities. + NSData *data = [GULSecureCoding archivedDataWithRootObject:[dictionary mutableCopy] + error:outError]; + if (data.length == 0) { + return NO; + } + + return [data writeToURL:writingFileURL atomically:YES]; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorageUserDefaults.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorageUserDefaults.m new file mode 100644 index 0000000..f8f1159 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorageUserDefaults.m @@ -0,0 +1,68 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h" + +@interface GULHeartbeatDateStorageUserDefaults () + +/** The storage to store the date of the last sent heartbeat. */ +@property(nonatomic, readonly) NSUserDefaults *userDefaults; + +/** The key for user defaults to store heartbeat information. */ +@property(nonatomic, readonly) NSString *key; + +@end + +@implementation GULHeartbeatDateStorageUserDefaults + +- (instancetype)initWithDefaults:(NSUserDefaults *)defaults key:(NSString *)key { + self = [super init]; + if (self) { + _userDefaults = defaults; + _key = key; + } + return self; +} + +- (NSMutableDictionary *)heartbeatDictionaryFromDefaults { + NSDictionary *heartbeatDict = [self.userDefaults objectForKey:self.key]; + if (heartbeatDict != nil) { + return [heartbeatDict mutableCopy]; + } else { + return [NSMutableDictionary dictionary]; + } +} + +- (nullable NSDate *)heartbeatDateForTag:(NSString *)tag { + NSDate *date = nil; + @synchronized(self.userDefaults) { + NSMutableDictionary *dict = [self heartbeatDictionaryFromDefaults]; + date = dict[tag]; + } + + return date; +} + +- (BOOL)setHearbeatDate:(NSDate *)date forTag:(NSString *)tag { + @synchronized(self.userDefaults) { + NSMutableDictionary *dict = [self heartbeatDictionaryFromDefaults]; + dict[tag] = date; + [self.userDefaults setObject:dict forKey:self.key]; + } + return true; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m new file mode 100644 index 0000000..21d5c2a --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m @@ -0,0 +1,103 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h" + +NSString *const kGULSecureCodingError = @"GULSecureCodingError"; + +@implementation GULSecureCoding + ++ (nullable id)unarchivedObjectOfClasses:(NSSet *)classes + fromData:(NSData *)data + error:(NSError **)outError { + id object; +#if __has_builtin(__builtin_available) + if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) { + object = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:data error:outError]; + } else +#endif // __has_builtin(__builtin_available) + { + @try { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; +#pragma clang diagnostic pop + unarchiver.requiresSecureCoding = YES; + + object = [unarchiver decodeObjectOfClasses:classes forKey:NSKeyedArchiveRootObjectKey]; + } @catch (NSException *exception) { + if (outError) { + *outError = [self archivingErrorWithException:exception]; + } + } + + if (object == nil && outError && *outError == nil) { + NSString *failureReason = @"NSKeyedUnarchiver failed to unarchive data."; + *outError = [NSError errorWithDomain:kGULSecureCodingError + code:-1 + userInfo:@{NSLocalizedFailureReasonErrorKey : failureReason}]; + } + } + + return object; +} + ++ (nullable id)unarchivedObjectOfClass:(Class)class + fromData:(NSData *)data + error:(NSError **)outError { + return [self unarchivedObjectOfClasses:[NSSet setWithObject:class] fromData:data error:outError]; +} + ++ (nullable NSData *)archivedDataWithRootObject:(id)object error:(NSError **)outError { + NSData *archiveData; +#if __has_builtin(__builtin_available) + if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) { + archiveData = [NSKeyedArchiver archivedDataWithRootObject:object + requiringSecureCoding:YES + error:outError]; + } else +#endif // __has_builtin(__builtin_available) + { + @try { + NSMutableData *data = [NSMutableData data]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; +#pragma clang diagnostic pop + archiver.requiresSecureCoding = YES; + + [archiver encodeObject:object forKey:NSKeyedArchiveRootObjectKey]; + [archiver finishEncoding]; + + archiveData = [data copy]; + } @catch (NSException *exception) { + if (outError) { + *outError = [self archivingErrorWithException:exception]; + } + } + } + + return archiveData; +} + ++ (NSError *)archivingErrorWithException:(NSException *)exception { + NSString *failureReason = [NSString + stringWithFormat:@"NSKeyedArchiver exception with name: %@, reason: %@, userInfo: %@", + exception.name, exception.reason, exception.userInfo]; + NSDictionary *errorUserInfo = @{NSLocalizedFailureReasonErrorKey : failureReason}; + + return [NSError errorWithDomain:kGULSecureCodingError code:-1 userInfo:errorUserInfo]; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h new file mode 100644 index 0000000..72c46c2 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h @@ -0,0 +1,60 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@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. ++ (nullable 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."); + +/// @return YES if Swift runtime detected in the app. ++ (BOOL)hasSwiftRuntime __deprecated; + +/// @return An Apple platform. Possible values "ios", "tvos", "macos", "watchos", "maccatalyst". ++ (NSString *)applePlatform; + +/// @return The way the library was added to the app, e.g. "swiftpm", "cocoapods", etc. ++ (NSString *)deploymentType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorable.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorable.h new file mode 100644 index 0000000..43d3740 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorable.h @@ -0,0 +1,40 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Describes an object that can store and fetch heartbeat dates for given tags. + */ +@protocol GULHeartbeatDateStorable + +/** + * 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/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h new file mode 100644 index 0000000..245b1a2 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h @@ -0,0 +1,54 @@ +/* + * 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 + +#import "GULHeartbeatDateStorable.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The name of the directory where the heartbeat data is stored. +extern NSString *const kGULHeartbeatStorageDirectory; + +/// 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/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h new file mode 100644 index 0000000..e6c7dda --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h @@ -0,0 +1,51 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULHeartbeatDateStorable.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Stores either a date or a dictionary to a specified file. +@interface GULHeartbeatDateStorageUserDefaults : NSObject + +/** + * Default initializer. tvOS can only write to the cache directory and + * there are no guarantees that the directory will persist. User defaults will + * be retained, so that should be used instead. + * @param defaults User defaults instance to store the heartbeat information. + * @param key The key to be used with the user defaults instance. + */ +- (instancetype)initWithDefaults:(NSUserDefaults *)defaults key:(NSString *)key; + +- (instancetype)init NS_UNAVAILABLE; + +/** + * 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/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h new file mode 100644 index 0000000..dc01a83 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/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 + +@class FBLPromise; + +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> *)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 *)setObject:(id)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 *)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/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h new file mode 100644 index 0000000..de4bef2 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/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 + +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/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h new file mode 100644 index 0000000..8484b39 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/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 + +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 *)classes + fromData:(NSData *)data + error:(NSError **)outError; + ++ (nullable id)unarchivedObjectOfClass:(Class)class + fromData:(NSData *)data + error:(NSError **)outError; + ++ (nullable NSData *)archivedDataWithRootObject:(id)object error:(NSError **)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h new file mode 100644 index 0000000..e88eb67 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** The class represents HTTP response received from `NSURLSession`. */ +@interface GULURLSessionDataResponse : NSObject + +@property(nonatomic, readonly) NSHTTPURLResponse *HTTPResponse; +@property(nonatomic, nullable, readonly) NSData *HTTPBody; + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response HTTPBody:(nullable NSData *)body; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h new file mode 100644 index 0000000..7bed005 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#import + +@class FBLPromise; +@class GULURLSessionDataResponse; + +NS_ASSUME_NONNULL_BEGIN + +/** Promise based API for `NSURLSession`. */ +@interface NSURLSession (GULPromises) + +/** Creates a promise wrapping `-[NSURLSession dataTaskWithRequest:completionHandler:]` method. + * @param URLRequest The request to create a data task with. + * @return A promise that is fulfilled when an HTTP response is received (with any response code), + * or is rejected with the error passed to the task completion. + */ +- (FBLPromise *)gul_dataTaskPromiseWithRequest: + (NSURLRequest *)URLRequest; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m new file mode 100644 index 0000000..3b4a2d9 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m @@ -0,0 +1,192 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h" +#import + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h" + +@interface GULKeychainStorage () +@property(nonatomic, readonly) dispatch_queue_t keychainQueue; +@property(nonatomic, readonly) dispatch_queue_t inMemoryCacheQueue; +@property(nonatomic, readonly) NSString *service; +@property(nonatomic, readonly) NSCache> *inMemoryCache; +@end + +@implementation GULKeychainStorage + +- (instancetype)initWithService:(NSString *)service { + NSCache *cache = [[NSCache alloc] init]; + // Cache up to 5 installations. + cache.countLimit = 5; + return [self initWithService:service cache:cache]; +} + +- (instancetype)initWithService:(NSString *)service cache:(NSCache *)cache { + self = [super init]; + if (self) { + _keychainQueue = + dispatch_queue_create("com.gul.KeychainStorage.Keychain", DISPATCH_QUEUE_SERIAL); + _inMemoryCacheQueue = + dispatch_queue_create("com.gul.KeychainStorage.InMemoryCache", DISPATCH_QUEUE_SERIAL); + _service = [service copy]; + _inMemoryCache = cache; + } + return self; +} + +#pragma mark - Public + +- (FBLPromise> *)getObjectForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup { + return [FBLPromise onQueue:self.inMemoryCacheQueue + do:^id _Nullable { + // Return cached object or fail otherwise. + id object = [self.inMemoryCache objectForKey:key]; + return object + ?: [[NSError alloc] + initWithDomain:FBLPromiseErrorDomain + code:FBLPromiseErrorCodeValidationFailure + userInfo:nil]; + }] + .recover(^id _Nullable(NSError *error) { + // Look for the object in the keychain. + return [self getObjectFromKeychainForKey:key + objectClass:objectClass + accessGroup:accessGroup]; + }); +} + +- (FBLPromise *)setObject:(id)object + forKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup { + return [FBLPromise onQueue:self.inMemoryCacheQueue + do:^id _Nullable { + // Save to the in-memory cache first. + [self.inMemoryCache setObject:object forKey:[key copy]]; + return [NSNull null]; + }] + .thenOn(self.keychainQueue, ^id(id result) { + // Then store the object to the keychain. + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + NSError *error; + NSData *encodedObject = [GULSecureCoding archivedDataWithRootObject:object error:&error]; + if (!encodedObject) { + return error; + } + + if (![GULKeychainUtils setItem:encodedObject withQuery:query error:&error]) { + return error; + } + + return [NSNull null]; + }); +} + +- (FBLPromise *)removeObjectForKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup { + return [FBLPromise onQueue:self.inMemoryCacheQueue + do:^id _Nullable { + [self.inMemoryCache removeObjectForKey:key]; + return nil; + }] + .thenOn(self.keychainQueue, ^id(id result) { + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + + NSError *error; + if (![GULKeychainUtils removeItemWithQuery:query error:&error]) { + return error; + } + + return [NSNull null]; + }); +} + +#pragma mark - Private + +- (FBLPromise> *)getObjectFromKeychainForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup { + // Look for the object in the keychain. + return [FBLPromise + onQueue:self.keychainQueue + do:^id { + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + NSError *error; + NSData *encodedObject = [GULKeychainUtils getItemWithQuery:query error:&error]; + + if (error) { + return error; + } + if (!encodedObject) { + return nil; + } + id object = [GULSecureCoding unarchivedObjectOfClass:objectClass + fromData:encodedObject + error:&error]; + if (error) { + return error; + } + + return object; + }] + .thenOn(self.inMemoryCacheQueue, + ^id _Nullable(id _Nullable object) { + // Save object to the in-memory cache if exists and return the object. + if (object) { + [self.inMemoryCache setObject:object forKey:[key copy]]; + } + return object; + }); +} + +- (void)resetInMemoryCache { + [self.inMemoryCache removeAllObjects]; +} + +#pragma mark - Keychain + +- (NSMutableDictionary *)keychainQueryWithKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup { + NSMutableDictionary *query = [NSMutableDictionary dictionary]; + + query[(__bridge NSString *)kSecClass] = (__bridge NSString *)kSecClassGenericPassword; + query[(__bridge NSString *)kSecAttrService] = self.service; + query[(__bridge NSString *)kSecAttrAccount] = key; + + if (accessGroup) { + query[(__bridge NSString *)kSecAttrAccessGroup] = accessGroup; + } + +#if TARGET_OS_OSX + if (self.keychainRef) { + query[(__bridge NSString *)kSecUseKeychain] = (__bridge id)(self.keychainRef); + query[(__bridge NSString *)kSecMatchSearchList] = @[ (__bridge id)(self.keychainRef) ]; + } +#endif // TARGET_OSX + + return query; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m new file mode 100644 index 0000000..687e6a7 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m @@ -0,0 +1,113 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h" + +NSString *const kGULKeychainUtilsErrorDomain = @"com.gul.keychain.ErrorDomain"; + +@implementation GULKeychainUtils + ++ (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *mutableQuery = [query mutableCopy]; + + mutableQuery[(__bridge id)kSecReturnData] = @YES; + mutableQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; + + CFDataRef result = NULL; + OSStatus status = + SecItemCopyMatching((__bridge CFDictionaryRef)mutableQuery, (CFTypeRef *)&result); + + if (status == errSecSuccess && result != NULL) { + if (outError) { + *outError = nil; + } + + return (__bridge_transfer NSData *)result; + } + + if (status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + } else { + if (outError) { + *outError = [self keychainErrorWithFunction:@"SecItemCopyMatching" status:status]; + } + } + return nil; +} + ++ (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSData *existingItem = [self getItemWithQuery:query error:outError]; + if (outError && *outError) { + return NO; + } + + NSMutableDictionary *mutableQuery = [query mutableCopy]; + mutableQuery[(__bridge id)kSecAttrAccessible] = + (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + + OSStatus status; + if (!existingItem) { + mutableQuery[(__bridge id)kSecValueData] = item; + status = SecItemAdd((__bridge CFDictionaryRef)mutableQuery, NULL); + } else { + NSDictionary *attributes = @{(__bridge id)kSecValueData : item}; + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes); + } + + if (status == noErr) { + if (outError) { + *outError = nil; + } + return YES; + } + + NSString *function = existingItem ? @"SecItemUpdate" : @"SecItemAdd"; + if (outError) { + *outError = [self keychainErrorWithFunction:function status:status]; + } + return NO; +} + ++ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError { + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); + + if (status == noErr || status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + return YES; + } + + if (outError) { + *outError = [self keychainErrorWithFunction:@"SecItemDelete" status:status]; + } + return NO; +} + +#pragma mark - Errors + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { + NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; + NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey : failureReason}; + return [NSError errorWithDomain:kGULKeychainUtilsErrorDomain code:0 userInfo:userInfo]; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m new file mode 100644 index 0000000..559875a --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h" + +@implementation GULURLSessionDataResponse + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response HTTPBody:(NSData *)body { + self = [super init]; + if (self) { + _HTTPResponse = response; + _HTTPBody = body; + } + return self; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m new file mode 100644 index 0000000..6c70310 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h" + +@implementation NSURLSession (GULPromises) + +- (FBLPromise *)gul_dataTaskPromiseWithRequest: + (NSURLRequest *)URLRequest { + return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + [[self dataTaskWithRequest:URLRequest + completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + reject(error); + } else { + fulfill([[GULURLSessionDataResponse alloc] + initWithResponse:(NSHTTPURLResponse *)response + HTTPBody:data]); + } + }] resume]; + }]; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m new file mode 100644 index 0000000..0dca899 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m @@ -0,0 +1,333 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" + +#import +#import +#import +#import +#import +#import + +#if TARGET_OS_IOS +#import +#endif + +/// The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from +/// the iPhoneOS or Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just +/// provide the definitions here. +#if TARGET_OS_SIMULATOR && !defined(LC_ENCRYPTION_INFO) +#define LC_ENCRYPTION_INFO 0x21 +struct encryption_info_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t cryptoff; + uint32_t cryptsize; + uint32_t cryptid; +}; +#endif + +@implementation GULAppEnvironmentUtil + +/// A key for the Info.plist to enable or disable checking if the App Store is running in a sandbox. +/// This will affect your data integrity when using Firebase Analytics, as it will disable some +/// necessary checks. +static NSString *const kFIRAppStoreReceiptURLCheckEnabledKey = + @"FirebaseAppStoreReceiptURLCheckEnabled"; + +/// The file name of the sandbox receipt. This is available on iOS >= 8.0 +static NSString *const kFIRAIdentitySandboxReceiptFileName = @"sandboxReceipt"; + +/// The following copyright from Landon J. Fuller applies to the isAppEncrypted function. +/// +/// Copyright (c) 2017 Landon J. Fuller +/// All rights reserved. +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy of this software +/// and associated documentation files (the "Software"), to deal in the Software without +/// restriction, including without limitation the rights to use, copy, modify, merge, publish, +/// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in all copies or +/// substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +/// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +/// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +/// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/// +/// Comment from iPhone Dev Wiki +/// Crack Prevention: +/// App Store binaries are signed by both their developer and Apple. This encrypts the binary so +/// that decryption keys are needed in order to make the binary readable. When iOS executes the +/// binary, the decryption keys are used to decrypt the binary into a readable state where it is +/// then loaded into memory and executed. iOS can tell the encryption status of a binary via the +/// cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is a non-zero +/// value then the binary is encrypted. +/// +/// 'Cracking' works by letting the kernel decrypt the binary then siphoning the decrypted data into +/// a new binary file, resigning, and repackaging. This will only work on jailbroken devices as +/// codesignature validation has been removed. Resigning takes place because while the codesignature +/// doesn't have to be valid thanks to the jailbreak, it does have to be in place unless you have +/// AppSync or similar to disable codesignature checks. +/// +/// More information at Landon Fuller's blog +static BOOL IsAppEncrypted() { + const struct mach_header *executableHeader = NULL; + for (uint32_t i = 0; i < _dyld_image_count(); i++) { + const struct mach_header *header = _dyld_get_image_header(i); + if (header && header->filetype == MH_EXECUTE) { + executableHeader = header; + break; + } + } + + if (!executableHeader) { + return NO; + } + + BOOL is64bit = (executableHeader->magic == MH_MAGIC_64); + uintptr_t cursor = (uintptr_t)executableHeader + + (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header)); + const struct segment_command *segmentCommand = NULL; + uint32_t i = 0; + + while (i++ < executableHeader->ncmds) { + segmentCommand = (struct segment_command *)cursor; + + if (!segmentCommand) { + continue; + } + + if ((!is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO) || + (is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO_64)) { + if (is64bit) { + struct encryption_info_command_64 *cryptCmd = + (struct encryption_info_command_64 *)segmentCommand; + return cryptCmd && cryptCmd->cryptid != 0; + } else { + struct encryption_info_command *cryptCmd = (struct encryption_info_command *)segmentCommand; + return cryptCmd && cryptCmd->cryptid != 0; + } + } + cursor += segmentCommand->cmdsize; + } + + return NO; +} + +static BOOL HasSCInfoFolder() { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + NSString *bundlePath = [NSBundle mainBundle].bundlePath; + NSString *scInfoPath = [bundlePath stringByAppendingPathComponent:@"SC_Info"]; + return [[NSFileManager defaultManager] fileExistsAtPath:scInfoPath]; +#elif TARGET_OS_OSX + return NO; +#endif +} + +static BOOL HasEmbeddedMobileProvision() { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + return [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"].length > 0; +#elif TARGET_OS_OSX + return NO; +#endif +} + ++ (BOOL)isFromAppStore { + static dispatch_once_t isEncryptedOnce; + static BOOL isEncrypted = NO; + + dispatch_once(&isEncryptedOnce, ^{ + isEncrypted = IsAppEncrypted(); + }); + + if ([GULAppEnvironmentUtil isSimulator]) { + return NO; + } + + // If an app contain the sandboxReceipt file, it means its coming from TestFlight + // This must be checked before the SCInfo Folder check below since TestFlight apps may + // also have an SCInfo folder. + if ([GULAppEnvironmentUtil isAppStoreReceiptSandbox]) { + return NO; + } + + if (HasSCInfoFolder()) { + // When iTunes downloads a .ipa, it also gets a customized .sinf file which is added to the + // main SC_Info directory. + return YES; + } + + // For iOS >= 8.0, iTunesMetadata.plist is moved outside of the sandbox. Any attempt to read + // the iTunesMetadata.plist outside of the sandbox will be rejected by Apple. + // If the app does not contain the embedded.mobileprovision which is stripped out by Apple when + // the app is submitted to store, then it is highly likely that it is from Apple Store. + return isEncrypted && !HasEmbeddedMobileProvision(); +} + ++ (BOOL)isAppStoreReceiptSandbox { + // Since checking the App Store's receipt URL can be memory intensive, check the option in the + // Info.plist if developers opted out of this check. + id enableSandboxCheck = + [[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRAppStoreReceiptURLCheckEnabledKey]; + if (enableSandboxCheck && [enableSandboxCheck isKindOfClass:[NSNumber class]] && + ![enableSandboxCheck boolValue]) { + return NO; + } + + NSURL *appStoreReceiptURL = [NSBundle mainBundle].appStoreReceiptURL; + NSString *appStoreReceiptFileName = appStoreReceiptURL.lastPathComponent; + return [appStoreReceiptFileName isEqualToString:kFIRAIdentitySandboxReceiptFileName]; +} + ++ (BOOL)isSimulator { +#if TARGET_OS_SIMULATOR + return YES; +#elif TARGET_OS_MACCATALYST + return NO; +#elif TARGET_OS_IOS || TARGET_OS_TV + NSString *platform = [GULAppEnvironmentUtil deviceModel]; + return [platform isEqual:@"x86_64"] || [platform isEqual:@"i386"]; +#elif TARGET_OS_OSX + return NO; +#endif + return NO; +} + ++ (NSString *)deviceModel { + static dispatch_once_t once; + static NSString *deviceModel; + +#if TARGET_OS_OSX || TARGET_OS_MACCATALYST + dispatch_once(&once, ^{ + // The `uname` function only returns x86_64 for Macs. Use `sysctlbyname` instead, but fall back + // to the `uname` function if it fails. + size_t size; + sysctlbyname("hw.model", NULL, &size, NULL, 0); + if (size > 0) { + char *machine = malloc(size); + sysctlbyname("hw.model", machine, &size, NULL, 0); + deviceModel = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding]; + free(machine); + } else { + struct utsname systemInfo; + if (uname(&systemInfo) == 0) { + deviceModel = [NSString stringWithUTF8String:systemInfo.machine]; + } + } + }); +#else + dispatch_once(&once, ^{ + struct utsname systemInfo; + if (uname(&systemInfo) == 0) { + deviceModel = [NSString stringWithUTF8String:systemInfo.machine]; + } + }); +#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST + return deviceModel; +} + ++ (NSString *)systemVersion { +#if TARGET_OS_IOS + return [UIDevice currentDevice].systemVersion; +#elif TARGET_OS_OSX || TARGET_OS_TV || TARGET_OS_WATCH + // Assemble the systemVersion, excluding the patch version if it's 0. + NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion; + NSMutableString *versionString = [[NSMutableString alloc] + initWithFormat:@"%ld.%ld", (long)osVersion.majorVersion, (long)osVersion.minorVersion]; + if (osVersion.patchVersion != 0) { + [versionString appendFormat:@".%ld", (long)osVersion.patchVersion]; + } + return versionString; +#endif +} + ++ (BOOL)isAppExtension { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + // Documented by Apple + BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + return appExtension; +#elif TARGET_OS_OSX + return NO; +#endif +} + ++ (BOOL)isIOS7OrHigher { + return YES; +} + ++ (BOOL)hasSwiftRuntime { + // The class + // [Swift._SwiftObject](https://github.com/apple/swift/blob/5eac3e2818eb340b11232aff83edfbd1c307fa03/stdlib/public/runtime/SwiftObject.h#L35) + // is a part of Swift runtime, so it should be present if Swift runtime is available. + + BOOL hasSwiftRuntime = + objc_lookUpClass("Swift._SwiftObject") != nil || + // Swift object class name before + // https://github.com/apple/swift/commit/9637b4a6e11ddca72f5f6dbe528efc7c92f14d01 + objc_getClass("_TtCs12_SwiftObject") != nil; + + return hasSwiftRuntime; +} + ++ (NSString *)applePlatform { + NSString *applePlatform = @"unknown"; + + // When a Catalyst app is run on macOS then both `TARGET_OS_MACCATALYST` and `TARGET_OS_IOS` are + // `true`, which means the condition list is order-sensitive. +#if TARGET_OS_MACCATALYST + applePlatform = @"maccatalyst"; +#elif TARGET_OS_IOS +#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 + if (@available(iOS 14.0, *)) { + // Early iOS 14 betas do not include isiOSAppOnMac (#6969) + applePlatform = ([[NSProcessInfo processInfo] respondsToSelector:@selector(isiOSAppOnMac)] && + [NSProcessInfo processInfo].isiOSAppOnMac) ? @"ios_on_mac" : @"ios"; + } else { + applePlatform = @"ios"; + } +#else // defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 + applePlatform = @"ios"; +#endif // defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 + +#elif TARGET_OS_TV + applePlatform = @"tvos"; +#elif TARGET_OS_OSX + applePlatform = @"macos"; +#elif TARGET_OS_WATCH + applePlatform = @"watchos"; +#endif // TARGET_OS_MACCATALYST + + return applePlatform; +} + ++ (NSString *)deploymentType { +#if SWIFT_PACKAGE + NSString *deploymentType = @"swiftpm"; +#elif FIREBASE_BUILD_CARTHAGE + NSString *deploymentType = @"carthage"; +#elif FIREBASE_BUILD_ZIP_FILE + NSString *deploymentType = @"zip"; +#else + NSString *deploymentType = @"cocoapods"; +#endif + + return deploymentType; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m new file mode 100644 index 0000000..c5f6f1d --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m @@ -0,0 +1,215 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +#include + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h" + +/// ASL client facility name used by GULLogger. +const char *kGULLoggerASLClientFacilityName = "com.google.utilities.logger"; + +static dispatch_once_t sGULLoggerOnceToken; + +static aslclient sGULLoggerClient; + +static dispatch_queue_t sGULClientQueue; + +static BOOL sGULLoggerDebugMode; + +static GULLoggerLevel sGULLoggerMaximumLevel; + +// Allow clients to register a version to include in the log. +static NSString *sVersion = @""; + +static GULLoggerService kGULLoggerLogger = @"[GULLogger]"; + +#ifdef DEBUG +/// The regex pattern for the message code. +static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$"; +static NSRegularExpression *sMessageCodeRegex; +#endif + +void GULLoggerInitializeASL(void) { + dispatch_once(&sGULLoggerOnceToken, ^{ + NSInteger majorOSVersion = [[GULAppEnvironmentUtil systemVersion] integerValue]; + uint32_t aslOptions = ASL_OPT_STDERR; +#if TARGET_OS_SIMULATOR + // The iOS 11 simulator doesn't need the ASL_OPT_STDERR flag. + if (majorOSVersion >= 11) { + aslOptions = 0; + } +#else + // Devices running iOS 10 or higher don't need the ASL_OPT_STDERR flag. + if (majorOSVersion >= 10) { + aslOptions = 0; + } +#endif // TARGET_OS_SIMULATOR + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // asl is deprecated + // Initialize the ASL client handle. + sGULLoggerClient = asl_open(NULL, kGULLoggerASLClientFacilityName, aslOptions); + sGULLoggerMaximumLevel = GULLoggerLevelNotice; + + // Set the filter used by system/device log. Initialize in default mode. + asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE)); + + sGULClientQueue = dispatch_queue_create("GULLoggingClientQueue", DISPATCH_QUEUE_SERIAL); + dispatch_set_target_queue(sGULClientQueue, + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)); +#ifdef DEBUG + sMessageCodeRegex = [NSRegularExpression regularExpressionWithPattern:kMessageCodePattern + options:0 + error:NULL]; +#endif + }); +} + +void GULLoggerEnableSTDERR(void) { + asl_add_log_file(sGULLoggerClient, STDERR_FILENO); +} + +void GULLoggerForceDebug(void) { + // We should enable debug mode if we're not running from App Store. + if (![GULAppEnvironmentUtil isFromAppStore]) { + sGULLoggerDebugMode = YES; + GULSetLoggerLevel(GULLoggerLevelDebug); + } +} + +__attribute__((no_sanitize("thread"))) void GULSetLoggerLevel(GULLoggerLevel loggerLevel) { + if (loggerLevel < GULLoggerLevelMin || loggerLevel > GULLoggerLevelMax) { + GULLogError(kGULLoggerLogger, NO, @"I-COR000023", @"Invalid logger level, %ld", + (long)loggerLevel); + return; + } + GULLoggerInitializeASL(); + // We should not raise the logger level if we are running from App Store. + if (loggerLevel >= GULLoggerLevelNotice && [GULAppEnvironmentUtil isFromAppStore]) { + return; + } + + sGULLoggerMaximumLevel = loggerLevel; + dispatch_async(sGULClientQueue, ^{ + asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(loggerLevel)); + }); +} + +/** + * Check if the level is high enough to be loggable. + */ +__attribute__((no_sanitize("thread"))) BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel) { + GULLoggerInitializeASL(); + if (sGULLoggerDebugMode) { + return YES; + } + return (BOOL)(loggerLevel <= sGULLoggerMaximumLevel); +} + +#ifdef DEBUG +void GULResetLogger(void) { + sGULLoggerOnceToken = 0; + sGULLoggerDebugMode = NO; +} + +aslclient getGULLoggerClient(void) { + return sGULLoggerClient; +} + +dispatch_queue_t getGULClientQueue(void) { + return sGULClientQueue; +} + +BOOL getGULLoggerDebugMode(void) { + return sGULLoggerDebugMode; +} +#endif + +void GULLoggerRegisterVersion(NSString *version) { + sVersion = version; +} + +void GULLogBasic(GULLoggerLevel level, + GULLoggerService service, + BOOL forceLog, + NSString *messageCode, + NSString *message, + va_list args_ptr) { + GULLoggerInitializeASL(); + if (!(level <= sGULLoggerMaximumLevel || sGULLoggerDebugMode || forceLog)) { + return; + } + +#ifdef DEBUG + NSCAssert(messageCode.length == 11, @"Incorrect message code length."); + NSRange messageCodeRange = NSMakeRange(0, messageCode.length); + NSUInteger numberOfMatches = [sMessageCodeRegex numberOfMatchesInString:messageCode + options:0 + range:messageCodeRange]; + NSCAssert(numberOfMatches == 1, @"Incorrect message code format."); +#endif + NSString *logMsg; + if (args_ptr == NULL) { + logMsg = message; + } else { + logMsg = [[NSString alloc] initWithFormat:message arguments:args_ptr]; + } + logMsg = [NSString stringWithFormat:@"%@ - %@[%@] %@", sVersion, service, messageCode, logMsg]; + dispatch_async(sGULClientQueue, ^{ + asl_log(sGULLoggerClient, NULL, (int)level, "%s", logMsg.UTF8String); + }); +} +#pragma clang diagnostic pop + +/** + * Generates the logging functions using macros. + * + * Calling GULLogError({service}, @"I-XYZ000001", @"Configure %@ failed.", @"blah") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [{service}][I-XYZ000001] Configure blah failed. + * Calling GULLogDebug({service}, @"I-XYZ000001", @"Configure succeed.") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [{service}][I-XYZ000001] Configure succeed. + */ +#define GUL_LOGGING_FUNCTION(level) \ + void GULLog##level(GULLoggerService service, BOOL force, NSString *messageCode, \ + NSString *message, ...) { \ + va_list args_ptr; \ + va_start(args_ptr, message); \ + GULLogBasic(GULLoggerLevel##level, service, force, messageCode, message, args_ptr); \ + va_end(args_ptr); \ + } + +GUL_LOGGING_FUNCTION(Error) +GUL_LOGGING_FUNCTION(Warning) +GUL_LOGGING_FUNCTION(Notice) +GUL_LOGGING_FUNCTION(Info) +GUL_LOGGING_FUNCTION(Debug) + +#undef GUL_MAKE_LOGGER + +#pragma mark - GULLoggerWrapper + +@implementation GULLoggerWrapper + ++ (void)logWithLevel:(GULLoggerLevel)level + withService:(GULLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args { + GULLogBasic(level, service, NO, messageCode, message, args); +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h new file mode 100644 index 0000000..6797399 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h @@ -0,0 +1,159 @@ +/* + * 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 + +#import "GULLoggerLevel.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * The services used in the logger. + */ +typedef NSString *const GULLoggerService; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Initialize GULLogger. + */ +extern void GULLoggerInitializeASL(void); + +/** + * Override log level to Debug. + */ +void GULLoggerForceDebug(void); + +/** + * Turn on logging to STDERR. + */ +extern void GULLoggerEnableSTDERR(void); + +/** + * Changes the default logging level of GULLoggerLevelNotice to a user-specified level. + * The default level cannot be set above GULLoggerLevelNotice if the app is running from App Store. + * (required) log level (one of the GULLoggerLevel enum values). + */ +extern void GULSetLoggerLevel(GULLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the GULLoggerLevel enum values). + */ +extern BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel); + +/** + * Register version to include in logs. + * (required) version + */ +extern void GULLoggerRegisterVersion(NSString *version); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than GULLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the GULLoggerLevel enum values). + * (required) service name of type GULLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void GULLogBasic(GULLoggerLevel level, + GULLoggerService service, + BOOL forceLog, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type GULLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * GULLogError(kGULLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void GULLogError(GULLoggerService service, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(4, 5); +extern void GULLogWarning(GULLoggerService service, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(4, 5); +extern void GULLogNotice(GULLoggerService service, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(4, 5); +extern void GULLogInfo(GULLoggerService service, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(4, 5); +extern void GULLogDebug(GULLoggerService service, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(4, 5); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +@interface GULLoggerWrapper : NSObject + +/** + * Objective-C wrapper for GULLogBasic to allow weak linking to GULLogger + * (required) log level (one of the GULLoggerLevel enum values). + * (required) service name of type GULLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ + ++ (void)logWithLevel:(GULLoggerLevel)level + withService:(GULLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h new file mode 100644 index 0000000..f0ee435 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h @@ -0,0 +1,37 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * The log levels used by internal logging. + */ +typedef NS_ENUM(NSInteger, GULLoggerLevel) { + /** Error level, matches ASL_LEVEL_ERR. */ + GULLoggerLevelError = 3, + /** Warning level, matches ASL_LEVEL_WARNING. */ + GULLoggerLevelWarning = 4, + /** Notice level, matches ASL_LEVEL_NOTICE. */ + GULLoggerLevelNotice = 5, + /** Info level, matches ASL_LEVEL_INFO. */ + GULLoggerLevelInfo = 6, + /** Debug level, matches ASL_LEVEL_DEBUG. */ + GULLoggerLevelDebug = 7, + /** Minimum log level. */ + GULLoggerLevelMin = GULLoggerLevelError, + /** Maximum log level. */ + GULLoggerLevelMax = GULLoggerLevelDebug +} NS_SWIFT_NAME(GoogleLoggerLevel); diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m new file mode 100644 index 0000000..e441e36 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m @@ -0,0 +1,207 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h" + +#import + +#define kChunkSize 1024 +#define Z_DEFAULT_COMPRESSION (-1) + +NSString *const GULNSDataZlibErrorDomain = @"com.google.GULNSDataZlibErrorDomain"; +NSString *const GULNSDataZlibErrorKey = @"GULNSDataZlibErrorKey"; +NSString *const GULNSDataZlibRemainingBytesKey = @"GULNSDataZlibRemainingBytesKey"; + +@implementation NSData (GULGzip) + ++ (NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error { + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + return nil; + } +#endif + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + int windowBits = 15; // 15 to enable any window size + windowBits += 32; // and +32 to enable zlib or gzip header detection. + + int retCode; + if ((retCode = inflateInit2(&strm, windowBits)) != Z_OK) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + } + + // Hint the size at 4x the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length * 4)]; + unsigned char output[kChunkSize]; + + // Loop to collect the data. + do { + // Update what we're passing in. + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = inflate(&strm, Z_NO_FLUSH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + if (error) { + NSMutableDictionary *userInfo = + [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + if (strm.msg) { + NSString *message = [NSString stringWithUTF8String:strm.msg]; + if (message) { + [userInfo setObject:message forKey:NSLocalizedDescriptionKey]; + } + } + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + inflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // Make sure there wasn't more data tacked onto the end of a valid compressed stream. + if (strm.avail_in != 0) { + if (error) { + NSDictionary *userInfo = + [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:strm.avail_in] + forKey:GULNSDataZlibRemainingBytesKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorDataRemaining + userInfo:userInfo]; + } + result = nil; + } + // The only way out of the loop was by hitting the end of the stream. + NSAssert(retCode == Z_STREAM_END, + @"Thought we finished inflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + inflateEnd(&strm); + + return result; +} + ++ (NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error { + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + + int level = Z_DEFAULT_COMPRESSION; + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + if (error) { + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorGreaterThan32BitsToCompress + userInfo:nil]; + } + return nil; + } +#endif + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + int memLevel = 8; // Default. + int windowBits = 15 + 16; // Enable gzip header instead of zlib header. + + int retCode; + if ((retCode = deflateInit2(&strm, level, Z_DEFLATED, windowBits, memLevel, + Z_DEFAULT_STRATEGY)) != Z_OK) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + } + + // Hint the size at 1/4 the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length / 4)]; + unsigned char output[kChunkSize]; + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + // Collect the data. + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = deflate(&strm, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + deflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // If the loop exits, it used all input and the stream ended. + NSAssert(strm.avail_in == 0, + @"Should have finished deflating without using all input, %u bytes left", strm.avail_in); + NSAssert(retCode == Z_STREAM_END, + @"thought we finished deflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + deflateEnd(&strm); + + return result; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h new file mode 100644 index 0000000..36f94a7 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h @@ -0,0 +1,49 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/// This is a copy of Google Toolbox for Mac library to avoid creating an extra framework. + +// NOTE: For 64bit, none of these apis handle input sizes >32bits, they will return nil when given +// such data. To handle data of that size you really should be streaming it rather then doing it all +// in memory. + +@interface NSData (GULGzip) + +/// Returns an data as the result of decompressing the payload of |data|.The data to decompress must +/// be a gzipped payloads. ++ (NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error; + +/// Returns an compressed data with the result of gzipping the payload of |data|. Uses the default +/// compression level. ++ (NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error; + +FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorDomain; +FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorKey; // NSNumber +FOUNDATION_EXPORT NSString *const GULNSDataZlibRemainingBytesKey; // NSNumber + +typedef NS_ENUM(NSInteger, GULNSDataZlibError) { + GULNSDataZlibErrorGreaterThan32BitsToCompress = 1024, + // An internal zlib error. + // GULNSDataZlibErrorKey will contain the error value. + // NSLocalizedDescriptionKey may contain an error string from zlib. + // Look in zlib.h for list of errors. + GULNSDataZlibErrorInternal, + // There was left over data in the buffer that was not used. + // GULNSDataZlibRemainingBytesKey will contain number of remaining bytes. + GULNSDataZlibErrorDataRemaining +}; + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m new file mode 100644 index 0000000..7726d15 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m @@ -0,0 +1,101 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +@implementation GULMutableDictionary { + /// The mutable dictionary. + NSMutableDictionary *_objects; + + /// Serial synchronization queue. All reads should use dispatch_sync, while writes use + /// dispatch_async. + dispatch_queue_t _queue; +} + +- (instancetype)init { + self = [super init]; + + if (self) { + _objects = [[NSMutableDictionary alloc] init]; + _queue = dispatch_queue_create("GULMutableDictionary", DISPATCH_QUEUE_SERIAL); + } + + return self; +} + +- (NSString *)description { + __block NSString *description; + dispatch_sync(_queue, ^{ + description = self->_objects.description; + }); + return description; +} + +- (id)objectForKey:(id)key { + __block id object; + dispatch_sync(_queue, ^{ + object = [self->_objects objectForKey:key]; + }); + return object; +} + +- (void)setObject:(id)object forKey:(id)key { + dispatch_async(_queue, ^{ + [self->_objects setObject:object forKey:key]; + }); +} + +- (void)removeObjectForKey:(id)key { + dispatch_async(_queue, ^{ + [self->_objects removeObjectForKey:key]; + }); +} + +- (void)removeAllObjects { + dispatch_async(_queue, ^{ + [self->_objects removeAllObjects]; + }); +} + +- (NSUInteger)count { + __block NSUInteger count; + dispatch_sync(_queue, ^{ + count = self->_objects.count; + }); + return count; +} + +- (id)objectForKeyedSubscript:(id)key { + __block id object; + dispatch_sync(_queue, ^{ + object = self->_objects[key]; + }); + return object; +} + +- (void)setObject:(id)obj forKeyedSubscript:(id)key { + dispatch_async(_queue, ^{ + self->_objects[key] = obj; + }); +} + +- (NSDictionary *)dictionary { + __block NSDictionary *dictionary; + dispatch_sync(_queue, ^{ + dictionary = [self->_objects copy]; + }); + return dictionary; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m new file mode 100644 index 0000000..ca697a3 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m @@ -0,0 +1,390 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h" +#import "GoogleUtilities/Network/GULNetworkInternal.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +/// Constant string for request header Content-Encoding. +static NSString *const kGULNetworkContentCompressionKey = @"Content-Encoding"; + +/// Constant string for request header Content-Encoding value. +static NSString *const kGULNetworkContentCompressionValue = @"gzip"; + +/// Constant string for request header Content-Length. +static NSString *const kGULNetworkContentLengthKey = @"Content-Length"; + +/// Constant string for request header Content-Type. +static NSString *const kGULNetworkContentTypeKey = @"Content-Type"; + +/// Constant string for request header Content-Type value. +static NSString *const kGULNetworkContentTypeValue = @"application/x-www-form-urlencoded"; + +/// Constant string for GET request method. +static NSString *const kGULNetworkGETRequestMethod = @"GET"; + +/// Constant string for POST request method. +static NSString *const kGULNetworkPOSTRequestMethod = @"POST"; + +/// Default constant string as a prefix for network logger. +static NSString *const kGULNetworkLogTag = @"Google/Utilities/Network"; + +@interface GULNetwork () +@end + +@implementation GULNetwork { + /// Network reachability. + GULReachabilityChecker *_reachability; + + /// The dictionary of requests by session IDs { NSString : id }. + GULMutableDictionary *_requests; +} + +- (instancetype)init { + return [self initWithReachabilityHost:kGULNetworkReachabilityHost]; +} + +- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost { + self = [super init]; + if (self) { + // Setup reachability. + _reachability = [[GULReachabilityChecker alloc] initWithReachabilityDelegate:self + withHost:reachabilityHost]; + if (![_reachability start]) { + return nil; + } + + _requests = [[GULMutableDictionary alloc] init]; + _timeoutInterval = kGULNetworkTimeOutInterval; + } + return self; +} + +- (void)dealloc { + _reachability.reachabilityDelegate = nil; + [_reachability stop]; +} + +#pragma mark - External Methods + ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler { + [GULNetworkURLSession handleEventsForBackgroundURLSessionID:sessionID + completionHandler:completionHandler]; +} + +- (NSString *)postURL:(NSURL *)url + payload:(NSData *)payload + queue:(dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + if (!url.absoluteString.length) { + [self handleErrorWithCode:GULErrorCodeNetworkInvalidURL queue:queue withHandler:handler]; + return nil; + } + + NSTimeInterval timeOutInterval = _timeoutInterval ?: kGULNetworkTimeOutInterval; + + NSMutableURLRequest *request = + [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:timeOutInterval]; + + if (!request) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + NSError *compressError = nil; + NSData *compressedData = [NSData gul_dataByGzippingData:payload error:&compressError]; + if (!compressedData || compressError) { + if (compressError || payload.length > 0) { + // If the payload is not empty but it fails to compress the payload, something has been wrong. + [self handleErrorWithCode:GULErrorCodeNetworkPayloadCompression + queue:queue + withHandler:handler]; + return nil; + } + compressedData = [[NSData alloc] init]; + } + + NSString *postLength = @(compressedData.length).stringValue; + + // Set up the request with the compressed data. + [request setValue:postLength forHTTPHeaderField:kGULNetworkContentLengthKey]; + request.HTTPBody = compressedData; + request.HTTPMethod = kGULNetworkPOSTRequestMethod; + [request setValue:kGULNetworkContentTypeValue forHTTPHeaderField:kGULNetworkContentTypeKey]; + [request setValue:kGULNetworkContentCompressionValue + forHTTPHeaderField:kGULNetworkContentCompressionKey]; + + GULNetworkURLSession *fetcher = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:self]; + fetcher.backgroundNetworkEnabled = usingBackgroundSession; + + __weak GULNetwork *weakSelf = self; + NSString *requestID = [fetcher + sessionIDFromAsyncPOSTRequest:request + completionHandler:^(NSHTTPURLResponse *response, NSData *data, + NSString *sessionID, NSError *error) { + GULNetwork *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + if (sessionID.length) { + [strongSelf->_requests removeObjectForKey:sessionID]; + } + if (handler) { + handler(response, data, error); + } + }); + }]; + if (!requestID) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + [self GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeNetwork000 + message:@"Uploading data. Host" + context:url]; + _requests[requestID] = fetcher; + return requestID; +} + +- (NSString *)getURL:(NSURL *)url + headers:(NSDictionary *)headers + queue:(dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + if (!url.absoluteString.length) { + [self handleErrorWithCode:GULErrorCodeNetworkInvalidURL queue:queue withHandler:handler]; + return nil; + } + + NSTimeInterval timeOutInterval = _timeoutInterval ?: kGULNetworkTimeOutInterval; + NSMutableURLRequest *request = + [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:timeOutInterval]; + + if (!request) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + request.HTTPMethod = kGULNetworkGETRequestMethod; + request.allHTTPHeaderFields = headers; + + GULNetworkURLSession *fetcher = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:self]; + fetcher.backgroundNetworkEnabled = usingBackgroundSession; + + __weak GULNetwork *weakSelf = self; + NSString *requestID = [fetcher + sessionIDFromAsyncGETRequest:request + completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSString *sessionID, + NSError *error) { + GULNetwork *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + if (sessionID.length) { + [strongSelf->_requests removeObjectForKey:sessionID]; + } + if (handler) { + handler(response, data, error); + } + }); + }]; + + if (!requestID) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + [self GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeNetwork001 + message:@"Downloading data. Host" + context:url]; + _requests[requestID] = fetcher; + return requestID; +} + +- (BOOL)hasUploadInProgress { + return _requests.count > 0; +} + +#pragma mark - Network Reachability + +/// Tells reachability delegate to call reachabilityDidChangeToStatus: to notify the network +/// reachability has changed. +- (void)reachability:(GULReachabilityChecker *)reachability + statusChanged:(GULReachabilityStatus)status { + _networkConnected = (status == kGULReachabilityViaCellular || status == kGULReachabilityViaWifi); + [_reachabilityDelegate reachabilityDidChange]; +} + +#pragma mark - Network logger delegate + +- (void)setLoggerDelegate:(id)loggerDelegate { + // Explicitly check whether the delegate responds to the methods because conformsToProtocol does + // not work correctly even though the delegate does respond to the methods. + if (!loggerDelegate || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:contexts:)] || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:context:)] || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:)]) { + GULLogError(kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULNetworkMessageCodeNetwork002], + @"Cannot set the network logger delegate: delegate does not conform to the network " + "logger protocol."); + return; + } + _loggerDelegate = loggerDelegate; +} + +#pragma mark - Private methods + +/// Handles network error and calls completion handler with the error. +- (void)handleErrorWithCode:(NSInteger)code + queue:(dispatch_queue_t)queue + withHandler:(GULNetworkCompletionHandler)handler { + NSDictionary *userInfo = @{kGULNetworkErrorContext : @"Failed to create network request"}; + NSError *error = [[NSError alloc] initWithDomain:kGULNetworkErrorDomain + code:code + userInfo:userInfo]; + [self GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeNetwork002 + message:@"Failed to create network request. Code, error" + contexts:@[ @(code), error ]]; + if (handler) { + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + handler(nil, nil, error); + }); + } +} + +#pragma mark - Network logger + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + contexts:(NSArray *)contexts { + // Let the delegate log the message if there is a valid logger delegate. Otherwise, just log + // errors/warnings/info messages to the console log. + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel + messageCode:messageCode + message:message + contexts:contexts]; + return; + } + if (_isDebugModeEnabled || logLevel == kGULNetworkLogLevelError || + logLevel == kGULNetworkLogLevelWarning || logLevel == kGULNetworkLogLevelInfo) { + NSString *formattedMessage = GULStringWithLogMessage(message, logLevel, contexts); + NSLog(@"%@", formattedMessage); + GULLogBasic((GULLoggerLevel)logLevel, kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)messageCode], formattedMessage, + NULL); + } +} + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + context:(id)context { + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel + messageCode:messageCode + message:message + context:context]; + return; + } + NSArray *contexts = context ? @[ context ] : @[]; + [self GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:contexts]; +} + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message { + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message]; + return; + } + [self GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:@[]]; +} + +/// Returns a string for the given log level (e.g. kGULNetworkLogLevelError -> @"ERROR"). +static NSString *GULLogLevelDescriptionFromLogLevel(GULNetworkLogLevel logLevel) { + static NSDictionary *levelNames = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + levelNames = @{ + @(kGULNetworkLogLevelError) : @"ERROR", + @(kGULNetworkLogLevelWarning) : @"WARNING", + @(kGULNetworkLogLevelInfo) : @"INFO", + @(kGULNetworkLogLevelDebug) : @"DEBUG" + }; + }); + return levelNames[@(logLevel)]; +} + +/// Returns a formatted string to be used for console logging. +static NSString *GULStringWithLogMessage(NSString *message, + GULNetworkLogLevel logLevel, + NSArray *contexts) { + if (!message) { + message = @"(Message was nil)"; + } else if (!message.length) { + message = @"(Message was empty)"; + } + NSMutableString *result = [[NSMutableString alloc] + initWithFormat:@"<%@/%@> %@", kGULNetworkLogTag, GULLogLevelDescriptionFromLogLevel(logLevel), + message]; + + if (!contexts.count) { + return result; + } + + NSMutableArray *formattedContexts = [[NSMutableArray alloc] init]; + for (id item in contexts) { + [formattedContexts addObject:(item != [NSNull null] ? item : @"(nil)")]; + } + + [result appendString:@": "]; + [result appendString:[formattedContexts componentsJoinedByString:@", "]]; + return result; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m new file mode 100644 index 0000000..e4b8469 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m @@ -0,0 +1,41 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +#import + +NSString *const kGULNetworkBackgroundSessionConfigIDPrefix = @"com.gul.network.background-upload"; +NSString *const kGULNetworkApplicationSupportSubdirectory = @"GUL/Network"; +NSString *const kGULNetworkTempDirectoryName = @"GULNetworkTemporaryDirectory"; +const NSTimeInterval kGULNetworkTempFolderExpireTime = 60 * 60; // 1 hour +const NSTimeInterval kGULNetworkTimeOutInterval = 60; // 1 minute. +NSString *const kGULNetworkReachabilityHost = @"app-measurement.com"; +NSString *const kGULNetworkErrorContext = @"Context"; + +const int kGULNetworkHTTPStatusOK = 200; +const int kGULNetworkHTTPStatusNoContent = 204; +const int kGULNetworkHTTPStatusCodeMultipleChoices = 300; +const int kGULNetworkHTTPStatusCodeMovedPermanently = 301; +const int kGULNetworkHTTPStatusCodeFound = 302; +const int kGULNetworkHTTPStatusCodeNotModified = 304; +const int kGULNetworkHTTPStatusCodeMovedTemporarily = 307; +const int kGULNetworkHTTPStatusCodeNotFound = 404; +const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic = 429; +const int kGULNetworkHTTPStatusCodeUnavailable = 503; + +NSString *const kGULNetworkErrorDomain = @"com.gul.network.ErrorDomain"; + +GULLoggerService kGULLoggerNetwork = @"[GULNetwork]"; diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h new file mode 100644 index 0000000..5aca9fd --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.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 + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +extern NSString *const kGULNetworkErrorDomain; + +/// The logger service for GULNetwork. +extern GULLoggerService kGULLoggerNetwork; diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m new file mode 100644 index 0000000..f78bdc1 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m @@ -0,0 +1,766 @@ +// 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 + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/GULNetworkInternal.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h" + +@interface GULNetworkURLSession () +@end + +@implementation GULNetworkURLSession { + /// The handler to be called when the request completes or error has occurs. + GULNetworkURLSessionCompletionHandler _completionHandler; + + /// Session ID generated randomly with a fixed prefix. + NSString *_sessionID; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + /// The session configuration. NSURLSessionConfiguration' is only available on iOS 7.0 or newer. + NSURLSessionConfiguration *_sessionConfig; + + /// The current NSURLSession. + NSURLSession *__weak _Nullable _URLSession; +#pragma clang diagnostic pop + + /// The path to the directory where all temporary files are stored before uploading. + NSURL *_networkDirectoryURL; + + /// The downloaded data from fetching. + NSData *_downloadedData; + + /// The path to the temporary file which stores the uploading data. + NSURL *_uploadingFileURL; + + /// The current request. + NSURLRequest *_request; +} + +#pragma mark - Init + +- (instancetype)initWithNetworkLoggerDelegate:(id)networkLoggerDelegate { + self = [super init]; + if (self) { + // Create URL to the directory where all temporary files to upload have to be stored. +#if TARGET_OS_TV + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); +#else + NSArray *paths = + NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); +#endif + NSString *storageDirectory = paths.firstObject; + NSArray *tempPathComponents = @[ + storageDirectory, kGULNetworkApplicationSupportSubdirectory, kGULNetworkTempDirectoryName + ]; + _networkDirectoryURL = [NSURL fileURLWithPathComponents:tempPathComponents]; + _sessionID = [NSString stringWithFormat:@"%@-%@", kGULNetworkBackgroundSessionConfigIDPrefix, + [[NSUUID UUID] UUIDString]]; + _loggerDelegate = networkLoggerDelegate; + } + return self; +} + +#pragma mark - External Methods + +#pragma mark - To be called from AppDelegate + ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler: + (GULNetworkSystemCompletionHandler)systemCompletionHandler { + // The session may not be Analytics background. Ignore those that do not have the prefix. + if (![sessionID hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) { + return; + } + GULNetworkURLSession *fetcher = [self fetcherWithSessionIdentifier:sessionID]; + if (fetcher != nil) { + [fetcher addSystemCompletionHandler:systemCompletionHandler forSession:sessionID]; + } else { + GULLogError(kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULNetworkMessageCodeNetwork003], + @"Failed to retrieve background session with ID %@ after app is relaunched.", + sessionID); + } +} + +#pragma mark - External Methods + +/// Sends an async POST request using NSURLSession for iOS >= 7.0, and returns an ID of the +/// connection. +- (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler + API_AVAILABLE(ios(7.0)) { + // NSURLSessionUploadTask does not work with NSData in the background. + // To avoid this issue, write the data to a temporary file to upload it. + // Make a temporary file with the data subset. + _uploadingFileURL = [self temporaryFilePathWithSessionID:_sessionID]; + NSError *writeError; + NSURLSessionUploadTask *postRequestTask; + NSURLSession *session; + BOOL didWriteFile = NO; + + // Clean up the entire temp folder to avoid temp files that remain in case the previous session + // crashed and did not clean up. + [self maybeRemoveTempFilesAtURL:_networkDirectoryURL + expiringTime:kGULNetworkTempFolderExpireTime]; + + // If there is no background network enabled, no need to write to file. This will allow default + // network session which runs on the foreground. + if (_backgroundNetworkEnabled && [self ensureTemporaryDirectoryExists]) { + didWriteFile = [request.HTTPBody writeToFile:_uploadingFileURL.path + options:NSDataWritingAtomic + error:&writeError]; + + if (writeError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession000 + message:@"Failed to write request data to file" + context:writeError]; + } + } + + if (didWriteFile) { + // Exclude this file from backing up to iTunes. There are conflicting reports that excluding + // directory from backing up does not exclude files of that directory from backing up. + [self excludeFromBackupForURL:_uploadingFileURL]; + + _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID]; + [self populateSessionConfig:_sessionConfig withRequest:request]; + session = [NSURLSession sessionWithConfiguration:_sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; + postRequestTask = [session uploadTaskWithRequest:request fromFile:_uploadingFileURL]; + } else { + // If we cannot write to file, just send it in the foreground. + _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + [self populateSessionConfig:_sessionConfig withRequest:request]; + session = [NSURLSession sessionWithConfiguration:_sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; + postRequestTask = [session uploadTaskWithRequest:request fromData:request.HTTPBody]; + } + + if (!session || !postRequestTask) { + NSError *error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkRequestCreation + userInfo:@{kGULNetworkErrorContext : @"Cannot create network session"}]; + [self callCompletionHandler:handler withResponse:nil data:nil error:error]; + return nil; + } + + _URLSession = session; + + // Save the session into memory. + [[self class] setSessionInFetcherMap:self forSessionID:_sessionID]; + + _request = [request copy]; + + // Store completion handler because background session does not accept handler block but custom + // delegate. + _completionHandler = [handler copy]; + [postRequestTask resume]; + + return _sessionID; +} + +/// Sends an async GET request using NSURLSession for iOS >= 7.0, and returns an ID of the session. +- (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler + API_AVAILABLE(ios(7.0)) { + if (_backgroundNetworkEnabled) { + _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID]; + } else { + _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + } + + [self populateSessionConfig:_sessionConfig withRequest:request]; + + // Do not cache the GET request. + _sessionConfig.URLCache = nil; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:_sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; + NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request]; + + if (!session || !downloadTask) { + NSError *error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkRequestCreation + userInfo:@{kGULNetworkErrorContext : @"Cannot create network session"}]; + [self callCompletionHandler:handler withResponse:nil data:nil error:error]; + return nil; + } + + _URLSession = session; + + // Save the session into memory. + [[self class] setSessionInFetcherMap:self forSessionID:_sessionID]; + + _request = [request copy]; + + _completionHandler = [handler copy]; + [downloadTask resume]; + + return _sessionID; +} + +#pragma mark - NSURLSessionDataDelegate + +/// Called by the NSURLSession when the data task has received some of the expected data. +/// Once the session is completed, URLSession:task:didCompleteWithError will be called and the +/// completion handler will be called with the downloaded data. +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + @synchronized(self) { + NSMutableData *mutableData = [[NSMutableData alloc] init]; + if (_downloadedData) { + mutableData = _downloadedData.mutableCopy; + } + [mutableData appendData:data]; + _downloadedData = mutableData; + } +} + +#pragma mark - NSURLSessionTaskDelegate + +/// Called by the NSURLSession once the download task is completed. The file is saved in the +/// provided URL so we need to read the data and store into _downloadedData. Once the session is +/// completed, URLSession:task:didCompleteWithError will be called and the completion handler will +/// be called with the downloaded data. +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)task + didFinishDownloadingToURL:(NSURL *)url API_AVAILABLE(ios(7.0)) { + if (!url.path) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession001 + message:@"Unable to read downloaded data from empty temp path"]; + _downloadedData = nil; + return; + } + + NSError *error; + _downloadedData = [NSData dataWithContentsOfFile:url.path options:0 error:&error]; + + if (error) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession002 + message:@"Cannot read the content of downloaded data" + context:error]; + _downloadedData = nil; + } +} + +#if TARGET_OS_IOS || TARGET_OS_TV +- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session + API_AVAILABLE(ios(7.0)) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession003 + message:@"Background session finished" + context:session.configuration.identifier]; + [self callSystemCompletionHandler:session.configuration.identifier]; +} +#endif + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error API_AVAILABLE(ios(7.0)) { + // Avoid any chance of recursive behavior leading to it being used repeatedly. + GULNetworkURLSessionCompletionHandler handler = _completionHandler; + _completionHandler = nil; + + if (task.response) { + // The following assertion should always be true for HTTP requests, see https://goo.gl/gVLxT7. + NSAssert([task.response isKindOfClass:[NSHTTPURLResponse class]], @"URL response must be HTTP"); + + // The server responded so ignore the error created by the system. + error = nil; + } else if (!error) { + error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkInvalidResponse + userInfo:@{kGULNetworkErrorContext : @"Network Error: Empty network response"}]; + } + + [self callCompletionHandler:handler + withResponse:(NSHTTPURLResponse *)task.response + data:_downloadedData + error:error]; + + // Remove the temp file to avoid trashing devices with lots of temp files. + [self removeTempItemAtURL:_uploadingFileURL]; + + // Try to clean up stale files again. + [self maybeRemoveTempFilesAtURL:_networkDirectoryURL + expiringTime:kGULNetworkTempFolderExpireTime]; + + // This is called without checking the sessionID here since non-background sessions + // won't have an ID. + [session finishTasksAndInvalidate]; + + // Explicitly remove the session so it won't be reused. The weak map table should + // remove the session on deallocation, but dealloc may not happen immediately after + // calling `finishTasksAndInvalidate`. + NSString *sessionID = session.configuration.identifier; + [[self class] setSessionInFetcherMap:nil forSessionID:sessionID]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential *credential))completionHandler + API_AVAILABLE(ios(7.0)) { + // The handling is modeled after GTMSessionFetcher. + if ([challenge.protectionSpace.authenticationMethod + isEqualToString:NSURLAuthenticationMethodServerTrust]) { + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + if (serverTrust == NULL) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession004 + message:@"Received empty server trust for host. Host" + context:_request.URL]; + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + return; + } + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + if (!credential) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession005 + message:@"Unable to verify server identity. Host" + context:_request.URL]; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + return; + } + + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession006 + message:@"Received SSL challenge for host. Host" + context:_request.URL]; + + void (^callback)(BOOL) = ^(BOOL allow) { + if (allow) { + completionHandler(NSURLSessionAuthChallengeUseCredential, credential); + } else { + [self->_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession007 + message:@"Cancelling authentication challenge for host. Host" + context:self->_request.URL]; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + }; + + // Retain the trust object to avoid a SecTrustEvaluate() crash on iOS 7. + CFRetain(serverTrust); + + // Evaluate the certificate chain. + // + // The delegate queue may be the main thread. Trust evaluation could cause some + // blocking network activity, so we must evaluate async, as documented at + // https://developer.apple.com/library/ios/technotes/tn2232/ + dispatch_queue_t evaluateBackgroundQueue = + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + dispatch_async(evaluateBackgroundQueue, ^{ + SecTrustResultType trustEval = kSecTrustResultInvalid; + BOOL shouldAllow; + OSStatus trustError; + + @synchronized([GULNetworkURLSession class]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + trustError = SecTrustEvaluate(serverTrust, &trustEval); +#pragma clang dianostic pop + } + + if (trustError != errSecSuccess) { + [self->_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession008 + message:@"Cannot evaluate server trust. Error, host" + contexts:@[ @(trustError), self->_request.URL ]]; + shouldAllow = NO; + } else { + // Having a trust level "unspecified" by the user is the usual result, described at + // https://developer.apple.com/library/mac/qa/qa1360 + shouldAllow = + (trustEval == kSecTrustResultUnspecified || trustEval == kSecTrustResultProceed); + } + + // Call the call back with the permission. + callback(shouldAllow); + + CFRelease(serverTrust); + }); + return; + } + + // Default handling for other Auth Challenges. + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); +} + +#pragma mark - Internal Methods + +/// Stores system completion handler with session ID as key. +- (void)addSystemCompletionHandler:(GULNetworkSystemCompletionHandler)handler + forSession:(NSString *)identifier { + if (!handler) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession009 + message:@"Cannot store nil system completion handler in network"]; + return; + } + + if (!identifier.length) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession010 + message:@"Cannot store system completion handler with empty network " + "session identifier"]; + return; + } + + GULMutableDictionary *systemCompletionHandlers = + [[self class] sessionIDToSystemCompletionHandlerDictionary]; + if (systemCompletionHandlers[identifier]) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession011 + message:@"Got multiple system handlers for a single session ID" + context:identifier]; + } + + systemCompletionHandlers[identifier] = handler; +} + +/// Calls the system provided completion handler with the session ID stored in the dictionary. +/// The handler will be removed from the dictionary after being called. +- (void)callSystemCompletionHandler:(NSString *)identifier { + GULMutableDictionary *systemCompletionHandlers = + [[self class] sessionIDToSystemCompletionHandlerDictionary]; + GULNetworkSystemCompletionHandler handler = [systemCompletionHandlers objectForKey:identifier]; + + if (handler) { + [systemCompletionHandlers removeObjectForKey:identifier]; + + dispatch_async(dispatch_get_main_queue(), ^{ + handler(); + }); + } +} + +/// Sets or updates the session ID of this session. +- (void)setSessionID:(NSString *)sessionID { + _sessionID = [sessionID copy]; +} + +/// Creates a background session configuration with the session ID using the supported method. +- (NSURLSessionConfiguration *)backgroundSessionConfigWithSessionID:(NSString *)sessionID + API_AVAILABLE(ios(7.0)) { +#if (TARGET_OS_OSX && defined(MAC_OS_X_VERSION_10_10) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) || \ + TARGET_OS_TV || \ + (TARGET_OS_IOS && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0) + + // iOS 8/10.10 builds require the new backgroundSessionConfiguration method name. + return [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionID]; + +#elif (TARGET_OS_OSX && defined(MAC_OS_X_VERSION_10_10) && \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10) || \ + (TARGET_OS_IOS && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0) + + // Do a runtime check to avoid a deprecation warning about using + // +backgroundSessionConfiguration: on iOS 8. + if ([NSURLSessionConfiguration + respondsToSelector:@selector(backgroundSessionConfigurationWithIdentifier:)]) { + // Running on iOS 8+/OS X 10.10+. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + return [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionID]; +#pragma clang diagnostic pop + } else { + // Running on iOS 7/OS X 10.9. + return [NSURLSessionConfiguration backgroundSessionConfiguration:sessionID]; + } + +#else + // Building with an SDK earlier than iOS 8/OS X 10.10. + return [NSURLSessionConfiguration backgroundSessionConfiguration:sessionID]; +#endif +} + +- (void)maybeRemoveTempFilesAtURL:(NSURL *)folderURL expiringTime:(NSTimeInterval)staleTime { + if (!folderURL.absoluteString.length) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + NSArray *properties = @[ NSURLCreationDateKey ]; + NSArray *directoryContent = + [fileManager contentsOfDirectoryAtURL:folderURL + includingPropertiesForKeys:properties + options:NSDirectoryEnumerationSkipsSubdirectoryDescendants + error:&error]; + if (error && error.code != NSFileReadNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession012 + message:@"Cannot get files from the temporary network folder. Error" + context:error]; + return; + } + + if (!directoryContent.count) { + return; + } + + NSTimeInterval now = [NSDate date].timeIntervalSince1970; + for (NSURL *tempFile in directoryContent) { + NSDate *creationDate; + BOOL getCreationDate = [tempFile getResourceValue:&creationDate + forKey:NSURLCreationDateKey + error:NULL]; + if (!getCreationDate) { + continue; + } + NSTimeInterval creationTimeInterval = creationDate.timeIntervalSince1970; + if (fabs(now - creationTimeInterval) > staleTime) { + [self removeTempItemAtURL:tempFile]; + } + } +} + +/// Removes the temporary file written to disk for sending the request. It has to be cleaned up +/// after the session is done. +- (void)removeTempItemAtURL:(NSURL *)fileURL { + if (!fileURL.absoluteString.length) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + if (![fileManager removeItemAtURL:fileURL error:&error] && error.code != NSFileNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession013 + message:@"Failed to remove temporary uploading data file. Error" + context:error.localizedDescription]; + } +} + +/// Gets the fetcher with the session ID. ++ (instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier { + GULNetworkURLSession *session = [self sessionFromFetcherMapForSessionID:sessionIdentifier]; + if (!session && [sessionIdentifier hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) { + session = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:nil]; + [session setSessionID:sessionIdentifier]; + [self setSessionInFetcherMap:session forSessionID:sessionIdentifier]; + } + return session; +} + +/// Returns a map of the fetcher by session ID. Creates a map if it is not created. +/// When reading and writing from/to the session map, don't use this method directly. +/// To avoid thread safety issues, use one of the helper methods at the bottom of the +/// file: setSessionInFetcherMap:forSessionID:, sessionFromFetcherMapForSessionID: ++ (NSMapTable *)sessionIDToFetcherMap { + static NSMapTable *sessionIDToFetcherMap; + + static dispatch_once_t sessionMapOnceToken; + dispatch_once(&sessionMapOnceToken, ^{ + sessionIDToFetcherMap = [NSMapTable strongToWeakObjectsMapTable]; + }); + return sessionIDToFetcherMap; +} + ++ (NSLock *)sessionIDToFetcherMapReadWriteLock { + static NSLock *lock; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + lock = [[NSLock alloc] init]; + }); + return lock; +} + +/// Returns a map of system provided completion handler by session ID. Creates a map if it is not +/// created. ++ (GULMutableDictionary *)sessionIDToSystemCompletionHandlerDictionary { + static GULMutableDictionary *systemCompletionHandlers; + + static dispatch_once_t systemCompletionHandlerOnceToken; + dispatch_once(&systemCompletionHandlerOnceToken, ^{ + systemCompletionHandlers = [[GULMutableDictionary alloc] init]; + }); + return systemCompletionHandlers; +} + +- (NSURL *)temporaryFilePathWithSessionID:(NSString *)sessionID { + NSString *tempName = [NSString stringWithFormat:@"GULUpload_temp_%@", sessionID]; + return [_networkDirectoryURL URLByAppendingPathComponent:tempName]; +} + +/// Makes sure that the directory to store temp files exists. If not, tries to create it and returns +/// YES. If there is anything wrong, returns NO. +- (BOOL)ensureTemporaryDirectoryExists { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + // Create a temporary directory if it does not exist or was deleted. + if ([_networkDirectoryURL checkResourceIsReachableAndReturnError:&error]) { + return YES; + } + + if (error && error.code != NSFileReadNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession014 + message:@"Error while trying to access Network temp folder. Error" + context:error]; + } + + NSError *writeError = nil; + + [fileManager createDirectoryAtURL:_networkDirectoryURL + withIntermediateDirectories:YES + attributes:nil + error:&writeError]; + if (writeError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession015 + message:@"Cannot create temporary directory. Error" + context:writeError]; + return NO; + } + + // Set the iCloud exclusion attribute on the Documents URL. + [self excludeFromBackupForURL:_networkDirectoryURL]; + + return YES; +} + +- (void)excludeFromBackupForURL:(NSURL *)url { + if (!url.path) { + return; + } + + // Set the iCloud exclusion attribute on the Documents URL. + NSError *preventBackupError = nil; + [url setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&preventBackupError]; + if (preventBackupError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession016 + message:@"Cannot exclude temporary folder from iTunes backup"]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler API_AVAILABLE(ios(7.0)) { + NSArray *nonAllowedRedirectionCodes = @[ + @(kGULNetworkHTTPStatusCodeFound), @(kGULNetworkHTTPStatusCodeMovedPermanently), + @(kGULNetworkHTTPStatusCodeMovedTemporarily), @(kGULNetworkHTTPStatusCodeMultipleChoices) + ]; + + // Allow those not in the non allowed list to be followed. + if (![nonAllowedRedirectionCodes containsObject:@(response.statusCode)]) { + completionHandler(request); + return; + } + + // Do not allow redirection if the response code is in the non-allowed list. + NSURLRequest *newRequest = request; + + if (response) { + newRequest = nil; + } + + completionHandler(newRequest); +} + +#pragma mark - Helper Methods + ++ (void)setSessionInFetcherMap:(GULNetworkURLSession *)session forSessionID:(NSString *)sessionID { + [[self sessionIDToFetcherMapReadWriteLock] lock]; + GULNetworkURLSession *existingSession = + [[[self class] sessionIDToFetcherMap] objectForKey:sessionID]; + if (existingSession) { + if (session) { + NSString *message = [NSString stringWithFormat:@"Discarding session: %@", existingSession]; + [existingSession->_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelInfo + messageCode:kGULNetworkMessageCodeURLSession019 + message:message]; + } + [existingSession->_URLSession finishTasksAndInvalidate]; + } + if (session) { + [[[self class] sessionIDToFetcherMap] setObject:session forKey:sessionID]; + } else { + [[[self class] sessionIDToFetcherMap] removeObjectForKey:sessionID]; + } + [[self sessionIDToFetcherMapReadWriteLock] unlock]; +} + ++ (nullable GULNetworkURLSession *)sessionFromFetcherMapForSessionID:(NSString *)sessionID { + [[self sessionIDToFetcherMapReadWriteLock] lock]; + GULNetworkURLSession *session = [[[self class] sessionIDToFetcherMap] objectForKey:sessionID]; + [[self sessionIDToFetcherMapReadWriteLock] unlock]; + return session; +} + +- (void)callCompletionHandler:(GULNetworkURLSessionCompletionHandler)handler + withResponse:(NSHTTPURLResponse *)response + data:(NSData *)data + error:(NSError *)error { + if (error) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession017 + message:@"Encounter network error. Code, error" + contexts:@[ @(error.code), error ]]; + } + + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(response, data, self->_sessionID, error); + }); + } +} + +// Always use the request parameters even if the default session configuration is more restrictive. +- (void)populateSessionConfig:(NSURLSessionConfiguration *)sessionConfig + withRequest:(NSURLRequest *)request API_AVAILABLE(ios(7.0)) { + sessionConfig.HTTPAdditionalHeaders = request.allHTTPHeaderFields; + sessionConfig.timeoutIntervalForRequest = request.timeoutInterval; + sessionConfig.timeoutIntervalForResource = request.timeoutInterval; + sessionConfig.requestCachePolicy = request.cachePolicy; +} + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h new file mode 100644 index 0000000..a8cc45b --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/// A mutable dictionary that provides atomic accessor and mutators. +@interface GULMutableDictionary : NSObject + +/// Returns an object given a key in the dictionary or nil if not found. +- (id)objectForKey:(id)key; + +/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. +- (void)setObject:(id)object forKey:(id)key; + +/// Removes the object given its session ID from the dictionary. +- (void)removeObjectForKey:(id)key; + +/// Removes all objects. +- (void)removeAllObjects; + +/// Returns the number of current objects in the dictionary. +- (NSUInteger)count; + +/// Returns an object given a key in the dictionary or nil if not found. +- (id)objectForKeyedSubscript:(id)key; + +/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. +- (void)setObject:(id)obj forKeyedSubscript:(id)key; + +/// Returns the immutable dictionary. +- (NSDictionary *)dictionary; + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h new file mode 100644 index 0000000..0e75ae5 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h @@ -0,0 +1,87 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULNetworkConstants.h" +#import "GULNetworkLoggerProtocol.h" +#import "GULNetworkURLSession.h" + +/// Delegate protocol for GULNetwork events. +@protocol GULNetworkReachabilityDelegate + +/// Tells the delegate to handle events when the network reachability changes to connected or not +/// connected. +- (void)reachabilityDidChange; + +@end + +/// The Network component that provides network status and handles network requests and responses. +/// This is not thread safe. +/// +/// NOTE: +/// User must add FIRAnalytics handleEventsForBackgroundURLSessionID:completionHandler to the +/// AppDelegate application:handleEventsForBackgroundURLSession:completionHandler: +@interface GULNetwork : NSObject + +/// Indicates if network connectivity is available. +@property(nonatomic, readonly, getter=isNetworkConnected) BOOL networkConnected; + +/// Indicates if there are any uploads in progress. +@property(nonatomic, readonly, getter=hasUploadInProgress) BOOL uploadInProgress; + +/// An optional delegate that can be used in the event when network reachability changes. +@property(nonatomic, weak) id reachabilityDelegate; + +/// An optional delegate that can be used to log messages, warnings or errors that occur in the +/// network operations. +@property(nonatomic, weak) id loggerDelegate; + +/// Indicates whether the logger should display debug messages. +@property(nonatomic, assign) BOOL isDebugModeEnabled; + +/// The time interval in seconds for the network request to timeout. +@property(nonatomic, assign) NSTimeInterval timeoutInterval; + +/// Initializes with the default reachability host. +- (instancetype)init; + +/// Initializes with a custom reachability host. +- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost; + +/// Handles events when background session with the given ID has finished. ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler; + +/// Compresses and sends a POST request with the provided data to the URL. The session will be +/// background session if usingBackgroundSession is YES. Otherwise, the POST session is default +/// session. Returns a session ID or nil if an error occurs. +- (NSString *)postURL:(NSURL *)url + payload:(NSData *)payload + queue:(dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +/// Sends a GET request with the provided data to the URL. The session will be background session +/// if usingBackgroundSession is YES. Otherwise, the GET session is default session. Returns a +/// session ID or nil if an error occurs. +- (NSString *)getURL:(NSURL *)url + headers:(NSDictionary *)headers + queue:(dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h new file mode 100644 index 0000000..1cbedd1 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h @@ -0,0 +1,71 @@ +/* + * 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 + +/// Error codes in Firebase Network error domain. +/// Note: these error codes should never change. It would make it harder to decode the errors if +/// we inadvertently altered any of these codes in a future SDK version. +typedef NS_ENUM(NSInteger, GULNetworkErrorCode) { + /// Unknown error. + GULNetworkErrorCodeUnknown = 0, + /// Error occurs when the request URL is invalid. + GULErrorCodeNetworkInvalidURL = 1, + /// Error occurs when request cannot be constructed. + GULErrorCodeNetworkRequestCreation = 2, + /// Error occurs when payload cannot be compressed. + GULErrorCodeNetworkPayloadCompression = 3, + /// Error occurs when session task cannot be created. + GULErrorCodeNetworkSessionTaskCreation = 4, + /// Error occurs when there is no response. + GULErrorCodeNetworkInvalidResponse = 5 +}; + +#pragma mark - Network constants + +/// The prefix of the ID of the background session. +extern NSString *const kGULNetworkBackgroundSessionConfigIDPrefix; + +/// The sub directory to store the files of data that is being uploaded in the background. +extern NSString *const kGULNetworkApplicationSupportSubdirectory; + +/// Name of the temporary directory that stores files for background uploading. +extern NSString *const kGULNetworkTempDirectoryName; + +/// The period when the temporary uploading file can stay. +extern const NSTimeInterval kGULNetworkTempFolderExpireTime; + +/// The default network request timeout interval. +extern const NSTimeInterval kGULNetworkTimeOutInterval; + +/// The host to check the reachability of the network. +extern NSString *const kGULNetworkReachabilityHost; + +/// The key to get the error context of the UserInfo. +extern NSString *const kGULNetworkErrorContext; + +#pragma mark - Network Status Code + +extern const int kGULNetworkHTTPStatusOK; +extern const int kGULNetworkHTTPStatusNoContent; +extern const int kGULNetworkHTTPStatusCodeMultipleChoices; +extern const int kGULNetworkHTTPStatusCodeMovedPermanently; +extern const int kGULNetworkHTTPStatusCodeFound; +extern const int kGULNetworkHTTPStatusCodeNotModified; +extern const int kGULNetworkHTTPStatusCodeMovedTemporarily; +extern const int kGULNetworkHTTPStatusCodeNotFound; +extern const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic; +extern const int kGULNetworkHTTPStatusCodeUnavailable; diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h new file mode 100644 index 0000000..425c073 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h @@ -0,0 +1,49 @@ +/* + * 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 + +#import "GULNetworkMessageCode.h" + +/// The log levels used by GULNetworkLogger. +typedef NS_ENUM(NSInteger, GULNetworkLogLevel) { + kGULNetworkLogLevelError = 3, + kGULNetworkLogLevelWarning = 4, + kGULNetworkLogLevelInfo = 6, + kGULNetworkLogLevelDebug = 7, +}; + +@protocol GULNetworkLoggerDelegate + +@required +/// Tells the delegate to log a message with an array of contexts and the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + contexts:(NSArray *)contexts; + +/// Tells the delegate to log a message with a context and the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + context:(id)context; + +/// Tells the delegate to log a message with the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message; + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h new file mode 100644 index 0000000..507bc5a --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h @@ -0,0 +1,47 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. +typedef NS_ENUM(NSInteger, GULNetworkMessageCode) { + // GULNetwork.m + kGULNetworkMessageCodeNetwork000 = 900000, // I-NET900000 + kGULNetworkMessageCodeNetwork001 = 900001, // I-NET900001 + kGULNetworkMessageCodeNetwork002 = 900002, // I-NET900002 + kGULNetworkMessageCodeNetwork003 = 900003, // I-NET900003 + // GULNetworkURLSession.m + kGULNetworkMessageCodeURLSession000 = 901000, // I-NET901000 + kGULNetworkMessageCodeURLSession001 = 901001, // I-NET901001 + kGULNetworkMessageCodeURLSession002 = 901002, // I-NET901002 + kGULNetworkMessageCodeURLSession003 = 901003, // I-NET901003 + kGULNetworkMessageCodeURLSession004 = 901004, // I-NET901004 + kGULNetworkMessageCodeURLSession005 = 901005, // I-NET901005 + kGULNetworkMessageCodeURLSession006 = 901006, // I-NET901006 + kGULNetworkMessageCodeURLSession007 = 901007, // I-NET901007 + kGULNetworkMessageCodeURLSession008 = 901008, // I-NET901008 + kGULNetworkMessageCodeURLSession009 = 901009, // I-NET901009 + kGULNetworkMessageCodeURLSession010 = 901010, // I-NET901010 + kGULNetworkMessageCodeURLSession011 = 901011, // I-NET901011 + kGULNetworkMessageCodeURLSession012 = 901012, // I-NET901012 + kGULNetworkMessageCodeURLSession013 = 901013, // I-NET901013 + kGULNetworkMessageCodeURLSession014 = 901014, // I-NET901014 + kGULNetworkMessageCodeURLSession015 = 901015, // I-NET901015 + kGULNetworkMessageCodeURLSession016 = 901016, // I-NET901016 + kGULNetworkMessageCodeURLSession017 = 901017, // I-NET901017 + kGULNetworkMessageCodeURLSession018 = 901018, // I-NET901018 + kGULNetworkMessageCodeURLSession019 = 901019, // I-NET901019 +}; diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h new file mode 100644 index 0000000..3f9f7f9 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULNetworkLoggerProtocol.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^GULNetworkCompletionHandler)(NSHTTPURLResponse *_Nullable response, + NSData *_Nullable data, + NSError *_Nullable error); +typedef void (^GULNetworkURLSessionCompletionHandler)(NSHTTPURLResponse *_Nullable response, + NSData *_Nullable data, + NSString *sessionID, + NSError *_Nullable error); +typedef void (^GULNetworkSystemCompletionHandler)(void); + +/// The protocol that uses NSURLSession for iOS >= 7.0 to handle requests and responses. +@interface GULNetworkURLSession : NSObject + +/// Indicates whether the background network is enabled. Default value is NO. +@property(nonatomic, getter=isBackgroundNetworkEnabled) BOOL backgroundNetworkEnabled; + +/// The logger delegate to log message, errors or warnings that occur during the network operations. +@property(nonatomic, weak, nullable) id loggerDelegate; + +/// Calls the system provided completion handler after the background session is finished. ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler; + +/// Initializes with logger delegate. +- (instancetype)initWithNetworkLoggerDelegate: + (nullable id)networkLoggerDelegate NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +/// Sends an asynchronous POST request and calls the provided completion handler when the request +/// completes or when errors occur, and returns an ID of the session/connection. +- (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler; + +/// Sends an asynchronous GET request and calls the provided completion handler when the request +/// completes or when errors occur, and returns an ID of the session. +- (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler; + +NS_ASSUME_NONNULL_END +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h new file mode 100644 index 0000000..103ed3b --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +#if !TARGET_OS_WATCH +typedef SCNetworkReachabilityRef (*GULReachabilityCreateWithNameFn)(CFAllocatorRef allocator, + const char *host); + +typedef Boolean (*GULReachabilitySetCallbackFn)(SCNetworkReachabilityRef target, + SCNetworkReachabilityCallBack callback, + SCNetworkReachabilityContext *context); +typedef Boolean (*GULReachabilityScheduleWithRunLoopFn)(SCNetworkReachabilityRef target, + CFRunLoopRef runLoop, + CFStringRef runLoopMode); +typedef Boolean (*GULReachabilityUnscheduleFromRunLoopFn)(SCNetworkReachabilityRef target, + CFRunLoopRef runLoop, + CFStringRef runLoopMode); + +typedef void (*GULReachabilityReleaseFn)(CFTypeRef cf); + +struct GULReachabilityApi { + GULReachabilityCreateWithNameFn createWithNameFn; + GULReachabilitySetCallbackFn setCallbackFn; + GULReachabilityScheduleWithRunLoopFn scheduleWithRunLoopFn; + GULReachabilityUnscheduleFromRunLoopFn unscheduleFromRunLoopFn; + GULReachabilityReleaseFn releaseFn; +}; +#endif +@interface GULReachabilityChecker (Internal) + +- (const struct GULReachabilityApi *)reachabilityApi; +- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi; + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m new file mode 100644 index 0000000..f0d1235 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m @@ -0,0 +1,263 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +#import "GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h" +#import "GoogleUtilities/Reachability/GULReachabilityMessageCode.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +static GULLoggerService kGULLoggerReachability = @"[GULReachability]"; +#if !TARGET_OS_WATCH +static void ReachabilityCallback(SCNetworkReachabilityRef reachability, + SCNetworkReachabilityFlags flags, + void *info); + +static const struct GULReachabilityApi kGULDefaultReachabilityApi = { + SCNetworkReachabilityCreateWithName, + SCNetworkReachabilitySetCallback, + SCNetworkReachabilityScheduleWithRunLoop, + SCNetworkReachabilityUnscheduleFromRunLoop, + CFRelease, +}; + +static NSString *const kGULReachabilityUnknownStatus = @"Unknown"; +static NSString *const kGULReachabilityConnectedStatus = @"Connected"; +static NSString *const kGULReachabilityDisconnectedStatus = @"Disconnected"; +#endif +@interface GULReachabilityChecker () + +@property(nonatomic, assign) const struct GULReachabilityApi *reachabilityApi; +@property(nonatomic, assign) GULReachabilityStatus reachabilityStatus; +@property(nonatomic, copy) NSString *host; +#if !TARGET_OS_WATCH +@property(nonatomic, assign) SCNetworkReachabilityRef reachability; +#endif + +@end + +@implementation GULReachabilityChecker + +@synthesize reachabilityApi = reachabilityApi_; +#if !TARGET_OS_WATCH +@synthesize reachability = reachability_; +#endif + +- (const struct GULReachabilityApi *)reachabilityApi { + return reachabilityApi_; +} + +- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi { +#if !TARGET_OS_WATCH + if (reachability_) { + GULLogError(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode000], + @"Cannot change reachability API while reachability is running. " + @"Call stop first."); + return; + } + reachabilityApi_ = reachabilityApi; +#endif +} + +@synthesize reachabilityStatus = reachabilityStatus_; +@synthesize host = host_; +@synthesize reachabilityDelegate = reachabilityDelegate_; + +- (BOOL)isActive { +#if !TARGET_OS_WATCH + return reachability_ != nil; +#else + return NO; +#endif +} + +- (void)setReachabilityDelegate:(id)reachabilityDelegate { + if (reachabilityDelegate && + (![(NSObject *)reachabilityDelegate conformsToProtocol:@protocol(GULReachabilityDelegate)])) { + GULLogError(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULReachabilityMessageCode005], + @"Reachability delegate doesn't conform to Reachability protocol."); + return; + } + reachabilityDelegate_ = reachabilityDelegate; +} + +- (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate + withHost:(NSString *)host { + self = [super init]; + + if (!host || !host.length) { + GULLogError(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode001], + @"Invalid host specified"); + return nil; + } + if (self) { +#if !TARGET_OS_WATCH + [self setReachabilityDelegate:reachabilityDelegate]; + reachabilityApi_ = &kGULDefaultReachabilityApi; + reachabilityStatus_ = kGULReachabilityUnknown; + host_ = [host copy]; + reachability_ = nil; +#endif + } + return self; +} + +- (void)dealloc { + reachabilityDelegate_ = nil; + [self stop]; +} + +- (BOOL)start { +#if TARGET_OS_WATCH + return NO; +#else + + if (!reachability_) { + reachability_ = reachabilityApi_->createWithNameFn(kCFAllocatorDefault, [host_ UTF8String]); + if (!reachability_) { + return NO; + } + SCNetworkReachabilityContext context = { + 0, /* version */ + (__bridge void *)(self), /* info (passed as last parameter to reachability callback) */ + NULL, /* retain */ + NULL, /* release */ + NULL /* copyDescription */ + }; + if (!reachabilityApi_->setCallbackFn(reachability_, ReachabilityCallback, &context) || + !reachabilityApi_->scheduleWithRunLoopFn(reachability_, CFRunLoopGetMain(), + kCFRunLoopCommonModes)) { + reachabilityApi_->releaseFn(reachability_); + reachability_ = nil; + + GULLogError(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode002], + @"Failed to start reachability handle"); + return NO; + } + } + GULLogDebug(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode003], + @"Monitoring the network status"); + return YES; +#endif +} + +- (void)stop { +#if !TARGET_OS_WATCH + if (reachability_) { + reachabilityStatus_ = kGULReachabilityUnknown; + reachabilityApi_->unscheduleFromRunLoopFn(reachability_, CFRunLoopGetMain(), + kCFRunLoopCommonModes); + reachabilityApi_->releaseFn(reachability_); + reachability_ = nil; + } +#endif +} + +#if !TARGET_OS_WATCH +- (GULReachabilityStatus)statusForFlags:(SCNetworkReachabilityFlags)flags { + GULReachabilityStatus status = kGULReachabilityNotReachable; + // If the Reachable flag is not set, we definitely don't have connectivity. + if (flags & kSCNetworkReachabilityFlagsReachable) { + // Reachable flag is set. Check further flags. + if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired)) { +// Connection required flag is not set, so we have connectivity. +#if TARGET_OS_IOS || TARGET_OS_TV + status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular + : kGULReachabilityViaWifi; +#elif TARGET_OS_OSX + status = kGULReachabilityViaWifi; +#endif + } else if ((flags & (kSCNetworkReachabilityFlagsConnectionOnDemand | + kSCNetworkReachabilityFlagsConnectionOnTraffic)) && + !(flags & kSCNetworkReachabilityFlagsInterventionRequired)) { +// If the connection on demand or connection on traffic flag is set, and user intervention +// is not required, we have connectivity. +#if TARGET_OS_IOS || TARGET_OS_TV + status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular + : kGULReachabilityViaWifi; +#elif TARGET_OS_OSX + status = kGULReachabilityViaWifi; +#endif + } + } + return status; +} + +- (void)reachabilityFlagsChanged:(SCNetworkReachabilityFlags)flags { + GULReachabilityStatus status = [self statusForFlags:flags]; + if (reachabilityStatus_ != status) { + NSString *reachabilityStatusString; + if (status == kGULReachabilityUnknown) { + reachabilityStatusString = kGULReachabilityUnknownStatus; + } else { + reachabilityStatusString = (status == kGULReachabilityNotReachable) + ? kGULReachabilityDisconnectedStatus + : kGULReachabilityConnectedStatus; + } + + GULLogDebug(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode004], + @"Network status has changed. Code:%@, status:%@", @(status), + reachabilityStatusString); + reachabilityStatus_ = status; + [reachabilityDelegate_ reachability:self statusChanged:reachabilityStatus_]; + } +} + +#endif +@end + +#if !TARGET_OS_WATCH +static void ReachabilityCallback(SCNetworkReachabilityRef reachability, + SCNetworkReachabilityFlags flags, + void *info) { + GULReachabilityChecker *checker = (__bridge GULReachabilityChecker *)info; + [checker reachabilityFlagsChanged:flags]; +} +#endif + +// This function used to be at the top of the file, but it was moved here +// as a workaround for a suspected compiler bug. When compiled in Release mode +// and run on an iOS device with WiFi disabled, the reachability code crashed +// when calling SCNetworkReachabilityScheduleWithRunLoop, or shortly thereafter. +// After unsuccessfully trying to diagnose the cause of the crash, it was +// discovered that moving this function to the end of the file magically fixed +// the crash. If you are going to edit this file, exercise caution and make sure +// to test thoroughly with an iOS device under various network conditions. +const NSString *GULReachabilityStatusString(GULReachabilityStatus status) { + switch (status) { + case kGULReachabilityUnknown: + return @"Reachability Unknown"; + + case kGULReachabilityNotReachable: + return @"Not reachable"; + + case kGULReachabilityViaWifi: + return @"Reachable via Wifi"; + + case kGULReachabilityViaCellular: + return @"Reachable via Cellular Data"; + + default: + return [NSString stringWithFormat:@"Invalid reachability status %d", (int)status]; + } +} diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h new file mode 100644 index 0000000..373e0af --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. +typedef NS_ENUM(NSInteger, GULReachabilityMessageCode) { + // GULReachabilityChecker.m + kGULReachabilityMessageCode000 = 902000, // I-NET902000 + kGULReachabilityMessageCode001 = 902001, // I-NET902001 + kGULReachabilityMessageCode002 = 902002, // I-NET902002 + kGULReachabilityMessageCode003 = 902003, // I-NET902003 + kGULReachabilityMessageCode004 = 902004, // I-NET902004 + kGULReachabilityMessageCode005 = 902005, // I-NET902005 + kGULReachabilityMessageCode006 = 902006, // I-NET902006 +}; diff --git a/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h new file mode 100644 index 0000000..0c70c05 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h @@ -0,0 +1,79 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#if !TARGET_OS_WATCH +#import +#endif + +/// Reachability Status +typedef enum { + kGULReachabilityUnknown, ///< Have not yet checked or been notified whether host is reachable. + kGULReachabilityNotReachable, ///< Host is not reachable. + kGULReachabilityViaWifi, ///< Host is reachable via Wifi. + kGULReachabilityViaCellular, ///< Host is reachable via cellular. +} GULReachabilityStatus; + +const NSString *GULReachabilityStatusString(GULReachabilityStatus status); + +@class GULReachabilityChecker; + +/// Google Analytics iOS Reachability Checker. +@protocol GULReachabilityDelegate +@required +/// Called when network status has changed. +- (void)reachability:(GULReachabilityChecker *)reachability + statusChanged:(GULReachabilityStatus)status; +@end + +/// Google Analytics iOS Network Status Checker. +@interface GULReachabilityChecker : NSObject + +/// The last known reachability status, or GULReachabilityStatusUnknown if the +/// checker is not active. +@property(nonatomic, readonly) GULReachabilityStatus reachabilityStatus; +/// The host to which reachability status is to be checked. +@property(nonatomic, copy, readonly) NSString *host; +/// The delegate to be notified of reachability status changes. +@property(nonatomic, weak) id reachabilityDelegate; +/// `YES` if the reachability checker is active, `NO` otherwise. +@property(nonatomic, readonly) BOOL isActive; + +/// Initialize the reachability checker. Note that you must call start to begin checking for and +/// receiving notifications about network status changes. +/// +/// @param reachabilityDelegate The delegate to be notified when reachability status to host +/// changes. +/// +/// @param host The name of the host. +/// +- (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate + withHost:(NSString *)host; + +- (instancetype)init NS_UNAVAILABLE; + +/// Start checking for reachability to the specified host. This has no effect if the status +/// checker is already checking for connectivity. +/// +/// @return `YES` if initiating status checking was successful or the status checking has already +/// been initiated, `NO` otherwise. +- (BOOL)start; + +/// Stop checking for reachability to the specified host. This has no effect if the status +/// checker is not checking for connectivity. +- (void)stop; + +@end diff --git a/saraWhatsUp/Pods/GoogleUtilities/LICENSE b/saraWhatsUp/Pods/GoogleUtilities/LICENSE new file mode 100644 index 0000000..30a8f72 --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/LICENSE @@ -0,0 +1,247 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +================================================================================ + +The following copyright from Landon J. Fuller applies to the isAppEncrypted +function in Environment/third_party/GULAppEnvironmentUtil.m. + +Copyright (c) 2017 Landon J. Fuller +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Comment from +iPhone Dev Wiki +Crack Prevention: App Store binaries are signed by both their developer +and Apple. This encrypts the binary so that decryption keys are needed in order +to make the binary readable. When iOS executes the binary, the decryption keys +are used to decrypt the binary into a readable state where it is then loaded +into memory and executed. iOS can tell the encryption status of a binary via the +cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is +a non-zero value then the binary is encrypted. + +'Cracking' works by letting the kernel decrypt the binary then siphoning the +decrypted data into a new binary file, resigning, and repackaging. This will +only work on jailbroken devices as codesignature validation has been removed. +Resigning takes place because while the codesignature doesn't have to be valid +thanks to the jailbreak, it does have to be in place unless you have AppSync or +similar to disable codesignature checks. + +More information at Landon +Fuller's blog diff --git a/saraWhatsUp/Pods/GoogleUtilities/README.md b/saraWhatsUp/Pods/GoogleUtilities/README.md new file mode 100644 index 0000000..ff9fe1a --- /dev/null +++ b/saraWhatsUp/Pods/GoogleUtilities/README.md @@ -0,0 +1,189 @@ +[![Version](https://img.shields.io/cocoapods/v/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) +[![License](https://img.shields.io/cocoapods/l/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) +[![Platform](https://img.shields.io/cocoapods/p/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) + +[![Actions Status][gh-google-utilities-badge]][gh-actions] + +# GoogleUtilities + +GoogleUtilities provides a set of utilities for Firebase and other Google SDKs for Apple platform +development. + +The utilities are not directly supported for non-Google library usage. + +## Integration Testing +These instructions apply to minor and patch version updates. Major versions need +a customized adaptation. + +After the CI is green: +* Determine the next version for release by checking the + [tagged releases](https://github.com/google/GoogleUtilities/tags). + Ensure that the next release version keeps the Swift PM and CocoaPods versions in sync. +* Verify that the releasing version is the latest entry in the [CHANGELOG.md](CHANGELOG.md), + updating it if necessary. +* Update the version in the podspec to match the latest entry in the [CHANGELOG.md](CHANGELOG.md) +* Checkout the `main` branch and ensure it is up to date + ```console + git checkout main + git pull + ``` +* Add the CocoaPods tag (`{version}` will be the latest version in the [podspec](GoogleUtilities.podspec#L3)) + ```console + git tag CocoaPods-{version} + git push origin CocoaPods-{version} + ``` +* Push the podspec to the designated repo + * If this version of GoogleUtilities is intended to launch **before or with** the next Firebase release: +
+ Push to SpecsStaging + + ```console + pod repo push --skip-tests staging GoogleUtilities.podspec + ``` + + If the command fails with `Unable to find the 'staging' repo.`, add the staging repo with: + ```console + pod repo add staging git@github.com:firebase/SpecsStaging.git + ``` +
+ * Otherwise: +
+ Push to SpecsDev + + ```console + pod repo push --skip-tests dev GoogleUtilities.podspec + ``` + + If the command fails with `Unable to find the 'dev' repo.`, add the dev repo with: + ```console + pod repo add dev git@github.com:firebase/SpecsDev.git + ``` +
+* Run Firebase CI by waiting until next nightly or adding a PR that touches `Gemfile`. +* On google3, run copybara using the command below. Then, start a global TAP on the generated CL. Deflake as needed. + ```console + third_party/firebase/ios/Releases/run_copy_bara.py --directory GoogleUtilities --branch main + ``` + +## Publishing +The release process is as follows: +1. [Tag and release for Swift PM](#swift-package-manager) +2. [Publish to CocoaPods](#cocoapods) +3. [Create GitHub Release](#create-github-release) +4. [Perform post release cleanup](#post-release-cleanup) + +### Swift Package Manager + By creating and [pushing a tag](https://github.com/google/GoogleUtilities/tags) + for Swift PM, the newly tagged version will be immediately released for public use. + Given this, please verify the intended time of release for Swift PM. + * Add a version tag for Swift PM + ```console + git tag {version} + git push origin {version} + ``` + *Note: Ensure that any inflight PRs that depend on the new `GoogleUtilities` version are updated to point to the + newly tagged version rather than a checksum.* + +### CocoaPods +* Publish the newly versioned pod to CocoaPods + + It's recommended to point to the `GoogleUtilities.podspec` in `staging` to make sure the correct spec is being published. + ```console + pod trunk push ~/.cocoapods/repos/staging/GoogleUtilities/{version}/GoogleUtilities.podspec + ``` + *Note: In some cases, it may be acceptable to `pod trunk push` with the `--skip-tests` flag. Please double check with + the maintainers before doing so.* + + The pod push was successful if the above command logs: `🚀 GoogleUtilities ({version}) successfully published`. + In addition, a new commit that publishes the new version (co-authored by [CocoaPodsAtGoogle](https://github.com/CocoaPodsAtGoogle)) + should appear in the [CocoaPods specs repo](https://github.com/CocoaPods/Specs). Last, the latest version should be displayed + on [GoogleUtilities's CocoaPods page](https://cocoapods.org/pods/GoogleUtilities). + +### [Create GitHub Release](https://github.com/google/GoogleUtilities/releases/new/) + Update the [release template](https://github.com/google/GoogleUtilities/releases/new/)'s **Tag version** and **Release title** + fields with the latest version. In addition, reference the [Release Notes](./CHANGELOG.md) in the release's description. + + See [this release](https://github.com/google/GoogleUtilities/releases/edit/9.0.1) for an example. + + *Don't forget to perform the [post release cleanup](#post-release-cleanup)!* + +### Post Release Cleanup +
+ Clean up SpecsStaging + + ```console + pwd=$(pwd) + mkdir -p /tmp/release-cleanup && cd $_ + git clone git@github.com:firebase/SpecsStaging.git + cd SpecsStaging/ + git rm -rf GoogleUtilities/ + git commit -m "Post publish cleanup" + git push origin master + rm -rf /tmp/release-cleanup + cd $pwd + ``` +
+ +## Development + +To develop in this repository, ensure that you have at least the following software: + + * Xcode 12.0 (or later) + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen GoogleUtilities.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. + +### Development for Catalyst +* `pod gen GoogleUtilities.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 + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@13 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +## Contributing + +See [Contributing](CONTRIBUTING.md). + +## License + +The contents of this repository is licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions +[gh-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg diff --git a/saraWhatsUp/Pods/Headers/Private/Firebase/Firebase.h b/saraWhatsUp/Pods/Headers/Private/Firebase/Firebase.h new file mode 120000 index 0000000..07ac6eb --- /dev/null +++ b/saraWhatsUp/Pods/Headers/Private/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/CoreOnly/Sources/Firebase.h \ No newline at end of file diff --git a/saraWhatsUp/Pods/Headers/Public/Firebase/Firebase.h b/saraWhatsUp/Pods/Headers/Public/Firebase/Firebase.h new file mode 120000 index 0000000..07ac6eb --- /dev/null +++ b/saraWhatsUp/Pods/Headers/Public/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/CoreOnly/Sources/Firebase.h \ No newline at end of file diff --git a/saraWhatsUp/Pods/Manifest.lock b/saraWhatsUp/Pods/Manifest.lock new file mode 100644 index 0000000..5268fca --- /dev/null +++ b/saraWhatsUp/Pods/Manifest.lock @@ -0,0 +1,97 @@ +PODS: + - Firebase/Auth (8.9.1): + - Firebase/CoreOnly + - FirebaseAuth (~> 8.9.0) + - Firebase/CoreOnly (8.9.1): + - FirebaseCore (= 8.9.1) + - Firebase/Database (8.9.1): + - Firebase/CoreOnly + - FirebaseDatabase (~> 8.9.0) + - Firebase/Storage (8.9.1): + - Firebase/CoreOnly + - FirebaseStorage (~> 8.9.0) + - FirebaseAuth (8.9.0): + - FirebaseCore (~> 8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/Environment (~> 7.6) + - GTMSessionFetcher/Core (~> 1.5) + - FirebaseCore (8.9.1): + - FirebaseCoreDiagnostics (~> 8.0) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/Logger (~> 7.6) + - FirebaseCoreDiagnostics (8.9.0): + - GoogleDataTransport (~> 9.1) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/Logger (~> 7.6) + - nanopb (~> 2.30908.0) + - FirebaseDatabase (8.9.0): + - FirebaseCore (~> 8.0) + - leveldb-library (~> 1.22) + - FirebaseStorage (8.9.0): + - FirebaseCore (~> 8.0) + - GTMSessionFetcher/Core (~> 1.5) + - GoogleDataTransport (9.1.2): + - GoogleUtilities/Environment (~> 7.2) + - nanopb (~> 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/AppDelegateSwizzler (7.6.0): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.6.0): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.6.0): + - GoogleUtilities/Environment + - GoogleUtilities/Network (7.6.0): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.6.0)" + - GoogleUtilities/Reachability (7.6.0): + - GoogleUtilities/Logger + - GTMSessionFetcher/Core (1.7.0) + - leveldb-library (1.22.1) + - nanopb (2.30908.0): + - nanopb/decode (= 2.30908.0) + - nanopb/encode (= 2.30908.0) + - nanopb/decode (2.30908.0) + - nanopb/encode (2.30908.0) + - PromisesObjC (2.0.0) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Database + - Firebase/Storage + +SPEC REPOS: + trunk: + - Firebase + - FirebaseAuth + - FirebaseCore + - FirebaseCoreDiagnostics + - FirebaseDatabase + - FirebaseStorage + - GoogleDataTransport + - GoogleUtilities + - GTMSessionFetcher + - leveldb-library + - nanopb + - PromisesObjC + +SPEC CHECKSUMS: + Firebase: fb5114cd2bf96e2ff7bcb01d0d9a156cf5fd2f07 + FirebaseAuth: 2b78b2a32c07b3ecfa4970bdf1d3632b8304099b + FirebaseCore: c5aab092d9c4b8efea894946166b04c9d9ef0e68 + FirebaseCoreDiagnostics: 5daa63f1c1409d981a2d5007daa100b36eac6a34 + FirebaseDatabase: 2236b804cf0cac165b4620669bedf7ee643a2bcc + FirebaseStorage: 452c98c31ccb40b819764bf3039426c4388d9939 + GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 + GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 + GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91 + leveldb-library: 50c7b45cbd7bf543c81a468fe557a16ae3db8729 + nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 + +PODFILE CHECKSUM: 5f3bfdda36c381b0c15c0819471cdda47eb5b3f8 + +COCOAPODS: 1.11.2 diff --git a/saraWhatsUp/Pods/Pods.xcodeproj/project.pbxproj b/saraWhatsUp/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5467505 --- /dev/null +++ b/saraWhatsUp/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,6464 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXAggregateTarget section */ + 072CEA044D2EF26F03496D5996BBF59F /* Firebase */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 6733F52BE3660369DC2674736EE30AB5 /* Build configuration list for PBXAggregateTarget "Firebase" */; + buildPhases = ( + ); + dependencies = ( + 1FAD10F2ADDA7371BE117ED09AE8A2C2 /* PBXTargetDependency */, + 67B7F8D7F211D4673775E9B7BBDB9CFC /* PBXTargetDependency */, + 96A4979FD7D11C6142FB66F6FE62AAA0 /* PBXTargetDependency */, + 4A85BEA2E67123EF3ECBA12CB1E92C67 /* PBXTargetDependency */, + ); + name = Firebase; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 00203A52C038200C1CE201185075F72A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B3125D500C1F70AC85CA5401A1F25E6A /* Security.framework */; }; + 00441B1F2F7E37B3F539A558956EFBF5 /* FIRComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = B8B222728C3FF9B9FD14A76423A49B1B /* FIRComponent.m */; }; + 010A11BD130B792268F92AA7E735218A /* FBLPromise.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 0DCE8B190588AF201D9521AFDEC1A12A /* FBLPromise.h */; }; + 012125DA48E713D2C1699D28A8A6CC80 /* FCompoundWrite.h in Headers */ = {isa = PBXBuildFile; fileRef = FBEE29B982D54AA103A5A271D98767DA /* FCompoundWrite.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 017FC76A8CAAD3A39931B5EFAEE8F881 /* FIRStorageDeleteTask.m in Sources */ = {isa = PBXBuildFile; fileRef = C7FAFE3089E9D23C2B1DBED2289F4CBC /* FIRStorageDeleteTask.m */; }; + 01A6C557909CAE5AEBD1FA6DDA823EB8 /* GULLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 56F81CBD795E02ECA8269A503DA73162 /* GULLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 01F16003BB6BAAC985F02EF2C694D86C /* FIRStartMFAEnrollmentResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = CB1E13E7998204FCB479D758BE566FDE /* FIRStartMFAEnrollmentResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0255589F47915265239B430239BB154D /* FIRSendVerificationCodeRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C404889F379D8E72FFA595E06698BE4 /* FIRSendVerificationCodeRequest.m */; }; + 02639C151CC5091634FA1BB5BA99B8CD /* GULNetwork.m in Sources */ = {isa = PBXBuildFile; fileRef = E20C20D7FAB01BCCA3A30E6B08C36B35 /* GULNetwork.m */; }; + 0275D6BB6D8357A70D80FA88FCD4D75E /* FIRMultiFactorAssertion+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = FC00211162E51E19F5561AD38A113BEE /* FIRMultiFactorAssertion+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 027F055BC8C56B06A7F4349AF2DEBF3C /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A362684A637B06059850B849A03F1349 /* CFNetwork.framework */; }; + 032F415D2387802BB88D8D8B7E762006 /* FPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 08A8ED18BAADFDE9B7B3D9B70CFE0AEA /* FPath.m */; }; + 03A2245681DDE936EFED41C4EC4E2413 /* FirebaseCoreDiagnostics-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 30C0F0FC7817DC60672EB31C8B7064E2 /* FirebaseCoreDiagnostics-dummy.m */; }; + 03CB74334AA7FFA8BF44063D2D39EEBE /* FBLPromise+Timeout.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FA17DB98BC67108253D4D33E6EA8312 /* FBLPromise+Timeout.m */; }; + 0427C524142A2BAFD41071E205D50445 /* FIRVerifyPasswordRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 47C6C963C21CCD40BCDAED4F0971499A /* FIRVerifyPasswordRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 047D57E0721FF5ED4C3764B03F9B0032 /* env.cc in Sources */ = {isa = PBXBuildFile; fileRef = 404EFB07CB1339C320835C4EDA1ED913 /* env.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 048C7DD0F80749D50084C32B02A0DF76 /* FIRCoreDiagnosticsConnector.h in Headers */ = {isa = PBXBuildFile; fileRef = B3F239DE45C16ECA602453788681BAAE /* FIRCoreDiagnosticsConnector.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 049C8EA5F88E7C3DE6F510974196ADDF /* GULHeartbeatDateStorageUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 87AE30E463E767DF440624B241B3A6A4 /* GULHeartbeatDateStorageUserDefaults.m */; }; + 04F09B4EF37F6D607E7728C0DEC587B0 /* GDTCORTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = 0238C971BE9A0CA5EF77CBFB630D350F /* GDTCORTransport.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 06AB1E0106C4611D37E4CD64459E6374 /* FIRAuthAPNSTokenType.h in Headers */ = {isa = PBXBuildFile; fileRef = E783CB68946D7A9FD139DFCE6DCA7EFF /* FIRAuthAPNSTokenType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 06F4EA32D50A1182187E39227D41B542 /* FIRAuthTokenResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 454D3B693F062A52555CB025AF94F840 /* FIRAuthTokenResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 076C5BC197E05230BEF99B0083072439 /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E907A35C1DEDA93701504221E550A28 /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 076D9173EE944FB9E6101BB16FA6324B /* firebasecore.nanopb.h in Headers */ = {isa = PBXBuildFile; fileRef = 85DF2F3A1C45FB8F162B24BEA791AF80 /* firebasecore.nanopb.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 079AADE89F4CAB46622CA4A8A865D34A /* GTMSessionFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 70C515513B0530D479DEC11A0222821F /* GTMSessionFetcher.m */; }; + 07B1DA9DB16424D0809ADA36F48FF480 /* FIRPhoneAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = C9B8B71643A846CA2ADA132AD852A522 /* FIRPhoneAuthCredential.m */; }; + 0802D6A8E0B4C610EBAF894E8CE2ABA1 /* fbase64.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F288DCDC36134E8DCCFE23B9B0A5552 /* fbase64.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 080AC7F5EB28B130A20F6A28DDD22996 /* FIRAuthWebUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B351FCC097D07CD16092C31C2CA42839 /* FIRAuthWebUtils.m */; }; + 08115A4E09DBD7C3D86DBCED9933A036 /* FValueIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 133C88D736DA8CED133F999B0912796E /* FValueIndex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 082FE8AC51D5B3FFC3E5905BF007A8FF /* FIRConfigurationInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = CFB14EC1E12FD320A96E0F01E8E89EB2 /* FIRConfigurationInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 08675D31F229AD82CB72555D60B690F5 /* FIROptionsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AF60A6D52FE8EBEB70B6B9CC52A6B3B /* FIROptionsInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 087074B8503FF61B5BA51AC409255283 /* FSnapshotHolder.m in Sources */ = {isa = PBXBuildFile; fileRef = B271E16961C347079CB7026341CA75D0 /* FSnapshotHolder.m */; }; + 0896582AFC794FF74E50CBA0DCB78FB7 /* FIRAuthGlobalWorkQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FE6FE37825B435D47D4B08F2AD91685 /* FIRAuthGlobalWorkQueue.m */; }; + 08989AE18374AA69F9740CC95C33B373 /* FIRWithdrawMFAResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E1F13E99D5CDC9053C648E227DB5A99B /* FIRWithdrawMFAResponse.m */; }; + 08AA505683FEE5F1E61A52D3B675846F /* FIREmailLinkSignInResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 822565DDCACE4B6CBA1EB346E3375B8E /* FIREmailLinkSignInResponse.m */; }; + 08E84CEF4C496BA696F88CE29419B3E0 /* FIRHeartbeatInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FF51B5689329B949790D00975C6F5130 /* FIRHeartbeatInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 08ED6191618A3D731FCE86CCB04F97A9 /* FIRFacebookAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E1CE3EB6A65FC8FD5A092AADD594C1 /* FIRFacebookAuthCredential.m */; }; + 08FFF6697B510E557E32009456A0E0E8 /* FIRAuthDefaultUIDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = AB2EF60C16B7021A14AE4954EF2F717B /* FIRAuthDefaultUIDelegate.m */; }; + 090414BA9AFDD5A1B7170AD140FEBBFD /* FIRGetAccountInfoRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = D30116979AF35FC25111CDB0F39355B5 /* FIRGetAccountInfoRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0922964D8333D1C15A7ECEA7C6DEDADF /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = 30F697CA73EBB0310B4076303AC5B7A8 /* FIRLibrary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 095785C9F47316B92925EDF9EFE641A4 /* FIRSignUpNewUserResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 39BE74A01BE5634F38B2B443E9F408E3 /* FIRSignUpNewUserResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 096F3C656D1C98DCFEF6BD074C105C35 /* GDTCORPlatform.m in Sources */ = {isa = PBXBuildFile; fileRef = DE506671538C7408F5B08E892EA3B6B4 /* GDTCORPlatform.m */; }; + 09D63733A04735D72560A28859B32A8E /* FIRLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = A2A67198D2ECE2676C622E472F2E7450 /* FIRLogger.m */; }; + 09DD61B576FEC57FB31A52B8B0E11E37 /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = BC0887BB80201541368EB5158D171A30 /* FIRComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0A49F2C5C977CD8F4A47A05EAE2E8BF8 /* FIRPhoneMultiFactorGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = E36EDB3F233F4325954736D9BD031692 /* FIRPhoneMultiFactorGenerator.m */; }; + 0A4CD8859C6A1F2ADA7A566661F41AEB /* FUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDA8FF09D2555F381F370A0422B2983 /* FUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0A9141E06052B3C07F8083DA193FF6F2 /* version_edit.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5D877752182A2E5845173CA3BF342E8F /* version_edit.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 0AD692D6D421F7E455D2FF45326EF715 /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 53DEF33906E89381205BFC84CE2B334E /* FIRComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0AE96C77ACA19C7D020DF69A79C1293A /* FTupleTSN.h in Headers */ = {isa = PBXBuildFile; fileRef = 7642C814801983526EC7A772DD7CB903 /* FTupleTSN.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0B73B7A94F807C465D7CE32E1208D5B5 /* FIndexedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 36E0D2029C3DAB914F381E3957231419 /* FIndexedNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0BD146AFD406DAD1F05068752B709894 /* FIRStoragePath.h in Headers */ = {isa = PBXBuildFile; fileRef = B9E907CA9588C9B9F242488583AC812D /* FIRStoragePath.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0BE6F49DC5D49B5120727BC3DD4AEB77 /* FIRStorageListTask.m in Sources */ = {isa = PBXBuildFile; fileRef = F6C91B026962F7836CFEC9875EB678D7 /* FIRStorageListTask.m */; }; + 0BFDCA8A93CE5D68C3B133E904258E87 /* FAckUserWrite.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AADA268A54385BD84C98DA9A5DE30EA /* FAckUserWrite.m */; }; + 0C07FE7898CF52FE71E7B1EAF5F50FC6 /* FirebaseStorage-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = C3FDDBCAD63AD6C646361AF484324D5D /* FirebaseStorage-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0C5317CF34D88C5F27BC8A41B17D9CC4 /* FIRCoreDiagnosticsConnector.m in Sources */ = {isa = PBXBuildFile; fileRef = 625B9F40AF5A3D6B6AFD638EB4F9A610 /* FIRCoreDiagnosticsConnector.m */; }; + 0C68FA06A72B4A4E52E0A993D84FC669 /* FIRStorageMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 60A8C73A7FD90C1255E0B6EFF7A2E47C /* FIRStorageMetadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0C9E95296CE1998832C22199DCA3153C /* FIRAuthProto.h in Headers */ = {isa = PBXBuildFile; fileRef = 210D3946C544D2F83F1556FD40016B78 /* FIRAuthProto.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0CC252D2D453B1029E504E7C718AE318 /* GDTCORReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 865CD6958FFE2BBE6CAAB27A454D920E /* GDTCORReachability.m */; }; + 0CD03BBFD9C64C56B2DA1D8C4EA7FD3E /* cct.nanopb.c in Sources */ = {isa = PBXBuildFile; fileRef = 925E43A65D1F0FB87B5EFE7FC554BA86 /* cct.nanopb.c */; }; + 0CFDC69D49F64438AFA9E3E6759E5278 /* GoogleDataTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = 378C8AD124FDA4F23AECAD552687460A /* GoogleDataTransport.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0D8CAA0FBDA1CC5A9C62B14FEC88CB89 /* FIRDependency.h in Headers */ = {isa = PBXBuildFile; fileRef = 851ED6E275B5A08DA28258677A801BFA /* FIRDependency.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0DA4DA5443A4A6CD5F0CC3A16EC22146 /* GULHeartbeatDateStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 925BD1DFC24947B884372F9062E7A526 /* GULHeartbeatDateStorage.m */; }; + 0DBA0C8D5C80C009FA5BFF953DCC786F /* FIRStorageTaskSnapshot.m in Sources */ = {isa = PBXBuildFile; fileRef = DF15EFABC8CF646F9AB391F67075A420 /* FIRStorageTaskSnapshot.m */; }; + 0DCAD134935C2C1F89B399FE3A174A8F /* FIRRetryHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A08BEE1730CF35A6FC437448ABA4FE9 /* FIRRetryHelper.m */; }; + 0E0644E775491C0D19300244E7AC3930 /* GDTCORAssert.m in Sources */ = {isa = PBXBuildFile; fileRef = 331A7C3422670ECCDF077EDA8C5B0FB7 /* GDTCORAssert.m */; }; + 0E1B862378B4F1E49A1D5B9D63F0F510 /* FIRGoogleAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = E66A45FDA42DCC78AC16BE6DAEFEBD90 /* FIRGoogleAuthCredential.m */; }; + 0E3969B21A0155C85DD249CB5E7168ED /* FIRGetAccountInfoResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 34BDBD173CB4896EB12F2BD922D4F0FB /* FIRGetAccountInfoResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0E820CB9B7AB02BCC2A703F49B6A6D09 /* snapshot.h in Headers */ = {isa = PBXBuildFile; fileRef = 201E994E5AB33B9C4F084310F0262E87 /* snapshot.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0ECD56A94543C55E2324ED27A027FBEC /* FIRAuthInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B3244BB9FA3011541F121A0ED25A91F /* FIRAuthInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0EFFA97BE71ACD272028C81539AEFDB3 /* GTMSessionUploadFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = B48A5067D93FC5220DF1348412F02223 /* GTMSessionUploadFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0F2A489C428CB5919CE1C743F319FFE2 /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BEBE0B8B4A3E59166D06E1963A6E893 /* FIRLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0F42E644A4435879EE2BFFA259E74272 /* FBLPromise+Always.h in Headers */ = {isa = PBXBuildFile; fileRef = 856378CC2E53007A66BBB5C102C82AE8 /* FBLPromise+Always.h */; }; + 0F43D4A86955BDEDD38662D2D48A5F2B /* GDTCOREvent.h in Headers */ = {isa = PBXBuildFile; fileRef = FA2E91A9425BE6BC994203B17F986063 /* GDTCOREvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0F4E913099947B1E8D9D7ACCCEB82A59 /* FIRStorageDownloadTask.h in Headers */ = {isa = PBXBuildFile; fileRef = C86A046017B5D5FA14470F7B2E9392BC /* FIRStorageDownloadTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0F5FF6B726D791FB48A21F3FCF3BE75D /* FIRVerifyCustomTokenRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1610050E12683DE6BCCC39B25A37C034 /* FIRVerifyCustomTokenRequest.m */; }; + 0F9637896E08E6D4C4420DE7FCCD8172 /* FIRActionCodeSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = B83D5E64ACCD27EE28AEF71FBD036120 /* FIRActionCodeSettings.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0FA2AD301EC5C86CB80B8281864B0ADB /* FIRGitHubAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = F3554235FC742EA63269C8BB2F6568B6 /* FIRGitHubAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0FB6B58DB914156D801A025D499934C2 /* block.h in Headers */ = {isa = PBXBuildFile; fileRef = C97ED48F534DAB71C30E29D42CE0C347 /* block.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0FC5F850C688112506AF13ACF5F15C79 /* FIRGetOOBConfirmationCodeResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EC5810CCA6032CB4BD0F14A8BD60522 /* FIRGetOOBConfirmationCodeResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 107E1A5608CABF3C09F93816F8DFDA44 /* FTupleNodePath.h in Headers */ = {isa = PBXBuildFile; fileRef = 873B7FE9A7FFF50DB78D82AE2BB1692A /* FTupleNodePath.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 10D1C792F4AB82496BC9156BAC561182 /* GDTCCTUploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 37529818565A88B7EA068C0B2810EB6B /* GDTCCTUploadOperation.m */; }; + 114563114C0901A942488FAD4CAD7B00 /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 692F12FCE20BD05DF9A601125B760F1F /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 11D0C54A62BA81A431F433D9AB4917AE /* FBLPromise+Delay.h in Headers */ = {isa = PBXBuildFile; fileRef = 62B3358312776954E31DF7EED58885A5 /* FBLPromise+Delay.h */; }; + 129EE9819D846904937054067888B78B /* FIRAuthAppCredentialManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DBE09261FF79AE8E86F6A6F51D71B3AB /* FIRAuthAppCredentialManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 12E6CEEB0D6E10BA1C3E75D613609C03 /* FValueIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 21D511E9F4CC3BC909ACE2417E6EEEB7 /* FValueIndex.m */; }; + 12FA59710EA94ACF21FB4436DD95867F /* FIRCoreDiagnostics.h in Headers */ = {isa = PBXBuildFile; fileRef = 456A00DB744DF00FBD9B147C646D1639 /* FIRCoreDiagnostics.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1301C1E90A36990079C201D51E94FE5A /* GDTCORUploadBatch.m in Sources */ = {isa = PBXBuildFile; fileRef = 368E3E5C4EF9356A8DA1ECE19D07E518 /* GDTCORUploadBatch.m */; }; + 139A4F1FFA65C5B8FFD58E58137DB58F /* FIRSetAccountInfoResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = A0E6A648E4E14D6B21A0F8DF95C04F9C /* FIRSetAccountInfoResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 14004F9876E592CF3971A3FB0413585D /* FIRTransactionResult.m in Sources */ = {isa = PBXBuildFile; fileRef = CDF8AC51DB6AC1BF9C30A265F6670B60 /* FIRTransactionResult.m */; }; + 14D0F96DBEF7812AD6955EB2E7295BC1 /* FIndexedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = EC370A05FD4A8730435B4248870B1E34 /* FIndexedNode.m */; }; + 14F22A663551AB534BFEBD41D8556A1A /* env.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A1F060899EF16D3F61A63082A459A58 /* env.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 155952A152951A07D66363290E3BA9BD /* FIRGetProjectConfigResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 7133273F65616CB95FFF840F84F09E70 /* FIRGetProjectConfigResponse.m */; }; + 15A4FA93FE3F877448AB1E59E4794471 /* FIREmailLinkSignInResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 074B1506E54F170E9D971DFA65A05BAE /* FIREmailLinkSignInResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 15CE9AD5A2BDF7359CC549311CCBBB86 /* FBLPromise+Any.h in Headers */ = {isa = PBXBuildFile; fileRef = 443546F817B6B0439A3F4A59985CD4B7 /* FBLPromise+Any.h */; }; + 15E63ED85B9CDE39662B77B16B34EB8A /* logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 51F316E9BA48B7969E95F23475DAF6CE /* logging.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 162171383C10D2C1C52E01CDDEE80116 /* FIRUserMetadata_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 634E95BC4CB95F90015C87024F41037B /* FIRUserMetadata_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 162488B6E75A20B4C3DDFA9C61090D5B /* FBLPromise+Reduce.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = A5EE7C10193DBDDADE98DC3A19921624 /* FBLPromise+Reduce.h */; }; + 16579A7E550864A3D752BFC07ED5F0AB /* FIRDatabaseConnectionContextProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A438F609CFC9332E652AAE024EE6EB4 /* FIRDatabaseConnectionContextProvider.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 166A023F8E2E7D06058547066461DE60 /* FIRBundleUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 64198B298948BC8CF0170A0327736352 /* FIRBundleUtil.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 167E2ED6C3D82E1176811283BA2094F5 /* pb_common.c in Sources */ = {isa = PBXBuildFile; fileRef = D4D60F9F02A0480B7DC03CCF3A8E0078 /* pb_common.c */; settings = {COMPILER_FLAGS = "-fno-objc-arc -fno-objc-arc -fno-objc-arc"; }; }; + 1687F98BF087FCAEC83D21F776ED1D12 /* FBLPromise+Any.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 443546F817B6B0439A3F4A59985CD4B7 /* FBLPromise+Any.h */; }; + 16D8E7082DEF7B79F60863C3E0230276 /* FIRAuthDataResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E1DBC7D23830F6FD970766C7D982680 /* FIRAuthDataResult.m */; }; + 16F4CF8087DC60B0730FC5BEB0FB578E /* FIRSendVerificationCodeResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E00A4986CBE1E251A2DFE3F3701905E7 /* FIRSendVerificationCodeResponse.m */; }; + 1760A120E6269179BDE56F874468EB0B /* FIRDataSnapshot.h in Headers */ = {isa = PBXBuildFile; fileRef = 3729170399646C0750A1FF4A324422C7 /* FIRDataSnapshot.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 17CC1D21750D15D3B526CF6D8F17E291 /* pb_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 56EE34A46421CDFB2307136C2B5B76C8 /* pb_decode.c */; settings = {COMPILER_FLAGS = "-fno-objc-arc -fno-objc-arc"; }; }; + 17FABFD8F4FAB1214C0759EB0798CDD6 /* FIRStorageDeleteTask.h in Headers */ = {isa = PBXBuildFile; fileRef = E9A820561E869395EB1638CC40A12C05 /* FIRStorageDeleteTask.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1804BB9F80D4AA5447BE4694A937C92C /* FIRStorageListResult.h in Headers */ = {isa = PBXBuildFile; fileRef = ABF88EF97C5E5AAC2CA3410AF223A810 /* FIRStorageListResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 180DAF37669451AA6451AC4401C81D4E /* FIRPhoneAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = D2E8DEE67BD4C3A24D7C052314CDDAA6 /* FIRPhoneAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 182F5009696A6603F30EE00CE08F56EA /* FTupleObjects.m in Sources */ = {isa = PBXBuildFile; fileRef = 65432ABDB449B9A041385A9150D9C1F9 /* FTupleObjects.m */; }; + 18F29E47671D54D44ED42A2AFE479FC3 /* FImmutableSortedSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A27E89E002CAEE5D35D573EA0401CF0 /* FImmutableSortedSet.m */; }; + 190E2C2A181DA99098B238220E368C59 /* FWriteRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BE3361A3F0C14B7DEFD6AF4BC8765A8 /* FWriteRecord.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 191D3D7482F908A17BE973DB5B225661 /* arena.cc in Sources */ = {isa = PBXBuildFile; fileRef = D3331DD7FCAE6B40EB649D6941B9148C /* arena.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 19DAE70F41E72B60CBB195E9C44F6670 /* FIRMultiFactor.m in Sources */ = {isa = PBXBuildFile; fileRef = 7274EC13DBD95E1A1FA081BC43E5B66A /* FIRMultiFactor.m */; }; + 19E7D9479B59A26D0D12E9E19E1475B5 /* FIRAuth_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 74821EC035B4458507191FC713CFE43F /* FIRAuth_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 19F751AA15289FCBB3B7383A538BEA07 /* FChange.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CAFBE8E892174EFAEA29FCBD9318A38 /* FChange.m */; }; + 1A2BEC4B5875E4BE2425808D1D2EE0A2 /* FBLPromise+Reduce.h in Headers */ = {isa = PBXBuildFile; fileRef = A5EE7C10193DBDDADE98DC3A19921624 /* FBLPromise+Reduce.h */; }; + 1A5C03846C5719D86BCAE60F1F6A785D /* FIRFirebaseUserAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = ACE8DCECAAD1F5B7F9D2031B60201FE3 /* FIRFirebaseUserAgent.m */; }; + 1A5D812605F3B4FCE14860AC51EA5B68 /* FSnapshotHolder.h in Headers */ = {isa = PBXBuildFile; fileRef = CBBEF9A24FDDF05863D1B193EB0592AA /* FSnapshotHolder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1AA55A0C66508AB5BDFE721BF39B7CC6 /* FEventGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = F7DC7FA75B31D1254763C9DD27879B6B /* FEventGenerator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1AC831FB9A5BDDCDC53B2E6CE19CE345 /* GULNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 87B50EC0E9EE9E6ECA780B6E21840EA0 /* GULNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1B520A625131C937020B0BD49E11BC23 /* FIRGetProjectConfigRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = EFB4F1F9A60522154D72062A7EBC8106 /* FIRGetProjectConfigRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1B5335738488AC6BD3971955DA2F6568 /* FirebaseDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = DD4A6114C542A0B76FFE2CD9F298C74B /* FirebaseDatabase.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1B601DC0C23710DA8BF2CB6483E582C2 /* FEventRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DC1248939AA214A9B49EF4F744EA070 /* FEventRegistration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1B7003D24D814169EF33A559EF2C4400 /* FIRAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = F8EE5397CAFFDE0ED6DFFBECF96F4DA8 /* FIRAuthProvider.m */; }; + 1C3A93DF5071A40B5896A1442F81FDE5 /* PromisesObjC-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E5807D571718FEBFE488332153F41E0 /* PromisesObjC-dummy.m */; }; + 1C6FF185F54442D54E0F8443A58D6169 /* FIRGetAccountInfoRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = D795AE629879BC01531BB9102F646DB3 /* FIRGetAccountInfoRequest.m */; }; + 1CAD0A2C66E9A998AC818F7F4786FB8E /* bloom.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6178C9FA032D52D1A34C47D97B5C12D5 /* bloom.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 1CBDCB86FA64F4B6B9739106A0B371F0 /* FBLPromise+Then.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 64CEE3E2D4A19A53504FB2177D8059B5 /* FBLPromise+Then.h */; }; + 1D7C4CA4082EC479BF83F8C3C2C61ADD /* FRepoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E82FD5AB387A0866240CEFF8BE02C4DD /* FRepoManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1DB975BA292FF3A41E3A113F94A2D594 /* log_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 17B6C9AB660C7ED9F3CDAA1F45F4D9EC /* log_reader.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 1DC2508CFB04B32022E61560A5738481 /* FIRMultiFactorInfo+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 0786F5F9A30289D84FD9C66F9D05C9BF /* FIRMultiFactorInfo+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1DF76C978674C0A91F03CB4F0B6A189B /* FirebaseAuth-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FF417F53059E610CCEF3ABB2470DDD8 /* FirebaseAuth-dummy.m */; }; + 1E140DDC2E8894E371E778AC3120DE9A /* FTrackedQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = B4653519E5F123F81CEF7260656B7E0B /* FTrackedQuery.m */; }; + 1E17B461DE251C9B6F1FA562DC7A8458 /* FNextPushId.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D62E8B3886374A1220D5ED548497AB3 /* FNextPushId.m */; }; + 1E37AAD1C8D636541BAC26BDF5FDF902 /* FBLPromisePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 76BEE430E44B481CB97A3647B5104EE7 /* FBLPromisePrivate.h */; }; + 1E75EEE40C4C1D14AA5FFCC6543DBB28 /* FIRVerifyCustomTokenRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 201D6B608DE3FFE2C2B74490C3F4004C /* FIRVerifyCustomTokenRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1ED666F1BA37880ADD5D627FB74B0A70 /* FIRStorageUpdateMetadataTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 568CCC590C28D73A8937CC57C00DC09E /* FIRStorageUpdateMetadataTask.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1F19AD338B9B9016B92A22CB78423BF7 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 86670524310C3DA3D11768477D60665F /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.m */; }; + 1F45A8D8097D8059298F1210E5CE440B /* FIRPhoneMultiFactorInfo+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 0940FE6F9786A2811E51E5B2AE96BF6F /* FIRPhoneMultiFactorInfo+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1F84E91268E0BC381F6CA02F637C37A9 /* FCacheNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B34CAD0C7390089C50B4AECD381D8AC5 /* FCacheNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1FB4FE2D9F2F1F551798C360FAB20486 /* options.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B80F50DB73B1D0034621B3CDB16BE58 /* options.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 20892A665BEC3104E996528D3F00EA4D /* FEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = F7DF3DE181967DAF4B834E4565CE8C52 /* FEvent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 20ACFAA65648768E8A14490D7956B105 /* FTupleObjectNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 54514D86CB405814FAC52602DC28EFF2 /* FTupleObjectNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 20DE19C0C85296A461424DF0000A9012 /* FBLPromiseError.h in Headers */ = {isa = PBXBuildFile; fileRef = 49529F7D99AFC203DC55C22A66EF500E /* FBLPromiseError.h */; }; + 21436097817C9C7C2E0ED524C5C9B25E /* GTMSessionFetcherLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 94235ABB6F648EA86DBC2A05160618EA /* GTMSessionFetcherLogging.m */; }; + 21DA0ED052218D23C276E23533319493 /* db_iter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 794B727CDE156C67F0B60B8D474D20C7 /* db_iter.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 2271AECE865036AE13A3ED9736FB06E8 /* FirebaseStorage-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 30F3823B8E8D7D7EF49EF692FEC92C49 /* FirebaseStorage-dummy.m */; }; + 22BE79CE0866A7C8D0FE3673FA1F2F35 /* FIRMultiFactorAssertion.h in Headers */ = {isa = PBXBuildFile; fileRef = CDEC520DB3D5CC6139576078A00C1FCD /* FIRMultiFactorAssertion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 22F5C879CD61751CA8CABE6CB582E361 /* FTrackedQueryManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F9B99A9DE81C98F23A7956ADBB6AAA44 /* FTrackedQueryManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2302A161C2E053F44ECA86B69F579336 /* FLimitedFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = A523A418D4F79A8D9FA56B6A3EDAF69C /* FLimitedFilter.m */; }; + 23102BA0EF95DF55764B795739FD989E /* FirebaseStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D3EF6641CC688F9E7B716DA42049B1C /* FirebaseStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2325EA10FFE47768B016BC8C50E0D155 /* GDTCORUploadBatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EB166DE4F074F3497F8F11DEA37944A /* GDTCORUploadBatch.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2362318B122BBE59D1948C20815B9D8E /* FTreeSortedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = CED377BFBEA5C61B77385FC87D617E93 /* FTreeSortedDictionary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 240DE67DAA1EC1BF1CD3E45C2226FE85 /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 26E785FC337EA22790808439DD1A5CD5 /* FIRComponentType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 241EEA15A7F02455B11B817D09591753 /* FIRDeleteAccountResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 09E760765D90D676A6B6F9E9B69247F7 /* FIRDeleteAccountResponse.m */; }; + 2468760844B2A127A728022BCB13CF5E /* FIREmailPasswordAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FCE4B4A66E84892717EF5F2F0CC8516 /* FIREmailPasswordAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 24699FD4161536D8449EDBB1E26100A9 /* db_impl.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9A08E0231CF2A46E1CAADFD0BF70218E /* db_impl.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 247CC367E3F037FECC615F5CD3F8855B /* FIRFinalizeMFASignInResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACC62B04F7F295C6F38A2DD14219DAA /* FIRFinalizeMFASignInResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 24B9CAC7D15EFBB66DAC206218DC9D45 /* FIRVerifyAssertionRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 41421C071CA3739A258EC0BA5CF15BD7 /* FIRVerifyAssertionRequest.m */; }; + 24C99BF35233726D8353F4F01C5C6785 /* FCompleteChildSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 139C0CF3E0B177E20E8F3550A4DEA5DD /* FCompleteChildSource.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 25C3E2A6B7FED090018299891019A38A /* FMerge.m in Sources */ = {isa = PBXBuildFile; fileRef = 80D9586B150ABF4E1C652803A8C8420B /* FMerge.m */; }; + 25C89D35C18013A381A5B0A9635914E6 /* FIRDependency.h in Headers */ = {isa = PBXBuildFile; fileRef = FEB354FDBF724286A5645BC99EB99BAB /* FIRDependency.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 26968B09D99EE5492D2CECDE9EFD0B06 /* log_writer.h in Headers */ = {isa = PBXBuildFile; fileRef = 79882FAC0E130E92163100F2906DC9EE /* log_writer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 270CF8EAFE4DC66E0CB73B177578FEAF /* FIRAuthDataResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 7850D19620E2E98D2EA9DEBDC1D95704 /* FIRAuthDataResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 278B5061DF66CE0EDC5B36BF924494F0 /* GULReachabilityChecker+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = FC53DDB0E8B2F43E1E0596009C054FDE /* GULReachabilityChecker+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 27DC29F6794F7616897180491C1A7D1E /* FIRPhoneMultiFactorAssertion.m in Sources */ = {isa = PBXBuildFile; fileRef = 16712385BBD6EFD20F637BE0027D43BD /* FIRPhoneMultiFactorAssertion.m */; }; + 28B0C95AE52879CB167AC1435ABED7CE /* FEventEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B14F659A087AA73A15A2172FDD72057 /* FEventEmitter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2906F6A4ADBECD6C8DE3C3D7E7F90FEC /* FIRMultiFactorConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = C7583A00EFC7FC0517BD69D6D09B32E2 /* FIRMultiFactorConstants.m */; }; + 29A67806B9BFEEB878F609E756B6289A /* table_builder.cc in Sources */ = {isa = PBXBuildFile; fileRef = E0600815FC2D83CC6D9B07E29B47A629 /* table_builder.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 29A6D7D6D45DD8EAED318BB51BFBF514 /* FIRAuthKeychainServices.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A2F3C5553C76F538ABC392A606C5232 /* FIRAuthKeychainServices.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 29C91BC3C328FD3DEDF61995A58D0194 /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 5AED10E896523AA3351EAC775C0DA052 /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 29F33F50160C2150EFDA1E88B186861F /* FQueryParams.h in Headers */ = {isa = PBXBuildFile; fileRef = B2ADA563135B97021B2C1F71DF0405B8 /* FQueryParams.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2A1AD3F7D09D799885439138BE268C7F /* comparator.h in Headers */ = {isa = PBXBuildFile; fileRef = 67AC37415B5E0F60D1AB77E62E71BCE2 /* comparator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2A4371FC7470C816E2D4F27401598109 /* dbformat.cc in Sources */ = {isa = PBXBuildFile; fileRef = DB475D8D0ED92EA291952E540077A838 /* dbformat.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 2A7228197434FA6CA7FFE183C763F8D2 /* log_format.h in Headers */ = {isa = PBXBuildFile; fileRef = 6737C17420EC2B9B78FD01C46864F7D7 /* log_format.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2A72AC548CBABC42B601AFB8BC4163CB /* FBLPromise+Always.m in Sources */ = {isa = PBXBuildFile; fileRef = 872149127BBFF2A884E7375618BF435F /* FBLPromise+Always.m */; }; + 2A9C04A41EA0F108D58E5458A8EDD7D8 /* FIRSignInWithGameCenterRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B90799188BF45540C038E6AD9774A36 /* FIRSignInWithGameCenterRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2B00B63E31CE509578C64831FA9ECC06 /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A46A292823A650C8E22CF1315EB369A /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 2B988C83446ACDC57A51250BC631168A /* FBLPromises.h in Headers */ = {isa = PBXBuildFile; fileRef = C0D982FA616BAFDFC5F2ADA6D865ACEE /* FBLPromises.h */; }; + 2BA5FA4D6D55E436E5B0C3455DD44316 /* FLLRBNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 39411F7390CCE0DB18B3C0435CA92BB0 /* FLLRBNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2C41315DBB9CE0D68B3AB4317D260D89 /* fbase64.c in Sources */ = {isa = PBXBuildFile; fileRef = 34065017EC1BF5B0A3A4A05A2FF0D861 /* fbase64.c */; }; + 2C4D1F5D50253C77429C2C5B0D6334D7 /* FIRAuthStoredUserManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 44DB219B5956C07D686FB110044AB975 /* FIRAuthStoredUserManager.m */; }; + 2D03E5F83ED6B8D5C86FD2D21A1C16D1 /* FIRCoreDiagnosticsInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E7CDABFB608D65FEE43A17EB8C75B0A /* FIRCoreDiagnosticsInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2D3BF3C7FB1A02253E78885F5674579D /* Pods-saraWhatsUp-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F05777D1035F3FD490D2B67C497F1D7 /* Pods-saraWhatsUp-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2D4526FBB219EF8BD8E3B044466EF591 /* FRepo.m in Sources */ = {isa = PBXBuildFile; fileRef = FADB445B0D83108D24457A1573E4CA4A /* FRepo.m */; }; + 2D5C78721BB459B078D801294DBE11D6 /* FIRAuthSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = FD493E804D720708FC542BCC08CBEB35 /* FIRAuthSettings.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2D9BA8A0B076740932B7B96CA7CD915C /* FIRUser.h in Headers */ = {isa = PBXBuildFile; fileRef = A28C5B0EEC2339F327C24C1DEED5DF14 /* FIRUser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2DB5CA3709377942B66D88362231A3EB /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = CB962D67899B3AA299F65B98309061FB /* FIRLibrary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2EB68F33E95F742138F9AFD04747CCE9 /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F8C1112535F34E3B6D933899281A7C /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2ED628469B135D0219D5AF2C53461CD4 /* FNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FAD94001809AEFE8281F5B87506A581 /* FNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2F09B0729F8F48F217140937F1363954 /* GDTCORLifecycle.m in Sources */ = {isa = PBXBuildFile; fileRef = FC8A2FC61EA1CF1F1CE6168D12AD5BC2 /* GDTCORLifecycle.m */; }; + 2F97631700959223AE6EBFD09AB344EB /* FIRApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 286D39398D1A765422E97AAAFD146BDB /* FIRApp.m */; }; + 2FE42BEEB04A6D0628AA86B43DEEE61C /* FIRCreateAuthURIRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CD4ED2472BA0526FFE6C73D576523AE /* FIRCreateAuthURIRequest.m */; }; + 2FE86192CEBBD515E8F2056A59879A82 /* FIRSecureTokenResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 21C565281E8122CD546FCFA1BF68DBA0 /* FIRSecureTokenResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3011994272318F5D1752BE484A812CE4 /* coding.cc in Sources */ = {isa = PBXBuildFile; fileRef = D75A71D6B0932410BBBF7B7C7ED86CF9 /* coding.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 30BEC42B24D859F5B892955C63165FEE /* GDTCCTUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = 9984587BC159E07ADBA1CBAFAF7A0DC4 /* GDTCCTUploader.m */; }; + 30F7C9B2C72A1411739797FF218E86E6 /* GDTCOREventDataObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F9B40A1541FA2FB2FD430EC3320EA58 /* GDTCOREventDataObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3105ECCF3D4F52E7930D9A34EAB09E4F /* FIRStorageLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = F1389AE7281393EE724613BC5D251B38 /* FIRStorageLogger.m */; }; + 311B84FEC2C6165AF25B7B772BE18338 /* table_cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63E1D53A4B14B4142DC4D4E2EBE46EF3 /* table_cache.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 31A7FFE377DB1B87E886B331C6855DF6 /* FBLPromises.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = C0D982FA616BAFDFC5F2ADA6D865ACEE /* FBLPromises.h */; }; + 31F957DC519496854853B6F5A8C55885 /* FBLPromise+Do.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 5AC2B509956CCDD9C8BED734854FE77A /* FBLPromise+Do.h */; }; + 31FCC6057730A3324E31FE25673F5258 /* FEmptyNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B1905F81A71DDC3422570810765B92E4 /* FEmptyNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 31FF175ECC67FEA8FFE92EF5DE720495 /* GTMSessionFetcher-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = C41052FC02AEECA1AEEB044D099DF29E /* GTMSessionFetcher-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 324EDD65C041C1AE8D1A84ECF3C291BC /* FIRAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A4EA889B8F6E87EFD595D77588F34C /* FIRAuthCredential.m */; }; + 32AE0A7150E1CA915BFE3D0EB4D5D582 /* FIRStartMFAEnrollmentResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = F7106C22A1E65102E4973A1912985F17 /* FIRStartMFAEnrollmentResponse.m */; }; + 32B7A27422654270432FC648B965BF39 /* FIRVerifyCustomTokenResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A148D6148ECB9DE570FBC7207973EB8 /* FIRVerifyCustomTokenResponse.m */; }; + 32BCBC79AA92404253EE80219E3A4AD4 /* FIREmailLinkSignInRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 855AA4953460F88C0D00DB72B639F3BD /* FIREmailLinkSignInRequest.m */; }; + 32F644C584A752ED539E3187B40985F0 /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = A2B257ECEC088990E9CDCDBCB30CC867 /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 33094CF89EBEA0CFE4E55E5E714A2A31 /* FIRStartMFASignInResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 2075D1CE05FA37BC5327F25CBE420441 /* FIRStartMFASignInResponse.m */; }; + 330F4E68C30A3B7FBE048A09D3193376 /* FIRStorageUploadTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 4933D04D038FAE70992539991986C709 /* FIRStorageUploadTask.m */; }; + 33162FD30D3F82CBC9D92371B09B0ACA /* FIRDataSnapshot_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DC38D0C9D92FB77059573CB698BE8E0D /* FIRDataSnapshot_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3372B0AA899112C0E54EA42D202A35E9 /* FDataEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CFA82C57837B7BB75C48CEDB9A28159 /* FDataEvent.m */; }; + 3377C22543E182655A05B7614263CC08 /* two_level_iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CD4886842838E480318693C78559A41 /* two_level_iterator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 337E024887E032C72637550A413CC012 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A978F386557998E5D34EB6BB8A499A13 /* SystemConfiguration.framework */; }; + 33EA40A4CEA003C0F73E7BD267135FD4 /* FNamedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 197C1470CE81C5D575279D2F7040971D /* FNamedNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 34773FD7E47A7A26FAA8F6EA4F577F7C /* FIRMultiFactorSession.m in Sources */ = {isa = PBXBuildFile; fileRef = D93608706A00D31B0997B306A4075DC8 /* FIRMultiFactorSession.m */; }; + 3480AED45250B4E730F013DA855C2EA0 /* GDTCORStorageEventSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = F15CFAD5BAA65469E2657BD24D8EFA9F /* GDTCORStorageEventSelector.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 34B5550B70CEAC67308C32D9271B51E2 /* FIREmailPasswordAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 4243357DACC2D3FCD431CCAB131AA063 /* FIREmailPasswordAuthCredential.m */; }; + 34C1AF702FA358ED3D006277A9312B95 /* FIRPhoneMultiFactorAssertion+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BC31B25EBCB529134F8A560ECCD3E6B /* FIRPhoneMultiFactorAssertion+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 355BF6E13C02002EC27761C3B789826B /* GULURLSessionDataResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 15FC3AC6278487A52B2F5A7FEEF30FAC /* GULURLSessionDataResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3570758C30D862D40FB420A986C9939E /* FMaxNode.m in Sources */ = {isa = PBXBuildFile; fileRef = AD619B86153088B111D40A2840C799F4 /* FMaxNode.m */; }; + 359C4AFAB4CB12A50BD17CD32F0B702F /* FRepoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 208565AD245BDE529154ACE5F559D5AB /* FRepoManager.m */; }; + 35C9EAA14ED0932DEA18768DE71266B1 /* iterator.cc in Sources */ = {isa = PBXBuildFile; fileRef = A1BFD9AE542728E653ADC18E3BB48638 /* iterator.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 3618F3039E3260EC1C7FA0D3695B4364 /* FSnapshotUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0391475D50E27C2921D0D820540DBF77 /* FSnapshotUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 361D8F8960D2F7B33B83FE77BF44FE75 /* FValueEventRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = 53BCB33DFFBC9068A6596EBFC554C15B /* FValueEventRegistration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 36282A5956905D74BBAB02782A494B07 /* FIRTwitterAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = C0A5DA5FFD9B0E3136640EFCA7795031 /* FIRTwitterAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 36672556635EB9CE0D1161CAE8DC1BE0 /* FImmutableSortedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 056885DA57DFF38866F1836927203DB2 /* FImmutableSortedDictionary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 36871998D4FD1B26426B968CC19E4641 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 83EADD4A625C351937A0DE2CD57B8951 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.m */; }; + 36D6F986C259D0296744DCDBEC4B6C52 /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = C0D33B98DFBE8B633825E3A7B7AD1632 /* FIRLibrary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 36F1762E563636B7ABE981D0662A7B44 /* FIRCoreDiagnosticsConnector.h in Headers */ = {isa = PBXBuildFile; fileRef = B89A3C3BE57CFAFD85B24D321FD6BF7C /* FIRCoreDiagnosticsConnector.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 36F62E55B71C819BDCC44B7D5FD22B6B /* FIRAuthTokenResult.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F96448F361676D974EF9A55C032F1F /* FIRAuthTokenResult.m */; }; + 37839D72126B75880996A624A52EA48A /* posix_logger.h in Headers */ = {isa = PBXBuildFile; fileRef = F8639C05F1651B89D57F11600A798BAA /* posix_logger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 37BA637B794968750B48D22ACC59091C /* GULMutableDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 159393C33349F60D4E04328017F2B565 /* GULMutableDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 37DAA639FA4FAADA09F7970A7FE66248 /* FIRVerifyCustomTokenResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 315FFAA5751909C6D0C74C10F003C319 /* FIRVerifyCustomTokenResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 37DF2AD96AB9BD9518253AC14700DE1F /* FIRAuthErrorUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2749E81E39B3205D93B88A62A6C4B8AA /* FIRAuthErrorUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 37F80B7AC810422C50AE42F80AE285A7 /* status.cc in Sources */ = {isa = PBXBuildFile; fileRef = 06026367C0383ADE30C5100DC880F6FD /* status.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 380DC670ED5FB081A38FF031692D9BCF /* FChange.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EB924A201604AACBB961E583E190D7A /* FChange.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 39655CFB325519B069E4F520C4918852 /* FLLRBValueNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 77F60AEC184F86B601A6887F1210545B /* FLLRBValueNode.m */; }; + 39B928D2B64C00E7E11A020C6F1DAAFD /* FImmutableTree.h in Headers */ = {isa = PBXBuildFile; fileRef = B6B8C36C9A9595FB83246E705A636C10 /* FImmutableTree.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 39C00A2F5368CE4CE4885C727A2349A5 /* FIRAuthOperationType.h in Headers */ = {isa = PBXBuildFile; fileRef = 51605F4C50CB89A5269DD361E6A5009E /* FIRAuthOperationType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 39C69069F1CB85D187824BBD7E4E4841 /* FIRAuthProtoStartMFAPhoneRequestInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E633C1B4BD6DAA2E6890291D5FEF70A /* FIRAuthProtoStartMFAPhoneRequestInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 39D906658BA6F799F716F3E6FD18F15A /* FIRAuthInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = E4CAFFC2083A3EA3A2BD75F28233A4D2 /* FIRAuthInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 39EDFA71AA87C5ED0804701D77887585 /* FIRStorageListTask.h in Headers */ = {isa = PBXBuildFile; fileRef = E9ABCEAE642F047E5F947C694A613C72 /* FIRStorageListTask.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 39F7BE218E2CFCE951F5A0E4B3B8DE7A /* FIRSetAccountInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 88F1093AF881820A5E667EC0F12F47EF /* FIRSetAccountInfoResponse.m */; }; + 3A2F0C67E9233CC78F946499B0A8A217 /* FTupleUserCallback.m in Sources */ = {isa = PBXBuildFile; fileRef = 05A833BF83229902996FDD783BD650CC /* FTupleUserCallback.m */; }; + 3A7EA8BC8F1611EF962D29F330ABB5A3 /* FBLPromise+Race.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 1A49AC9D79084068C17D46C29FA998AA /* FBLPromise+Race.h */; }; + 3AA7566EEC0DC99AA661AC7BFB5BF31A /* GTMSessionFetcherService.m in Sources */ = {isa = PBXBuildFile; fileRef = ACD4A4491817F56E21D0F68271612C7D /* GTMSessionFetcherService.m */; }; + 3B7C49B121C9879013EB6BED44F3B1A3 /* FBLPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 0DCE8B190588AF201D9521AFDEC1A12A /* FBLPromise.h */; }; + 3B9841EBFA524494AF3C7CCD7300825D /* FIRDiagnosticsData.m in Sources */ = {isa = PBXBuildFile; fileRef = 8090F51A62764AFD707E8DC587EFBD37 /* FIRDiagnosticsData.m */; }; + 3BB69CF0EAD9B2F0119D6E159D3C9976 /* FIRGetOOBConfirmationCodeResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F43048B9E301D69301AEBFC0D7CA811 /* FIRGetOOBConfirmationCodeResponse.m */; }; + 3C1A098456FE8892D2AB50774E7378D3 /* GoogleUtilities-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DAE27593E4EA4BA28B1EFE6B4235D25 /* GoogleUtilities-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3C5CC104B3D20A2AFF430228DF095FA8 /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DD5351F61E4051917ECC0C45DF0E5F8D /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3C989AB29293B1AE39987F7B10D50C12 /* FOperationSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B4CAA944EC31C6A4379E65C073335EF /* FOperationSource.m */; }; + 3CB5719F46E10DEE2058AD808BE6D9B1 /* FPendingPut.m in Sources */ = {isa = PBXBuildFile; fileRef = 5893F46AF93CDDCFE5279B6FCCF0030A /* FPendingPut.m */; }; + 3DB07976E0E7822B1F0E0F64847F30A9 /* GDTCOREndpoints_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DF67656B1014EB5D0F8C31628A0F8D40 /* GDTCOREndpoints_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3E6B4D3C66796EB7765B8C1E8DB4E5B9 /* FIRDatabaseComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 4881E794C59369CE1B4F97ED9D5EE21E /* FIRDatabaseComponent.m */; }; + 3E9658324B66B119A40D7851B6F1BB3A /* FAtomicNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 74CB9232E11BC701A20AA685EB0A9152 /* FAtomicNumber.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3EDE237CF1424F8E7221DD100E531D05 /* FIRGetProjectConfigRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1E3CB165C3CBF81DF3C343B01BF719 /* FIRGetProjectConfigRequest.m */; }; + 3F19D09BDB49AB424E546489835ECDAB /* FSyncPoint.m in Sources */ = {isa = PBXBuildFile; fileRef = D3342AFD54F753153E244BABE9B38DFF /* FSyncPoint.m */; }; + 3F8CF7CBEF48B8FFA875E0EC4A521C6C /* FIRVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B7B7C27019F0E6D7ED6C457C4FEFCB5 /* FIRVersion.m */; }; + 3FC92D4827CF604044CBC62286BAC7AC /* FIRUserInfoImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = B792817C5B5886C0147589470D6CCB0B /* FIRUserInfoImpl.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4002B79502F640837CF88CA9C61F2BA8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + 4035F77D3A22F98815F808BEA74B2D0A /* GULReachabilityChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = FC4DA8C6D73E78C03EED1C783C61202E /* GULReachabilityChecker.m */; }; + 404163498D0820368DEA729341FA7C11 /* FCancelEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 7082914B8A3D20F7FA5BB89F2ABA8DB2 /* FCancelEvent.m */; }; + 40AF4F48135996792818E09341F587F2 /* FPersistenceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AB906146CF850CAF5331097EACEF462C /* FPersistenceManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4133B75C944C9093CE765E9C6A827FA1 /* FIRMultiFactor.h in Headers */ = {isa = PBXBuildFile; fileRef = C0924D6996644371910F4B789323F05F /* FIRMultiFactor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 41581AA344EA604C1A6E05A66770AB34 /* filename.cc in Sources */ = {isa = PBXBuildFile; fileRef = 80CDF9EB8D8F9AC9F7C8BF0A0F2D50B3 /* filename.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 4160033A7F659B11F088A28FF13EBD23 /* FRepo_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = B827A66AEACAE0FAE2795D9338925F12 /* FRepo_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 41B04D6909FEB1A696ABF27698BCF6F5 /* FIRUser.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE24A706CEBF7649A1C7B1E338AA52C /* FIRUser.m */; }; + 41EA43D95F45177AA1BC1AEEE89C81B5 /* FWriteTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CC5392A5C437F2EB22C9AEEE9E80264 /* FWriteTree.m */; }; + 41F0F520F05EDA9798A6D7ED82DB697D /* FView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F1E284083A40C9553A9E065850B8A1C /* FView.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 41FA6A18DB6685F8A2E288D3E5510C47 /* FServerValues.m in Sources */ = {isa = PBXBuildFile; fileRef = C9B9793C13F569DADCC8C8F0E04F16A5 /* FServerValues.m */; }; + 4203BCA824BCE9A3942DFC20304EC053 /* FIRSignUpNewUserRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2003FCD7C349868CB3AAB8389B0A816A /* FIRSignUpNewUserRequest.m */; }; + 42543BA65C0125AEC372C1C0C6FAE1CE /* table_cache.h in Headers */ = {isa = PBXBuildFile; fileRef = EA254A1DD38BCE10EC20E3DEB1B9E69F /* table_cache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 42D688F55A84AD8DEE4773BC15B5EE61 /* FIRAuthWebUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E55AF603E677DAB13AAF1DECCB0780A /* FIRAuthWebUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4319E26000B6345DA43EC87429391531 /* FirebaseAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = 59E834E72180D1D0389618CEE6D091AD /* FirebaseAuth.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 434E2B0D588A666BACCB686DEA2B41DD /* FIRDatabaseConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 4465D325944B7C664432A0C8703A429D /* FIRDatabaseConfig.m */; }; + 437548A50764EA3E328987360A34E839 /* GDTCOREndpoints.h in Headers */ = {isa = PBXBuildFile; fileRef = 8016DF8549B631F0298ACC705E2FEB07 /* GDTCOREndpoints.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43A30D94083E44E1F1C93C359017E2C8 /* GTMSessionUploadFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B1977B027A730291BFC8865A04CCC89 /* GTMSessionUploadFetcher.m */; }; + 444108C4CCFCEC6AA785F6380E31FB80 /* FOperationSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E92455A3DBBF14B5F80114EDBC5BF3 /* FOperationSource.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 44427C44D0B0466B7059B032C914F33E /* FIRConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 0063F6261147793EDA01C98F131EE381 /* FIRConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 44600199E64B23381555EEADAEBA6296 /* FIRStorageGetMetadataTask.h in Headers */ = {isa = PBXBuildFile; fileRef = BC69DBAD903AA8D81D0899406634F740 /* FIRStorageGetMetadataTask.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 449952E83715CFC4D0A7E4947C2856E2 /* FIRDeleteAccountResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA1C279CD7AB01391FC73FF502E99AD /* FIRDeleteAccountResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 44B9E396D8F40BDDD0BF3A8B07491D59 /* FIRAuthWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BD613FA63F113B835232228E5415A586 /* FIRAuthWebViewController.m */; }; + 44D331D1753DE918C661FE61E69B50DF /* FIRVerifyClientResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = B6FFCD446AFFF8D411EFD5BBB944A1BE /* FIRVerifyClientResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 459FFE1AC91BBE48BA56F12747343557 /* FAckUserWrite.h in Headers */ = {isa = PBXBuildFile; fileRef = CC269863983FDEAD924D5FBE3FD87236 /* FAckUserWrite.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 45C12B64C2E4BB5400AF0F137DB6D127 /* GDTCORAssert.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B631A61906DC5D2C67D668AC690D0F0 /* GDTCORAssert.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4690F1FED12CEC922DDB6BE8EBF6A73B /* FIRServerValue.m in Sources */ = {isa = PBXBuildFile; fileRef = D30D1AD3D4C298E46ACC5D9738D366E7 /* FIRServerValue.m */; }; + 46F87315A3677964D8B9C2DA2CE41CFA /* FCompoundWrite.m in Sources */ = {isa = PBXBuildFile; fileRef = BE74BCE8877C97E09DCE08D7221FFDFD /* FCompoundWrite.m */; }; + 4712C4518C8F4EA3B14A783D24E60F96 /* table.cc in Sources */ = {isa = PBXBuildFile; fileRef = C999B82DC40782937B995EB4447F67C1 /* table.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 477FF7E782971D6C63093C2C8AF03367 /* GDTCORReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 01770DBB442B8AC1A2AA89A8B06AE1CD /* GDTCORReachability.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 478BE3B492B4F334DA5B0AAF7580BD96 /* FBLPromise+Delay.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7E408A6A285E49DF1591FCF1591362 /* FBLPromise+Delay.m */; }; + 47C62EEB8B69C5CD508E366A67CF2729 /* FIRPhoneAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 28DDBFE577910A14716DE2BB33652A6C /* FIRPhoneAuthProvider.m */; }; + 47D4A624F2376E4D984804510C5851FE /* FIRTwitterAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 253DAA1F6C666E88A854BEA3ADC06CBE /* FIRTwitterAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 47E7B25D201A7C6C56A87415B725A5D2 /* format.h in Headers */ = {isa = PBXBuildFile; fileRef = A694F59813CCC4BC2AC445313784F0F2 /* format.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 48221D69CE4E8000F85D00E3555E0BE8 /* GULReachabilityMessageCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B6ED693CFD0B6CC4D958CF81650ED80 /* GULReachabilityMessageCode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 48A8A0B879F894F4F893891CA84BCCAF /* GDTCORRegistrar_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C54003B69296239A18EDF3744A8DF41 /* GDTCORRegistrar_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4932F067F6F168B31D602D275969A184 /* FQueryParams.m in Sources */ = {isa = PBXBuildFile; fileRef = D96ED13249834AE23DF273A121C5C859 /* FQueryParams.m */; }; + 494D189EC4E6A6A063946C0D4AE7F1B0 /* FIROptionsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B9CBE9C4D930B497C1A0FF04203D438 /* FIROptionsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 49A49F4A2C0E68AF62BC963531922CF9 /* FIRAuthSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 736E2A05989CEB2E4B585E5C7E684F45 /* FIRAuthSettings.m */; }; + 49F4E17FC3D3F69C33BBBB101A94D69A /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 507EA49345E185C0EF9E6311E5748B3F /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4ADAC66A365D665F495CD73CD98D3C36 /* FChildChangeAccumulator.h in Headers */ = {isa = PBXBuildFile; fileRef = 63B3501F8CDAFD84E1E6CFBDF3AB5A1A /* FChildChangeAccumulator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4AEBC6ECFAE24CF92AA8FFA5E34FEF6A /* FTupleObjectNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C8A2339EA1A42BEC98EB1E8282BC101 /* FTupleObjectNode.m */; }; + 4B2DAC9546BCDCD5FF1BE8A47C6DAC8D /* FBLPromise+Reduce.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B7777FBCD8B1C6CFD56B64CACAFF882 /* FBLPromise+Reduce.m */; }; + 4B2DFE5E5C7FFC7A7B9BA57C82DC0171 /* FPendingPut.h in Headers */ = {isa = PBXBuildFile; fileRef = D05CC9584CA83D98144C21E350DFBE48 /* FPendingPut.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4B9FB8FD9006135B9F1847CD1F274058 /* FIRSignInWithGameCenterResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 113B2DB0C57859DE9BA3B3D6280DF261 /* FIRSignInWithGameCenterResponse.m */; }; + 4BDC5BEB880CB70824A5BF415D1B4AE7 /* format.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB5E508280625F1411B9EFB92FE8198F /* format.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 4C3A2D99DF80874FAF4E3A656D44851D /* GDTCORFlatFileStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DA865334FCBB6542CCD3A0506BFD36A /* GDTCORFlatFileStorage.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4C782F3642F126D0A2A58466B9F08F4D /* cache.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C28C18AE3A3486767C01ED576BFB6E2 /* cache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C995A985CAA266B79E5646A9B83C408 /* FIRFacebookAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BBBA5BA7566D21A1AA9929A5E96F5D8 /* FIRFacebookAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4CBFCFFCE73FE33BF2793C9FFBE698A4 /* FIRDatabaseConfig_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0421C48DDFB0098D497DCD3542BB99DA /* FIRDatabaseConfig_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4CF229992D5C19643BEC8E2B10DB0F3F /* FIRCoreDiagnosticsConnector.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BD5FF574F7F2B568DF85ED53271EC97 /* FIRCoreDiagnosticsConnector.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4D187759F8D1ADDF7083B4B6AA242641 /* GTMSessionFetcherLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F8EDD5168E6EE7045D53755BA6ACE3B /* GTMSessionFetcherLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4D419E2528582F83F93AAEDD8DA82CF7 /* FIRAuthDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BDFC31F2515C00C3EF1D1C333356F6C /* FIRAuthDispatcher.m */; }; + 4D4C74A2E9E4C5B50A98AE5C94D70D58 /* FIRSecureTokenRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B90DF6FA77A19EB3BAD0E1750EA2D94 /* FIRSecureTokenRequest.m */; }; + 4DCB33A7DB6E96D4866ED2B2646B91CD /* log_reader.h in Headers */ = {isa = PBXBuildFile; fileRef = C00C0C9FE788D4BEAEE1CD97C5B7CA54 /* log_reader.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4E3A26D6ED2332B474474099F7E27EF6 /* FIRMultiFactorSession+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 33B69E4645D853E9D3C1AE7C7736CA58 /* FIRMultiFactorSession+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4E8471B03FB2B976EAEE1A0FA58E27F5 /* FIRAuthProtoStartMFAPhoneRequestInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = D83CA594DD91D43406561F75B2FF9BAF /* FIRAuthProtoStartMFAPhoneRequestInfo.m */; }; + 4EB0800AA06AAD774619AF4B6E6F3393 /* FCompoundHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E4E4F4AC0B704BEE2F5186BA1744611 /* FCompoundHash.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4F27AA54C609AD6FABA4A5FC12BBBC25 /* FWriteTreeRef.h in Headers */ = {isa = PBXBuildFile; fileRef = DFEB773E723D577BD5E2FCEEA9EF8BBC /* FWriteTreeRef.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4F376635FBD32FE1FDE8E645219D64DD /* GDTCORConsoleLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E327D29008B38CAD50251DFE43B0910 /* GDTCORConsoleLogger.m */; }; + 4F77FB5B9F98A2AC10EAB9C0D47CF062 /* FIRDependency.h in Headers */ = {isa = PBXBuildFile; fileRef = 4225BD34B5EB613DF261A853B2DE3A60 /* FIRDependency.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 502A1FD7AF817552FE2D5C8353DBF016 /* FIRTransactionResult_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 18459382C69E8CE80FF371CDA0344FE1 /* FIRTransactionResult_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 508A180F40CFD02AE17D220BDFDCD08D /* FBLPromise+Retry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD222A708C236933A0C9863252657F2 /* FBLPromise+Retry.h */; }; + 50A19B7DD718B38490B672612AFF3372 /* FTrackedQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = DD69A621B862C551477417091A95F91C /* FTrackedQuery.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 514DC3B501DCAB3718AEFA9542482B47 /* GULURLSessionDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F749420BEE22809423074866B4C77F2 /* GULURLSessionDataResponse.m */; }; + 518F84055CAD670D7120F5B79849A576 /* FIRAuthStoredUserManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 90A27BDCA5211C8EC45EA81FBF65E552 /* FIRAuthStoredUserManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 51D758558CFDE52A847FB8E00A855F79 /* FIRVerifyPasswordRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = C379D2DA2D639963933E2B6BD2FBF6D1 /* FIRVerifyPasswordRequest.m */; }; + 527C5C9A44B32B8644E964996742D7D2 /* GDTCORUploadCoordinator.m in Sources */ = {isa = PBXBuildFile; fileRef = AF73E4F33B65F69FB06DB662B11DE607 /* GDTCORUploadCoordinator.m */; }; + 528453DA9A9FA271085D4FC82DD3F870 /* FIRDatabaseConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 74F3BD0F4A31AD80E7C2313A180504CC /* FIRDatabaseConfig.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 52E0327EF9892E5401A79C084C0F15CA /* FIRGoogleAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 056C7AA7E700ABF039F5DB1D2E516E59 /* FIRGoogleAuthProvider.m */; }; + 5352601D1BA065C5DF9C6448EC197595 /* FBLPromise+Wrap.m in Sources */ = {isa = PBXBuildFile; fileRef = E25806EF4D31B0F9738F7B89249DE5D0 /* FBLPromise+Wrap.m */; }; + 53537A7686F5394BFE5F75761DCEBCB2 /* FBLPromise+All.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = BF7B94731C7027BE19E68D31F0CDEBEA /* FBLPromise+All.h */; }; + 541E5DC7C13CF8E8D896D2716203FCA6 /* FIRStorageObservableTask.h in Headers */ = {isa = PBXBuildFile; fileRef = FAA49E2FDC1193C1C227B4B4A414812E /* FIRStorageObservableTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 543F33C26FF8B3B22D1EBA874B7B8D15 /* FWebSocketConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = D84A34181EF2D407DFCDDACAA34AEB56 /* FWebSocketConnection.m */; }; + 5459DE085ED7C4A66DB23115757E2A9E /* FIRAuthInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E18993DAD8C46A4A4E3A64FF7677CC5 /* FIRAuthInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 547C7A4FBAF369AA9F54C479836FDE25 /* FRangeMerge.h in Headers */ = {isa = PBXBuildFile; fileRef = 08349AC39718E09B5546C61A59E2FDB6 /* FRangeMerge.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 54E53FF8B3F78D30C731D56DC7FD86B9 /* pb.h in Headers */ = {isa = PBXBuildFile; fileRef = 332156AC66B8A5BE893815856DA94D3C /* pb.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5501A1D079AA938AB2D3B1120B519F0D /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 291B38DFC54C1CE23A2902F96EEB66D7 /* FIRLogger.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 5529BE079D4B59388ED9AC5471DC5D96 /* FTreeNode.h in Headers */ = {isa = PBXBuildFile; fileRef = EC324A417D58FDC1DA10C0B10DD50D40 /* FTreeNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 553439CF8D1DA0324EEFB78B3DCD2D3F /* FTupleUserCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = A10858F9FD018F9DF1B20B62C3C26C77 /* FTupleUserCallback.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 555190201D020AD45D745A0A3E088714 /* leveldb-library-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = E034F1CE93125D1722311B3DE473783A /* leveldb-library-dummy.m */; }; + 555C4E07D98A783FB5980901900350FC /* FLimitedFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 49144B923E72023870AA11B1320F1F4D /* FLimitedFilter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5594EB3D40CA11ACC2260C04E09A57F5 /* log_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 971E8724264AB745B9E5A5BCF8718493 /* log_writer.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 55A4789FB986581A2FEA0BFBF275A352 /* FIRDiagnosticsData.h in Headers */ = {isa = PBXBuildFile; fileRef = 462FEA23E29047E8A7CA6843CA61F009 /* FIRDiagnosticsData.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5608A77DEA4AD864171308E65D3DE826 /* FPruneForest.h in Headers */ = {isa = PBXBuildFile; fileRef = 1235ADB2B49B751EFEAF8A7A2CC2C36F /* FPruneForest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 561DDF8E056C94C867FEA95C1C5FD196 /* pb_decode.h in Headers */ = {isa = PBXBuildFile; fileRef = AEFAC1E7E8D13CF3F8C80D787FC8EA68 /* pb_decode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 56220FCC40302B7D54214F0E8871880B /* FIRStorageGetMetadataTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F3CD1B9DAD528B29819D6C23F49BDD7 /* FIRStorageGetMetadataTask.m */; }; + 56724F131CDCE6B877F2CC89195FD352 /* GULNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = A7164E84783F2E49EAEC72DB3D512690 /* GULNSData+zlib.m */; }; + 56EC819E759B8E5CD45AC0897CD0817F /* GDTCORUploader.h in Headers */ = {isa = PBXBuildFile; fileRef = 845238B4F985C6B229BBD312689D4F16 /* GDTCORUploader.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 573B7B99F444E3A73999FC84FC79440D /* FListenComplete.h in Headers */ = {isa = PBXBuildFile; fileRef = 95EF2C77F4AF7EEB9D7C7F24A0662678 /* FListenComplete.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 575446EDA5833B9BFB7996F3450101CD /* FChildChangeAccumulator.m in Sources */ = {isa = PBXBuildFile; fileRef = 0653C3E0475AAA695FF29332FB69418C /* FChildChangeAccumulator.m */; }; + 580464CFB9172044A7B5FECE112921F4 /* FRepoInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = D51CE1651DCD28277901923BB6345C4B /* FRepoInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5821A1ED0B68A385E3C1E907E69D4BB0 /* FTupleStringNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 42DDF78AE884D504E56DD3D1843DD15F /* FTupleStringNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 583954BFD701D58D6A1B93FE23089483 /* FBLPromise+All.h in Headers */ = {isa = PBXBuildFile; fileRef = BF7B94731C7027BE19E68D31F0CDEBEA /* FBLPromise+All.h */; }; + 5859F25320F41073E40ACF4608F61C03 /* FBLPromise+Timeout.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = E2DCA620D3D076030DA2B13428F8DEA0 /* FBLPromise+Timeout.h */; }; + 58C93368ED6F500E21548239C62979D0 /* FIRStorageConstants_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CE46C58D06DFEBA5227D7A202DEE514 /* FIRStorageConstants_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 58D8CFC8852282D743776D0FFB4AB07A /* FBLPromise+Validate.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 56793ED84A5687D192F21FFE912AFD81 /* FBLPromise+Validate.h */; }; + 58E33604E98B48869C2342DD27515367 /* FIRServerValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A8E98FC9F43E3599FC43038D8F3A086 /* FIRServerValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5A8449C256C7ED0DE9DE9CD8B90D312B /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B3125D500C1F70AC85CA5401A1F25E6A /* Security.framework */; }; + 5A89BBC727393C7C9A2930885172A577 /* GDTCORTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 54F92AA596420F49A8CE62BF16ACD771 /* GDTCORTransformer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5AB0712C9E382FA2433264E108A3A25F /* FParsedUrl.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DCE0B526350A606F7712387B591E2D9 /* FParsedUrl.m */; }; + 5AFA49633DF5CD52228123D0A40FEF61 /* FIRMutableData.h in Headers */ = {isa = PBXBuildFile; fileRef = 41458221673789BB327991D743219EDC /* FIRMutableData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5B02A3E3FD1A87C4B23D46EE93866A80 /* FIRFinalizeMFASignInRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 65E647C1250D83FF8B141CDD6D7AB22D /* FIRFinalizeMFASignInRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5B0A142FDBF995D8E4AC243E0D1ED7D5 /* builder.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BAC185425DBFA92432FC48DC8E975D5 /* builder.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 5B0A6CB985EB036BD563219410BDE55F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + 5B0EFE0A8BD311854B7E7DA6CF087198 /* hash.cc in Sources */ = {isa = PBXBuildFile; fileRef = A24B571815B03F78DBFCF213BC206922 /* hash.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 5B0FEB83A4F5F7CF12CB78B28EEEAF3D /* FIRWithdrawMFARequest.m in Sources */ = {isa = PBXBuildFile; fileRef = C6BE8F46BEE35DA8571C06A26A640632 /* FIRWithdrawMFARequest.m */; }; + 5B1372FE89C5FD1CE1FC20060EB7B0DA /* FIROptions.m in Sources */ = {isa = PBXBuildFile; fileRef = B53B4F47E785737B058E7A4C89B15D48 /* FIROptions.m */; }; + 5BA4AEB9ACF731DB33AA25C7C0BA6420 /* repair.cc in Sources */ = {isa = PBXBuildFile; fileRef = 033F4C2158EF7093260D0330792F029F /* repair.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 5C06F048ED12F3A8C551E8D67739C9DC /* FIRAuthGlobalWorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 60309DD4339A47378854B0E21D2290C3 /* FIRAuthGlobalWorkQueue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5C73A188E56617C05C11BCF74984D3CC /* FIRGetOOBConfirmationCodeRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C49AB2D1242CB4AEE03BD5D1FDAD050 /* FIRGetOOBConfirmationCodeRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5C92F3D83A17F078D0B42E92A1BA19BD /* FIRSecureTokenRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A33E05B62B2DDAEABACB7EE4520E03A /* FIRSecureTokenRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5CFD98A13822F82EDB38A762D3CD1DBF /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 33AC8DDC34080E0C8F6B67968DBCD4E2 /* FIRLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5D479C5ACA7CD9A038502936898ADAD5 /* FSRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = FADE0B752CA28920C36DFE5EBFBD2EAC /* FSRWebSocket.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5D5898632CD8963E3FA4682EE2702BBA /* pb_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 8FF27683F341192130EB44D127CBA99A /* pb_common.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5EDCFF0B8FF8BAC118B97D7A0C9EE4D2 /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = 304757A5D03E8A05E64E70D59C041A7D /* logging.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 5EDD5B50DD1356EF677C687409FE0853 /* FSyncTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 690301B45D9E8D31056AE28BE54B2A32 /* FSyncTree.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5F5099298A59B6F867A046EA0D1A2283 /* FIRGoogleAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A7D82FD36D69E637ED2F86EA9CCCFC6 /* FIRGoogleAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5F551BF53EDDC2F198AC908DBC42E1F6 /* comparator.cc in Sources */ = {isa = PBXBuildFile; fileRef = E05A9C8A4A5E398CC84792414886CFDF /* comparator.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6033F62A41BBCEAA7BFA756FEE021418 /* FIRResetPasswordRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 16321AB5E9D6A5632ECCD98C46E259C1 /* FIRResetPasswordRequest.m */; }; + 60481150898E4F0010B3E2D167AA4A62 /* coding.h in Headers */ = {isa = PBXBuildFile; fileRef = 5EF7576689BC01D4194E19EF9A62732C /* coding.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 609B53B50AD2672F4805D60C2B47DD39 /* FIRStartMFAEnrollmentRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DA191F722C849464E09ED0BF996686F /* FIRStartMFAEnrollmentRequest.m */; }; + 60BA97B8834498ADE5023FC7DAD2EBCD /* FIRConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = ABEFDEDD9204F734E8CF7156DB34EAC2 /* FIRConfiguration.m */; }; + 60DAF5108D66A54C3CB0A05E7C3E0D61 /* GDTCCTUploadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A6AEEDC723439C1699E7CF8FCCD9CA8 /* GDTCCTUploadOperation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 614A388909C3449BDDFFA0DA220A12C0 /* FIRStorageDownloadTask_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 253F33B4DBFD01CAA5A4802942933E2A /* FIRStorageDownloadTask_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 616B2E89D32FD69F07E92AB1B11D2CBC /* table.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A3CB08CA78834D9A4E195F7E0FE927A /* table.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 617FB4DD5E4E749392DBA95B82582F36 /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C49A0050512E4D846C5B20571F192808 /* SafariServices.framework */; }; + 61BAD4B3AC092595A4DBD710410C78DD /* NSData+FIRBase64.h in Headers */ = {isa = PBXBuildFile; fileRef = D772660D348EDA152D9FA9274A4FD651 /* NSData+FIRBase64.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 61DB8504F985F28E725F9C3AD6ADB4CA /* FTupleFirebase.h in Headers */ = {isa = PBXBuildFile; fileRef = 50C162F8A131149A66AA8D00EB16FD47 /* FTupleFirebase.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 61E2DB574A18AE2C6D301B9FF657AEBB /* GULMutableDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCB2BF6F6A5EB6D04951F3D60060A14 /* GULMutableDictionary.m */; }; + 6253AB48F6EC0AE958CA1B9469A64C71 /* FConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D67BEA48283ED3EBBC32F2CE1FB54D /* FConstants.m */; }; + 62A83818CD40006D6BA70CBED6490D29 /* FIRAuthProtoStartMFAPhoneResponseInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = CFE231493E8C735456EE5EE7B5E7B915 /* FIRAuthProtoStartMFAPhoneResponseInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 62BC134F5E129851682E2B83446C82CE /* GoogleUtilities-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 92C8D3FC28E367731EFA7DA60B5B2769 /* GoogleUtilities-dummy.m */; }; + 62DE02710C62D6496823D1B88364634A /* GDTCORReachability_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 031CCD2F09059BB876AEF36C4CCA549D /* GDTCORReachability_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 63764E43C4E5B8288446633D0A055AFC /* FIRAuthExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 13334C7932E2839836F8564E47E5E95F /* FIRAuthExceptionUtils.m */; }; + 63AB34CB59ACAEDDA595EDF91BF8FDB1 /* crc32c.cc in Sources */ = {isa = PBXBuildFile; fileRef = 999D8DF2DEB3C92825F53ACD82C3DB9C /* crc32c.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 63CA3834470B3A2EDE6EC9143A4AEEF1 /* FTupleBoolBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 78510B2DAF0836E51218B1E6D69962F7 /* FTupleBoolBlock.m */; }; + 6440AAEB698149F1076ABD1C2EB7728C /* FIROptions.h in Headers */ = {isa = PBXBuildFile; fileRef = C17F19ED839D7947EFCF4E484C64AF60 /* FIROptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 64458AFBFBE0268F3136FD2249AEE654 /* GDTCOREvent+GDTCCTSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 01E75FBC9C58CDC564AC74535ABAF369 /* GDTCOREvent+GDTCCTSupport.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 651BD9FBA52511E2F13EB0DA9E563031 /* FIRPhoneAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FC1446EF19FFFB8FD40DA8AD3896B58 /* FIRPhoneAuthCredential.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 655EBDF94BCD02187A918254978A1034 /* FIRResetPasswordResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369B16C386867CF042633E43E33BE17 /* FIRResetPasswordResponse.m */; }; + 6635A1592B385FE08057D0186B149966 /* FIRVerifyAssertionResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = B205E2A02343B83399E353E5848FB22C /* FIRVerifyAssertionResponse.m */; }; + 6670345A52E74A2A2CFD531CD287E190 /* GDTCCTCompressionHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 9292823C54252CB8B2596AC4FCB873ED /* GDTCCTCompressionHelper.m */; }; + 6674DEE755366B1AA3BC1C8DA72EE0BB /* FIRMultiFactorAssertion.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DAB47641886E577CCFD751778C9F2CB /* FIRMultiFactorAssertion.m */; }; + 668D655F32BA7A18033B1F19266C28FE /* testutil.h in Headers */ = {isa = PBXBuildFile; fileRef = 85CE11515F2C205F76C8BFC8719857B2 /* testutil.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 669BFAF0CC62D4215D9DD4B1C5C6F2C3 /* FBLPromise+Async.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = EAF26E5359FBEEEBFA7845231AC4195A /* FBLPromise+Async.h */; }; + 66B6AE4725AC401C60EF58C089F8A881 /* FIRComponentContainerInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = B4F8D21D4F75C7ACFB902F78724ADF00 /* FIRComponentContainerInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 67AC814AB27FF6C1E884EE473F9D47F1 /* FIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = C3ED5F9B71BB5AB9B21AD796059C1958 /* FIndex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 67CD5BEC3720F441D6EB28B07A42C7B4 /* FIRVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1123E7A9203EDCC45A75D4C556249693 /* FIRVersion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 680C99CBF3FFA946B0D6573BCA10A097 /* env_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = DFE085E90848700012D4C7E2953F5CB7 /* env_posix.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 683D61CDFA54C10A91D7128E05A707F0 /* GDTCORRegistrar.h in Headers */ = {isa = PBXBuildFile; fileRef = 7990098C6933A9C3ACFD403877E938CC /* GDTCORRegistrar.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 687C49AC74D75C7064C4BCD1FEF165A2 /* FBLPromise+Race.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A49AC9D79084068C17D46C29FA998AA /* FBLPromise+Race.h */; }; + 68C7362E00FFE0E070F04E6BB537E5E9 /* FIRVerifyPasswordResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 47E1657B953672DCE7012A9F6150D4BE /* FIRVerifyPasswordResponse.m */; }; + 68C9F99D0E1EB247247E7CC741EDCE29 /* FLeafNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 650A616FFDB77F03EEF97D722373AC34 /* FLeafNode.m */; }; + 6951325278388C26E3AC2560642800E8 /* FImmutableSortedSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DAC3C48DBA947FB36971090D8CC75A0 /* FImmutableSortedSet.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6962B76E990566CA13B470EE1130E7C2 /* GTMSessionFetcher-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = EDB91576C5DBF9C1A9EE8EA285461D1B /* GTMSessionFetcher-dummy.m */; }; + 6979B7B344E7603BC52FA8BD0FEA6205 /* version_edit.h in Headers */ = {isa = PBXBuildFile; fileRef = FC4238AE7DE4CF32B916F6526C7E4208 /* version_edit.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 699224F417B88B9E5ED92E5DE4EE3A2D /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D2D2CDA157BA843AC5E477C656AC3A5 /* FIRComponentType.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 69DC2A9F6509B50FDF64F9C216069134 /* FBLPromise+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = E80F127499254D575F9567C7C18C951A /* FBLPromise+Catch.m */; }; + 69F4290E7823430720A47749DC834A66 /* FIRDatabaseQuery_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 08FBB509F7F005C11D635808E7C3B594 /* FIRDatabaseQuery_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6B16A68AC63ED6F5D3128DDDD407DE60 /* FIROptionsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 1DEC7CA169AF37FBEE1A5945F3D3241B /* FIROptionsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6B58C5A2D34339AC44AC12211778ED64 /* FBLPromise+Retry.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 4DD222A708C236933A0C9863252657F2 /* FBLPromise+Retry.h */; }; + 6C037F0F700DC983738B413D71829682 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + 6C1E37DF84299791836DF45885744CBA /* port_example.h in Headers */ = {isa = PBXBuildFile; fileRef = 597E0977016E0C422EE40E3D6BFECCA0 /* port_example.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6C3C85FACFD8BA5961C50A7D613C375C /* GDTCORPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B660D391F0513F69F3840BAF34FAF6A /* GDTCORPlatform.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6C4C3AF66F2F27E39972465C10D5FED8 /* FIRIdentityToolkitRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 35818AD85F2784E8B89CB71D38ACD3F1 /* FIRIdentityToolkitRequest.m */; }; + 6C84AB2FE56227E3CB6D7B77C85AB3D0 /* GULSecureCoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C3A935A0E1C775C388B504E26363B9D /* GULSecureCoding.m */; }; + 6C9859DECFAC995CDA6D055CC454EB1A /* port.h in Headers */ = {isa = PBXBuildFile; fileRef = 5104C396E6DF2C443D0D8078264E91FF /* port.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6CBF35F4F530975DB66F9FD017473901 /* FIRSignUpNewUserRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 91F64E407B7C5996C15B0EA7E2CC6D8D /* FIRSignUpNewUserRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6D061BDBC2E0310C7648D3417594E229 /* FBLPromise+Await.m in Sources */ = {isa = PBXBuildFile; fileRef = 355AACCB7DBED4FAC573C5B11C78B4FD /* FBLPromise+Await.m */; }; + 6D4F24F8F42A4EF2DC3725A798398213 /* filter_block.h in Headers */ = {isa = PBXBuildFile; fileRef = 7FE96EDA64C9137D9B8CCBCA2E2B050C /* filter_block.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6D6A2333C5E7DD95CE37F1DDAC75FD06 /* FTupleNodePath.m in Sources */ = {isa = PBXBuildFile; fileRef = C75BC3FDB221D20BFF8AC4B4906E6172 /* FTupleNodePath.m */; }; + 6E48076C21BE60B79C6CD1FD27A7D7CC /* FTupleBoolBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 9319464784A2E9CF7514BBF5FB7DE52B /* FTupleBoolBlock.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6ED6CB026B6CE440864EF27A2C6A30A2 /* FIRStorageUploadTask_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 184FB4DAC7ECA7641F9F273B2C2EE276 /* FIRStorageUploadTask_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6F520679C3B53DCA82460DE364BDC4CC /* FIRSetAccountInfoRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = D67D2536574B85AAEE67A9876A505335 /* FIRSetAccountInfoRequest.m */; }; + 6F53C577E5D2BB146AFD3363832D2BEF /* db.h in Headers */ = {isa = PBXBuildFile; fileRef = F697F7EA92D4F5BEA9A9ED3F7DB01CA5 /* db.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6F57C9DEBE484729475F1DEC6154B4E6 /* FIRBundleUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 659FED812C988A2D8BF2D7E6F39661B8 /* FIRBundleUtil.m */; }; + 706232F8C368B5471D7101E2848CF38B /* no_destructor.h in Headers */ = {isa = PBXBuildFile; fileRef = DD4864542B99534D826884212D610051 /* no_destructor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 70A52996349B60E0C637D744305677C3 /* FIRStorageMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = E8DB7C81B442901E0C90FBD3C7639CE1 /* FIRStorageMetadata.m */; }; + 70DEF84DC8BEF8FB292EF9E29C5A0F0F /* GULAppEnvironmentUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = CA5DF7383A09BA07C99F52E2965F0A2E /* GULAppEnvironmentUtil.m */; }; + 70F1FD0154E875CA3B8EFACA8CA32E6A /* FIRGitHubAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 6577A54ABE028DEF2E168EC3A7B37FCA /* FIRGitHubAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 71061B2E67F8751EF2EEF89DB2DF51D9 /* FIRAppCheckTokenResultInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 52473D87AE13917BE131E5B55A668691 /* FIRAppCheckTokenResultInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 716E198B020891EEF1D43C2C48C1E4F5 /* FTupleOnDisconnect.h in Headers */ = {isa = PBXBuildFile; fileRef = 442329955158D6F017C4BE628CC72663 /* FTupleOnDisconnect.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7172A6567FC9674DB16DEE23677E36AF /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = D3D10DEEC9195C5E381FF9C71A38D7D0 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7173ADD487449BB30C047AAF031EB41E /* FIROAuthCredential_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 49517E3675D59087A341DEDAB824FAB3 /* FIROAuthCredential_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 71F58DD428B816B771DDC1E0AB9C5E89 /* filter_policy.h in Headers */ = {isa = PBXBuildFile; fileRef = 811110CD8732C07CA742FCB28DD59DAF /* filter_policy.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 724F47B500A1B5067FF0C83F91800FB6 /* c.h in Headers */ = {isa = PBXBuildFile; fileRef = A0D696069DC52E2EA049543F7F8A9256 /* c.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 72C5FBC8B9ED1885E1E7CE2DD89ADDFF /* FTupleTSN.m in Sources */ = {isa = PBXBuildFile; fileRef = 407581F15079BCCB5BC45C24943E6FD2 /* FTupleTSN.m */; }; + 72F4F980A56274C51D938593FDE57EDF /* FUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = BB265518B2679102E1A6CCB3C247F6BE /* FUtilities.m */; }; + 7306ED79AC4A8B9425C5880284AB780A /* FIRStorageReference.h in Headers */ = {isa = PBXBuildFile; fileRef = C4E35116F3D5249AB4E261D67CDF74A6 /* FIRStorageReference.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7397DFEC139CDABF8CB5789951BDD66E /* FIRStorageConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D6DD1667F0E2BB21268B5CC194CA594 /* FIRStorageConstants.m */; }; + 73ADD3668F2482196FC451065E2B46F7 /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = 771B1D692CD92E2E80BCF92ADE963A96 /* FIRLibrary.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 740135820DB418029232BACB1470FDFB /* Pods-saraWhatsUp-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F94EBAB96F11BB0CEA8C3C329A569C6 /* Pods-saraWhatsUp-dummy.m */; }; + 742AB4CF041E58979F850575F0E1C633 /* FIRAppAssociationRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = 65CC113A8D6258FFC99A804308B6D18E /* FIRAppAssociationRegistration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 74F74F232328099A92DBE70AD8D5B008 /* two_level_iterator.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6A063636D2C9CF47A66A3A4D96EB2A2 /* two_level_iterator.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 75824117DB3AEA2D0E30E6157B4654CB /* FQuerySpec.m in Sources */ = {isa = PBXBuildFile; fileRef = CB0BECAA820EA39FDA6E794C088A9F72 /* FQuerySpec.m */; }; + 7585FB9893C47574C714EC0CD2504C97 /* FIRStorage_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A802E95D84E016849CCD84A2FA5A5E /* FIRStorage_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 759B15456E9CA9130BEE3022AFC10F49 /* FIRStorageUploadTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 4FB87C0E75DE3B5B7C9A8E0BAB0197F3 /* FIRStorageUploadTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75E819D7151D7CCE92C79AE2DDA1F95F /* FIRStorageObservableTask_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A79C412D90BBA0C242A6222476E3C0F /* FIRStorageObservableTask_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 760BA4FFAA6A2C1651C5673DB42095D4 /* FIRCoreDiagnosticsData.h in Headers */ = {isa = PBXBuildFile; fileRef = 451F026B97D69D675820DFD19C8B211B /* FIRCoreDiagnosticsData.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7622B5ED0A4FB6DCD78A15CAC63027F6 /* db_iter.h in Headers */ = {isa = PBXBuildFile; fileRef = D881285A593D28B3D30B443110BFD856 /* db_iter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 76598E46A0503077124CDABA6A6ADEA6 /* FConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 93ED49D06A2C2D3717C9989F17DC95E2 /* FConstants.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 765F1A85400A99B67576382E569A9972 /* APLevelDB.mm in Sources */ = {isa = PBXBuildFile; fileRef = EC42A40F3D6145F7FF3837DFE3B986C8 /* APLevelDB.mm */; }; + 76AE78B5CBE2112303D0B9CD1D4A5D85 /* firebasecore.nanopb.c in Sources */ = {isa = PBXBuildFile; fileRef = F9261B348836363F87E4E2D8EAF2156F /* firebasecore.nanopb.c */; }; + 76F3760E8A249FBEE27DF68F81073F39 /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = B251FA096ACFF51E3C472B66C3246C5E /* FIRComponent.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 773A7355F15490EA982DF17AE6676998 /* FIRWithdrawMFARequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AB58E982FA948803C8BFFFE072A8FA7 /* FIRWithdrawMFARequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 77590AB689347900DF0F519AF3B0F2F6 /* FValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = B619FA3B200C111A548E62024E1C5A0A /* FValidation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 778DC5CEEB3B4DD44DD01DCE7A2B439F /* FIRAdditionalUserInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = EE320D6805F4B2836B7394747D3FCD01 /* FIRAdditionalUserInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 77B0BDB698070CCA95A70089BAC23AF4 /* FIRAuthAppCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 09C911FD759302267DF9A71825701EE0 /* FIRAuthAppCredential.m */; }; + 7A2CA8D03EACFAAC906606B551F830A6 /* FIRMultiFactorResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = C74C1F1761112ECCEAF3300A37403DDD /* FIRMultiFactorResolver.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7A752A831BAEC391DA358C31B9B5AB45 /* GDTCORFlatFileStorage+Promises.h in Headers */ = {isa = PBXBuildFile; fileRef = 796FC6CF1B3D7E3AC02697E08E2EA1F6 /* GDTCORFlatFileStorage+Promises.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7AADF931BA9247F31B1D59A864D1BD2D /* FIRFinalizeMFASignInResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D3910738ACD998D1901C556AB4335C /* FIRFinalizeMFASignInResponse.m */; }; + 7AB306C95D7D95B57430E1D8097D448C /* FServerValues.h in Headers */ = {isa = PBXBuildFile; fileRef = 01333A9556B2952D3BF8EF47FE063E14 /* FServerValues.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7AB54867E38488F0C42A6601C1DA6208 /* FIRAuthBackend+MultiFactor.h in Headers */ = {isa = PBXBuildFile; fileRef = F0BC27D6656FB79C7E72378BE364E49F /* FIRAuthBackend+MultiFactor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7ADFF49C61F88C284EBC3F8F3BFC7E70 /* FKeepSyncedEventRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = 893755B5174475866FE50238A792D3D4 /* FKeepSyncedEventRegistration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7AE56FDB079D733CB05F64F0E662E9F5 /* FIRAppAssociationRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = 68E626CB79A2ADC613582CCD54AF80C3 /* FIRAppAssociationRegistration.m */; }; + 7AFAE54E97C44681D98FC93CD357912F /* FIRAuthRequestConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FE2B96A5E3FEAB7406E5F37AD224EBD /* FIRAuthRequestConfiguration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7B00D6A4319C96E8C195A62236AAE45D /* FIRFinalizeMFAEnrollmentRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 16AA4D274A47351AFC341E2F1303F464 /* FIRFinalizeMFAEnrollmentRequest.m */; }; + 7B2F9EEA7062C0B40A50D13A0BF27BA6 /* FirebaseDatabase-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 65C9D3135B91FB7527D0EA93EE04C9F7 /* FirebaseDatabase-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7B5A0F99CB075CCFC9BA1EEFE29ED77F /* FIRMultiFactorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = D3C31E13AF424AADDB899510E6244150 /* FIRMultiFactorInfo.m */; }; + 7B982C6250B9F6A3033B02685F010590 /* FPruneForest.m in Sources */ = {isa = PBXBuildFile; fileRef = 610635289C0D10AC1C508932A13F5139 /* FPruneForest.m */; }; + 7BE47D6D30ACA7C520E2AAE337DDE6E4 /* FIRAuthNotificationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 85396FA2E4FB7242703B77E534BB96FA /* FIRAuthNotificationManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7BE9BFF47CD87967D9BFB28966CC9F26 /* export.h in Headers */ = {isa = PBXBuildFile; fileRef = CC9F05108D2A9DE51B409B2429608A48 /* export.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7C36F8DD3064D160FB7149D357F3CD87 /* FListenComplete.m in Sources */ = {isa = PBXBuildFile; fileRef = 46E0D19B44DD2105DB3A82048DF5D5B3 /* FListenComplete.m */; }; + 7C9FB6475EDF8467952C11002E43B5C1 /* FIRMutableData.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCF37B07E3507CC4E49BC6EB62D2AFE /* FIRMutableData.m */; }; + 7D0188C317EF3E96695742D4E163DD8A /* GULApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 0219F46A3DB232BA4625B09FCAC5F422 /* GULApplication.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7D0CEB45C774DBD9AED7942C23E8D100 /* FIRAuthBackend.m in Sources */ = {isa = PBXBuildFile; fileRef = E59A2BB16DF1C8DF51ED04E0F073F51B /* FIRAuthBackend.m */; }; + 7D6065C88C5BDF90AB8F00CD1BF6C276 /* FSyncPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 70E16CDF231339A38CEFC419256AF4B6 /* FSyncPoint.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7D77834592C464F004194603DE79FFED /* nanopb-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = EB97D7B83E06FEC9F876862742C3101F /* nanopb-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7D785B8DD4B6471135EE117CFA4300BC /* FIRAuthInternalErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = F70BCE209E6D671E54D0B43EC43C99DA /* FIRAuthInternalErrors.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7D813D99BD9C92C5CD4129300C5AC498 /* FCachePolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = 771D448D527F0ED9A6589CFA7D620F5B /* FCachePolicy.m */; }; + 7DD314CFB3E341990B3E317139A123D0 /* FIRAuthUIDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 640F8AEF999AB871A9CF0301174BAFB5 /* FIRAuthUIDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7E3600898B2058A29ACC86B5A6013B5F /* FCacheNode.m in Sources */ = {isa = PBXBuildFile; fileRef = B17F92A2601314D41826CAB86DA61688 /* FCacheNode.m */; }; + 7E41BFA699D5160081068728DD661040 /* FIRSecureTokenService.h in Headers */ = {isa = PBXBuildFile; fileRef = 495A1CBF66ED76B976B4117DD6223B93 /* FIRSecureTokenService.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7E5CE79823249FC02E6F9F0BCD720E30 /* FTupleTransaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 454FA5FBE52280258D0A13B8B42FC8B0 /* FTupleTransaction.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7F6139B893BFFDED3B16B2D252C8FDBA /* FBLPromise+Recover.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = E66BECCDBDAFF7F21FD65107CE127127 /* FBLPromise+Recover.h */; }; + 7F6A49312DE0FEEA8670C33BB7C8FCD7 /* FirebaseDatabase-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 36757A52A1527757F814CD6DF5597901 /* FirebaseDatabase-dummy.m */; }; + 7FA7C0F81141C2CB9A7B998AF7D9E9C8 /* iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CAA0FD11D8FBE058FA3A8121AEA112E /* iterator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8024622AE0E5CB515628DD4D344CFBBC /* FIRUser_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2321555A80BE5C47A7147561FDF2F40E /* FIRUser_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 80F4B66C43F64C2A05ED6245F69641BA /* FIREmailAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = A41EFA62EBC841BCB7E78DB7374FFDDC /* FIREmailAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 81A6E9D26B117B3E7E9E9042C8AC5BC7 /* GDTCCTNanopbHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 7479F6204A3F34CDEC48DB0D5C66BAF3 /* GDTCCTNanopbHelpers.m */; }; + 81AB97AF31AF1535F743922CBB797777 /* FWriteTreeRef.m in Sources */ = {isa = PBXBuildFile; fileRef = E0070AA5B17F5B089940E9DF9C7EAEBB /* FWriteTreeRef.m */; }; + 81E4C37AC1B89BC2F316636CD0D4481C /* FOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC729ED3D4FBA1AF83B8B5321C688EF /* FOperation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 82421185BFECC0330891863B6C6B9E1A /* FIRAuthAPNSToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 03215B0ED3F49AAA67906E78ABBB23BB /* FIRAuthAPNSToken.m */; }; + 82858EA79C6545989FD16116DC1046E2 /* FIRFacebookAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = C63E288BFEA73AB13BADC975423E2506 /* FIRFacebookAuthProvider.m */; }; + 82A04219A742044F706375B21F507E28 /* NSData+SRB64Additions.h in Headers */ = {isa = PBXBuildFile; fileRef = A7281F8592B9D881F237AD35C3339C04 /* NSData+SRB64Additions.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 82A793EAA095E4ECDCEAFACE9FD08C6F /* FTupleFirebase.m in Sources */ = {isa = PBXBuildFile; fileRef = 051169EAD8CE8968374F95BB47451BBA /* FTupleFirebase.m */; }; + 82FB414CA71D1A4977412181A6C8668C /* FIRDataSnapshot.m in Sources */ = {isa = PBXBuildFile; fileRef = 9023A0DEA45F88CB202B8E8DB8ADE4D2 /* FIRDataSnapshot.m */; }; + 82FB76596854911C8990D63666D960AE /* FNextPushId.h in Headers */ = {isa = PBXBuildFile; fileRef = 27F950C7EE4B76D2428D26EF8510C489 /* FNextPushId.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8301D0F695FF1765CDAD6EB734E42EE1 /* FIRAuthAppCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = FF4238AE1711F98CE953B5A47C7A908F /* FIRAuthAppCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 831E11B569812416126CC430EB44832F /* GDTCORUploadCoordinator.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B560758433B7E849C46B3873B69351A /* GDTCORUploadCoordinator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 838BB38C313133CBE50C29C938E94F58 /* FIRAuthWebView.h in Headers */ = {isa = PBXBuildFile; fileRef = F83254030B3331F8B9250016B3E90536 /* FIRAuthWebView.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 83CA89EB2806F46C872FF1551D0ED171 /* FRangedFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B80F6F5EC765ED2536E876CFA12A6A /* FRangedFilter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 83D72576BFB730F7EA50FE092466BEEF /* FIRAuthBackend+MultiFactor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0BF52AE10A30F5BD8A7D2E4F4080E8 /* FIRAuthBackend+MultiFactor.m */; }; + 83E4DF34F5C45E17F19AE7215F8ECD48 /* FIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 24E003B576B1D07E80E0F3159C8D80AA /* FIndex.m */; }; + 842596B7741229FA10A6C0FE65968239 /* FIRAuthTokenResult_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = EBC6EA870A2561076AA0403C29B72C92 /* FIRAuthTokenResult_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 844FA7C3837151A737442BD27727B428 /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 919646B9BE59C2A4A31EE830A2CA8068 /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 845C86D673765B84369EA75ED1C27476 /* FChildrenNode.m in Sources */ = {isa = PBXBuildFile; fileRef = CC53772094E8CA6243B6A7930C6D7E99 /* FChildrenNode.m */; }; + 846CCCD44A615EB057E9117834B3D044 /* FIRCoreDiagnosticsConnector.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B51D95619BDA00B9016FAE302AD53F5 /* FIRCoreDiagnosticsConnector.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 84B9473B74CE8DD54941D7A03B160895 /* FRepoInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = E7453502726C5BF4194ADE99C1058FDC /* FRepoInfo.m */; }; + 84D9680CC81C18ADEDBBAFF0FFD5A373 /* GDTCOREventTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = D1284A968E76C7AB80F7D25481E15AED /* GDTCOREventTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 84E620F824D728AEB6D3786457B951E5 /* FTupleObjects.h in Headers */ = {isa = PBXBuildFile; fileRef = 1782CB220CA1344F5845A55A1A958C8C /* FTupleObjects.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 84FB53E0059CA2D5C7A6ECE534229BCC /* FIRMultiFactorInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BBBA3A61F8609CF2D274B58E72304564 /* FIRMultiFactorInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 85571F0848D48FC93C449C1986C012C9 /* FIRMultiFactorResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = FA5E2A052EEFA5DAC5C85689BC871BD0 /* FIRMultiFactorResolver.m */; }; + 85FF342CC7BFC4625D7ABF6102E106F6 /* GULLoggerLevel.h in Headers */ = {isa = PBXBuildFile; fileRef = 28E8C18EF9243B01130C42F9F7FF6092 /* GULLoggerLevel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 862645997A150ACCA48117A58C676B4C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + 868FF3395EE1C4FCC3004281B340E1EB /* NSData+FIRBase64.m in Sources */ = {isa = PBXBuildFile; fileRef = 07C17F9E595A3429B033D37E557FFA35 /* NSData+FIRBase64.m */; }; + 86CC8FA2A361B3AC6266A57E7013AB7E /* FBLPromise+Retry.m in Sources */ = {isa = PBXBuildFile; fileRef = B80FA25AA1ED7576FF55175F0718FB6F /* FBLPromise+Retry.m */; }; + 87509592DC4D483D79B5ECFBAED06C94 /* GDTCORClock.m in Sources */ = {isa = PBXBuildFile; fileRef = A27989CBB3630E8519D5EF0AF4D86AC3 /* GDTCORClock.m */; }; + 885F224793EF37BF5179907F21F453B4 /* FIRStartMFASignInResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = F7041D7B7DBE5353E7092A9A3BC10198 /* FIRStartMFASignInResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8861C1ECE26C3BB7606E1E749D322F21 /* GULKeychainUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 93DD3C0ECA96FFC0C58657AFB6F07DE0 /* GULKeychainUtils.m */; }; + 88FCE7252AB682CC6F73DD96624930A8 /* FIRDatabaseReference.m in Sources */ = {isa = PBXBuildFile; fileRef = B98C573562E1874BD238096257145128 /* FIRDatabaseReference.m */; }; + 89103EC97A6B11F06DFFF3AEC331E05B /* block.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA511F39EE0137DB4B0ACAA4F2EB5714 /* block.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 8960245F1AC80306C58DD9D2ECC80EDD /* cct.nanopb.h in Headers */ = {isa = PBXBuildFile; fileRef = 71EE8EAC0D7B50883AEF17DADF5767A2 /* cct.nanopb.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 896F863E67F27EAA3DFF0D1549F76F6F /* FIRDatabaseConnectionContextProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E0B842AE076438EDED02B289F208B47 /* FIRDatabaseConnectionContextProvider.m */; }; + 89C77D7AE3380CE0141805EC830108BB /* pb_encode.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C7CA6595BF223D4051F9ACD7821516 /* pb_encode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 89DC919325A25CC1DE4B44094DA0A962 /* FIRMultiFactor+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = ABE44E0B7E460C06F92D3D1CE8AF490B /* FIRMultiFactor+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8A3ACA70369FD7CD07746EB652CBF841 /* FSyncTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 2500B7FB71DA82CBFDDDB4822D95A314 /* FSyncTree.m */; }; + 8A71B72D50C8320631C8BF80018502DD /* FParsedUrl.h in Headers */ = {isa = PBXBuildFile; fileRef = EBF684FC3AFCE3789A8D7312D9A91EF7 /* FParsedUrl.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8A8908AA3F89244EFF01B5C6CFC2B4AE /* FSnapshotUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = A47B0B236ECF15DBE883A4F85C21E999 /* FSnapshotUtilities.m */; }; + 8B40C2853D08740082E7D01F5320B46E /* FIRAuthAppCredentialManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3548EDB27273E2BA2A7598B23531161F /* FIRAuthAppCredentialManager.m */; }; + 8B4A58C4EFA72BCD77996DBC7BEB8982 /* FTypedefs.h in Headers */ = {isa = PBXBuildFile; fileRef = 2224951413E013BC93CDFA9F58D26A34 /* FTypedefs.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8BB8EDC25F690CD7D1773F68CA73E87A /* FBLPromise+Await.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = A3B520AC90F216E89C6A144E34C7B728 /* FBLPromise+Await.h */; }; + 8BDDC7BAFF8F9398888B59D7CC24CEEC /* env_windows_test_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 17B17FDF8C1411944C7BAF3A650948E1 /* env_windows_test_helper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8C44314F95042D95380E7F1F84A7649C /* FIRAuthSerialTaskQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D32FC791A2013E36F3CDA08B9612433B /* FIRAuthSerialTaskQueue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8C75B4E09A6E9E6E3668E763066434FA /* FIRDatabaseQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = FA57C47826950D4B1DDB1508EB0E38BA /* FIRDatabaseQuery.m */; }; + 8C8B9AA671EE9F83E0C2ECD13F9E5306 /* FIREmailLinkSignInRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = C59EBCCA53061961256AE11C24B8DA68 /* FIREmailLinkSignInRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8CA7CC4B775AE20BF05D8FF2FD4D9C50 /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = C7251F3F7533A9A216EFD0FF18A7FEA5 /* FIRComponentType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8D2DE777CC28353B240AD75391B5719A /* cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 902BFA8AA57755F097F4A2314A70024E /* cache.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 8D4A065A5FE18A77C437F63675CE5BC6 /* FPriorityIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 0EB4424F6DC448437D09153671506EF7 /* FPriorityIndex.m */; }; + 8D57BA44161FEE21D99506D077456B7F /* FIRRetryHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C112FFED625306176513F53215AE57A /* FIRRetryHelper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8D5D3323F9C4566FCA2CC7C6500CB7DD /* FTupleOnDisconnect.m in Sources */ = {isa = PBXBuildFile; fileRef = DC228939E4F3D2C027921DDE205BF92A /* FTupleOnDisconnect.m */; }; + 8D626225F9AE2D98416282F2BDEA26C3 /* FSparseSnapshotTree.m in Sources */ = {isa = PBXBuildFile; fileRef = B67EF49828FB87A7A9D76CFCE913F31F /* FSparseSnapshotTree.m */; }; + 8DA1AE4EACC98378C44DBC65DFB282B1 /* merger.h in Headers */ = {isa = PBXBuildFile; fileRef = 366AEC787A39A50848D53D417F5F40BA /* merger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8E117DDEF71D85E84D5C6C6F4CCF504D /* FIROAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C78EC07E7A21AED745FCFE8199BD2B7 /* FIROAuthCredential.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8EBBE1DE3E49C903EBFE8B2AF59D6CFC /* GULSecureCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E907B698BBF0F9109ABFC14AC18417C /* GULSecureCoding.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8F1D38C0AD2AB9C132D750E6A0453312 /* FIRSecureTokenService.m in Sources */ = {isa = PBXBuildFile; fileRef = D09720D9CE5B015636E0BF2DF73B40A2 /* FIRSecureTokenService.m */; }; + 9017C1C93750182F2A32736B460C699A /* FTupleSetIdPath.h in Headers */ = {isa = PBXBuildFile; fileRef = CA348D76247362411205819BEBAE4021 /* FTupleSetIdPath.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 905DA99BAB170BC93513360519722DA8 /* FIRAuthUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D52FE533230E7D91A995F0E70F0875C /* FIRAuthUserDefaults.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9085186086C8E31DE65E85131737F2B6 /* FIRAuthWebViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A6B7DA408335681D8EBB8E8A8195300 /* FIRAuthWebViewController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 90C2795D5858544C6636A77AE6BB9088 /* FIRStorageTokenAuthorizer.m in Sources */ = {isa = PBXBuildFile; fileRef = C228A639A3A804038FCAFE0D56A11E97 /* FIRStorageTokenAuthorizer.m */; }; + 910D87141418C7D0A20563D926EE51EA /* GTMSessionFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 35079459556846DC42E6BAD6EF998A09 /* GTMSessionFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9194640A5BA4E355C067A4E4AE1F6AE3 /* GDTCORTransformer_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = E956BC1D004B2B30234ADA67B946DC7B /* GDTCORTransformer_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 919D6CD31FF106A4CF8B8F4DF20AC772 /* FDataEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 45AF18302FA22D80E5512B30C06C4070 /* FDataEvent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 91A136B8AD4777A463238ECB23804731 /* FIRStartMFAEnrollmentRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 5431265B4569BAA9C924F890E9684329 /* FIRStartMFAEnrollmentRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 91AED5DBBD2528772364BA8B702366D9 /* FIRAppCheckTokenResultInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C8C7273435FEBC73D2074E6266738FF /* FIRAppCheckTokenResultInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 92144C5729C6F1D3860886BE4F9B3A19 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EB45EC81F9E789E892AA3B0F212BD9B /* CoreTelephony.framework */; }; + 9224B111DC38D2B9FCB47095C27DEE63 /* GDTCORStorageProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = A028346C0A515F7539EB33C42B3D0DF5 /* GDTCORStorageProtocol.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 92D78842802FAAEBD807246D070DDD9E /* testharness.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2362DA688BE060908187030599778FF2 /* testharness.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 92E2001590E01893E9512EE4B749966E /* GDTCOREvent.m in Sources */ = {isa = PBXBuildFile; fileRef = B23EC38971E21F4A29F30D17FB217E7D /* GDTCOREvent.m */; }; + 935BB5128361756AF5CC5B3650130A14 /* FIRPhoneMultiFactorAssertion.h in Headers */ = {isa = PBXBuildFile; fileRef = 02A800184212263B2434BD36BD5C4123 /* FIRPhoneMultiFactorAssertion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9479CCD356F14DE6D7FC3D887F0754BB /* FIRApp.h in Headers */ = {isa = PBXBuildFile; fileRef = D2EC0D304F2E147D3F387897C17F1887 /* FIRApp.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 948EC119E467DCC735AF49A4636925A0 /* GDTCORTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BBAE436FDDBE0D788ED31A281A08436 /* GDTCORTransformer.m */; }; + 9490844671235A0D95556CB1BA93C23E /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 22C249A29BE5C894E90F84F5C51D9ACE /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 94DD516831437C2320440D0EC212CC7E /* FIndexedFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D928F363DB19E4AFCF00059587BBEA8 /* FIndexedFilter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 94F4C13BDBFFB1CA1E8F8B9DC83D60C6 /* FValidation.m in Sources */ = {isa = PBXBuildFile; fileRef = FC108E601CFE8FE0A56A55196000DBAD /* FValidation.m */; }; + 9526755F9FD25D5080DF620EA5A1FC5B /* FKeepSyncedEventRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = EC19D3E58E78BDD743A8EFAD9BC684CD /* FKeepSyncedEventRegistration.m */; }; + 954381EDA4655CC7F6DB05DCECFE2304 /* FIRDatabaseReference.h in Headers */ = {isa = PBXBuildFile; fileRef = 1157C2EB85FDBA73F430398032A06509 /* FIRDatabaseReference.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 95856B75ABD2C00249DCC69921C3308F /* FIRFinalizeMFAEnrollmentRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 7809E5411EAED2D217B878048273E546 /* FIRFinalizeMFAEnrollmentRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 95A247CC80E3EB7AC11BCF40F0834F7E /* FValueEventRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = FE04F0C80BC6BB55DA64201AB87C33F2 /* FValueEventRegistration.m */; }; + 95D70E62A632D2A32C3BA4EFBD64A64B /* FIRAuthURLPresenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 49DEF809FDF8A0305B56D6382AF927F3 /* FIRAuthURLPresenter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 95E4525FEDACD00BF456ED9CD7576AE7 /* leveldb-library-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = F2598F081516F4371B1C222199738340 /* leveldb-library-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 960CA75E0D157997A6E272FF20C3CC7B /* FBLPromise+Always.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 856378CC2E53007A66BBB5C102C82AE8 /* FBLPromise+Always.h */; }; + 96213AB03142B1DD9BB63FE042AB7C07 /* FIRHeartbeatInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = D82232D321C3210F5B247FF6E16F7766 /* FIRHeartbeatInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 962BA17595BF9C8593F20FA476C14B63 /* FIRDataEventType.h in Headers */ = {isa = PBXBuildFile; fileRef = F9A27AB3D82A79375F5B1A39D4C39E51 /* FIRDataEventType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 964ABA6B10275C7E330A0D309950289D /* FIRStoragePath.m in Sources */ = {isa = PBXBuildFile; fileRef = 694A67A5D2B3C84DB25148DB4DCB6DA1 /* FIRStoragePath.m */; }; + 97BBC5F4455ED893A97241B577B1F730 /* FIRUserMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 12BDC2F59494AAB3007671C257F6E5DA /* FIRUserMetadata.m */; }; + 97E3E024B11C53FBEA9C7E479C3AB5F7 /* GULKeychainStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = DC7F516FF78C44446D8D2E2CFABA526E /* GULKeychainStorage.m */; }; + 983063CD03376A95785053451C780F79 /* FIRAdditionalUserInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = E97BE04562F1B5A9A7E1E67C0AE0A3D2 /* FIRAdditionalUserInfo.m */; }; + 9830E352C83DB50348E3D0D881A325C3 /* block_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = 305D63F18BFD331E7B6F6CDBAE3A86E6 /* block_builder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9867E35C8A464F28432A045E347E6E1F /* FTreeSortedDictionaryEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 553C71FD43D0F02F1FEC498375086661 /* FTreeSortedDictionaryEnumerator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 98A2F4537B02F1D78E793955B8DBEF28 /* FTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 02EF7686404E69DBF2E3EB1866181B14 /* FTree.m */; }; + 98D2915ED1960931C77A97E81308E382 /* FIRStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 032DF10AB85867F30E7D46A814B88652 /* FIRStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 994339AA7CCBEFBED50F5BC63DCF5BA3 /* FIRVerifyClientResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = D023DA0E20514A607A76BF8E49A6BD1E /* FIRVerifyClientResponse.m */; }; + 9950B0D533276E07A93A0128E073772A /* FIRAuthRequestConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 7C81B5E725699C2DA74037AE3F016F3A /* FIRAuthRequestConfiguration.m */; }; + 997C6F4200D2C4B6D9448E2D03348CCE /* FIRDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = 405D1DB51D9EF49A3D1757A17D0FA23F /* FIRDatabase.m */; }; + 9988E4C42954BF79A32A3F4FF4F46623 /* FIRWithdrawMFAResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 648736713307A30F715716CC0D7E6610 /* FIRWithdrawMFAResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 998C42C051A9F25D40DC5655B2C22699 /* GULAppDelegateSwizzler.h in Headers */ = {isa = PBXBuildFile; fileRef = 6978362BA33830B7AD0B5DB7A2947616 /* GULAppDelegateSwizzler.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9A282E7CF0544BFD51A2B3A85DF3D497 /* FIRAuthWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 49A179A28D55D47B136047F2D340ACD9 /* FIRAuthWebView.m */; }; + 9A3768AF9A2672E527D21C02951F429F /* FIRDatabase_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = B8481B7DCD916B592B3296314358DC65 /* FIRDatabase_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9A3DF0E0712125EF260817821D6F3906 /* FBLPromise+Wrap.h in Headers */ = {isa = PBXBuildFile; fileRef = A56068F39B274E2B955D1D4B80323F59 /* FBLPromise+Wrap.h */; }; + 9A475899EBC2C5CBEC957510DC7F1D80 /* FSRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = F23127FE4B314F0651762F66488965CB /* FSRWebSocket.m */; }; + 9A6E94B1D1A2358210F733A8E496F8A0 /* FIRDatabaseReference_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2905F41AAD3BA1F44F8213EB56CF38DC /* FIRDatabaseReference_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9A94706483A056C0330BDEE4CD5BCAEE /* FIRVerifyPhoneNumberResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EA1CB32F3E439672046D86007DE8A31 /* FIRVerifyPhoneNumberResponse.m */; }; + 9B033FEB7AC385C943AA6DF22C7BC21D /* GULHeartbeatDateStorable.h in Headers */ = {isa = PBXBuildFile; fileRef = 38DE2A3494BE61EDB0B876D18D0A55E0 /* GULHeartbeatDateStorable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9B6E962EB5B8EF07974D3E49CA7136E1 /* FImmutableTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 154C7482FFED67A2563A3F0107E9E0C1 /* FImmutableTree.m */; }; + 9C2C06E8ABD475C6118E5E86CC54B713 /* FLLRBValueNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 69BC8DBB9DB5918FB6B6612E7F3B8B24 /* FLLRBValueNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9C490071CB4398966A66F174EB99002B /* FIRSendVerificationCodeResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 3839B8982A1F73C34171ED3275C50F6C /* FIRSendVerificationCodeResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9C987C18401657468C5F525822AC6A84 /* slice.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CD8E0EADF4EE6B3E91C089CE16D4F17 /* slice.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9CBAC2F3BA42653FD0A59B84C661FE42 /* APLevelDB.h in Headers */ = {isa = PBXBuildFile; fileRef = 7140D4B6712D57946886774F209BB1F6 /* APLevelDB.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9D95F0989A0963F06494FD5553237D53 /* FIRGameCenterAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 147C429D780487E0278FCBF69F77608C /* FIRGameCenterAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9DAC647A3322128CCE17A1791F69A994 /* memtable.h in Headers */ = {isa = PBXBuildFile; fileRef = 36FA3C599D68ACB54C990556F1DFB016 /* memtable.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9DAD3A85765D97A269EB2EAC99D718D7 /* FIRPhoneMultiFactorGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = EE23D8515841BDBE32E6EAC54862B5F0 /* FIRPhoneMultiFactorGenerator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9DF82C7BA9CD423B35691FD6324B8AA1 /* FIRStorageReference_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 17CA14733B2F2512D271981AC3222251 /* FIRStorageReference_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9EAEC5A0C55761EF5A63A372673A78E3 /* FIRStorageReference.m in Sources */ = {isa = PBXBuildFile; fileRef = D0925C8787A05CA82DB6EEA81561F989 /* FIRStorageReference.m */; }; + 9F76C947C77B8723023D491F27C9F0D6 /* FIRStorageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BA2D1D9C6E20FA4187ECDEB666F5808 /* FIRStorageUtils.m */; }; + 9F7F90E44AFE3A5D85810CE12C55C7CA /* FSparseSnapshotTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E03B7B8FE3DD5EF2526A5EAF9FDE1 /* FSparseSnapshotTree.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9F855716602F307970A8EF9075F89470 /* windows_logger.h in Headers */ = {isa = PBXBuildFile; fileRef = 301EA6A4343640583F1D76E4D3FDB21C /* windows_logger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A032C28EE93C9DF961E1FA7BC1F33526 /* FArraySortedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = F6AC2404030727486B0D2FBBED6A41F4 /* FArraySortedDictionary.m */; }; + A0435254199DE6EA39E2BC07447DE789 /* FIRStorageTaskSnapshot.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A824F119286E0C31278A847591BB786 /* FIRStorageTaskSnapshot.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A175967AB93B855356D5AE3D0E823868 /* GULHeartbeatDateStorageUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = BCE449A532CA88DFB2BC752B06041EC5 /* GULHeartbeatDateStorageUserDefaults.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A17B06B481158F43A12DD588A6ECF79D /* FAtomicNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 3459404751ACFD08EDD0BDFD7ED39B97 /* FAtomicNumber.m */; }; + A209431E9F65430989E16A0CAFC0814D /* FirebaseAuth-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 60AAFFD70875A35BF0E1C81AD8D50ACD /* FirebaseAuth-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A21A4177EDFA1C529D9DB22B64C0C746 /* GDTCORDirectorySizeTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EADB06838DAC9C43A23D0F1CA0C0AD1 /* GDTCORDirectorySizeTracker.m */; }; + A298FA59BD8627CE99CCFDB3C7DC25A3 /* FIRAuthAPNSToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC172B36355B2633118EA66E1485D28 /* FIRAuthAPNSToken.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A30466BAA21728774E49A960C85F7B9A /* FTreeSortedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = E6B4F302F320A7E32801438DE388BEDE /* FTreeSortedDictionary.m */; }; + A4231C94CE4FF52E27891A416233DFE1 /* FTuplePathValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 22563121E7EF6298E5CECCE8FF24294E /* FTuplePathValue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A45AC11ED4BFD423B03444A242AA1701 /* GULNetworkInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C3CFCB3EEDDF72A8350385FABE6EED2 /* GULNetworkInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A4618E1F90D7B02D624DCEAF3F627C7A /* GDTCORDirectorySizeTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 50CB80E6E0BEAE2308EE795D8EFF0E61 /* GDTCORDirectorySizeTracker.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A5AE02E69658A425C1B01230F4C8FA14 /* FIRAuthAPNSTokenManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A723A7F93D474EA6452E32D7F163FEA5 /* FIRAuthAPNSTokenManager.m */; }; + A5B26244F8DF411FE1941B6B250887A2 /* merger.cc in Sources */ = {isa = PBXBuildFile; fileRef = 24D69FACD4B23716EBCD5F309571F61A /* merger.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + A6056E88E32AD462E6BED36F9564BC30 /* FViewProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = DA37457479E7EB67EA481AD09874D1CE /* FViewProcessor.m */; }; + A61F472DE3BEB12D7C83FB9C4D6B72BB /* FBLPromise+Async.h in Headers */ = {isa = PBXBuildFile; fileRef = EAF26E5359FBEEEBFA7845231AC4195A /* FBLPromise+Async.h */; }; + A6637B7CE1805725D3E8D1A7EDA8BC2C /* FIRGameCenterAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 3541E5F8A62C143380AFE1A197B39A4C /* FIRGameCenterAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A68B6CC82203D8A16467CF424E3811A7 /* FIRAuthBackend.h in Headers */ = {isa = PBXBuildFile; fileRef = BFF584623DAE6086D9A916D16C35507D /* FIRAuthBackend.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A7363B8B2B99FAE5371CAFBE1CDF1C98 /* GULReachabilityChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 827DDBDAFAD49886E84E1065A72F70CC /* GULReachabilityChecker.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A7DF2F55597EEE231E653DA5134B45A1 /* FViewCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CCD9D69D9B4F40FDDB4FD5B8C08322 /* FViewCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A8D659AA923AF2B46E3C49BD3550BE77 /* testharness.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A77E7C65037F8961C4FAE7B34A6CB32 /* testharness.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A8D7F7255B740EE0753FA6B5C5116976 /* FBLPromise+Recover.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BFDCC2F82C100448FE007F05AC497C7 /* FBLPromise+Recover.m */; }; + A900D4217CF53FDA3F8F3D553B25F2A9 /* dumpfile.h in Headers */ = {isa = PBXBuildFile; fileRef = A13F6D7C44A5A2A6597076C8707DBA66 /* dumpfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A962CC9503BC18B8D19D8558B72742F7 /* FIRStorageObservableTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BB3746D9D29A0B4A79E4F46A7FB50BF /* FIRStorageObservableTask.m */; }; + A980B6617604CBEAEB28471F381DC146 /* FBLPromiseError.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 49529F7D99AFC203DC55C22A66EF500E /* FBLPromiseError.h */; }; + A982B39A61FF5A33A02F3D6242ED68F2 /* FBLPromise+Then.h in Headers */ = {isa = PBXBuildFile; fileRef = 64CEE3E2D4A19A53504FB2177D8059B5 /* FBLPromise+Then.h */; }; + A9A7BC87548A483EBCB078708A62D14F /* nanopb-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA0532B6963DB6C4B82B68B1AEEDAFE /* nanopb-dummy.m */; }; + A9F12F228547516954D393968C536101 /* FTupleCallbackStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 05102F03FEA97AD55CCDD5D1FB4A90E3 /* FTupleCallbackStatus.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A9F9A7D04BA928EDD35F54A6F6972460 /* FIRStartMFASignInRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2307F3C89639D9D2EE17E026359A8CB2 /* FIRStartMFASignInRequest.m */; }; + AA6A220380568BBD8AF6E5685285C8C7 /* FIRFederatedAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = F9F04272698BB7D889AA4AF0525CEC7E /* FIRFederatedAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AA7396B6A63C43B7178BB91B97C65F05 /* FRepo.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AAD55BD4ADB6669E2A7308808EDF999 /* FRepo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AA9029987BA6BD3CFC6BD3F6370E26CA /* PromisesObjC-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B07424603BC0D2D1C7EED9F0FD930D9 /* PromisesObjC-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AAA432F7101046D3317CFEBD825F04D3 /* GULSceneDelegateSwizzler_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 938BD4E24A0851466BAFC3F07E2FF33F /* GULSceneDelegateSwizzler_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AB48521AEE62CC461BAEC39B1D208CA2 /* FBLPromisePrivate.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 76BEE430E44B481CB97A3647B5104EE7 /* FBLPromisePrivate.h */; }; + AB487380FD00FCDAA86BC950F7AABF4A /* FIRDependency.h in Headers */ = {isa = PBXBuildFile; fileRef = B981E34571A9050A1158813B45ABAA57 /* FIRDependency.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AB4E9A49AD1EE8933D81C93FD442A80D /* GDTCORStorageEventSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 757945FA220DFAC917470EC142BCAC20 /* GDTCORStorageEventSelector.m */; }; + AB8234A3C959B0965FAE3C29D86DCE16 /* FViewProcessorResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B3073A4C243406F1A0F8ECB78D00C96 /* FViewProcessorResult.m */; }; + ABBAF1AF392C10314861702CFDE0C755 /* FIRLoggerLevel.h in Headers */ = {isa = PBXBuildFile; fileRef = B23BBEB7E4D6A74D7D47CE8C255EB839 /* FIRLoggerLevel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ABD508BD058D25EFFC469A55D18F3338 /* GDTCORFlatFileStorage+Promises.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C83E99C8390879BAAE9ED2AE7E505CA /* GDTCORFlatFileStorage+Promises.m */; }; + ABD53B75BFB346D62B25DAD08E896676 /* FIRFinalizeMFAEnrollmentResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = E3CB1603F1188E8F482B76E8992658CA /* FIRFinalizeMFAEnrollmentResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ABFE736014A60F960ABB80269549A344 /* FIRStorageTask_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7FE598826DA18D6CAB2AE10119075A /* FIRStorageTask_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AC2CB1EA26FFDEB7A9F152416D7E3466 /* FCachePolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 0496FD94D83CBCCC1DB7ECDDC894B162 /* FCachePolicy.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AC3EF2A397AF4C794642F1C5C8A25671 /* FTupleSetIdPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 52B93F9A3FDAF910EB354BCC66677B36 /* FTupleSetIdPath.m */; }; + ACBDC7FCC6F8600B0271A6D2ED9DCD10 /* FIRMultiFactorSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B61E1F94800DA4E1CC5D0C0EE897345 /* FIRMultiFactorSession.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ACDD46248AC4A90760036423CF1F8A56 /* FTreeNode.m in Sources */ = {isa = PBXBuildFile; fileRef = B613B172469E17F497E9203011CE9EA6 /* FTreeNode.m */; }; + ACEAFD5A113B324C7495335ADD47E09E /* FPath.h in Headers */ = {isa = PBXBuildFile; fileRef = B3AD7AA0EA6D0ACE1BE4E5D12C5F2869 /* FPath.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ACF9FE54BA2F0156346E031B4EFD50EC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + AD59610EE5CA729018A039AAEB6EED27 /* FBLPromise+Recover.h in Headers */ = {isa = PBXBuildFile; fileRef = E66BECCDBDAFF7F21FD65107CE127127 /* FBLPromise+Recover.h */; }; + AD764AB0D5391E74186C7FFD145AB61D /* FIRStorageDownloadTask.m in Sources */ = {isa = PBXBuildFile; fileRef = AC9918E2FAE139C78CDF7F9F674FFA1F /* FIRStorageDownloadTask.m */; }; + ADB42C6F214D308DEC02B4314C456BCE /* FKeyIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 1668C7B0D52CEFD7E0B83C5A403D1F50 /* FKeyIndex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AE0FE5E9ECDC9F7683BA6C708587B6F6 /* FIRVerifyPhoneNumberResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = D8BFA0DF95EDE6A4BA5277DE642A52D9 /* FIRVerifyPhoneNumberResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AEB4611A733BD69C755AEA8B9DA27DB8 /* FStringUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 870F25C34E7DB23FF55A93605E9D93D1 /* FStringUtilities.m */; }; + AEBED04183009BCB8FE00B797BAA5C10 /* FIRFinalizeMFASignInRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1527CD4FCB8B349B9F014B7A2E846416 /* FIRFinalizeMFASignInRequest.m */; }; + AEEF9EA0FF80C36AA368A47603D40E41 /* FClock.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B2E8CE344E4A43DE5471284EB56977 /* FClock.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AF1EC2D893B1469BD782FD2D9DB48A28 /* FRangedFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 98440E5E33E773D89A33711F76183D1B /* FRangedFilter.m */; }; + AF4A5F72481F3D76A53D5B1D4BA41B29 /* FIRPhoneAuthCredential_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F06531259055A8A9A7BB2EB37E8FEB6 /* FIRPhoneAuthCredential_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AF62E045B3D6B1D77B0C924A0425C7A2 /* FClock.m in Sources */ = {isa = PBXBuildFile; fileRef = AFC22D41599A2CA8D184D8CF956E77FB /* FClock.m */; }; + AFADBEBF673D850D8622C156A12E6CE3 /* FIRSignUpNewUserResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = D51B00D1359AF39D419D7B0DD5CF6526 /* FIRSignUpNewUserResponse.m */; }; + AFB8C112E07196E7F75B5DF77A71F0C0 /* crc32c.h in Headers */ = {isa = PBXBuildFile; fileRef = 088B296CBACE0AC12047F6B7A5570A89 /* crc32c.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AFFBBA38004514281DFBE8BCCDBFC499 /* pb_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 27D1CAC99D5E7E545C7793FED2EC6FAC /* pb_encode.c */; settings = {COMPILER_FLAGS = "-fno-objc-arc -fno-objc-arc"; }; }; + B02FB6DB95132E1D42F318F4E612B974 /* FIRStorageComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 711156AE176D1D7C9932201F14669A1D /* FIRStorageComponent.m */; }; + B032E00F4C4DF04F459DAE54F536B967 /* FIRVerifyPhoneNumberRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 08A9BE54D383AFB306E187521BE6F953 /* FIRVerifyPhoneNumberRequest.m */; }; + B0B39BE500B9567B25B71977881DA1EC /* FIRSecureTokenResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 4422077BBC9F62B127CFA81DA71D3004 /* FIRSecureTokenResponse.m */; }; + B0CB1B155C99B22C97F45E0ADA5D4618 /* FIROAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 89D4A7CF292E75C9E41386A232050E33 /* FIROAuthProvider.m */; }; + B1E22EFBE7A18A107CB8B080CCEF3C45 /* FOverwrite.m in Sources */ = {isa = PBXBuildFile; fileRef = A38345444096C985E3396DA12EEA60C5 /* FOverwrite.m */; }; + B23FB28D502F22ABAB8D1D89C869D1E6 /* FBLPromise+Delay.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 62B3358312776954E31DF7EED58885A5 /* FBLPromise+Delay.h */; }; + B2BC0CD6B278E9320C111E67490609EB /* FTupleTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = C3B84167E1CB948B5A68D8197312567B /* FTupleTransaction.m */; }; + B2E756461CC6A5BD2B8606CC644B265B /* GDTCORTransport_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3162E87790D20F6130A7D9273AD557D3 /* GDTCORTransport_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B31CB8B76A17C1FB22E8699181911418 /* GULNetworkMessageCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 172F05B85B5EC79590698D2BEECF63CE /* GULNetworkMessageCode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B3F50D04804292AD05F78547D620A900 /* FBLPromise+Do.h in Headers */ = {isa = PBXBuildFile; fileRef = 5AC2B509956CCDD9C8BED734854FE77A /* FBLPromise+Do.h */; }; + B46BBAAE5DA7EF5E935FECCCD06C75E2 /* options.h in Headers */ = {isa = PBXBuildFile; fileRef = B936B1C80480FC87F5447A70D6AD27EC /* options.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B49260928D40C22AAD88457E25E20AF2 /* FIRAuthDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 7EB66E7098D9785F63022238AC94D1C3 /* FIRAuthDispatcher.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B4D3E1FFD0CA59374B88AE0EC1501AF0 /* FIRSignInWithGameCenterResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 649B129D8BEEA4D78AF895FF4FB20EA9 /* FIRSignInWithGameCenterResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B4EBF2714763916DA75F6EBDFE90B519 /* FIRDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81BE1C255D9D09005E15D96253E22B /* FIRDatabase.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B546014D2EA0A30EB6773AF2DC7061AC /* FIRGitHubAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 27232BB0E72527AA10C5843D2372057F /* FIRGitHubAuthProvider.m */; }; + B61D69DCFAD6E8012B0579E17504C8DD /* FTreeSortedDictionaryEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B3B105917EE8719FEB00E3C8D4DFA56 /* FTreeSortedDictionaryEnumerator.m */; }; + B622904A4E718D7597D72C8BEC372E82 /* FStringUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 78DB71C20DCE241E1C54F53EFAC77530 /* FStringUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B63B5F33C0685A724FBC3AD8E23506CC /* GDTCOREndpoints.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A665156BBF095A8DAE862B03D76D49E /* GDTCOREndpoints.m */; }; + B66E7B15E38E793C6549E94508D919BB /* FNodeFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B53883A091A5CB2C1CF6564AF14CE4B /* FNodeFilter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B6771332A6FC860E5EE45C46992E5200 /* FIRAuthRPCRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 68D36AB3BDFAE5C55B9C8F45A1A5CEBE /* FIRAuthRPCRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B6E11C1ABF52EE75E6ED6912FCF2E0C0 /* GULLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 876CF2F8FB95158F946B9DEA3869F659 /* GULLogger.m */; }; + B6F992FC08FB0ED6273F7B46068D759D /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 330336A17C4F23BA8D30F48A6BD38303 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B72F55435B9C6CB06083E13D6665F40A /* FTupleRemovedQueriesEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = FD44137A3A06146041EBB23278EDC30D /* FTupleRemovedQueriesEvents.m */; }; + B7C45D6E0E1EB8D02E3B775C47EB2BEE /* FIRAuthErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A9BE2440239D2864323211F1A7436E5 /* FIRAuthErrors.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B7DC9F344D21854AAB027B5AAE167C69 /* FViewProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D845130CEB654D57DB488C212CDA7DF /* FViewProcessor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B885B226B693B0E4EE91BE442B1F1F64 /* FBLPromise+Timeout.h in Headers */ = {isa = PBXBuildFile; fileRef = E2DCA620D3D076030DA2B13428F8DEA0 /* FBLPromise+Timeout.h */; }; + B89AC9425E84B0E196D73C0B9F7B37B4 /* FIRStorageTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D5503EED647D08F5A54F1B20F33761C /* FIRStorageTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8D1B1A447AC953BF707719698BE4F24 /* FBLPromise+Any.m in Sources */ = {isa = PBXBuildFile; fileRef = 5607EBC07C127505AD967D102AE1952C /* FBLPromise+Any.m */; }; + B8FB2090DCAE05BE7C3F7A2930F34C34 /* GULAppEnvironmentUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 30F3F1287E0C40F9E4C1D4DDD5807784 /* GULAppEnvironmentUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B988F8276ED672315FFAE905F52BF82B /* FIRGetOOBConfirmationCodeRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E0500670DA9C6B6BB264619E4475ED6 /* FIRGetOOBConfirmationCodeRequest.m */; }; + B9C2451354D749B3A325F6118C8993B6 /* GULKeychainUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 132E0228BE7AC8D19E9CF7E085EE282D /* GULKeychainUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BA5EF3BD647DEB3661D6E3116A574FCD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + BA65ACA1F5302B5BDD840CF54AE66381 /* FIRTwitterAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = C2EC8C6C780C5860481702B4A1E37E4B /* FIRTwitterAuthCredential.m */; }; + BA7A212B29E1823D0C8197CC961A21F8 /* GDTCCTCompressionHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = DC734172FD9BB1B7FA869203F23EC521 /* GDTCCTCompressionHelper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BAB6B2212BFB6894F97DD45C157F82EC /* FIRStorageGetDownloadURLTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F00695EF92C4DF50D63567271334E34 /* FIRStorageGetDownloadURLTask.m */; }; + BAC83030415DB61C8F2A72D3275FD0A2 /* FIRSetAccountInfoRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 16BF111B8E55C4502E51954BA7333CCF /* FIRSetAccountInfoRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BB2B28EC729D847F2799663DC2D607E2 /* FIRAuthExceptionUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 22A27923B3B28E3BBE217714A2394B13 /* FIRAuthExceptionUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BB6C989703542377BA56A5B8659C7C95 /* FBLPromise+Race.m in Sources */ = {isa = PBXBuildFile; fileRef = 63546985BB72619AA1BD5BF3034999D8 /* FBLPromise+Race.m */; }; + BB9FF975D160432407D7AB68F140FE9B /* FIRAnalyticsConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 60308EFBF8231E4B777992DB527F71E9 /* FIRAnalyticsConfiguration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BBCFF4694A34B0BC29020592E3C5E91A /* FBLPromise+All.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DEBB1A11CC1186F9865672E1A758722 /* FBLPromise+All.m */; }; + BC14302FF04BFD07C8B67121AC2B029E /* GDTCORRegistrar.m in Sources */ = {isa = PBXBuildFile; fileRef = D26AF22ECA5F16578D950CF2E197D91C /* GDTCORRegistrar.m */; }; + BC375D294E17AA52FAF84BEADB8EE59C /* FIRCoreDiagnosticsInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 453E14DB73F09FBD36D1DB25E717FB5C /* FIRCoreDiagnosticsInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BC4C03A39AC31AD6FBA78B7A67C27323 /* FIRAuthDefaultUIDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 46DA95FEB78C1157595667E76D6B019A /* FIRAuthDefaultUIDelegate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BC62E8C20DB20E06D369EBE8CB5EABD3 /* FMaxNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 656498BDC1CD14E38CB662D4FC560689 /* FMaxNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BCB7DA75FCCCCCF265BDC85802F1BD7F /* FIRStorageUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C1CC4F20E09860CA4DC1D7D915C1D73 /* FIRStorageUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BCBDBBE502C6F0BB4E0460BBA12FAF36 /* FLeafNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C351DF20BBDB7C2D3D122CDE9CECB69 /* FLeafNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BCC14122E551CCC35044E9556D8EFEA7 /* FTree.h in Headers */ = {isa = PBXBuildFile; fileRef = A13E5ECB9FF3870B0D27C2277B9EEF55 /* FTree.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BCCB46EB32A9E24902524A998C4B5584 /* FIRAnalyticsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E25132C2CD03254F7E2A6E3C4F929F7 /* FIRAnalyticsConfiguration.m */; }; + BD305E0759965D608D0E31B92349F585 /* FTrackedQueryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E35E50F5AA58D33E3A9E5B16C83258F2 /* FTrackedQueryManager.m */; }; + BD7D262468B0C6C4E0AD0C6E8D0A9D39 /* FViewCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CCC54EEE3F4DC8C1F48E8CBA72E1888 /* FViewCache.m */; }; + BDE8C2DE7F3E69FABD65269D3C05F3EF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + BEA2F4D80157029982D56B9393BF8473 /* GDTCORClock.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A0B3E5EA3F8111247486DB742BB6DB7 /* GDTCORClock.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BF071C51C6DDC89D5C83A4CBBFF6E7BA /* FChildEventRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = D5E1524A0256E64E49CDA88A4D9F15F0 /* FChildEventRegistration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BF1740ADD46742AD919219C6F7871B64 /* FBLPromise+Testing.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E340A1BB7B1090345005734CE131B8D /* FBLPromise+Testing.h */; }; + BF28E6C7CA2213275AD07A5004BFC80F /* FIRUserMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 983164803595694315F7F6A1821F52FB /* FIRUserMetadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BF83BAC1BCD21156C30C7C08EFFA2C42 /* FIRVerifyAssertionRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = C57780199E3F445CA56E1EF2ADA32EB1 /* FIRVerifyAssertionRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BFB28739975EBEE8A1746207CCF23A05 /* GDTCORTargets.h in Headers */ = {isa = PBXBuildFile; fileRef = 090C4DF6889DD5CE158AF416BFE28E37 /* GDTCORTargets.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BFED5C657A0082C3174DEC1019124B57 /* FBLPromise+Testing.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 5E340A1BB7B1090345005734CE131B8D /* FBLPromise+Testing.h */; }; + C07C128E45C881057605D65DE7B3C7B8 /* histogram.cc in Sources */ = {isa = PBXBuildFile; fileRef = 98624617DE7BFE80191230F4C3EA8C8F /* histogram.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C0E00E871F12EE2A24BF42E0E8DEDCD4 /* FIRAuthDataResult_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 393EC1FCE7664B19AE80AF8CAFF77554 /* FIRAuthDataResult_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C0EB9A1236CDA0B8873DB61249666620 /* NSURLSession+GULPromises.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E69939A365088C66AD857717FF633A8 /* NSURLSession+GULPromises.m */; }; + C102B48CF761B1706D9566805FD656B2 /* FLLRBEmptyNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F249B6371F8719C64CA57FC11118CC4 /* FLLRBEmptyNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C134C09ACCA380020449862BDE7A0027 /* c.cc in Sources */ = {isa = PBXBuildFile; fileRef = 33DB693963458E6D16D408C4E387BBA6 /* c.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C15048B150D27AC9A2911992961F0D19 /* FIndexedFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = A5921FBD031DE0BA0224527B5D044FCF /* FIndexedFilter.m */; }; + C20F33C7CCC33D585B948D3CD5FCCD14 /* thread_annotations.h in Headers */ = {isa = PBXBuildFile; fileRef = 74E042EA7A7F096AF1B67AA3C772EBF5 /* thread_annotations.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C24C75C71AC1DAB2432F95E03EE82863 /* FIRResetPasswordResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D36F7FBE8A5B0A49ADB656C0A724B5D /* FIRResetPasswordResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C290897AE33B258A9108AE01766F9B1F /* FIRAuthNotificationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BD97CC4A3A756852B6EDC695CC98557 /* FIRAuthNotificationManager.m */; }; + C2942C7F216D4AA42ACFACB52AA86464 /* FIRAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = C2DCA7FCB2F1AA7E5182524022DDFAC9 /* FIRAuth.m */; }; + C3882C73D5566E24F1F6272E0D22BCFF /* version_set.h in Headers */ = {isa = PBXBuildFile; fileRef = B291863611DA98B373B9B2EB0CD48177 /* version_set.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C3AC3E4E5967BACA1EEEE37CB9F52C59 /* FIRAuthProtoMFAEnrollment.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D5A80CA37F8BD29B4EAF0D339F38F7 /* FIRAuthProtoMFAEnrollment.m */; }; + C3FBE3E8B32D8563D2BA5755EE507762 /* FIRStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 765D98B1AC54CE64FBC591B6AFCC533E /* FIRStorage.m */; }; + C40A24EC73BA5696B23A9EE559F2EBAD /* FBLPromise+Do.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F64C372A6E12EF616E2930965FB8336 /* FBLPromise+Do.m */; }; + C416FFC65F0BA38BF7B7044352F0AC33 /* FIRSignInWithGameCenterRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A4F9E7A0915ED7FBEC30A8F71AD07C5 /* FIRSignInWithGameCenterRequest.m */; }; + C418761AEB68F5EC72E5DDDF109470CB /* GDTCCTNanopbHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = FC3008FE520DAA1E2912594F5C522BFC /* GDTCCTNanopbHelpers.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C525285F2BAFE7FF68FA51BECC0B234A /* FListenProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = FD2E6D7850FD2B0697176C4A6261522A /* FListenProvider.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C53BD5B9468D548C9F321DB406A2AAD3 /* GULNetworkURLSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 531AD53C3115F7F7EB5D782FD9813823 /* GULNetworkURLSession.m */; }; + C544C2B25329C18043D7AECF1DF694D2 /* FIRStorageErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A1FF88AB4CE2399AC22479042C14C0 /* FIRStorageErrors.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C55B5EF82F094F12A583069B9EBA9B70 /* NSData+SRB64Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 2422BB9F3FEE8E73CD7604E104FB6565 /* NSData+SRB64Additions.m */; }; + C58878BE15065DD13399FFC43BBF9190 /* GULHeartbeatDateStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = B8032A0DB492656E1C113353FB6D43DE /* GULHeartbeatDateStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C6834D2615A8F126B9213F90852AFB08 /* GULKeychainStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = E24707A940249750B09DC979B64197AB /* GULKeychainStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C6E58F6D8D0E4AEE8D9F085A1A50178F /* histogram.h in Headers */ = {isa = PBXBuildFile; fileRef = E20F0CE3E9E3B51A9C596A24A248E86A /* histogram.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C7014B9B704B62751CB17B9A92036CE7 /* filter_block.cc in Sources */ = {isa = PBXBuildFile; fileRef = 895057CB8373A1993247A9B6D4D8115C /* filter_block.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C7153BF71E3F492E3C70F66CE9703ACC /* FIRVerifyClientRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 53E41845656DD3E593FDD4F6F3339B32 /* FIRVerifyClientRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C730C445099A2487F6757A413534B5AE /* table_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = E573656466A4A2CCC24C84FC97BBCE87 /* table_builder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C73612CBD6B206416D4610074A8919F9 /* GULNetworkConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D828B5EF58C384892390572BC508C4 /* GULNetworkConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C7CD10F59FD55CF5279D11DADB5E1E27 /* FIRStorageUpdateMetadataTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AE9920117FF484590C20A61903F5796 /* FIRStorageUpdateMetadataTask.m */; }; + C88BA30F71DD393322BAD9563C5B6340 /* FirebaseCoreDiagnostics-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0C566769D33EBA1455071400D6E307 /* FirebaseCoreDiagnostics-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C8BCABB8A2D71683AC3A7B9E3EEE3DB7 /* FKeyIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 653F3E17804F6B21D223272C94E3141E /* FKeyIndex.m */; }; + C8E1E5A7D28FE6F8395FDD6872EDD268 /* FIRAuthProtoStartMFAPhoneResponseInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D9BB15B65A8F9774E2C2D7FA9C5A52 /* FIRAuthProtoStartMFAPhoneResponseInfo.m */; }; + C93FF0CD7824C73523BF9D0317A0E4B6 /* write_batch.cc in Sources */ = {isa = PBXBuildFile; fileRef = 949794C45F737460830D38D5C890CD72 /* write_batch.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C9402F165499D55858F5C915929A4AC0 /* FListenProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 658D0800BC15A31285C173FA8D9CB733 /* FListenProvider.m */; }; + C950A66489D14C17FB5E9A46229F2935 /* GULNetworkConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB8FBCE6B02585240FAEBCEF664AFEF /* GULNetworkConstants.m */; }; + C99CCBBF389F215B44BFEB1747F41FE3 /* FIRVerifyAssertionResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = DD426E865FC8F06B2B303FB46EDD4415 /* FIRVerifyAssertionResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CA72344D2EDA5DB6077582CC8BC03782 /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 923643A2605DC868E971C64C0BF28726 /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; + CA826459C93EC48AE5582E8BFD65109D /* env_posix_test_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 035DB386647B61CA504DED882F157E0E /* env_posix_test_helper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CACEA5D18E4B9D0FDE6AEBAC1288BAA3 /* GULNSData+zlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A884E90C80E2A19BF969865E5AFB5AC /* GULNSData+zlib.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CAD1D04F06D5BF83530988BD89042E11 /* port_stdcxx.h in Headers */ = {isa = PBXBuildFile; fileRef = E839F6DD585A7A414970E839F31D2E7D /* port_stdcxx.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CB415C77247CFD4E364CD24C16958F0D /* hash.h in Headers */ = {isa = PBXBuildFile; fileRef = E71462E7A638DD8650951BF1796855AB /* hash.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CB50B470D6EBE84A11C92E3280C0436C /* FLLRBEmptyNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 33CEE7A426306395DC3DC59B63FD36AB /* FLLRBEmptyNode.m */; }; + CBDA17A4CDF98B881ECA098998AF1748 /* GULNetworkLoggerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = E5E00737AB979B86E4AF9B01699CDFF3 /* GULNetworkLoggerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CC2CFD1D05BC58D5D8FB0A3681ADFFD4 /* filename.h in Headers */ = {isa = PBXBuildFile; fileRef = FABDF831904EB454A599B7FFBF8ABE65 /* filename.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CC8296CE73D7B0B4A0C5F339AEC0F21F /* GDTCOREvent+GDTCCTSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F669B599B173989CB4B85439CACA8B /* GDTCOREvent+GDTCCTSupport.m */; }; + CD088DBB485A8B3A5596B476CDF32EB3 /* FViewProcessorResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 70252C7F4F088EF4BFE7BC92EA6FB86D /* FViewProcessorResult.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CD210BBFAEEB890616D971AED87950BF /* FIROptionsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 693831C5F92916966D1C6D6E899EB871 /* FIROptionsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CD7844100B03C3662B63E3ACA3AF355A /* FIRGetAccountInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 24166623AEBAC71E3A602781955498B7 /* FIRGetAccountInfoResponse.m */; }; + CD79651074CA9C1C344D7FD6B744D183 /* FMerge.h in Headers */ = {isa = PBXBuildFile; fileRef = 476FDE8C0ED7BDCEDFCF04830CE7F6D9 /* FMerge.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CDAC97BF51759B8CE575D84AF040B480 /* iterator_wrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = EA5CDBD4BB26A7AE9E17E18093DD93DD /* iterator_wrapper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CE16ACD45316BE13DC49A139E0C22348 /* skiplist.h in Headers */ = {isa = PBXBuildFile; fileRef = CE5BA5A1C569D1F8BED18C2C5EC763C1 /* skiplist.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CEAF992BEDADDBA5FFC72B74BB08AC15 /* FIRAuthSerialTaskQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 493F18C6B603AF3ADDFD8FB37F07FEC3 /* FIRAuthSerialTaskQueue.m */; }; + CEE667501017D637317753CBEEC3FB5A /* FIRStorageConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE9BAEEBABE76B47CF2BD6325FC5602 /* FIRStorageConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CF2AD4472ACC9EC61D962CC6B6265DD5 /* FBLPromise+Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = FE92A8ADFFB2CD95AFE36381C008D8F2 /* FBLPromise+Testing.m */; }; + CF3B4720A3C872F0AF839839BA3F82E8 /* FBLPromise+Catch.h in Headers */ = {isa = PBXBuildFile; fileRef = EDC4641849E572F5723A6A116D0352EB /* FBLPromise+Catch.h */; }; + CF9359A9819113A07B6258E3DFDE0780 /* FBLPromiseError.m in Sources */ = {isa = PBXBuildFile; fileRef = 99F0C019D3C879F3942E5D425FAEB1A4 /* FBLPromiseError.m */; }; + CFB23CC4B1823197B18A2ECC2CD31393 /* FIRTwitterAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = C49ED58E11F92CAF3C06EC8A74B9BC36 /* FIRTwitterAuthProvider.m */; }; + D031957FCE83D94F33D8D37815702565 /* FIRAuthAPNSTokenManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 33B64A8F94A6603E23D737D56A9EFAC2 /* FIRAuthAPNSTokenManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D059406F02D5BEB2BD9E08AF105CB626 /* FIRGameCenterAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 896724F78E9E336F7C61BAA5D7FDA1C1 /* FIRGameCenterAuthCredential.m */; }; + D0933029DF3B4C4D162A112AFE46DFF3 /* random.h in Headers */ = {isa = PBXBuildFile; fileRef = CF352B6F70E09752E60EF9E4B1A9FDD3 /* random.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D0B3526CF455B9D4413E7B36CABA0C39 /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D84B1B010E37FBC800DEA3F33B0C3B9 /* FIRComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D0BCD49FF240ED8289440F635CD424C1 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B3125D500C1F70AC85CA5401A1F25E6A /* Security.framework */; }; + D0D624770FBC61B098ADCBF66B8AEA3D /* FIRGitHubAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 01BFBDF82820583C2FB719EBC08FF100 /* FIRGitHubAuthCredential.m */; }; + D177E0DDD59B390EB73E0D6E18279DFF /* FIRGetProjectConfigResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = B1E900E5749E319AC8DD9C2AA0A26B7A /* FIRGetProjectConfigResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D1986F0BBE69E4BFE273DBF515E54786 /* FLevelDBStorageEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = C532F2EFDCFDAA9E763A5DAB92A56843 /* FLevelDBStorageEngine.m */; }; + D1D230A0D628080378C66C2C2F044AAC /* FIRAuthProtoMFAEnrollment.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EAA9F352B333A6C73F732D89352E248 /* FIRAuthProtoMFAEnrollment.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D1ED8FFED3E8D3E7808F85AC5AB07397 /* arena.h in Headers */ = {isa = PBXBuildFile; fileRef = 288E61A06D7AA62E0EC62D1A11CE0FEA /* arena.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D2AC8A997825E8AE897EED8EF1EA1164 /* dbformat.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B9919D2A47D4A51AA0F110EA67FACAB /* dbformat.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D2AE1D75C11C565C8DD366CC7733E668 /* FIRStorageTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 77994AF3EB2E00C13B79A21F6BCF9CBE /* FIRStorageTask.m */; }; + D32D19A4DCDEE3E3C0E64880A091B011 /* FBLPromise+Then.m in Sources */ = {isa = PBXBuildFile; fileRef = D605890E41506261712FA9D98D2E022D /* FBLPromise+Then.m */; }; + D33386E098005F5A61553F8274B2A5EE /* FIRCreateAuthURIRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = EF6A924BD6D1FE28BB9EEFD69CAE7638 /* FIRCreateAuthURIRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D3B7D0731E8F8449D4E19F62FF712313 /* write_batch.h in Headers */ = {isa = PBXBuildFile; fileRef = 3955A3844EE1F657DC3F3734E0E90A45 /* write_batch.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D3C82A51CC1481C9C0C4D0186733797D /* FIRVerifyClientRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 887930CE266A149A0909951039008F18 /* FIRVerifyClientRequest.m */; }; + D4BC3EA08275D757E3BDCF11318112E8 /* GDTCORConsoleLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EB0CDD50EC9532DC424B2BE44B2FE29 /* GDTCORConsoleLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D4C5D302824251B2B21AE98658F328C0 /* FBLPromise.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ABAB0517BE907A3D48AA8FAC13726E3 /* FBLPromise.m */; }; + D4FB0D111E3FCD4CC9DF4C2B5CD03885 /* FIRDependency.m in Sources */ = {isa = PBXBuildFile; fileRef = 7381E483AC0125ADF1E57858686F50A4 /* FIRDependency.m */; }; + D51D33E2C449E5ECE30337BEF4A20739 /* FIRGoogleAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 89F007636FBF9CE37E8E53001CC953CF /* FIRGoogleAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D5B6B157E13AA27ADB87E34A3339E67D /* FView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AA3FC4AAA0E5EBF67505C5E0EA20BCB /* FView.m */; }; + D5C16683C91904C6C571736F1E4DBCC5 /* FIRCoreDiagnosticsData.h in Headers */ = {isa = PBXBuildFile; fileRef = 4266E39FA9DD1D55C7E5F79F7F3BCEE6 /* FIRCoreDiagnosticsData.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D5FFA49A70CE9337ECB5F4CE91D59065 /* FCancelEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = ABA74436D35D18B787BA88238D23AF32 /* FCancelEvent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D61708EBC2CE36A7083910134C74D83E /* FIRSendVerificationCodeRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 22C0B9849699E858234B44466DE39EC9 /* FIRSendVerificationCodeRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D61B73C38B18C79EACE64318FDE63055 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + D61C497480BD1BC00C0AAB970049A9F4 /* GDTCOREvent_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = B4FF56EBCE0455EE942F1411CAD7E3B4 /* GDTCOREvent_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D64E86413E22E49040D5B01142065FBB /* FIRAuthCredential_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B55A91D7EFF5E8B052CBC046587F562 /* FIRAuthCredential_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D6A103007C2AB29EAC8101085D4F81E1 /* FIRStorageGetDownloadURLTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E7374CA2BAFFE4EC6CCE7724CF719C /* FIRStorageGetDownloadURLTask.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D6DD92622533BA664AF231CABBFECC6B /* FIRStorageListResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 408EE725ADF5418AEB303B645FEFECE1 /* FIRStorageListResult.m */; }; + D6FF6BF5F8218696F0A74D6377691F63 /* FIRHeartbeatInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E6A08E5885D93950E50FCD40CF9F022 /* FIRHeartbeatInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D7100BF0D1835C402E4DFFB82DAEF21F /* FNamedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 859B86587165B2DCC9980C52B661009A /* FNamedNode.m */; }; + D7B239A33F49499F91052059EEE0DB61 /* FEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = F94E060978237A794872573025EA4BAA /* FEventEmitter.m */; }; + D8220CF3253C9D0B3B3A47CEF7A4AC3A /* FEventRaiser.m in Sources */ = {isa = PBXBuildFile; fileRef = E1EA944496A2573E7E46DDFBCACDB6C7 /* FEventRaiser.m */; }; + D82CC806256F9A36104BA01C5EFCAB8E /* GULNetworkURLSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D5D02FA20F7768EBC412798CA562E0F /* GULNetworkURLSession.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D8A9620AD633A6ABDFE8515D7C51FDFF /* FIROAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = BA0C130C5AD4E78EF53F155ED1EEBDC5 /* FIROAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D906AB3695DB3EEDD49AD7FCB873D2E3 /* FIRAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C9AFD1F65D89843CF8C273F7BDCA6F7 /* FIRAuth.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D92144BBA6B27D4767881FFB77AC81F1 /* FIRPhoneMultiFactorInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = E89944D89A09B02235F24FCB467AB808 /* FIRPhoneMultiFactorInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D988B762510FBF565BE6F6196DCA7908 /* FTransformedEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 1370B793664C2C3E3CE6DDC3053F7618 /* FTransformedEnumerator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DA8FB749210D21FFC114D2742EF9F937 /* status.h in Headers */ = {isa = PBXBuildFile; fileRef = 76C2FA149D8C26F195DE9762321A1920 /* status.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DA9D9277224DB2B1842CB36671C1B652 /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = CFA9A98B0E39FA0EEA43D511B134FC95 /* FIRComponentType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DAACE24070F232857EB6CD2969FD2485 /* GDTCCTUploader.h in Headers */ = {isa = PBXBuildFile; fileRef = A5760DF131877B2B89137DEBFEF1A3C1 /* GDTCCTUploader.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DABA54962787244E9B239EFF0C9FA7CF /* FIRAuthUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F7C5E48CD0159B1D1C694CE8FEBCC3E /* FIRAuthUserDefaults.m */; }; + DB07070680E837F75151B85E667F2A80 /* FIRCreateAuthURIResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F46401767E51CCF943E45AC97804AFD /* FIRCreateAuthURIResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DB2C57B40DE78EFA9D39CD99B54B21F4 /* FIRVerifyPhoneNumberRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 334F251C2F070D6DB3EB649734DB97B4 /* FIRVerifyPhoneNumberRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DB4E927F6600C2D39A6D66933588496F /* FIRUserInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 39A02C6A98117D425B34FD66D0FE409D /* FIRUserInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DBA1765E03F6D0686D5F2B6BD6D1C9C1 /* FIRDeleteAccountRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 883F3061318EB3429FEE92B8E6EF94D5 /* FIRDeleteAccountRequest.m */; }; + DBA96093F6297C3EBAA4039933CE6160 /* FIRAdditionalUserInfo_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D26DFB51D254693004507B17D7B737 /* FIRAdditionalUserInfo_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DBB0561A746EFF3AFC734E061D0AC32C /* FPersistentConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = F0C3D851DBEE7696D21526FF5443A526 /* FPersistentConnection.m */; }; + DC9B237AFA813047F87DB936973435FE /* FPathIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 097A3DBCD1FEDB6F15FC566B8F6EBB4D /* FPathIndex.m */; }; + DCD352BF594C668193B293354AA4B5AC /* FConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C30D81E6407995A697635D198C8DDDF /* FConnection.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DD52C95627433F57E34DEDE919094B61 /* FBLPromise+Await.h in Headers */ = {isa = PBXBuildFile; fileRef = A3B520AC90F216E89C6A144E34C7B728 /* FBLPromise+Await.h */; }; + DDCD533E1D00FFFEBE01D45415ED1E8B /* FIRResetPasswordRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 046A1A8B23BD286D6422499C9BC42BC5 /* FIRResetPasswordRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DDCE00601F5E710E85D7A6C9CF863D06 /* FPriorityIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EBBD605D3354FDA906B9F9C13C7F23 /* FPriorityIndex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DE1288E9B67BADB1CEA4C4AEC4E971EC /* GTMSessionFetcherService.h in Headers */ = {isa = PBXBuildFile; fileRef = 81117FB9C9B2BBBD3119E04D9F265A56 /* GTMSessionFetcherService.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DE6619D3FC39F975C2B469A346872302 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + DEF75A559FA8171C4661C1ABF27387C6 /* GULAppDelegateSwizzler.m in Sources */ = {isa = PBXBuildFile; fileRef = 91F8FFEB623B614F5EDF8885F5E8C780 /* GULAppDelegateSwizzler.m */; }; + DF1C0C13094591C04536CC2881E673B4 /* FTuplePathValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 96C114DA8C3BF81BDD0DE26B97B6754A /* FTuplePathValue.m */; }; + DF2F9FEB4F4019602C85B9DA0CDEEC64 /* FRangeMerge.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C5B7637C35100D4E00B41FB959B5377 /* FRangeMerge.m */; }; + DF5BD1E9663A16B3F87DF6AAEBF6A8D9 /* FIRCoreDiagnostics.m in Sources */ = {isa = PBXBuildFile; fileRef = 70C8399F3F73FA8401A82FF892984E39 /* FIRCoreDiagnostics.m */; }; + DF69EACB95BF1F1ABB752B5CE347D2BE /* GDTCORFlatFileStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 68045793108BA0560D877E755265EF7B /* GDTCORFlatFileStorage.m */; }; + DF80641143FD2B4E0B73B5488BF70E8A /* FIRVerifyPasswordResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E783914DD89D8CE4F5851BF32F1F3AD /* FIRVerifyPasswordResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E055EA1332DC10E277EA2CA3F5F05D2E /* FTypedefs_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E9B301EABBEF76F916373F59140BDB7 /* FTypedefs_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E065D09B532FC0101947B7995808A409 /* FChildEventRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = D5A4E78107B016AF69DC439FF2711A08 /* FChildEventRegistration.m */; }; + E083913AA645AA88506806BF99854FB6 /* FIREmailAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 59038A4766E4CC1722C7B60EEC4B33B7 /* FIREmailAuthProvider.m */; }; + E08E50B62AAC152B2F6A294CF8457D8B /* FBLPromise+Catch.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = EDC4641849E572F5723A6A116D0352EB /* FBLPromise+Catch.h */; }; + E11ED6EE81AD639DAA965CB3BE20B446 /* FirebaseCore-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = AA9244E063FD307DF5A1C224EFF32D86 /* FirebaseCore-dummy.m */; }; + E16954B672CF8317F31A5D91D9D3C565 /* FPersistenceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B305CFA4A65CC751131EB86AA4DB3ED7 /* FPersistenceManager.m */; }; + E18DFABCF8FCF7E7903EDB94CDE350FB /* FOverwrite.h in Headers */ = {isa = PBXBuildFile; fileRef = 4355106D4E229F6C43EFA4F9DCF22898 /* FOverwrite.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E192AAE3C2E9C093F032A3C97B3EAD5D /* FWriteRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C7BF91AA178CDB48E76323D48504F27 /* FWriteRecord.m */; }; + E1E26E23A30A3592F8710792945C6B4B /* FIRStorageListResult_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DF7510634B456A9A5EB9BB8C7D93BEE9 /* FIRStorageListResult_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E232D23ECC2F1C664A6E2A6727FB369F /* FIRStorageMetadata_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 563A9C1C12ED779F8A95FBF46C9A61B9 /* FIRStorageMetadata_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E25CB13A772897B1185B8C1AE0D6DFF2 /* FIRAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = BBAF527ADC6259102C1FC8064BB26450 /* FIRAuthCredential.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E2806B51DBD95AC52C85D27E8FC92974 /* memtable.cc in Sources */ = {isa = PBXBuildFile; fileRef = 55306428FD4A4CD23EE65BE697D86C37 /* memtable.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + E2AE6DDEC4BD3DC6C1FC6E80D179C236 /* FIROAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 932BDA2F912838F24A80D4B9D69D594B /* FIROAuthCredential.m */; }; + E2F18677E67B604C0777E83C0C5C478D /* FIRStorageComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 75EAD854551E311C33A9678D3417E4B3 /* FIRStorageComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E34BD8F0410576B6F7B3947447474943 /* FIRPhoneMultiFactorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = F567C2F9688D82CA1EBA475DB0D1A069 /* FIRPhoneMultiFactorInfo.m */; }; + E374EC108F866C2E59DFDC69AC76D352 /* FWriteTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F44676D510C821AA4FCBEB2EDC7C1A9 /* FWriteTree.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E3908B4FB5DC3976FDF132C9A2B7C4B8 /* FIRAuthKeychainServices.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C3364F87A61B16B7B80534FF7547C6 /* FIRAuthKeychainServices.m */; }; + E3C4DB21732FACFEF57CFAB786696223 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A978F386557998E5D34EB6BB8A499A13 /* SystemConfiguration.framework */; }; + E43DF6F8DE107CCEF4B6CC66DD731794 /* NSURLSession+GULPromises.h in Headers */ = {isa = PBXBuildFile; fileRef = B81795EFF3756C6009403EB7B9A9868C /* NSURLSession+GULPromises.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E5263593CD4CBEF49D2CAFCAC3CDE6F9 /* FIRMultiFactorResolver+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2B3391E6BB1E5093C9FD919D7CF549 /* FIRMultiFactorResolver+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E5BBF211DB1D35E120279AF32B411374 /* FEventGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C9AF37FA21020C49EB931FE36D6FBD5 /* FEventGenerator.m */; }; + E5E9E6CCAA1C59C1E1A78C96A8E69404 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A978F386557998E5D34EB6BB8A499A13 /* SystemConfiguration.framework */; }; + E6120B2B605040F43A888737A69188BE /* FIRDatabaseQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = E3D37CD5FB23804B82EB8F6D3DA8919A /* FIRDatabaseQuery.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E66621BE38D05EB8E972C7F230CB475B /* FIRAppCheckInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 017EFF960BB5DB0C88DEA74292152B14 /* FIRAppCheckInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E6A4EF24DA64A4DAFE707341ACF1A4EE /* FIRStorageTaskSnapshot_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 340A99536CB0153ECB0A771942C373CE /* FIRStorageTaskSnapshot_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E6A967ACA9DA5AD23C8AE3338F0C9086 /* FIRStorageGetDownloadURLTask_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CC991F7C85A64C9B896F9778873BE2 /* FIRStorageGetDownloadURLTask_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E74F94588B8C7F5B7AB3986D7ABC96E4 /* FTransformedEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 41BE35522F50B182192D5DC520C3216C /* FTransformedEnumerator.m */; }; + E75FA822B3BF50E4A0FBB8D61E4333E2 /* GULAppDelegateSwizzler_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 13FE74E1B86265EF9348F21E3F3E09D9 /* GULAppDelegateSwizzler_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E76C5D45261CCB5439F7F863F5F7CD04 /* FIRComponentContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BD69D14E151B50FC47885567CC1F00A /* FIRComponentContainer.m */; }; + E7BE3488F8FC2E0281CC39C7F83E2E62 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + E879D9A07D20613BE2289126ECDBBF3B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + E8E9459994F1D1F8679202672ECF412C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 900BF383BC85BE28DB45649BAB939A60 /* UIKit.framework */; }; + E9D78DB10436001DC5906559BDA7345D /* version_set.cc in Sources */ = {isa = PBXBuildFile; fileRef = EA02B385FB2B4B2B9E246CA24BD2EF26 /* version_set.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + E9F86F2E14D4C9C645FBCB3ECCB64C57 /* FStorageEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 6AF3DE1BF05C1C5CC8171AF15BF8E4AC /* FStorageEngine.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EA41CD95E22020D58A4C5FCF022FC174 /* GULSceneDelegateSwizzler.m in Sources */ = {isa = PBXBuildFile; fileRef = D938E13F6F589C189B60C4CA4465EB1D /* GULSceneDelegateSwizzler.m */; }; + EAE37CF4772BAFD674FAEFEC92CB00F6 /* GDTCORTransport.m in Sources */ = {isa = PBXBuildFile; fileRef = F5089FA76BD0882F080BDA39DD2EDED3 /* GDTCORTransport.m */; }; + EB71967B8DFC8099E0B414067D99A0FD /* GULLoggerCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 43F82C12F24B532F8411A78ACE0EAC72 /* GULLoggerCodes.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EBCBFBBCD3C06237EA6012DF9EB06182 /* block_builder.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8242A9A4631DC19F5D16EA6821C81ACE /* block_builder.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + ED48733738C7B0E42B7BEF11BDA94641 /* FWebSocketConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 90CAAB7C291E0685B9F1381EE7D4BFE7 /* FWebSocketConnection.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EDAA92E3A8D3731C13A0C2743909267D /* FIRFinalizeMFAEnrollmentResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8797BE5BA0ED09CCC332EA884D1440E0 /* FIRFinalizeMFAEnrollmentResponse.m */; }; + EE524090F6836405CDED5B68AE70CD18 /* FLevelDBStorageEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = FC88E5BA67478422684CEA9786F3440D /* FLevelDBStorageEngine.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EE7F44F0BB5BE6ABFDC653436231FE6E /* FPersistentConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = E1B4086F8CC23FC6345F410D5A962EE8 /* FPersistentConnection.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EF1F810E63261DCF91D30E4ECC047AFA /* FIRFacebookAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 55F190ACA77146C5187A0BB15DA6EAF5 /* FIRFacebookAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EF8B926D831C87D3592A1EEAD326E946 /* FChildrenNode.h in Headers */ = {isa = PBXBuildFile; fileRef = A23BCDA5AC206E7CB756611195DEA81D /* FChildrenNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F09DE2AA47714D5DC0AD93935920529F /* FIRStartMFASignInRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = AB7DB6EF23B9761561E1598918C90693 /* FIRStartMFASignInRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F1071EDACCB6BA39951ADE36C88C8A01 /* FCompoundHash.m in Sources */ = {isa = PBXBuildFile; fileRef = 89475AC8A6957A1C6B79D64857558539 /* FCompoundHash.m */; }; + F176AF70E20F4C6E7D504E0413D9779E /* FIRStorageLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = D6CC30E2B10C146529670C215CCFE97F /* FIRStorageLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F1E78E4BE10C1B0FA712035CDF29E63B /* FBLPromise+Validate.m in Sources */ = {isa = PBXBuildFile; fileRef = BF8645293BD84FC36ED2B54D4E52D0AF /* FBLPromise+Validate.m */; }; + F22B5419E9003421796BCFE4BE3306B5 /* FIRHeartbeatInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 75483AC2AE9B94CA4D4431712A9E010F /* FIRHeartbeatInfo.m */; }; + F271C03971AC5CE29FADBA38397BD038 /* FConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 83E2E567BD461A1E4963298CA03E1F4F /* FConnection.m */; }; + F29FF6369D8D010F9ADF4CFFAB600FDC /* FTupleCallbackStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = F3E6618C894D10C116BC2F0FD09C91F0 /* FTupleCallbackStatus.m */; }; + F2FACCE09C3F3900E03111D4A942EBF2 /* FIRComponentType.m in Sources */ = {isa = PBXBuildFile; fileRef = B17EC1FDC566D6EE01633B7220A39230 /* FIRComponentType.m */; }; + F331A2E53F59CA601620F3A75C80276D /* filter_policy.cc in Sources */ = {isa = PBXBuildFile; fileRef = D3357AC70DA0AB1A2DBC4B94318BA7F5 /* filter_policy.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + F34F0C3F59D1284F845DC2CD2D140E41 /* FIRHeartbeatInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FED184F8D1B40AFEA217EA44E8B7422E /* FIRHeartbeatInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F390066B1BD3328086F242BE4552C15B /* write_batch_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 91B88E934D122F562EFA30F1738C3C2A /* write_batch_internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F430C6D7960DAE857DC6EB878F54AF69 /* FIRDeleteAccountRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = B95010BC3EBD9FC0909725BDB3ABF4D9 /* FIRDeleteAccountRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F47775DDD768C9D734A3264CCC7ACCD3 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B3125D500C1F70AC85CA5401A1F25E6A /* Security.framework */; }; + F4873A6E8872E9742B0617AE89AEC464 /* FIRAuthErrorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A9B3935AD68926702185D93B9797C7E /* FIRAuthErrorUtils.m */; }; + F49754B4A9604F7B6232D876B7A13EDF /* FQuerySpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CD22871E7B3423E28E68F9F67339019 /* FQuerySpec.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F4BB4F154F7744A7D223165024CA476A /* FIRStorageErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D28BF6F99FC527C5CAF3B8CE13E578A /* FIRStorageErrors.m */; }; + F642A4B2D3D8562AF1D5A27419B79011 /* FIRTransactionResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D037AF2BB90F895A3501FFF67FAD5C1 /* FIRTransactionResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F6E841C487590F3620A592D5DEA0224A /* FBLPromise+Wrap.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = A56068F39B274E2B955D1D4B80323F59 /* FBLPromise+Wrap.h */; }; + F717D60CB93C2CCB02B839D89521DA7A /* FIRActionCodeSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C470B429F1B0F7C5C9717C34523B5CD /* FIRActionCodeSettings.m */; }; + F745EE6A5ADA4EFDBB3B8E6C59D80C3E /* GDTCORLifecycle.h in Headers */ = {isa = PBXBuildFile; fileRef = FA52D7A5FF113ACBFD33CBBC3183A141 /* GDTCORLifecycle.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F7C8FF0DDF61B71E4B3BA2A79F0BFF1F /* GoogleDataTransport-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 99BD44EA0561B5CE9F0F17331D6086DF /* GoogleDataTransport-dummy.m */; }; + F7ED8CD914AE49A13627556BD0A4F3A3 /* dumpfile.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3530277F290B77EE13F89290A41E04C4 /* dumpfile.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + F7FAAE40AFA76716EE0B4EA4657FEC5F /* FTupleStringNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F6E3155820E7453FEBBF8026C3B8DE6 /* FTupleStringNode.m */; }; + F833AB8826B1B846DC77605FBC603A1D /* builder.h in Headers */ = {isa = PBXBuildFile; fileRef = 10FE76B048D51686FA8712B5F472ECE3 /* builder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F85431750FFA77723656EEE949F74503 /* FIRDatabaseComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 89E31E2A96FD20D003BF0BCAA06EA6AE /* FIRDatabaseComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F88537120E41C136B1EE60FE5D54CA78 /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 23BE7FAC4E42333FA445C40033DA4A17 /* FIRLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F947986DEE834871DDAFA1BC57DBFB6A /* FEventRaiser.h in Headers */ = {isa = PBXBuildFile; fileRef = 820A9143A1B34097FC8811A6824024EE /* FEventRaiser.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F9A37700BD48A2C1CF21FB246E389C75 /* FIRIdentityToolkitRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 4562E63F64CA70681763C3716BE3EF3D /* FIRIdentityToolkitRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F9FCEC45422BBCCE393D9E3A563FD9E5 /* FIRUserInfoImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A7C906E5F537583800EE44AA0B4F724 /* FIRUserInfoImpl.m */; }; + FA30A98124EF6F3559022A7FE0B4B5F1 /* FIRMutableData_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C60545B543575471D5F2B720681B8F4F /* FIRMutableData_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FA4F8353D59E5A188F487D06AF00DA77 /* mutexlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 4054C2CE5E6C42242A0D1ED848DB68B4 /* mutexlock.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FA5A3FDC4ECDCE3D754B050F40BD8AFE /* FIRStorageTokenAuthorizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EAFE0E8FC6D0A618CC1951440D5D862 /* FIRStorageTokenAuthorizer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FA5D554F9F4670EAD6E7828911A5C15E /* FTupleRemovedQueriesEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = 40C49E450975211339D6732631127E8B /* FTupleRemovedQueriesEvents.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FA94D9DC939A04D35D1634AC721E87F4 /* FBLPromise+Async.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C0983B32DB733B5AAA3960177D9F143 /* FBLPromise+Async.m */; }; + FAA6A295C4B9EBEE073C6CB253577F5F /* FIRAuthRPCResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = A18052F86CDC309B984F2A072E0B8350 /* FIRAuthRPCResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FB6B518F0FC056ABABAA42355E6B4B0A /* GULSceneDelegateSwizzler.h in Headers */ = {isa = PBXBuildFile; fileRef = D2752476EEBD2EB1C3C03EB7D629DE55 /* GULSceneDelegateSwizzler.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FB6DEA4AEA597F3BC2F9294C593B2CA2 /* FArraySortedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 744F3A29E3170CC5C41C864DAC5D4235 /* FArraySortedDictionary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FC768D07C0AA62AF339CF13F0ACEA358 /* FIRAppCheckInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EEAF592B74F318B32710ADCF9E91B1 /* FIRAppCheckInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FD29C1D724C822E2D8DACC9619355C09 /* FIRFirebaseUserAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = CED836F5AB275798DF1EF9CEDBAFD697 /* FIRFirebaseUserAgent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FD4C2A53F7E0A9F1AB92B058D3C443DA /* FIRAuthURLPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = A75A814253FC19978642F5B98FBE1C54 /* FIRAuthURLPresenter.m */; }; + FD7FDDB9112DDE055134DFD0241426AA /* FImmutableSortedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 013A9B84A0D24B29F424C2D7B299946B /* FImmutableSortedDictionary.m */; }; + FDB2A038E79C965885210DE71FD289B8 /* FIRCreateAuthURIResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 80FDC76D3FBAC817FFB275752A4E8648 /* FIRCreateAuthURIResponse.m */; }; + FDBFA8572C4EA56E9A77D2680DE48E11 /* FirebaseCore-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 77B9E73A06A93EA6F9C153639F6C4AB7 /* FirebaseCore-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FDE74312FC2EF956F883236DEACF2B02 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */; }; + FDEE3281E745802214A26F1EEB91A414 /* FEmptyNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A2C5A6D778216B937ECDD7C4907FE6 /* FEmptyNode.m */; }; + FDFE6C98DB63331DE9AF23C835A8950E /* db_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = C4CC188B7B93B535D5F12913B4B2F37E /* db_impl.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FEC68219ED7543FB9D5E99CC7ACBBA85 /* GoogleDataTransport-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 40F5FBEE90FA0FAA88EBC934B01FF63B /* GoogleDataTransport-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FEFE957B39AA88C9760C2B8ECC8F3780 /* FirebaseCore.h in Headers */ = {isa = PBXBuildFile; fileRef = DF92A3DC3872C2E019717A99ABFC4BAF /* FirebaseCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FF58BBB0D998FE73A97B7B3499824ABA /* FBLPromise+Validate.h in Headers */ = {isa = PBXBuildFile; fileRef = 56793ED84A5687D192F21FFE912AFD81 /* FBLPromise+Validate.h */; }; + FF8F64995C8D9DE5A6436742B340C075 /* FPathIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = E83C685792DEC69A5B185422B4AC2E7A /* FPathIndex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FFA4A408774EC7345E0684BC1CD37F5D /* FIRGameCenterAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = C04D966A10440A875CD3413E6B4B651C /* FIRGameCenterAuthProvider.m */; }; + FFF620F49ED2780182A3F1B1DBB28B1C /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 966A1DBDE4EC817C40A7AA5C8B1ABE0A /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 0039D1FC45AE117EFAC3EA76115AA794 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9307B7A119490930CF70393AB529AAC1; + remoteInfo = "leveldb-library"; + }; + 068109FB101AF2DF8EFB1D2B0BFD9FC1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + 0DC214B31BED7E8AFD6FCD8F29B5F7E8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BBF7206D7FAC92C82A042A99C4A98F8; + remoteInfo = PromisesObjC; + }; + 1B4D34C5D204EE17B15C4BB0E90E4977 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2B5E7DCCBBFB32341D857D01211A1A3; + remoteInfo = nanopb; + }; + 1F6166552149452762F1E1B5F99C25ED /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 620E05868772C10B4920DC7E324F2C87; + remoteInfo = FirebaseCoreDiagnostics; + }; + 21FF479D036F39B4A377FCAB253F6FDF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 620E05868772C10B4920DC7E324F2C87; + remoteInfo = FirebaseCoreDiagnostics; + }; + 2727A0893CA5320676761CF88ADECCE1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BBF7206D7FAC92C82A042A99C4A98F8; + remoteInfo = PromisesObjC; + }; + 47DE645704CB21514D16F705FFE571DA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2B5E7DCCBBFB32341D857D01211A1A3; + remoteInfo = nanopb; + }; + 4AFF0692751D81CF6C455BE917797094 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 736AF68F6527ACF6B4A4C54728824A1C; + remoteInfo = FirebaseDatabase; + }; + 55C5159A2E28785F579342492CF8CB4A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6AE4A3D573DED275B034E20506596C62; + remoteInfo = FirebaseAuth; + }; + 5B459D35C2F52F6CAB89E2AFF8E67681 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 618532CFB81B9E8D6011AB704FFC6E1F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D676E21115185671D7258A56944ABE98; + remoteInfo = GTMSessionFetcher; + }; + 6EE7768875FA3C3DA32788B5154C2542 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 7471C818C9AC163CF1477F4D461FCFBE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D676E21115185671D7258A56944ABE98; + remoteInfo = GTMSessionFetcher; + }; + 77C27BFD921CF2C54EBF77F5011AACB6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + 7C82CCF17BB0C84E09F48FFA457AC415 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 8B24FC45F289EBE4D7BDD409C070D853 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 23E7C4A52360C026F97E4A96D91B03CE; + remoteInfo = FirebaseStorage; + }; + 91F232AD1BA09F4868F0E4904046F26E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 943DE89A070FEE11065D1A77CD396E61 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BBF7206D7FAC92C82A042A99C4A98F8; + remoteInfo = PromisesObjC; + }; + 9B9016F1CFBF6136DDD385802B8500A1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9307B7A119490930CF70393AB529AAC1; + remoteInfo = "leveldb-library"; + }; + AEB825C55B5967AB91433DE739FAC516 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 23E7C4A52360C026F97E4A96D91B03CE; + remoteInfo = FirebaseStorage; + }; + B3ADDF90A3EEE0CBAE2BA87E3A2FE1F1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + C55870D10A2B6A8AFC8F92B1AE79A411 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5C0371EE948D0357B8EE0E34ABB44BF0; + remoteInfo = GoogleDataTransport; + }; + C6E808461B0093E1F31C36B97E1EC639 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 736AF68F6527ACF6B4A4C54728824A1C; + remoteInfo = FirebaseDatabase; + }; + D63595C6316C71F11E47E6C6141EBD2B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6AE4A3D573DED275B034E20506596C62; + remoteInfo = FirebaseAuth; + }; + DFF7FFF85F84655DCDAADCB5A3129EE6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + E2D756F966650B368D3D2843C66A1A3B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + E7DDC8831E140251F0308321E8DC7DF1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5C0371EE948D0357B8EE0E34ABB44BF0; + remoteInfo = GoogleDataTransport; + }; + EB214D8092C459994B327B14448BFAA7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + F18E7FBF39FF9F9F1EDA2644DA483EAC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2B5E7DCCBBFB32341D857D01211A1A3; + remoteInfo = nanopb; + }; + FD4F0BD27C60009A5D24D74ECEB38198 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 072CEA044D2EF26F03496D5996BBF59F; + remoteInfo = Firebase; + }; + FECBB6C757065DC08E79F3662B8F88A4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D676E21115185671D7258A56944ABE98; + remoteInfo = GTMSessionFetcher; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 6E2DAB853E8F090EA06FFBB8FBDD25F3 /* Copy . Public Headers */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(PUBLIC_HEADERS_FOLDER_PATH)/."; + dstSubfolderSpec = 16; + files = ( + 010A11BD130B792268F92AA7E735218A /* FBLPromise.h in Copy . Public Headers */, + 53537A7686F5394BFE5F75761DCEBCB2 /* FBLPromise+All.h in Copy . Public Headers */, + 960CA75E0D157997A6E272FF20C3CC7B /* FBLPromise+Always.h in Copy . Public Headers */, + 1687F98BF087FCAEC83D21F776ED1D12 /* FBLPromise+Any.h in Copy . Public Headers */, + 669BFAF0CC62D4215D9DD4B1C5C6F2C3 /* FBLPromise+Async.h in Copy . Public Headers */, + 8BB8EDC25F690CD7D1773F68CA73E87A /* FBLPromise+Await.h in Copy . Public Headers */, + E08E50B62AAC152B2F6A294CF8457D8B /* FBLPromise+Catch.h in Copy . Public Headers */, + B23FB28D502F22ABAB8D1D89C869D1E6 /* FBLPromise+Delay.h in Copy . Public Headers */, + 31F957DC519496854853B6F5A8C55885 /* FBLPromise+Do.h in Copy . Public Headers */, + 3A7EA8BC8F1611EF962D29F330ABB5A3 /* FBLPromise+Race.h in Copy . Public Headers */, + 7F6139B893BFFDED3B16B2D252C8FDBA /* FBLPromise+Recover.h in Copy . Public Headers */, + 162488B6E75A20B4C3DDFA9C61090D5B /* FBLPromise+Reduce.h in Copy . Public Headers */, + 6B58C5A2D34339AC44AC12211778ED64 /* FBLPromise+Retry.h in Copy . Public Headers */, + BFED5C657A0082C3174DEC1019124B57 /* FBLPromise+Testing.h in Copy . Public Headers */, + 1CBDCB86FA64F4B6B9739106A0B371F0 /* FBLPromise+Then.h in Copy . Public Headers */, + 5859F25320F41073E40ACF4608F61C03 /* FBLPromise+Timeout.h in Copy . Public Headers */, + 58D8CFC8852282D743776D0FFB4AB07A /* FBLPromise+Validate.h in Copy . Public Headers */, + F6E841C487590F3620A592D5DEA0224A /* FBLPromise+Wrap.h in Copy . Public Headers */, + A980B6617604CBEAEB28471F381DC146 /* FBLPromiseError.h in Copy . Public Headers */, + 31A7FFE377DB1B87E886B331C6855DF6 /* FBLPromises.h in Copy . Public Headers */, + ); + name = "Copy . Public Headers"; + runOnlyForDeploymentPostprocessing = 0; + }; + FF2903366EFB7A36DEC66D583781A3E0 /* Copy . Private Headers */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(PRIVATE_HEADERS_FOLDER_PATH)/."; + dstSubfolderSpec = 16; + files = ( + AB48521AEE62CC461BAEC39B1D208CA2 /* FBLPromisePrivate.h in Copy . Private Headers */, + ); + name = "Copy . Private Headers"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 00107F5D3773418497630039D598AABF /* FirebaseCore.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCore.debug.xcconfig; sourceTree = ""; }; + 0063F6261147793EDA01C98F131EE381 /* FIRConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRConfiguration.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h; sourceTree = ""; }; + 01333A9556B2952D3BF8EF47FE063E14 /* FServerValues.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FServerValues.h; path = FirebaseDatabase/Sources/Core/FServerValues.h; sourceTree = ""; }; + 013A9B84A0D24B29F424C2D7B299946B /* FImmutableSortedDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FImmutableSortedDictionary.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.m; sourceTree = ""; }; + 01770DBB442B8AC1A2AA89A8B06AE1CD /* GDTCORReachability.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORReachability.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h; sourceTree = ""; }; + 017EFF960BB5DB0C88DEA74292152B14 /* FIRAppCheckInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppCheckInterop.h; path = FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h; sourceTree = ""; }; + 01BFBDF82820583C2FB719EBC08FF100 /* FIRGitHubAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGitHubAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.m; sourceTree = ""; }; + 01E75FBC9C58CDC564AC74535ABAF369 /* GDTCOREvent+GDTCCTSupport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GDTCOREvent+GDTCCTSupport.h"; path = "GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h"; sourceTree = ""; }; + 0219F46A3DB232BA4625B09FCAC5F422 /* GULApplication.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULApplication.h; path = GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h; sourceTree = ""; }; + 0238C971BE9A0CA5EF77CBFB630D350F /* GDTCORTransport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORTransport.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h; sourceTree = ""; }; + 02A800184212263B2434BD36BD5C4123 /* FIRPhoneMultiFactorAssertion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneMultiFactorAssertion.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h; sourceTree = ""; }; + 02EF7686404E69DBF2E3EB1866181B14 /* FTree.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTree.m; path = FirebaseDatabase/Sources/Core/Utilities/FTree.m; sourceTree = ""; }; + 031CCD2F09059BB876AEF36C4CCA549D /* GDTCORReachability_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORReachability_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h; sourceTree = ""; }; + 03215B0ED3F49AAA67906E78ABBB23BB /* FIRAuthAPNSToken.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthAPNSToken.m; path = FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.m; sourceTree = ""; }; + 032DF10AB85867F30E7D46A814B88652 /* FIRStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorage.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorage.h; sourceTree = ""; }; + 033F4C2158EF7093260D0330792F029F /* repair.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = repair.cc; path = db/repair.cc; sourceTree = ""; }; + 035DB386647B61CA504DED882F157E0E /* env_posix_test_helper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = env_posix_test_helper.h; path = util/env_posix_test_helper.h; sourceTree = ""; }; + 0391475D50E27C2921D0D820540DBF77 /* FSnapshotUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSnapshotUtilities.h; path = FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h; sourceTree = ""; }; + 03E1CE3EB6A65FC8FD5A092AADD594C1 /* FIRFacebookAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFacebookAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.m; sourceTree = ""; }; + 0421C48DDFB0098D497DCD3542BB99DA /* FIRDatabaseConfig_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseConfig_Private.h; path = FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h; sourceTree = ""; }; + 044F6E5467DFFE0E5874B2368601CF31 /* FirebaseStorage.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseStorage.debug.xcconfig; sourceTree = ""; }; + 046A1A8B23BD286D6422499C9BC42BC5 /* FIRResetPasswordRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRResetPasswordRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h; sourceTree = ""; }; + 0496FD94D83CBCCC1DB7ECDDC894B162 /* FCachePolicy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCachePolicy.h; path = FirebaseDatabase/Sources/Persistence/FCachePolicy.h; sourceTree = ""; }; + 04D67BEA48283ED3EBBC32F2CE1FB54D /* FConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FConstants.m; path = FirebaseDatabase/Sources/Constants/FConstants.m; sourceTree = ""; }; + 05102F03FEA97AD55CCDD5D1FB4A90E3 /* FTupleCallbackStatus.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleCallbackStatus.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h; sourceTree = ""; }; + 051169EAD8CE8968374F95BB47451BBA /* FTupleFirebase.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleFirebase.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.m; sourceTree = ""; }; + 056885DA57DFF38866F1836927203DB2 /* FImmutableSortedDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FImmutableSortedDictionary.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h; sourceTree = ""; }; + 056C7AA7E700ABF039F5DB1D2E516E59 /* FIRGoogleAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGoogleAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthProvider.m; sourceTree = ""; }; + 05A833BF83229902996FDD783BD650CC /* FTupleUserCallback.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleUserCallback.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.m; sourceTree = ""; }; + 06026367C0383ADE30C5100DC880F6FD /* status.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = status.cc; path = util/status.cc; sourceTree = ""; }; + 0653C3E0475AAA695FF29332FB69418C /* FChildChangeAccumulator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FChildChangeAccumulator.m; path = FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.m; sourceTree = ""; }; + 06FC5C9CF96D60C50FCD47D339C91951 /* nanopb */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = nanopb; path = nanopb.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 074B1506E54F170E9D971DFA65A05BAE /* FIREmailLinkSignInResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIREmailLinkSignInResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h; sourceTree = ""; }; + 0786F5F9A30289D84FD9C66F9D05C9BF /* FIRMultiFactorInfo+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMultiFactorInfo+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h"; sourceTree = ""; }; + 07C17F9E595A3429B033D37E557FFA35 /* NSData+FIRBase64.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+FIRBase64.m"; path = "FirebaseAuth/Sources/Utilities/NSData+FIRBase64.m"; sourceTree = ""; }; + 08349AC39718E09B5546C61A59E2FDB6 /* FRangeMerge.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRangeMerge.h; path = FirebaseDatabase/Sources/Core/FRangeMerge.h; sourceTree = ""; }; + 088B296CBACE0AC12047F6B7A5570A89 /* crc32c.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = crc32c.h; path = util/crc32c.h; sourceTree = ""; }; + 08A8ED18BAADFDE9B7B3D9B70CFE0AEA /* FPath.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPath.m; path = FirebaseDatabase/Sources/Core/Utilities/FPath.m; sourceTree = ""; }; + 08A9BE54D383AFB306E187521BE6F953 /* FIRVerifyPhoneNumberRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyPhoneNumberRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.m; sourceTree = ""; }; + 08FBB509F7F005C11D635808E7C3B594 /* FIRDatabaseQuery_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseQuery_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h; sourceTree = ""; }; + 090C4DF6889DD5CE158AF416BFE28E37 /* GDTCORTargets.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORTargets.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h; sourceTree = ""; }; + 0940FE6F9786A2811E51E5B2AE96BF6F /* FIRPhoneMultiFactorInfo+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRPhoneMultiFactorInfo+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h"; sourceTree = ""; }; + 097A3DBCD1FEDB6F15FC566B8F6EBB4D /* FPathIndex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPathIndex.m; path = FirebaseDatabase/Sources/FPathIndex.m; sourceTree = ""; }; + 09C911FD759302267DF9A71825701EE0 /* FIRAuthAppCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthAppCredential.m; path = FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.m; sourceTree = ""; }; + 09E760765D90D676A6B6F9E9B69247F7 /* FIRDeleteAccountResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDeleteAccountResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.m; sourceTree = ""; }; + 0A77E7C65037F8961C4FAE7B34A6CB32 /* testharness.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = testharness.h; path = util/testharness.h; sourceTree = ""; }; + 0A9F46A999C47653013D3AD854352507 /* leveldb-library */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "leveldb-library"; path = leveldb.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0B90799188BF45540C038E6AD9774A36 /* FIRSignInWithGameCenterRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSignInWithGameCenterRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h; sourceTree = ""; }; + 0B90DF6FA77A19EB3BAD0E1750EA2D94 /* FIRSecureTokenRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSecureTokenRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.m; sourceTree = ""; }; + 0BD69D14E151B50FC47885567CC1F00A /* FIRComponentContainer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRComponentContainer.m; path = FirebaseCore/Sources/FIRComponentContainer.m; sourceTree = ""; }; + 0C0983B32DB733B5AAA3960177D9F143 /* FBLPromise+Async.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Async.m"; path = "Sources/FBLPromises/FBLPromise+Async.m"; sourceTree = ""; }; + 0C2B3391E6BB1E5093C9FD919D7CF549 /* FIRMultiFactorResolver+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMultiFactorResolver+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h"; sourceTree = ""; }; + 0C30D81E6407995A697635D198C8DDDF /* FConnection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FConnection.h; path = FirebaseDatabase/Sources/Realtime/FConnection.h; sourceTree = ""; }; + 0C5B7637C35100D4E00B41FB959B5377 /* FRangeMerge.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FRangeMerge.m; path = FirebaseDatabase/Sources/Core/FRangeMerge.m; sourceTree = ""; }; + 0C7BF91AA178CDB48E76323D48504F27 /* FWriteRecord.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FWriteRecord.m; path = FirebaseDatabase/Sources/Core/FWriteRecord.m; sourceTree = ""; }; + 0CFA82C57837B7BB75C48CEDB9A28159 /* FDataEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FDataEvent.m; path = FirebaseDatabase/Sources/Core/View/FDataEvent.m; sourceTree = ""; }; + 0D3EF6641CC688F9E7B716DA42049B1C /* FirebaseStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseStorage.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FirebaseStorage.h; sourceTree = ""; }; + 0D62E8B3886374A1220D5ED548497AB3 /* FNextPushId.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FNextPushId.m; path = FirebaseDatabase/Sources/Utilities/FNextPushId.m; sourceTree = ""; }; + 0DCE8B190588AF201D9521AFDEC1A12A /* FBLPromise.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromise.h; path = Sources/FBLPromises/include/FBLPromise.h; sourceTree = ""; }; + 0E0B842AE076438EDED02B289F208B47 /* FIRDatabaseConnectionContextProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabaseConnectionContextProvider.m; path = FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.m; sourceTree = ""; }; + 0E25132C2CD03254F7E2A6E3C4F929F7 /* FIRAnalyticsConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAnalyticsConfiguration.m; path = FirebaseCore/Sources/FIRAnalyticsConfiguration.m; sourceTree = ""; }; + 0EB4424F6DC448437D09153671506EF7 /* FPriorityIndex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPriorityIndex.m; path = FirebaseDatabase/Sources/FPriorityIndex.m; sourceTree = ""; }; + 0F7FE598826DA18D6CAB2AE10119075A /* FIRStorageTask_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageTask_Private.h; path = FirebaseStorage/Sources/FIRStorageTask_Private.h; sourceTree = ""; }; + 0FDA8FF09D2555F381F370A0422B2983 /* FUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FUtilities.h; path = FirebaseDatabase/Sources/Utilities/FUtilities.h; sourceTree = ""; }; + 10726F9298E233D645FE70928D347C8E /* Pods-saraWhatsUp.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-saraWhatsUp.modulemap"; sourceTree = ""; }; + 10FE76B048D51686FA8712B5F472ECE3 /* builder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = builder.h; path = db/builder.h; sourceTree = ""; }; + 1123E7A9203EDCC45A75D4C556249693 /* FIRVersion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVersion.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h; sourceTree = ""; }; + 113B2DB0C57859DE9BA3B3D6280DF261 /* FIRSignInWithGameCenterResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSignInWithGameCenterResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.m; sourceTree = ""; }; + 1157C2EB85FDBA73F430398032A06509 /* FIRDatabaseReference.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseReference.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h; sourceTree = ""; }; + 1235ADB2B49B751EFEAF8A7A2CC2C36F /* FPruneForest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPruneForest.h; path = FirebaseDatabase/Sources/Persistence/FPruneForest.h; sourceTree = ""; }; + 12BDC2F59494AAB3007671C257F6E5DA /* FIRUserMetadata.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRUserMetadata.m; path = FirebaseAuth/Sources/User/FIRUserMetadata.m; sourceTree = ""; }; + 132E0228BE7AC8D19E9CF7E085EE282D /* GULKeychainUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULKeychainUtils.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h; sourceTree = ""; }; + 13334C7932E2839836F8564E47E5E95F /* FIRAuthExceptionUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthExceptionUtils.m; path = FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.m; sourceTree = ""; }; + 133C88D736DA8CED133F999B0912796E /* FValueIndex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FValueIndex.h; path = FirebaseDatabase/Sources/FValueIndex.h; sourceTree = ""; }; + 1370B793664C2C3E3CE6DDC3053F7618 /* FTransformedEnumerator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTransformedEnumerator.h; path = FirebaseDatabase/Sources/FTransformedEnumerator.h; sourceTree = ""; }; + 139C0CF3E0B177E20E8F3550A4DEA5DD /* FCompleteChildSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCompleteChildSource.h; path = FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h; sourceTree = ""; }; + 13FE74E1B86265EF9348F21E3F3E09D9 /* GULAppDelegateSwizzler_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULAppDelegateSwizzler_Private.h; path = GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h; sourceTree = ""; }; + 147C429D780487E0278FCBF69F77608C /* FIRGameCenterAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGameCenterAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h; sourceTree = ""; }; + 1527CD4FCB8B349B9F014B7A2E846416 /* FIRFinalizeMFASignInRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFinalizeMFASignInRequest.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.m; sourceTree = ""; }; + 154C7482FFED67A2563A3F0107E9E0C1 /* FImmutableTree.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FImmutableTree.m; path = FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.m; sourceTree = ""; }; + 159393C33349F60D4E04328017F2B565 /* GULMutableDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULMutableDictionary.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h; sourceTree = ""; }; + 15FC3AC6278487A52B2F5A7FEEF30FAC /* GULURLSessionDataResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULURLSessionDataResponse.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h; sourceTree = ""; }; + 1610050E12683DE6BCCC39B25A37C034 /* FIRVerifyCustomTokenRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyCustomTokenRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.m; sourceTree = ""; }; + 16321AB5E9D6A5632ECCD98C46E259C1 /* FIRResetPasswordRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRResetPasswordRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.m; sourceTree = ""; }; + 1668C7B0D52CEFD7E0B83C5A403D1F50 /* FKeyIndex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FKeyIndex.h; path = FirebaseDatabase/Sources/FKeyIndex.h; sourceTree = ""; }; + 16712385BBD6EFD20F637BE0027D43BD /* FIRPhoneMultiFactorAssertion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRPhoneMultiFactorAssertion.m; path = FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion.m; sourceTree = ""; }; + 16AA4D274A47351AFC341E2F1303F464 /* FIRFinalizeMFAEnrollmentRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFinalizeMFAEnrollmentRequest.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.m; sourceTree = ""; }; + 16BF111B8E55C4502E51954BA7333CCF /* FIRSetAccountInfoRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSetAccountInfoRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h; sourceTree = ""; }; + 172F05B85B5EC79590698D2BEECF63CE /* GULNetworkMessageCode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkMessageCode.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h; sourceTree = ""; }; + 173AF725A61B69DB8626BC934E56526F /* FirebaseDatabase.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseDatabase.release.xcconfig; sourceTree = ""; }; + 1782CB220CA1344F5845A55A1A958C8C /* FTupleObjects.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleObjects.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.h; sourceTree = ""; }; + 17B17FDF8C1411944C7BAF3A650948E1 /* env_windows_test_helper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = env_windows_test_helper.h; path = util/env_windows_test_helper.h; sourceTree = ""; }; + 17B6C9AB660C7ED9F3CDAA1F45F4D9EC /* log_reader.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = log_reader.cc; path = db/log_reader.cc; sourceTree = ""; }; + 17CA14733B2F2512D271981AC3222251 /* FIRStorageReference_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageReference_Private.h; path = FirebaseStorage/Sources/FIRStorageReference_Private.h; sourceTree = ""; }; + 17F669B599B173989CB4B85439CACA8B /* GDTCOREvent+GDTCCTSupport.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GDTCOREvent+GDTCCTSupport.m"; path = "GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m"; sourceTree = ""; }; + 18459382C69E8CE80FF371CDA0344FE1 /* FIRTransactionResult_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRTransactionResult_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h; sourceTree = ""; }; + 184FB4DAC7ECA7641F9F273B2C2EE276 /* FIRStorageUploadTask_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageUploadTask_Private.h; path = FirebaseStorage/Sources/FIRStorageUploadTask_Private.h; sourceTree = ""; }; + 197C1470CE81C5D575279D2F7040971D /* FNamedNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FNamedNode.h; path = FirebaseDatabase/Sources/FNamedNode.h; sourceTree = ""; }; + 1A0BF52AE10A30F5BD8A7D2E4F4080E8 /* FIRAuthBackend+MultiFactor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FIRAuthBackend+MultiFactor.m"; path = "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.m"; sourceTree = ""; }; + 1A27E89E002CAEE5D35D573EA0401CF0 /* FImmutableSortedSet.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FImmutableSortedSet.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.m; sourceTree = ""; }; + 1A49AC9D79084068C17D46C29FA998AA /* FBLPromise+Race.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Race.h"; path = "Sources/FBLPromises/include/FBLPromise+Race.h"; sourceTree = ""; }; + 1A4F9E7A0915ED7FBEC30A8F71AD07C5 /* FIRSignInWithGameCenterRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSignInWithGameCenterRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.m; sourceTree = ""; }; + 1A824F119286E0C31278A847591BB786 /* FIRStorageTaskSnapshot.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageTaskSnapshot.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h; sourceTree = ""; }; + 1B61E1F94800DA4E1CC5D0C0EE897345 /* FIRMultiFactorSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMultiFactorSession.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h; sourceTree = ""; }; + 1BAC185425DBFA92432FC48DC8E975D5 /* builder.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = builder.cc; path = db/builder.cc; sourceTree = ""; }; + 1BB3746D9D29A0B4A79E4F46A7FB50BF /* FIRStorageObservableTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageObservableTask.m; path = FirebaseStorage/Sources/FIRStorageObservableTask.m; sourceTree = ""; }; + 1BB4D7A6FFFF742F2E980F08A9EA3AF3 /* FirebaseDatabase-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseDatabase-Info.plist"; sourceTree = ""; }; + 1BE3361A3F0C14B7DEFD6AF4BC8765A8 /* FWriteRecord.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FWriteRecord.h; path = FirebaseDatabase/Sources/Core/FWriteRecord.h; sourceTree = ""; }; + 1BECDD459D9B73BE4F02893E75E11FE2 /* Firebase.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Firebase.debug.xcconfig; sourceTree = ""; }; + 1BFDCC2F82C100448FE007F05AC497C7 /* FBLPromise+Recover.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Recover.m"; path = "Sources/FBLPromises/FBLPromise+Recover.m"; sourceTree = ""; }; + 1C351DF20BBDB7C2D3D122CDE9CECB69 /* FLeafNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLeafNode.h; path = FirebaseDatabase/Sources/Snapshot/FLeafNode.h; sourceTree = ""; }; + 1C9AFD1F65D89843CF8C273F7BDCA6F7 /* FIRAuth.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuth.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h; sourceTree = ""; }; + 1D037AF2BB90F895A3501FFF67FAD5C1 /* FIRTransactionResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRTransactionResult.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h; sourceTree = ""; }; + 1D5503EED647D08F5A54F1B20F33761C /* FIRStorageTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageTask.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTask.h; sourceTree = ""; }; + 1DEC7CA169AF37FBEE1A5945F3D3241B /* FIROptionsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptionsInternal.h; path = FirebaseCore/Sources/Private/FIROptionsInternal.h; sourceTree = ""; }; + 1E69939A365088C66AD857717FF633A8 /* NSURLSession+GULPromises.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSURLSession+GULPromises.m"; path = "GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m"; sourceTree = ""; }; + 1E907A35C1DEDA93701504221E550A28 /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Sources/Private/FirebaseCoreInternal.h; sourceTree = ""; }; + 1EC729ED3D4FBA1AF83B8B5321C688EF /* FOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FOperation.h; path = FirebaseDatabase/Sources/Core/Operation/FOperation.h; sourceTree = ""; }; + 1F0C566769D33EBA1455071400D6E307 /* FirebaseCoreDiagnostics-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseCoreDiagnostics-umbrella.h"; sourceTree = ""; }; + 1F288DCDC36134E8DCCFE23B9B0A5552 /* fbase64.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = fbase64.h; path = FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h; sourceTree = ""; }; + 1F64C372A6E12EF616E2930965FB8336 /* FBLPromise+Do.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Do.m"; path = "Sources/FBLPromises/FBLPromise+Do.m"; sourceTree = ""; }; + 1F6E3155820E7453FEBBF8026C3B8DE6 /* FTupleStringNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleStringNode.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.m; sourceTree = ""; }; + 1FC1446EF19FFFB8FD40DA8AD3896B58 /* FIRPhoneAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneAuthCredential.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h; sourceTree = ""; }; + 1FCE4B4A66E84892717EF5F2F0CC8516 /* FIREmailPasswordAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIREmailPasswordAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h; sourceTree = ""; }; + 2003FCD7C349868CB3AAB8389B0A816A /* FIRSignUpNewUserRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSignUpNewUserRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m; sourceTree = ""; }; + 201D6B608DE3FFE2C2B74490C3F4004C /* FIRVerifyCustomTokenRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyCustomTokenRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h; sourceTree = ""; }; + 201E994E5AB33B9C4F084310F0262E87 /* snapshot.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = snapshot.h; path = db/snapshot.h; sourceTree = ""; }; + 2075D1CE05FA37BC5327F25CBE420441 /* FIRStartMFASignInResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStartMFASignInResponse.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.m; sourceTree = ""; }; + 208565AD245BDE529154ACE5F559D5AB /* FRepoManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FRepoManager.m; path = FirebaseDatabase/Sources/Core/FRepoManager.m; sourceTree = ""; }; + 210D3946C544D2F83F1556FD40016B78 /* FIRAuthProto.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProto.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h; sourceTree = ""; }; + 21C565281E8122CD546FCFA1BF68DBA0 /* FIRSecureTokenResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSecureTokenResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h; sourceTree = ""; }; + 21D511E9F4CC3BC909ACE2417E6EEEB7 /* FValueIndex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FValueIndex.m; path = FirebaseDatabase/Sources/FValueIndex.m; sourceTree = ""; }; + 21E7374CA2BAFFE4EC6CCE7724CF719C /* FIRStorageGetDownloadURLTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageGetDownloadURLTask.h; path = FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h; sourceTree = ""; }; + 2224951413E013BC93CDFA9F58D26A34 /* FTypedefs.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTypedefs.h; path = FirebaseDatabase/Sources/Utilities/FTypedefs.h; sourceTree = ""; }; + 22563121E7EF6298E5CECCE8FF24294E /* FTuplePathValue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTuplePathValue.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h; sourceTree = ""; }; + 22A27923B3B28E3BBE217714A2394B13 /* FIRAuthExceptionUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthExceptionUtils.h; path = FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h; sourceTree = ""; }; + 22A2C5A6D778216B937ECDD7C4907FE6 /* FEmptyNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FEmptyNode.m; path = FirebaseDatabase/Sources/Snapshot/FEmptyNode.m; sourceTree = ""; }; + 22ACFD8A65A5EDB477F1472FAB19B5DC /* GTMSessionFetcher.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GTMSessionFetcher.debug.xcconfig; sourceTree = ""; }; + 22C0B9849699E858234B44466DE39EC9 /* FIRSendVerificationCodeRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSendVerificationCodeRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h; sourceTree = ""; }; + 22C249A29BE5C894E90F84F5C51D9ACE /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Sources/Private/FIRComponentContainer.h; sourceTree = ""; }; + 2307F3C89639D9D2EE17E026359A8CB2 /* FIRStartMFASignInRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStartMFASignInRequest.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.m; sourceTree = ""; }; + 2321555A80BE5C47A7147561FDF2F40E /* FIRUser_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUser_Internal.h; path = FirebaseAuth/Sources/User/FIRUser_Internal.h; sourceTree = ""; }; + 234E03B7B8FE3DD5EF2526A5EAF9FDE1 /* FSparseSnapshotTree.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSparseSnapshotTree.h; path = FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h; sourceTree = ""; }; + 2362DA688BE060908187030599778FF2 /* testharness.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = testharness.cc; path = util/testharness.cc; sourceTree = ""; }; + 23BE7FAC4E42333FA445C40033DA4A17 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Sources/Private/FIRLogger.h; sourceTree = ""; }; + 24166623AEBAC71E3A602781955498B7 /* FIRGetAccountInfoResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetAccountInfoResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.m; sourceTree = ""; }; + 2422BB9F3FEE8E73CD7604E104FB6565 /* NSData+SRB64Additions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+SRB64Additions.m"; path = "FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.m"; sourceTree = ""; }; + 24D69FACD4B23716EBCD5F309571F61A /* merger.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = merger.cc; path = table/merger.cc; sourceTree = ""; }; + 24E003B576B1D07E80E0F3159C8D80AA /* FIndex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIndex.m; path = FirebaseDatabase/Sources/FIndex.m; sourceTree = ""; }; + 2500B7FB71DA82CBFDDDB4822D95A314 /* FSyncTree.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSyncTree.m; path = FirebaseDatabase/Sources/Core/FSyncTree.m; sourceTree = ""; }; + 253DAA1F6C666E88A854BEA3ADC06CBE /* FIRTwitterAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRTwitterAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h; sourceTree = ""; }; + 253F33B4DBFD01CAA5A4802942933E2A /* FIRStorageDownloadTask_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageDownloadTask_Private.h; path = FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h; sourceTree = ""; }; + 26E785FC337EA22790808439DD1A5CD5 /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Sources/Private/FIRComponentType.h; sourceTree = ""; }; + 27232BB0E72527AA10C5843D2372057F /* FIRGitHubAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGitHubAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthProvider.m; sourceTree = ""; }; + 2749E81E39B3205D93B88A62A6C4B8AA /* FIRAuthErrorUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthErrorUtils.h; path = FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h; sourceTree = ""; }; + 27D1CAC99D5E7E545C7793FED2EC6FAC /* pb_encode.c */ = {isa = PBXFileReference; includeInIndex = 1; path = pb_encode.c; sourceTree = ""; }; + 27F950C7EE4B76D2428D26EF8510C489 /* FNextPushId.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FNextPushId.h; path = FirebaseDatabase/Sources/Utilities/FNextPushId.h; sourceTree = ""; }; + 286D39398D1A765422E97AAAFD146BDB /* FIRApp.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRApp.m; path = FirebaseCore/Sources/FIRApp.m; sourceTree = ""; }; + 288E61A06D7AA62E0EC62D1A11CE0FEA /* arena.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = arena.h; path = util/arena.h; sourceTree = ""; }; + 28DDBFE577910A14716DE2BB33652A6C /* FIRPhoneAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRPhoneAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthProvider.m; sourceTree = ""; }; + 28E8C18EF9243B01130C42F9F7FF6092 /* GULLoggerLevel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULLoggerLevel.h; path = GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h; sourceTree = ""; }; + 28E9C68290B23C26900DBEA3E551D14E /* nanopb.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = nanopb.release.xcconfig; sourceTree = ""; }; + 2905F41AAD3BA1F44F8213EB56CF38DC /* FIRDatabaseReference_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseReference_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h; sourceTree = ""; }; + 291B38DFC54C1CE23A2902F96EEB66D7 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Sources/Private/FIRLogger.h; sourceTree = ""; }; + 298ED93877CC4D1E87C81BA2A07083D5 /* GTMSessionFetcher-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "GTMSessionFetcher-Info.plist"; sourceTree = ""; }; + 2A33E05B62B2DDAEABACB7EE4520E03A /* FIRSecureTokenRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSecureTokenRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h; sourceTree = ""; }; + 2AB58E982FA948803C8BFFFE072A8FA7 /* FIRWithdrawMFARequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRWithdrawMFARequest.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h; sourceTree = ""; }; + 2ACC62B04F7F295C6F38A2DD14219DAA /* FIRFinalizeMFASignInResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFinalizeMFASignInResponse.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h; sourceTree = ""; }; + 2AF60A6D52FE8EBEB70B6B9CC52A6B3B /* FIROptionsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptionsInternal.h; path = FirebaseCore/Sources/Private/FIROptionsInternal.h; sourceTree = ""; }; + 2B3B105917EE8719FEB00E3C8D4DFA56 /* FTreeSortedDictionaryEnumerator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTreeSortedDictionaryEnumerator.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.m; sourceTree = ""; }; + 2B55A91D7EFF5E8B052CBC046587F562 /* FIRAuthCredential_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthCredential_Internal.h; path = FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h; sourceTree = ""; }; + 2B660D391F0513F69F3840BAF34FAF6A /* GDTCORPlatform.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORPlatform.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h; sourceTree = ""; }; + 2B98F9FAC4E46C99230030CD824F79A4 /* FirebaseCoreDiagnostics.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCoreDiagnostics.release.xcconfig; sourceTree = ""; }; + 2BA2D1D9C6E20FA4187ECDEB666F5808 /* FIRStorageUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageUtils.m; path = FirebaseStorage/Sources/FIRStorageUtils.m; sourceTree = ""; }; + 2BBAE436FDDBE0D788ED31A281A08436 /* GDTCORTransformer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORTransformer.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m; sourceTree = ""; }; + 2C404889F379D8E72FFA595E06698BE4 /* FIRSendVerificationCodeRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSendVerificationCodeRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.m; sourceTree = ""; }; + 2CD4ED2472BA0526FFE6C73D576523AE /* FIRCreateAuthURIRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRCreateAuthURIRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.m; sourceTree = ""; }; + 2CE46C58D06DFEBA5227D7A202DEE514 /* FIRStorageConstants_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageConstants_Private.h; path = FirebaseStorage/Sources/FIRStorageConstants_Private.h; sourceTree = ""; }; + 2D6DD1667F0E2BB21268B5CC194CA594 /* FIRStorageConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageConstants.m; path = FirebaseStorage/Sources/FIRStorageConstants.m; sourceTree = ""; }; + 2D84B1B010E37FBC800DEA3F33B0C3B9 /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Sources/Private/FIRComponent.h; sourceTree = ""; }; + 2D928F363DB19E4AFCF00059587BBEA8 /* FIndexedFilter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIndexedFilter.h; path = FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h; sourceTree = ""; }; + 2DAB47641886E577CCFD751778C9F2CB /* FIRMultiFactorAssertion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactorAssertion.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion.m; sourceTree = ""; }; + 2DEBB1A11CC1186F9865672E1A758722 /* FBLPromise+All.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+All.m"; path = "Sources/FBLPromises/FBLPromise+All.m"; sourceTree = ""; }; + 2E55AF603E677DAB13AAF1DECCB0780A /* FIRAuthWebUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthWebUtils.h; path = FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h; sourceTree = ""; }; + 2EA1CB32F3E439672046D86007DE8A31 /* FIRVerifyPhoneNumberResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyPhoneNumberResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.m; sourceTree = ""; }; + 2EAFE0E8FC6D0A618CC1951440D5D862 /* FIRStorageTokenAuthorizer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageTokenAuthorizer.h; path = FirebaseStorage/Sources/FIRStorageTokenAuthorizer.h; sourceTree = ""; }; + 2EB0CDD50EC9532DC424B2BE44B2FE29 /* GDTCORConsoleLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORConsoleLogger.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h; sourceTree = ""; }; + 2F43048B9E301D69301AEBFC0D7CA811 /* FIRGetOOBConfirmationCodeResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetOOBConfirmationCodeResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.m; sourceTree = ""; }; + 2F6B0DD02D0223F2F0DD71412C7EB585 /* GoogleDataTransport.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleDataTransport.release.xcconfig; sourceTree = ""; }; + 301EA6A4343640583F1D76E4D3FDB21C /* windows_logger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = windows_logger.h; path = util/windows_logger.h; sourceTree = ""; }; + 304757A5D03E8A05E64E70D59C041A7D /* logging.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = logging.cc; path = util/logging.cc; sourceTree = ""; }; + 305D63F18BFD331E7B6F6CDBAE3A86E6 /* block_builder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = block_builder.h; path = table/block_builder.h; sourceTree = ""; }; + 30C0F0FC7817DC60672EB31C8B7064E2 /* FirebaseCoreDiagnostics-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseCoreDiagnostics-dummy.m"; sourceTree = ""; }; + 30F3823B8E8D7D7EF49EF692FEC92C49 /* FirebaseStorage-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseStorage-dummy.m"; sourceTree = ""; }; + 30F3F1287E0C40F9E4C1D4DDD5807784 /* GULAppEnvironmentUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULAppEnvironmentUtil.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h; sourceTree = ""; }; + 30F697CA73EBB0310B4076303AC5B7A8 /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Sources/Private/FIRLibrary.h; sourceTree = ""; }; + 315FFAA5751909C6D0C74C10F003C319 /* FIRVerifyCustomTokenResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyCustomTokenResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h; sourceTree = ""; }; + 3162E87790D20F6130A7D9273AD557D3 /* GDTCORTransport_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORTransport_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h; sourceTree = ""; }; + 321DBB4C7DC419E9D6B93E9AF1BEF5EB /* FirebaseCoreDiagnostics.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseCoreDiagnostics.modulemap; sourceTree = ""; }; + 32CCD9D69D9B4F40FDDB4FD5B8C08322 /* FViewCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FViewCache.h; path = FirebaseDatabase/Sources/Core/View/FViewCache.h; sourceTree = ""; }; + 32D828B5EF58C384892390572BC508C4 /* GULNetworkConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkConstants.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h; sourceTree = ""; }; + 330336A17C4F23BA8D30F48A6BD38303 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProtoFinalizeMFAPhoneRequestInfo.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h; sourceTree = ""; }; + 331A7C3422670ECCDF077EDA8C5B0FB7 /* GDTCORAssert.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORAssert.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m; sourceTree = ""; }; + 332156AC66B8A5BE893815856DA94D3C /* pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb.h; sourceTree = ""; }; + 3347A1AB6546F0A3977529B8F199DC41 /* PromisesObjC */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = PromisesObjC; path = FBLPromises.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 334F251C2F070D6DB3EB649734DB97B4 /* FIRVerifyPhoneNumberRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyPhoneNumberRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h; sourceTree = ""; }; + 33AC8DDC34080E0C8F6B67968DBCD4E2 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Sources/Private/FIRLogger.h; sourceTree = ""; }; + 33B64A8F94A6603E23D737D56A9EFAC2 /* FIRAuthAPNSTokenManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthAPNSTokenManager.h; path = FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h; sourceTree = ""; }; + 33B69E4645D853E9D3C1AE7C7736CA58 /* FIRMultiFactorSession+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMultiFactorSession+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h"; sourceTree = ""; }; + 33CEE7A426306395DC3DC59B63FD36AB /* FLLRBEmptyNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLLRBEmptyNode.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.m; sourceTree = ""; }; + 33DB693963458E6D16D408C4E387BBA6 /* c.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = c.cc; path = db/c.cc; sourceTree = ""; }; + 34065017EC1BF5B0A3A4A05A2FF0D861 /* fbase64.c */ = {isa = PBXFileReference; includeInIndex = 1; name = fbase64.c; path = FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.c; sourceTree = ""; }; + 340A99536CB0153ECB0A771942C373CE /* FIRStorageTaskSnapshot_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageTaskSnapshot_Private.h; path = FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h; sourceTree = ""; }; + 3459404751ACFD08EDD0BDFD7ED39B97 /* FAtomicNumber.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FAtomicNumber.m; path = FirebaseDatabase/Sources/Utilities/FAtomicNumber.m; sourceTree = ""; }; + 34BDBD173CB4896EB12F2BD922D4F0FB /* FIRGetAccountInfoResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetAccountInfoResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h; sourceTree = ""; }; + 35079459556846DC42E6BAD6EF998A09 /* GTMSessionFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcher.h; path = Source/GTMSessionFetcher.h; sourceTree = ""; }; + 3530277F290B77EE13F89290A41E04C4 /* dumpfile.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = dumpfile.cc; path = db/dumpfile.cc; sourceTree = ""; }; + 3541E5F8A62C143380AFE1A197B39A4C /* FIRGameCenterAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGameCenterAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h; sourceTree = ""; }; + 3548EDB27273E2BA2A7598B23531161F /* FIRAuthAppCredentialManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthAppCredentialManager.m; path = FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.m; sourceTree = ""; }; + 355434705FF7B7073A4B9D11E25224D7 /* leveldb-library.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "leveldb-library.debug.xcconfig"; sourceTree = ""; }; + 355AACCB7DBED4FAC573C5B11C78B4FD /* FBLPromise+Await.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Await.m"; path = "Sources/FBLPromises/FBLPromise+Await.m"; sourceTree = ""; }; + 35818AD85F2784E8B89CB71D38ACD3F1 /* FIRIdentityToolkitRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRIdentityToolkitRequest.m; path = FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.m; sourceTree = ""; }; + 35E92455A3DBBF14B5F80114EDBC5BF3 /* FOperationSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FOperationSource.h; path = FirebaseDatabase/Sources/Core/Operation/FOperationSource.h; sourceTree = ""; }; + 366AEC787A39A50848D53D417F5F40BA /* merger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = merger.h; path = table/merger.h; sourceTree = ""; }; + 36757A52A1527757F814CD6DF5597901 /* FirebaseDatabase-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseDatabase-dummy.m"; sourceTree = ""; }; + 368E3E5C4EF9356A8DA1ECE19D07E518 /* GDTCORUploadBatch.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORUploadBatch.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m; sourceTree = ""; }; + 36E0D2029C3DAB914F381E3957231419 /* FIndexedNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIndexedNode.h; path = FirebaseDatabase/Sources/Snapshot/FIndexedNode.h; sourceTree = ""; }; + 36FA3C599D68ACB54C990556F1DFB016 /* memtable.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = memtable.h; path = db/memtable.h; sourceTree = ""; }; + 3729170399646C0750A1FF4A324422C7 /* FIRDataSnapshot.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDataSnapshot.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h; sourceTree = ""; }; + 37529818565A88B7EA068C0B2810EB6B /* GDTCCTUploadOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCCTUploadOperation.m; path = GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m; sourceTree = ""; }; + 378C8AD124FDA4F23AECAD552687460A /* GoogleDataTransport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GoogleDataTransport.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h; sourceTree = ""; }; + 3839B8982A1F73C34171ED3275C50F6C /* FIRSendVerificationCodeResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSendVerificationCodeResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h; sourceTree = ""; }; + 38DE2A3494BE61EDB0B876D18D0A55E0 /* GULHeartbeatDateStorable.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULHeartbeatDateStorable.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorable.h; sourceTree = ""; }; + 393EC1FCE7664B19AE80AF8CAFF77554 /* FIRAuthDataResult_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthDataResult_Internal.h; path = FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h; sourceTree = ""; }; + 39411F7390CCE0DB18B3C0435CA92BB0 /* FLLRBNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLLRBNode.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h; sourceTree = ""; }; + 3955A3844EE1F657DC3F3734E0E90A45 /* write_batch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = write_batch.h; path = include/leveldb/write_batch.h; sourceTree = ""; }; + 39A02C6A98117D425B34FD66D0FE409D /* FIRUserInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUserInfo.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h; sourceTree = ""; }; + 39B80F6F5EC765ED2536E876CFA12A6A /* FRangedFilter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRangedFilter.h; path = FirebaseDatabase/Sources/FRangedFilter.h; sourceTree = ""; }; + 39BE74A01BE5634F38B2B443E9F408E3 /* FIRSignUpNewUserResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSignUpNewUserResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h; sourceTree = ""; }; + 3A0B3E5EA3F8111247486DB742BB6DB7 /* GDTCORClock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORClock.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h; sourceTree = ""; }; + 3A148D6148ECB9DE570FBC7207973EB8 /* FIRVerifyCustomTokenResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyCustomTokenResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.m; sourceTree = ""; }; + 3A1F060899EF16D3F61A63082A459A58 /* env.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = env.h; path = include/leveldb/env.h; sourceTree = ""; }; + 3A79C412D90BBA0C242A6222476E3C0F /* FIRStorageObservableTask_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageObservableTask_Private.h; path = FirebaseStorage/Sources/FIRStorageObservableTask_Private.h; sourceTree = ""; }; + 3AADA268A54385BD84C98DA9A5DE30EA /* FAckUserWrite.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FAckUserWrite.m; path = FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.m; sourceTree = ""; }; + 3ABA0E9A7429B48D6B8C6BF47DF70702 /* GTMSessionFetcher-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GTMSessionFetcher-prefix.pch"; sourceTree = ""; }; + 3B07424603BC0D2D1C7EED9F0FD930D9 /* PromisesObjC-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PromisesObjC-umbrella.h"; sourceTree = ""; }; + 3B53883A091A5CB2C1CF6564AF14CE4B /* FNodeFilter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FNodeFilter.h; path = FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h; sourceTree = ""; }; + 3C3A935A0E1C775C388B504E26363B9D /* GULSecureCoding.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULSecureCoding.m; path = GoogleUtilities/Environment/GULSecureCoding.m; sourceTree = ""; }; + 3C83E99C8390879BAAE9ED2AE7E505CA /* GDTCORFlatFileStorage+Promises.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GDTCORFlatFileStorage+Promises.m"; path = "GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m"; sourceTree = ""; }; + 3CAA0FD11D8FBE058FA3A8121AEA112E /* iterator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = iterator.h; path = include/leveldb/iterator.h; sourceTree = ""; }; + 3DCE0B526350A606F7712387B591E2D9 /* FParsedUrl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FParsedUrl.m; path = FirebaseDatabase/Sources/Utilities/FParsedUrl.m; sourceTree = ""; }; + 3E9B301EABBEF76F916373F59140BDB7 /* FTypedefs_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTypedefs_Private.h; path = FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h; sourceTree = ""; }; + 3EAA9F352B333A6C73F732D89352E248 /* FIRAuthProtoMFAEnrollment.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProtoMFAEnrollment.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h; sourceTree = ""; }; + 3EB166DE4F074F3497F8F11DEA37944A /* GDTCORUploadBatch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORUploadBatch.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h; sourceTree = ""; }; + 3EB45EC81F9E789E892AA3B0F212BD9B /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CoreTelephony.framework; sourceTree = DEVELOPER_DIR; }; + 3EC5810CCA6032CB4BD0F14A8BD60522 /* FIRGetOOBConfirmationCodeResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetOOBConfirmationCodeResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h; sourceTree = ""; }; + 3F05777D1035F3FD490D2B67C497F1D7 /* Pods-saraWhatsUp-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-saraWhatsUp-umbrella.h"; sourceTree = ""; }; + 3F249B6371F8719C64CA57FC11118CC4 /* FLLRBEmptyNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLLRBEmptyNode.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h; sourceTree = ""; }; + 3FF417F53059E610CCEF3ABB2470DDD8 /* FirebaseAuth-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseAuth-dummy.m"; sourceTree = ""; }; + 4009389C08D129836F4FBC79F341D4AB /* GoogleDataTransport-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "GoogleDataTransport-Info.plist"; sourceTree = ""; }; + 404EFB07CB1339C320835C4EDA1ED913 /* env.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = env.cc; path = util/env.cc; sourceTree = ""; }; + 4054C2CE5E6C42242A0D1ED848DB68B4 /* mutexlock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = mutexlock.h; path = util/mutexlock.h; sourceTree = ""; }; + 405D1DB51D9EF49A3D1757A17D0FA23F /* FIRDatabase.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabase.m; path = FirebaseDatabase/Sources/Api/FIRDatabase.m; sourceTree = ""; }; + 407581F15079BCCB5BC45C24943E6FD2 /* FTupleTSN.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleTSN.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.m; sourceTree = ""; }; + 408EE725ADF5418AEB303B645FEFECE1 /* FIRStorageListResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageListResult.m; path = FirebaseStorage/Sources/FIRStorageListResult.m; sourceTree = ""; }; + 40C49E450975211339D6732631127E8B /* FTupleRemovedQueriesEvents.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleRemovedQueriesEvents.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h; sourceTree = ""; }; + 40F5FBEE90FA0FAA88EBC934B01FF63B /* GoogleDataTransport-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GoogleDataTransport-umbrella.h"; sourceTree = ""; }; + 41421C071CA3739A258EC0BA5CF15BD7 /* FIRVerifyAssertionRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyAssertionRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m; sourceTree = ""; }; + 41458221673789BB327991D743219EDC /* FIRMutableData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMutableData.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h; sourceTree = ""; }; + 41BE35522F50B182192D5DC520C3216C /* FTransformedEnumerator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTransformedEnumerator.m; path = FirebaseDatabase/Sources/FTransformedEnumerator.m; sourceTree = ""; }; + 41D26DFB51D254693004507B17D7B737 /* FIRAdditionalUserInfo_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAdditionalUserInfo_Internal.h; path = FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h; sourceTree = ""; }; + 4225BD34B5EB613DF261A853B2DE3A60 /* FIRDependency.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDependency.h; path = FirebaseCore/Sources/Private/FIRDependency.h; sourceTree = ""; }; + 4243357DACC2D3FCD431CCAB131AA063 /* FIREmailPasswordAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIREmailPasswordAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.m; sourceTree = ""; }; + 4266E39FA9DD1D55C7E5F79F7F3BCEE6 /* FIRCoreDiagnosticsData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCoreDiagnosticsData.h; path = Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h; sourceTree = ""; }; + 42DDF78AE884D504E56DD3D1843DD15F /* FTupleStringNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleStringNode.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h; sourceTree = ""; }; + 4355106D4E229F6C43EFA4F9DCF22898 /* FOverwrite.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FOverwrite.h; path = FirebaseDatabase/Sources/Core/Operation/FOverwrite.h; sourceTree = ""; }; + 4369B16C386867CF042633E43E33BE17 /* FIRResetPasswordResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRResetPasswordResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.m; sourceTree = ""; }; + 43B1E4CD7B30B9FD278100133C2AC788 /* FirebaseAuth */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseAuth; path = FirebaseAuth.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 43F82C12F24B532F8411A78ACE0EAC72 /* GULLoggerCodes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULLoggerCodes.h; path = GoogleUtilities/Common/GULLoggerCodes.h; sourceTree = ""; }; + 4422077BBC9F62B127CFA81DA71D3004 /* FIRSecureTokenResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSecureTokenResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.m; sourceTree = ""; }; + 442329955158D6F017C4BE628CC72663 /* FTupleOnDisconnect.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleOnDisconnect.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h; sourceTree = ""; }; + 443546F817B6B0439A3F4A59985CD4B7 /* FBLPromise+Any.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Any.h"; path = "Sources/FBLPromises/include/FBLPromise+Any.h"; sourceTree = ""; }; + 4465D325944B7C664432A0C8703A429D /* FIRDatabaseConfig.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabaseConfig.m; path = FirebaseDatabase/Sources/Api/FIRDatabaseConfig.m; sourceTree = ""; }; + 44DB219B5956C07D686FB110044AB975 /* FIRAuthStoredUserManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthStoredUserManager.m; path = FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m; sourceTree = ""; }; + 451F026B97D69D675820DFD19C8B211B /* FIRCoreDiagnosticsData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCoreDiagnosticsData.h; path = Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h; sourceTree = ""; }; + 453E14DB73F09FBD36D1DB25E717FB5C /* FIRCoreDiagnosticsInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCoreDiagnosticsInterop.h; path = Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h; sourceTree = ""; }; + 454D3B693F062A52555CB025AF94F840 /* FIRAuthTokenResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthTokenResult.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h; sourceTree = ""; }; + 454FA5FBE52280258D0A13B8B42FC8B0 /* FTupleTransaction.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleTransaction.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h; sourceTree = ""; }; + 4562E63F64CA70681763C3716BE3EF3D /* FIRIdentityToolkitRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRIdentityToolkitRequest.h; path = FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h; sourceTree = ""; }; + 456A00DB744DF00FBD9B147C646D1639 /* FIRCoreDiagnostics.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCoreDiagnostics.h; path = Firebase/CoreDiagnostics/FIRCDLibrary/Public/FIRCoreDiagnostics.h; sourceTree = ""; }; + 45AF18302FA22D80E5512B30C06C4070 /* FDataEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FDataEvent.h; path = FirebaseDatabase/Sources/Core/View/FDataEvent.h; sourceTree = ""; }; + 462FEA23E29047E8A7CA6843CA61F009 /* FIRDiagnosticsData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDiagnosticsData.h; path = FirebaseCore/Sources/FIRDiagnosticsData.h; sourceTree = ""; }; + 46DA95FEB78C1157595667E76D6B019A /* FIRAuthDefaultUIDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthDefaultUIDelegate.h; path = FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h; sourceTree = ""; }; + 46E0D19B44DD2105DB3A82048DF5D5B3 /* FListenComplete.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FListenComplete.m; path = FirebaseDatabase/Sources/FListenComplete.m; sourceTree = ""; }; + 476FDE8C0ED7BDCEDFCF04830CE7F6D9 /* FMerge.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FMerge.h; path = FirebaseDatabase/Sources/Core/Operation/FMerge.h; sourceTree = ""; }; + 47C6C963C21CCD40BCDAED4F0971499A /* FIRVerifyPasswordRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyPasswordRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h; sourceTree = ""; }; + 47E1657B953672DCE7012A9F6150D4BE /* FIRVerifyPasswordResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyPasswordResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.m; sourceTree = ""; }; + 4881E794C59369CE1B4F97ED9D5EE21E /* FIRDatabaseComponent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabaseComponent.m; path = FirebaseDatabase/Sources/Api/FIRDatabaseComponent.m; sourceTree = ""; }; + 49144B923E72023870AA11B1320F1F4D /* FLimitedFilter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLimitedFilter.h; path = FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h; sourceTree = ""; }; + 4933D04D038FAE70992539991986C709 /* FIRStorageUploadTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageUploadTask.m; path = FirebaseStorage/Sources/FIRStorageUploadTask.m; sourceTree = ""; }; + 493F18C6B603AF3ADDFD8FB37F07FEC3 /* FIRAuthSerialTaskQueue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthSerialTaskQueue.m; path = FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.m; sourceTree = ""; }; + 49517E3675D59087A341DEDAB824FAB3 /* FIROAuthCredential_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROAuthCredential_Internal.h; path = FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h; sourceTree = ""; }; + 49529F7D99AFC203DC55C22A66EF500E /* FBLPromiseError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromiseError.h; path = Sources/FBLPromises/include/FBLPromiseError.h; sourceTree = ""; }; + 495A1CBF66ED76B976B4117DD6223B93 /* FIRSecureTokenService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSecureTokenService.h; path = FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h; sourceTree = ""; }; + 49A179A28D55D47B136047F2D340ACD9 /* FIRAuthWebView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthWebView.m; path = FirebaseAuth/Sources/Utilities/FIRAuthWebView.m; sourceTree = ""; }; + 49DEF809FDF8A0305B56D6382AF927F3 /* FIRAuthURLPresenter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthURLPresenter.h; path = FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h; sourceTree = ""; }; + 4A6B7DA408335681D8EBB8E8A8195300 /* FIRAuthWebViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthWebViewController.h; path = FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h; sourceTree = ""; }; + 4A9B3935AD68926702185D93B9797C7E /* FIRAuthErrorUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthErrorUtils.m; path = FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m; sourceTree = ""; }; + 4B4CAA944EC31C6A4379E65C073335EF /* FOperationSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FOperationSource.m; path = FirebaseDatabase/Sources/Core/Operation/FOperationSource.m; sourceTree = ""; }; + 4B9919D2A47D4A51AA0F110EA67FACAB /* dbformat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = dbformat.h; path = db/dbformat.h; sourceTree = ""; }; + 4BC172B36355B2633118EA66E1485D28 /* FIRAuthAPNSToken.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthAPNSToken.h; path = FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h; sourceTree = ""; }; + 4BDFC31F2515C00C3EF1D1C333356F6C /* FIRAuthDispatcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthDispatcher.m; path = FirebaseAuth/Sources/Auth/FIRAuthDispatcher.m; sourceTree = ""; }; + 4C54003B69296239A18EDF3744A8DF41 /* GDTCORRegistrar_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORRegistrar_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h; sourceTree = ""; }; + 4CCB2BF6F6A5EB6D04951F3D60060A14 /* GULMutableDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULMutableDictionary.m; path = GoogleUtilities/Network/GULMutableDictionary.m; sourceTree = ""; }; + 4DAE27593E4EA4BA28B1EFE6B4235D25 /* GoogleUtilities-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GoogleUtilities-umbrella.h"; sourceTree = ""; }; + 4DC1248939AA214A9B49EF4F744EA070 /* FEventRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEventRegistration.h; path = FirebaseDatabase/Sources/Core/View/FEventRegistration.h; sourceTree = ""; }; + 4DD222A708C236933A0C9863252657F2 /* FBLPromise+Retry.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Retry.h"; path = "Sources/FBLPromises/include/FBLPromise+Retry.h"; sourceTree = ""; }; + 4E18993DAD8C46A4A4E3A64FF7677CC5 /* FIRAuthInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthInterop.h; path = Interop/Auth/Public/FIRAuthInterop.h; sourceTree = ""; }; + 4E1DBC7D23830F6FD970766C7D982680 /* FIRAuthDataResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthDataResult.m; path = FirebaseAuth/Sources/Auth/FIRAuthDataResult.m; sourceTree = ""; }; + 4E5807D571718FEBFE488332153F41E0 /* PromisesObjC-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "PromisesObjC-dummy.m"; sourceTree = ""; }; + 4E6A08E5885D93950E50FCD40CF9F022 /* FIRHeartbeatInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatInfo.h; path = FirebaseCore/Sources/Private/FIRHeartbeatInfo.h; sourceTree = ""; }; + 4EB924A201604AACBB961E583E190D7A /* FChange.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FChange.h; path = FirebaseDatabase/Sources/Core/View/FChange.h; sourceTree = ""; }; + 4F06531259055A8A9A7BB2EB37E8FEB6 /* FIRPhoneAuthCredential_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneAuthCredential_Internal.h; path = FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h; sourceTree = ""; }; + 4F1E284083A40C9553A9E065850B8A1C /* FView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FView.h; path = FirebaseDatabase/Sources/Core/View/FView.h; sourceTree = ""; }; + 4F7C5E48CD0159B1D1C694CE8FEBCC3E /* FIRAuthUserDefaults.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthUserDefaults.m; path = FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.m; sourceTree = ""; }; + 4F8EDD5168E6EE7045D53755BA6ACE3B /* GTMSessionFetcherLogging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherLogging.h; path = Source/GTMSessionFetcherLogging.h; sourceTree = ""; }; + 4FB87C0E75DE3B5B7C9A8E0BAB0197F3 /* FIRStorageUploadTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageUploadTask.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageUploadTask.h; sourceTree = ""; }; + 507EA49345E185C0EF9E6311E5748B3F /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Sources/Private/FIRComponentContainer.h; sourceTree = ""; }; + 50C162F8A131149A66AA8D00EB16FD47 /* FTupleFirebase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleFirebase.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h; sourceTree = ""; }; + 50CB80E6E0BEAE2308EE795D8EFF0E61 /* GDTCORDirectorySizeTracker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORDirectorySizeTracker.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h; sourceTree = ""; }; + 5104C396E6DF2C443D0D8078264E91FF /* port.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = port.h; path = port/port.h; sourceTree = ""; }; + 51605F4C50CB89A5269DD361E6A5009E /* FIRAuthOperationType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthOperationType.h; path = FirebaseAuth/Sources/Auth/FIRAuthOperationType.h; sourceTree = ""; }; + 51671C73F008B5C0C3751B3855999213 /* FirebaseDatabase */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseDatabase; path = FirebaseDatabase.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 51DADC6EA95F8D9FE2935B2D17FFF724 /* GoogleDataTransport.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleDataTransport.debug.xcconfig; sourceTree = ""; }; + 51F316E9BA48B7969E95F23475DAF6CE /* logging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = logging.h; path = util/logging.h; sourceTree = ""; }; + 52473D87AE13917BE131E5B55A668691 /* FIRAppCheckTokenResultInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppCheckTokenResultInterop.h; path = FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h; sourceTree = ""; }; + 52B93F9A3FDAF910EB354BCC66677B36 /* FTupleSetIdPath.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleSetIdPath.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.m; sourceTree = ""; }; + 531AD53C3115F7F7EB5D782FD9813823 /* GULNetworkURLSession.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetworkURLSession.m; path = GoogleUtilities/Network/GULNetworkURLSession.m; sourceTree = ""; }; + 53BCB33DFFBC9068A6596EBFC554C15B /* FValueEventRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FValueEventRegistration.h; path = FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h; sourceTree = ""; }; + 53DEF33906E89381205BFC84CE2B334E /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Sources/Private/FIRComponent.h; sourceTree = ""; }; + 53E41845656DD3E593FDD4F6F3339B32 /* FIRVerifyClientRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyClientRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h; sourceTree = ""; }; + 5431265B4569BAA9C924F890E9684329 /* FIRStartMFAEnrollmentRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStartMFAEnrollmentRequest.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h; sourceTree = ""; }; + 54514D86CB405814FAC52602DC28EFF2 /* FTupleObjectNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleObjectNode.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h; sourceTree = ""; }; + 54F92AA596420F49A8CE62BF16ACD771 /* GDTCORTransformer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORTransformer.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h; sourceTree = ""; }; + 55306428FD4A4CD23EE65BE697D86C37 /* memtable.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = memtable.cc; path = db/memtable.cc; sourceTree = ""; }; + 553C71FD43D0F02F1FEC498375086661 /* FTreeSortedDictionaryEnumerator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTreeSortedDictionaryEnumerator.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h; sourceTree = ""; }; + 55F190ACA77146C5187A0BB15DA6EAF5 /* FIRFacebookAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFacebookAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h; sourceTree = ""; }; + 5607EBC07C127505AD967D102AE1952C /* FBLPromise+Any.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Any.m"; path = "Sources/FBLPromises/FBLPromise+Any.m"; sourceTree = ""; }; + 563A9C1C12ED779F8A95FBF46C9A61B9 /* FIRStorageMetadata_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageMetadata_Private.h; path = FirebaseStorage/Sources/FIRStorageMetadata_Private.h; sourceTree = ""; }; + 56793ED84A5687D192F21FFE912AFD81 /* FBLPromise+Validate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Validate.h"; path = "Sources/FBLPromises/include/FBLPromise+Validate.h"; sourceTree = ""; }; + 568CCC590C28D73A8937CC57C00DC09E /* FIRStorageUpdateMetadataTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageUpdateMetadataTask.h; path = FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.h; sourceTree = ""; }; + 56C3364F87A61B16B7B80534FF7547C6 /* FIRAuthKeychainServices.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthKeychainServices.m; path = FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.m; sourceTree = ""; }; + 56EE34A46421CDFB2307136C2B5B76C8 /* pb_decode.c */ = {isa = PBXFileReference; includeInIndex = 1; path = pb_decode.c; sourceTree = ""; }; + 56F81CBD795E02ECA8269A503DA73162 /* GULLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULLogger.h; path = GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h; sourceTree = ""; }; + 5893F46AF93CDDCFE5279B6FCCF0030A /* FPendingPut.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPendingPut.m; path = FirebaseDatabase/Sources/Persistence/FPendingPut.m; sourceTree = ""; }; + 59038A4766E4CC1722C7B60EEC4B33B7 /* FIREmailAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIREmailAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/Email/FIREmailAuthProvider.m; sourceTree = ""; }; + 597E0977016E0C422EE40E3D6BFECCA0 /* port_example.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = port_example.h; path = port/port_example.h; sourceTree = ""; }; + 59E834E72180D1D0389618CEE6D091AD /* FirebaseAuth.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseAuth.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h; sourceTree = ""; }; + 5A08BEE1730CF35A6FC437448ABA4FE9 /* FIRRetryHelper.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRRetryHelper.m; path = FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.m; sourceTree = ""; }; + 5A2F3C5553C76F538ABC392A606C5232 /* FIRAuthKeychainServices.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthKeychainServices.h; path = FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h; sourceTree = ""; }; + 5A3CB08CA78834D9A4E195F7E0FE927A /* table.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = table.h; path = include/leveldb/table.h; sourceTree = ""; }; + 5A9BE2440239D2864323211F1A7436E5 /* FIRAuthErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthErrors.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h; sourceTree = ""; }; + 5AC2B509956CCDD9C8BED734854FE77A /* FBLPromise+Do.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Do.h"; path = "Sources/FBLPromises/include/FBLPromise+Do.h"; sourceTree = ""; }; + 5AED10E896523AA3351EAC775C0DA052 /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Sources/Private/FIRComponentContainer.h; sourceTree = ""; }; + 5B631A61906DC5D2C67D668AC690D0F0 /* GDTCORAssert.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORAssert.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h; sourceTree = ""; }; + 5B6ED693CFD0B6CC4D958CF81650ED80 /* GULReachabilityMessageCode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULReachabilityMessageCode.h; path = GoogleUtilities/Reachability/GULReachabilityMessageCode.h; sourceTree = ""; }; + 5BE7A17DB0DB60B1B5B2023B4EEE3911 /* Pods-saraWhatsUp-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-saraWhatsUp-Info.plist"; sourceTree = ""; }; + 5C321A8D9A1BFC778344F7F211DE5680 /* Pods-saraWhatsUp */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-saraWhatsUp"; path = Pods_saraWhatsUp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5C3CFCB3EEDDF72A8350385FABE6EED2 /* GULNetworkInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkInternal.h; path = GoogleUtilities/Network/GULNetworkInternal.h; sourceTree = ""; }; + 5C470B429F1B0F7C5C9717C34523B5CD /* FIRActionCodeSettings.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRActionCodeSettings.m; path = FirebaseAuth/Sources/Auth/FIRActionCodeSettings.m; sourceTree = ""; }; + 5C8C7273435FEBC73D2074E6266738FF /* FIRAppCheckTokenResultInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppCheckTokenResultInterop.h; path = FirebaseAppCheck/Sources/Interop/FIRAppCheckTokenResultInterop.h; sourceTree = ""; }; + 5CD4886842838E480318693C78559A41 /* two_level_iterator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = two_level_iterator.h; path = table/two_level_iterator.h; sourceTree = ""; }; + 5CD8E0EADF4EE6B3E91C089CE16D4F17 /* slice.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = slice.h; path = include/leveldb/slice.h; sourceTree = ""; }; + 5D28BF6F99FC527C5CAF3B8CE13E578A /* FIRStorageErrors.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageErrors.m; path = FirebaseStorage/Sources/FIRStorageErrors.m; sourceTree = ""; }; + 5D52FE533230E7D91A995F0E70F0875C /* FIRAuthUserDefaults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthUserDefaults.h; path = FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h; sourceTree = ""; }; + 5D877752182A2E5845173CA3BF342E8F /* version_edit.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = version_edit.cc; path = db/version_edit.cc; sourceTree = ""; }; + 5E340A1BB7B1090345005734CE131B8D /* FBLPromise+Testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Testing.h"; path = "Sources/FBLPromises/include/FBLPromise+Testing.h"; sourceTree = ""; }; + 5E9476011EBE9536D02B60D647D208FF /* leveldb-library-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "leveldb-library-Info.plist"; sourceTree = ""; }; + 5EADB06838DAC9C43A23D0F1CA0C0AD1 /* GDTCORDirectorySizeTracker.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORDirectorySizeTracker.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m; sourceTree = ""; }; + 5EF7576689BC01D4194E19EF9A62732C /* coding.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = coding.h; path = util/coding.h; sourceTree = ""; }; + 5F3CD1B9DAD528B29819D6C23F49BDD7 /* FIRStorageGetMetadataTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageGetMetadataTask.m; path = FirebaseStorage/Sources/FIRStorageGetMetadataTask.m; sourceTree = ""; }; + 5F46401767E51CCF943E45AC97804AFD /* FIRCreateAuthURIResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCreateAuthURIResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h; sourceTree = ""; }; + 5F749420BEE22809423074866B4C77F2 /* GULURLSessionDataResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULURLSessionDataResponse.m; path = GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m; sourceTree = ""; }; + 5FA17DB98BC67108253D4D33E6EA8312 /* FBLPromise+Timeout.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Timeout.m"; path = "Sources/FBLPromises/FBLPromise+Timeout.m"; sourceTree = ""; }; + 5FE2B96A5E3FEAB7406E5F37AD224EBD /* FIRAuthRequestConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthRequestConfiguration.h; path = FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h; sourceTree = ""; }; + 60308EFBF8231E4B777992DB527F71E9 /* FIRAnalyticsConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAnalyticsConfiguration.h; path = FirebaseCore/Sources/FIRAnalyticsConfiguration.h; sourceTree = ""; }; + 60309DD4339A47378854B0E21D2290C3 /* FIRAuthGlobalWorkQueue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthGlobalWorkQueue.h; path = FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h; sourceTree = ""; }; + 60A8C73A7FD90C1255E0B6EFF7A2E47C /* FIRStorageMetadata.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageMetadata.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageMetadata.h; sourceTree = ""; }; + 60AAFFD70875A35BF0E1C81AD8D50ACD /* FirebaseAuth-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseAuth-umbrella.h"; sourceTree = ""; }; + 610635289C0D10AC1C508932A13F5139 /* FPruneForest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPruneForest.m; path = FirebaseDatabase/Sources/Persistence/FPruneForest.m; sourceTree = ""; }; + 6178C9FA032D52D1A34C47D97B5C12D5 /* bloom.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = bloom.cc; path = util/bloom.cc; sourceTree = ""; }; + 625B9F40AF5A3D6B6AFD638EB4F9A610 /* FIRCoreDiagnosticsConnector.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRCoreDiagnosticsConnector.m; path = FirebaseCore/Sources/FIRCoreDiagnosticsConnector.m; sourceTree = ""; }; + 62B3358312776954E31DF7EED58885A5 /* FBLPromise+Delay.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Delay.h"; path = "Sources/FBLPromises/include/FBLPromise+Delay.h"; sourceTree = ""; }; + 634E95BC4CB95F90015C87024F41037B /* FIRUserMetadata_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUserMetadata_Internal.h; path = FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h; sourceTree = ""; }; + 63546985BB72619AA1BD5BF3034999D8 /* FBLPromise+Race.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Race.m"; path = "Sources/FBLPromises/FBLPromise+Race.m"; sourceTree = ""; }; + 63B3501F8CDAFD84E1E6CFBDF3AB5A1A /* FChildChangeAccumulator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FChildChangeAccumulator.h; path = FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h; sourceTree = ""; }; + 63E1D53A4B14B4142DC4D4E2EBE46EF3 /* table_cache.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = table_cache.cc; path = db/table_cache.cc; sourceTree = ""; }; + 640F8AEF999AB871A9CF0301174BAFB5 /* FIRAuthUIDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthUIDelegate.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h; sourceTree = ""; }; + 64198B298948BC8CF0170A0327736352 /* FIRBundleUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRBundleUtil.h; path = FirebaseCore/Sources/FIRBundleUtil.h; sourceTree = ""; }; + 648736713307A30F715716CC0D7E6610 /* FIRWithdrawMFAResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRWithdrawMFAResponse.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h; sourceTree = ""; }; + 649B129D8BEEA4D78AF895FF4FB20EA9 /* FIRSignInWithGameCenterResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSignInWithGameCenterResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h; sourceTree = ""; }; + 64CEE3E2D4A19A53504FB2177D8059B5 /* FBLPromise+Then.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Then.h"; path = "Sources/FBLPromises/include/FBLPromise+Then.h"; sourceTree = ""; }; + 650A616FFDB77F03EEF97D722373AC34 /* FLeafNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLeafNode.m; path = FirebaseDatabase/Sources/Snapshot/FLeafNode.m; sourceTree = ""; }; + 653F3E17804F6B21D223272C94E3141E /* FKeyIndex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FKeyIndex.m; path = FirebaseDatabase/Sources/FKeyIndex.m; sourceTree = ""; }; + 65432ABDB449B9A041385A9150D9C1F9 /* FTupleObjects.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleObjects.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.m; sourceTree = ""; }; + 656498BDC1CD14E38CB662D4FC560689 /* FMaxNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FMaxNode.h; path = FirebaseDatabase/Sources/FMaxNode.h; sourceTree = ""; }; + 6577A54ABE028DEF2E168EC3A7B37FCA /* FIRGitHubAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGitHubAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h; sourceTree = ""; }; + 658D0800BC15A31285C173FA8D9CB733 /* FListenProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FListenProvider.m; path = FirebaseDatabase/Sources/Core/FListenProvider.m; sourceTree = ""; }; + 659FED812C988A2D8BF2D7E6F39661B8 /* FIRBundleUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRBundleUtil.m; path = FirebaseCore/Sources/FIRBundleUtil.m; sourceTree = ""; }; + 65C8D8B0C48090B294FF04FE3E6DC375 /* FirebaseAuth.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseAuth.modulemap; sourceTree = ""; }; + 65C9D3135B91FB7527D0EA93EE04C9F7 /* FirebaseDatabase-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseDatabase-umbrella.h"; sourceTree = ""; }; + 65CC113A8D6258FFC99A804308B6D18E /* FIRAppAssociationRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppAssociationRegistration.h; path = FirebaseCore/Sources/FIRAppAssociationRegistration.h; sourceTree = ""; }; + 65DD11E9D029D8A94119F4C9657DD571 /* GoogleUtilities.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = GoogleUtilities.modulemap; sourceTree = ""; }; + 65E647C1250D83FF8B141CDD6D7AB22D /* FIRFinalizeMFASignInRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFinalizeMFASignInRequest.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h; sourceTree = ""; }; + 663C76ADAD38564E75D41755802032D1 /* leveldb-library.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "leveldb-library.release.xcconfig"; sourceTree = ""; }; + 6737C17420EC2B9B78FD01C46864F7D7 /* log_format.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = log_format.h; path = db/log_format.h; sourceTree = ""; }; + 67AC37415B5E0F60D1AB77E62E71BCE2 /* comparator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = comparator.h; path = include/leveldb/comparator.h; sourceTree = ""; }; + 68045793108BA0560D877E755265EF7B /* GDTCORFlatFileStorage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORFlatFileStorage.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m; sourceTree = ""; }; + 68D36AB3BDFAE5C55B9C8F45A1A5CEBE /* FIRAuthRPCRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthRPCRequest.h; path = FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h; sourceTree = ""; }; + 68E626CB79A2ADC613582CCD54AF80C3 /* FIRAppAssociationRegistration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAppAssociationRegistration.m; path = FirebaseCore/Sources/FIRAppAssociationRegistration.m; sourceTree = ""; }; + 690301B45D9E8D31056AE28BE54B2A32 /* FSyncTree.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSyncTree.h; path = FirebaseDatabase/Sources/Core/FSyncTree.h; sourceTree = ""; }; + 692F12FCE20BD05DF9A601125B760F1F /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Sources/Private/FirebaseCoreInternal.h; sourceTree = ""; }; + 693831C5F92916966D1C6D6E899EB871 /* FIROptionsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptionsInternal.h; path = FirebaseCore/Sources/Private/FIROptionsInternal.h; sourceTree = ""; }; + 694A67A5D2B3C84DB25148DB4DCB6DA1 /* FIRStoragePath.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStoragePath.m; path = FirebaseStorage/Sources/FIRStoragePath.m; sourceTree = ""; }; + 6978362BA33830B7AD0B5DB7A2947616 /* GULAppDelegateSwizzler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULAppDelegateSwizzler.h; path = GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h; sourceTree = ""; }; + 69A1FF88AB4CE2399AC22479042C14C0 /* FIRStorageErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageErrors.h; path = FirebaseStorage/Sources/FIRStorageErrors.h; sourceTree = ""; }; + 69BC8DBB9DB5918FB6B6612E7F3B8B24 /* FLLRBValueNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLLRBValueNode.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h; sourceTree = ""; }; + 6AA3FC4AAA0E5EBF67505C5E0EA20BCB /* FView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FView.m; path = FirebaseDatabase/Sources/Core/View/FView.m; sourceTree = ""; }; + 6AF3DE1BF05C1C5CC8171AF15BF8E4AC /* FStorageEngine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FStorageEngine.h; path = FirebaseDatabase/Sources/Persistence/FStorageEngine.h; sourceTree = ""; }; + 6B3244BB9FA3011541F121A0ED25A91F /* FIRAuthInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthInterop.h; path = Interop/Auth/Public/FIRAuthInterop.h; sourceTree = ""; }; + 6B560758433B7E849C46B3873B69351A /* GDTCORUploadCoordinator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORUploadCoordinator.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h; sourceTree = ""; }; + 6BD5FF574F7F2B568DF85ED53271EC97 /* FIRCoreDiagnosticsConnector.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCoreDiagnosticsConnector.h; path = FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h; sourceTree = ""; }; + 6BD97CC4A3A756852B6EDC695CC98557 /* FIRAuthNotificationManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthNotificationManager.m; path = FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.m; sourceTree = ""; }; + 6C1CC4F20E09860CA4DC1D7D915C1D73 /* FIRStorageUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageUtils.h; path = FirebaseStorage/Sources/FIRStorageUtils.h; sourceTree = ""; }; + 6C28C18AE3A3486767C01ED576BFB6E2 /* cache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = cache.h; path = include/leveldb/cache.h; sourceTree = ""; }; + 6C9AF37FA21020C49EB931FE36D6FBD5 /* FEventGenerator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FEventGenerator.m; path = FirebaseDatabase/Sources/FEventGenerator.m; sourceTree = ""; }; + 6CC5392A5C437F2EB22C9AEEE9E80264 /* FWriteTree.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FWriteTree.m; path = FirebaseDatabase/Sources/Core/FWriteTree.m; sourceTree = ""; }; + 6CD22871E7B3423E28E68F9F67339019 /* FQuerySpec.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FQuerySpec.h; path = FirebaseDatabase/Sources/Core/FQuerySpec.h; sourceTree = ""; }; + 6DA191F722C849464E09ED0BF996686F /* FIRStartMFAEnrollmentRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStartMFAEnrollmentRequest.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.m; sourceTree = ""; }; + 6DAC3C48DBA947FB36971090D8CC75A0 /* FImmutableSortedSet.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FImmutableSortedSet.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h; sourceTree = ""; }; + 6E327D29008B38CAD50251DFE43B0910 /* GDTCORConsoleLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORConsoleLogger.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m; sourceTree = ""; }; + 6E38458165FD4E6AD15616E1CA142196 /* Pods-saraWhatsUp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-saraWhatsUp.debug.xcconfig"; sourceTree = ""; }; + 6E4E4F4AC0B704BEE2F5186BA1744611 /* FCompoundHash.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCompoundHash.h; path = FirebaseDatabase/Sources/Core/FCompoundHash.h; sourceTree = ""; }; + 6E633C1B4BD6DAA2E6890291D5FEF70A /* FIRAuthProtoStartMFAPhoneRequestInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProtoStartMFAPhoneRequestInfo.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h; sourceTree = ""; }; + 6E783914DD89D8CE4F5851BF32F1F3AD /* FIRVerifyPasswordResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyPasswordResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h; sourceTree = ""; }; + 70252C7F4F088EF4BFE7BC92EA6FB86D /* FViewProcessorResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FViewProcessorResult.h; path = FirebaseDatabase/Sources/FViewProcessorResult.h; sourceTree = ""; }; + 7082914B8A3D20F7FA5BB89F2ABA8DB2 /* FCancelEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FCancelEvent.m; path = FirebaseDatabase/Sources/Core/View/FCancelEvent.m; sourceTree = ""; }; + 70998E41522AEE00454C7810173EB2F3 /* Firebase.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Firebase.release.xcconfig; sourceTree = ""; }; + 70C515513B0530D479DEC11A0222821F /* GTMSessionFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcher.m; path = Source/GTMSessionFetcher.m; sourceTree = ""; }; + 70C8399F3F73FA8401A82FF892984E39 /* FIRCoreDiagnostics.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRCoreDiagnostics.m; path = Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m; sourceTree = ""; }; + 70E16CDF231339A38CEFC419256AF4B6 /* FSyncPoint.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSyncPoint.h; path = FirebaseDatabase/Sources/Core/FSyncPoint.h; sourceTree = ""; }; + 711156AE176D1D7C9932201F14669A1D /* FIRStorageComponent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageComponent.m; path = FirebaseStorage/Sources/FIRStorageComponent.m; sourceTree = ""; }; + 7133273F65616CB95FFF840F84F09E70 /* FIRGetProjectConfigResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetProjectConfigResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.m; sourceTree = ""; }; + 7140D4B6712D57946886774F209BB1F6 /* APLevelDB.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = APLevelDB.h; path = "FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h"; sourceTree = ""; }; + 71EE8EAC0D7B50883AEF17DADF5767A2 /* cct.nanopb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = cct.nanopb.h; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h; sourceTree = ""; }; + 7274EC13DBD95E1A1FA081BC43E5B66A /* FIRMultiFactor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactor.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactor.m; sourceTree = ""; }; + 736E2A05989CEB2E4B585E5C7E684F45 /* FIRAuthSettings.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthSettings.m; path = FirebaseAuth/Sources/Auth/FIRAuthSettings.m; sourceTree = ""; }; + 7370EFBF89FC3CF254734605FBB4493B /* Firebase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Firebase.h; path = CoreOnly/Sources/Firebase.h; sourceTree = ""; }; + 7381E483AC0125ADF1E57858686F50A4 /* FIRDependency.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDependency.m; path = FirebaseCore/Sources/FIRDependency.m; sourceTree = ""; }; + 744F3A29E3170CC5C41C864DAC5D4235 /* FArraySortedDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FArraySortedDictionary.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h; sourceTree = ""; }; + 7479F6204A3F34CDEC48DB0D5C66BAF3 /* GDTCCTNanopbHelpers.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCCTNanopbHelpers.m; path = GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m; sourceTree = ""; }; + 74821EC035B4458507191FC713CFE43F /* FIRAuth_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuth_Internal.h; path = FirebaseAuth/Sources/Auth/FIRAuth_Internal.h; sourceTree = ""; }; + 74CB9232E11BC701A20AA685EB0A9152 /* FAtomicNumber.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FAtomicNumber.h; path = FirebaseDatabase/Sources/Utilities/FAtomicNumber.h; sourceTree = ""; }; + 74E042EA7A7F096AF1B67AA3C772EBF5 /* thread_annotations.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = thread_annotations.h; path = port/thread_annotations.h; sourceTree = ""; }; + 74F3BD0F4A31AD80E7C2313A180504CC /* FIRDatabaseConfig.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseConfig.h; path = FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h; sourceTree = ""; }; + 75483AC2AE9B94CA4D4431712A9E010F /* FIRHeartbeatInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRHeartbeatInfo.m; path = FirebaseCore/Sources/FIRHeartbeatInfo.m; sourceTree = ""; }; + 757945FA220DFAC917470EC142BCAC20 /* GDTCORStorageEventSelector.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORStorageEventSelector.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m; sourceTree = ""; }; + 75CC991F7C85A64C9B896F9778873BE2 /* FIRStorageGetDownloadURLTask_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageGetDownloadURLTask_Private.h; path = FirebaseStorage/Sources/FIRStorageGetDownloadURLTask_Private.h; sourceTree = ""; }; + 75EAD854551E311C33A9678D3417E4B3 /* FIRStorageComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageComponent.h; path = FirebaseStorage/Sources/FIRStorageComponent.h; sourceTree = ""; }; + 7642C814801983526EC7A772DD7CB903 /* FTupleTSN.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleTSN.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h; sourceTree = ""; }; + 765D98B1AC54CE64FBC591B6AFCC533E /* FIRStorage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorage.m; path = FirebaseStorage/Sources/FIRStorage.m; sourceTree = ""; }; + 76BEE430E44B481CB97A3647B5104EE7 /* FBLPromisePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromisePrivate.h; path = Sources/FBLPromises/include/FBLPromisePrivate.h; sourceTree = ""; }; + 76C2FA149D8C26F195DE9762321A1920 /* status.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = status.h; path = include/leveldb/status.h; sourceTree = ""; }; + 771B1D692CD92E2E80BCF92ADE963A96 /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Sources/Private/FIRLibrary.h; sourceTree = ""; }; + 771D448D527F0ED9A6589CFA7D620F5B /* FCachePolicy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FCachePolicy.m; path = FirebaseDatabase/Sources/Persistence/FCachePolicy.m; sourceTree = ""; }; + 77994AF3EB2E00C13B79A21F6BCF9CBE /* FIRStorageTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageTask.m; path = FirebaseStorage/Sources/FIRStorageTask.m; sourceTree = ""; }; + 77B9E73A06A93EA6F9C153639F6C4AB7 /* FirebaseCore-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseCore-umbrella.h"; sourceTree = ""; }; + 77E9E4BDDA17F583BD30ED9F9BD9E915 /* FirebaseAuth.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseAuth.debug.xcconfig; sourceTree = ""; }; + 77F60AEC184F86B601A6887F1210545B /* FLLRBValueNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLLRBValueNode.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.m; sourceTree = ""; }; + 7809E5411EAED2D217B878048273E546 /* FIRFinalizeMFAEnrollmentRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFinalizeMFAEnrollmentRequest.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h; sourceTree = ""; }; + 7850D19620E2E98D2EA9DEBDC1D95704 /* FIRAuthDataResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthDataResult.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h; sourceTree = ""; }; + 78510B2DAF0836E51218B1E6D69962F7 /* FTupleBoolBlock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleBoolBlock.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.m; sourceTree = ""; }; + 78DB71C20DCE241E1C54F53EFAC77530 /* FStringUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FStringUtilities.h; path = FirebaseDatabase/Sources/Utilities/FStringUtilities.h; sourceTree = ""; }; + 794B727CDE156C67F0B60B8D474D20C7 /* db_iter.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = db_iter.cc; path = db/db_iter.cc; sourceTree = ""; }; + 796FC6CF1B3D7E3AC02697E08E2EA1F6 /* GDTCORFlatFileStorage+Promises.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GDTCORFlatFileStorage+Promises.h"; path = "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h"; sourceTree = ""; }; + 79882FAC0E130E92163100F2906DC9EE /* log_writer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = log_writer.h; path = db/log_writer.h; sourceTree = ""; }; + 7990098C6933A9C3ACFD403877E938CC /* GDTCORRegistrar.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORRegistrar.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h; sourceTree = ""; }; + 7997B21891AEA54D42E3DA56720D5EC5 /* FirebaseCore-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseCore-Info.plist"; sourceTree = ""; }; + 7A438F609CFC9332E652AAE024EE6EB4 /* FIRDatabaseConnectionContextProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseConnectionContextProvider.h; path = FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h; sourceTree = ""; }; + 7A46A292823A650C8E22CF1315EB369A /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Sources/Private/FirebaseCoreInternal.h; sourceTree = ""; }; + 7A7C906E5F537583800EE44AA0B4F724 /* FIRUserInfoImpl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRUserInfoImpl.m; path = FirebaseAuth/Sources/User/FIRUserInfoImpl.m; sourceTree = ""; }; + 7A7D82FD36D69E637ED2F86EA9CCCFC6 /* FIRGoogleAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGoogleAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h; sourceTree = ""; }; + 7A884E90C80E2A19BF969865E5AFB5AC /* GULNSData+zlib.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GULNSData+zlib.h"; path = "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h"; sourceTree = ""; }; + 7ABAB0517BE907A3D48AA8FAC13726E3 /* FBLPromise.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBLPromise.m; path = Sources/FBLPromises/FBLPromise.m; sourceTree = ""; }; + 7B14F659A087AA73A15A2172FDD72057 /* FEventEmitter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEventEmitter.h; path = FirebaseDatabase/Sources/Utilities/FEventEmitter.h; sourceTree = ""; }; + 7B51D95619BDA00B9016FAE302AD53F5 /* FIRCoreDiagnosticsConnector.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCoreDiagnosticsConnector.h; path = FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h; sourceTree = ""; }; + 7B7777FBCD8B1C6CFD56B64CACAFF882 /* FBLPromise+Reduce.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Reduce.m"; path = "Sources/FBLPromises/FBLPromise+Reduce.m"; sourceTree = ""; }; + 7B7B7C27019F0E6D7ED6C457C4FEFCB5 /* FIRVersion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVersion.m; path = FirebaseCore/Sources/FIRVersion.m; sourceTree = ""; }; + 7B9CBE9C4D930B497C1A0FF04203D438 /* FIROptionsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptionsInternal.h; path = FirebaseCore/Sources/Private/FIROptionsInternal.h; sourceTree = ""; }; + 7BEBE0B8B4A3E59166D06E1963A6E893 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Sources/Private/FIRLogger.h; sourceTree = ""; }; + 7C81B5E725699C2DA74037AE3F016F3A /* FIRAuthRequestConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthRequestConfiguration.m; path = FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.m; sourceTree = ""; }; + 7D845130CEB654D57DB488C212CDA7DF /* FViewProcessor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FViewProcessor.h; path = FirebaseDatabase/Sources/FViewProcessor.h; sourceTree = ""; }; + 7DA865334FCBB6542CCD3A0506BFD36A /* GDTCORFlatFileStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORFlatFileStorage.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h; sourceTree = ""; }; + 7E0500670DA9C6B6BB264619E4475ED6 /* FIRGetOOBConfirmationCodeRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetOOBConfirmationCodeRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.m; sourceTree = ""; }; + 7E7CDABFB608D65FEE43A17EB8C75B0A /* FIRCoreDiagnosticsInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCoreDiagnosticsInterop.h; path = Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h; sourceTree = ""; }; + 7E907B698BBF0F9109ABFC14AC18417C /* GULSecureCoding.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULSecureCoding.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h; sourceTree = ""; }; + 7EB66E7098D9785F63022238AC94D1C3 /* FIRAuthDispatcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthDispatcher.h; path = FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h; sourceTree = ""; }; + 7F94EBAB96F11BB0CEA8C3C329A569C6 /* Pods-saraWhatsUp-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-saraWhatsUp-dummy.m"; sourceTree = ""; }; + 7FE6FE37825B435D47D4B08F2AD91685 /* FIRAuthGlobalWorkQueue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthGlobalWorkQueue.m; path = FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.m; sourceTree = ""; }; + 7FE96EDA64C9137D9B8CCBCA2E2B050C /* filter_block.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = filter_block.h; path = table/filter_block.h; sourceTree = ""; }; + 8016DF8549B631F0298ACC705E2FEB07 /* GDTCOREndpoints.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREndpoints.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h; sourceTree = ""; }; + 8090F51A62764AFD707E8DC587EFBD37 /* FIRDiagnosticsData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDiagnosticsData.m; path = FirebaseCore/Sources/FIRDiagnosticsData.m; sourceTree = ""; }; + 80CDF9EB8D8F9AC9F7C8BF0A0F2D50B3 /* filename.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = filename.cc; path = db/filename.cc; sourceTree = ""; }; + 80D9586B150ABF4E1C652803A8C8420B /* FMerge.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FMerge.m; path = FirebaseDatabase/Sources/Core/Operation/FMerge.m; sourceTree = ""; }; + 80FDC76D3FBAC817FFB275752A4E8648 /* FIRCreateAuthURIResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRCreateAuthURIResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.m; sourceTree = ""; }; + 811110CD8732C07CA742FCB28DD59DAF /* filter_policy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = filter_policy.h; path = include/leveldb/filter_policy.h; sourceTree = ""; }; + 81117FB9C9B2BBBD3119E04D9F265A56 /* GTMSessionFetcherService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherService.h; path = Source/GTMSessionFetcherService.h; sourceTree = ""; }; + 81EEAF592B74F318B32710ADCF9E91B1 /* FIRAppCheckInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppCheckInterop.h; path = FirebaseAppCheck/Sources/Interop/FIRAppCheckInterop.h; sourceTree = ""; }; + 820A9143A1B34097FC8811A6824024EE /* FEventRaiser.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEventRaiser.h; path = FirebaseDatabase/Sources/Core/View/FEventRaiser.h; sourceTree = ""; }; + 822565DDCACE4B6CBA1EB346E3375B8E /* FIREmailLinkSignInResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIREmailLinkSignInResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.m; sourceTree = ""; }; + 8242A9A4631DC19F5D16EA6821C81ACE /* block_builder.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = block_builder.cc; path = table/block_builder.cc; sourceTree = ""; }; + 827DDBDAFAD49886E84E1065A72F70CC /* GULReachabilityChecker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULReachabilityChecker.h; path = GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h; sourceTree = ""; }; + 83A802E95D84E016849CCD84A2FA5A5E /* FIRStorage_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorage_Private.h; path = FirebaseStorage/Sources/FIRStorage_Private.h; sourceTree = ""; }; + 83E2E567BD461A1E4963298CA03E1F4F /* FConnection.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FConnection.m; path = FirebaseDatabase/Sources/Realtime/FConnection.m; sourceTree = ""; }; + 83EADD4A625C351937A0DE2CD57B8951 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProtoFinalizeMFAPhoneResponseInfo.m; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.m; sourceTree = ""; }; + 83F8C1112535F34E3B6D933899281A7C /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Sources/Private/FIRComponentContainer.h; sourceTree = ""; }; + 845238B4F985C6B229BBD312689D4F16 /* GDTCORUploader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORUploader.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h; sourceTree = ""; }; + 84D3910738ACD998D1901C556AB4335C /* FIRFinalizeMFASignInResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFinalizeMFASignInResponse.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.m; sourceTree = ""; }; + 84DD600E57DB8E6E08CD086A2207EC82 /* leveldb-library.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "leveldb-library.modulemap"; sourceTree = ""; }; + 851ED6E275B5A08DA28258677A801BFA /* FIRDependency.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDependency.h; path = FirebaseCore/Sources/Private/FIRDependency.h; sourceTree = ""; }; + 85396FA2E4FB7242703B77E534BB96FA /* FIRAuthNotificationManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthNotificationManager.h; path = FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h; sourceTree = ""; }; + 855AA4953460F88C0D00DB72B639F3BD /* FIREmailLinkSignInRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIREmailLinkSignInRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.m; sourceTree = ""; }; + 856378CC2E53007A66BBB5C102C82AE8 /* FBLPromise+Always.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Always.h"; path = "Sources/FBLPromises/include/FBLPromise+Always.h"; sourceTree = ""; }; + 856B5CD56F194FAD26EA91620B66D614 /* GoogleDataTransport */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = GoogleDataTransport; path = GoogleDataTransport.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 859B86587165B2DCC9980C52B661009A /* FNamedNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FNamedNode.m; path = FirebaseDatabase/Sources/FNamedNode.m; sourceTree = ""; }; + 85CE11515F2C205F76C8BFC8719857B2 /* testutil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = testutil.h; path = util/testutil.h; sourceTree = ""; }; + 85DF2F3A1C45FB8F162B24BEA791AF80 /* firebasecore.nanopb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = firebasecore.nanopb.h; path = Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h; sourceTree = ""; }; + 865CD6958FFE2BBE6CAAB27A454D920E /* GDTCORReachability.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORReachability.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m; sourceTree = ""; }; + 86670524310C3DA3D11768477D60665F /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProtoFinalizeMFAPhoneRequestInfo.m; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.m; sourceTree = ""; }; + 86C7CA6595BF223D4051F9ACD7821516 /* pb_encode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb_encode.h; sourceTree = ""; }; + 86EBBD605D3354FDA906B9F9C13C7F23 /* FPriorityIndex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPriorityIndex.h; path = FirebaseDatabase/Sources/FPriorityIndex.h; sourceTree = ""; }; + 870F25C34E7DB23FF55A93605E9D93D1 /* FStringUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FStringUtilities.m; path = FirebaseDatabase/Sources/Utilities/FStringUtilities.m; sourceTree = ""; }; + 872149127BBFF2A884E7375618BF435F /* FBLPromise+Always.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Always.m"; path = "Sources/FBLPromises/FBLPromise+Always.m"; sourceTree = ""; }; + 873B7FE9A7FFF50DB78D82AE2BB1692A /* FTupleNodePath.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleNodePath.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h; sourceTree = ""; }; + 876CF2F8FB95158F946B9DEA3869F659 /* GULLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULLogger.m; path = GoogleUtilities/Logger/GULLogger.m; sourceTree = ""; }; + 8797BE5BA0ED09CCC332EA884D1440E0 /* FIRFinalizeMFAEnrollmentResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFinalizeMFAEnrollmentResponse.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.m; sourceTree = ""; }; + 87AE30E463E767DF440624B241B3A6A4 /* GULHeartbeatDateStorageUserDefaults.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULHeartbeatDateStorageUserDefaults.m; path = GoogleUtilities/Environment/GULHeartbeatDateStorageUserDefaults.m; sourceTree = ""; }; + 87B50EC0E9EE9E6ECA780B6E21840EA0 /* GULNetwork.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetwork.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h; sourceTree = ""; }; + 883F3061318EB3429FEE92B8E6EF94D5 /* FIRDeleteAccountRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDeleteAccountRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.m; sourceTree = ""; }; + 887930CE266A149A0909951039008F18 /* FIRVerifyClientRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyClientRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.m; sourceTree = ""; }; + 88C693850F5DD1C8C6CF617B4A4686A4 /* FirebaseAuth-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseAuth-Info.plist"; sourceTree = ""; }; + 88F1093AF881820A5E667EC0F12F47EF /* FIRSetAccountInfoResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSetAccountInfoResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.m; sourceTree = ""; }; + 893755B5174475866FE50238A792D3D4 /* FKeepSyncedEventRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FKeepSyncedEventRegistration.h; path = FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h; sourceTree = ""; }; + 89475AC8A6957A1C6B79D64857558539 /* FCompoundHash.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FCompoundHash.m; path = FirebaseDatabase/Sources/Core/FCompoundHash.m; sourceTree = ""; }; + 895057CB8373A1993247A9B6D4D8115C /* filter_block.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = filter_block.cc; path = table/filter_block.cc; sourceTree = ""; }; + 896724F78E9E336F7C61BAA5D7FDA1C1 /* FIRGameCenterAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGameCenterAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.m; sourceTree = ""; }; + 89D4A7CF292E75C9E41386A232050E33 /* FIROAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIROAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m; sourceTree = ""; }; + 89E31E2A96FD20D003BF0BCAA06EA6AE /* FIRDatabaseComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseComponent.h; path = FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h; sourceTree = ""; }; + 89F007636FBF9CE37E8E53001CC953CF /* FIRGoogleAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGoogleAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h; sourceTree = ""; }; + 8A19AACF745587E8B91E0E6FACA7BF1E /* FirebaseDatabase.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseDatabase.debug.xcconfig; sourceTree = ""; }; + 8A665156BBF095A8DAE862B03D76D49E /* GDTCOREndpoints.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCOREndpoints.m; path = GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m; sourceTree = ""; }; + 8AE9920117FF484590C20A61903F5796 /* FIRStorageUpdateMetadataTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageUpdateMetadataTask.m; path = FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.m; sourceTree = ""; }; + 8B80F50DB73B1D0034621B3CDB16BE58 /* options.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = options.cc; path = util/options.cc; sourceTree = ""; }; + 8BC31B25EBCB529134F8A560ECCD3E6B /* FIRPhoneMultiFactorAssertion+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRPhoneMultiFactorAssertion+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h"; sourceTree = ""; }; + 8BCF37B07E3507CC4E49BC6EB62D2AFE /* FIRMutableData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMutableData.m; path = FirebaseDatabase/Sources/Api/FIRMutableData.m; sourceTree = ""; }; + 8C49AB2D1242CB4AEE03BD5D1FDAD050 /* FIRGetOOBConfirmationCodeRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetOOBConfirmationCodeRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h; sourceTree = ""; }; + 8C78EC07E7A21AED745FCFE8199BD2B7 /* FIROAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROAuthCredential.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h; sourceTree = ""; }; + 8CC9178C366942FD6FF6A115604EAD58 /* FirebaseCoreDiagnostics */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseCoreDiagnostics; path = FirebaseCoreDiagnostics.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D36F7FBE8A5B0A49ADB656C0A724B5D /* FIRResetPasswordResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRResetPasswordResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h; sourceTree = ""; }; + 8F6D8A5072C17C800028473C1B8DF4C8 /* GoogleUtilities-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "GoogleUtilities-Info.plist"; sourceTree = ""; }; + 8FF27683F341192130EB44D127CBA99A /* pb_common.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb_common.h; sourceTree = ""; }; + 900BF383BC85BE28DB45649BAB939A60 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + 9023A0DEA45F88CB202B8E8DB8ADE4D2 /* FIRDataSnapshot.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDataSnapshot.m; path = FirebaseDatabase/Sources/Api/FIRDataSnapshot.m; sourceTree = ""; }; + 902BFA8AA57755F097F4A2314A70024E /* cache.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = cache.cc; path = util/cache.cc; sourceTree = ""; }; + 90A27BDCA5211C8EC45EA81FBF65E552 /* FIRAuthStoredUserManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthStoredUserManager.h; path = FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h; sourceTree = ""; }; + 90CAAB7C291E0685B9F1381EE7D4BFE7 /* FWebSocketConnection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FWebSocketConnection.h; path = FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h; sourceTree = ""; }; + 919646B9BE59C2A4A31EE830A2CA8068 /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Sources/Private/FIRAppInternal.h; sourceTree = ""; }; + 91B88E934D122F562EFA30F1738C3C2A /* write_batch_internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = write_batch_internal.h; path = db/write_batch_internal.h; sourceTree = ""; }; + 91F64E407B7C5996C15B0EA7E2CC6D8D /* FIRSignUpNewUserRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSignUpNewUserRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h; sourceTree = ""; }; + 91F8FFEB623B614F5EDF8885F5E8C780 /* GULAppDelegateSwizzler.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULAppDelegateSwizzler.m; path = GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m; sourceTree = ""; }; + 923643A2605DC868E971C64C0BF28726 /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Sources/Private/FIRAppInternal.h; sourceTree = ""; }; + 925BD1DFC24947B884372F9062E7A526 /* GULHeartbeatDateStorage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULHeartbeatDateStorage.m; path = GoogleUtilities/Environment/GULHeartbeatDateStorage.m; sourceTree = ""; }; + 925E43A65D1F0FB87B5EFE7FC554BA86 /* cct.nanopb.c */ = {isa = PBXFileReference; includeInIndex = 1; name = cct.nanopb.c; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c; sourceTree = ""; }; + 9292823C54252CB8B2596AC4FCB873ED /* GDTCCTCompressionHelper.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCCTCompressionHelper.m; path = GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m; sourceTree = ""; }; + 92C8D3FC28E367731EFA7DA60B5B2769 /* GoogleUtilities-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GoogleUtilities-dummy.m"; sourceTree = ""; }; + 9319464784A2E9CF7514BBF5FB7DE52B /* FTupleBoolBlock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleBoolBlock.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h; sourceTree = ""; }; + 932BDA2F912838F24A80D4B9D69D594B /* FIROAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIROAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m; sourceTree = ""; }; + 938BD4E24A0851466BAFC3F07E2FF33F /* GULSceneDelegateSwizzler_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULSceneDelegateSwizzler_Private.h; path = GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h; sourceTree = ""; }; + 93DD3C0ECA96FFC0C58657AFB6F07DE0 /* GULKeychainUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULKeychainUtils.m; path = GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m; sourceTree = ""; }; + 93ED49D06A2C2D3717C9989F17DC95E2 /* FConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FConstants.h; path = FirebaseDatabase/Sources/Constants/FConstants.h; sourceTree = ""; }; + 94235ABB6F648EA86DBC2A05160618EA /* GTMSessionFetcherLogging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherLogging.m; path = Source/GTMSessionFetcherLogging.m; sourceTree = ""; }; + 949794C45F737460830D38D5C890CD72 /* write_batch.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = write_batch.cc; path = db/write_batch.cc; sourceTree = ""; }; + 95EF2C77F4AF7EEB9D7C7F24A0662678 /* FListenComplete.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FListenComplete.h; path = FirebaseDatabase/Sources/FListenComplete.h; sourceTree = ""; }; + 966A1DBDE4EC817C40A7AA5C8B1ABE0A /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Sources/Private/FIRAppInternal.h; sourceTree = ""; }; + 96C114DA8C3BF81BDD0DE26B97B6754A /* FTuplePathValue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTuplePathValue.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.m; sourceTree = ""; }; + 971E8724264AB745B9E5A5BCF8718493 /* log_writer.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = log_writer.cc; path = db/log_writer.cc; sourceTree = ""; }; + 983164803595694315F7F6A1821F52FB /* FIRUserMetadata.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUserMetadata.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h; sourceTree = ""; }; + 98440E5E33E773D89A33711F76183D1B /* FRangedFilter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FRangedFilter.m; path = FirebaseDatabase/Sources/FRangedFilter.m; sourceTree = ""; }; + 98624617DE7BFE80191230F4C3EA8C8F /* histogram.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = histogram.cc; path = util/histogram.cc; sourceTree = ""; }; + 9984587BC159E07ADBA1CBAFAF7A0DC4 /* GDTCCTUploader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCCTUploader.m; path = GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m; sourceTree = ""; }; + 999D8DF2DEB3C92825F53ACD82C3DB9C /* crc32c.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = crc32c.cc; path = util/crc32c.cc; sourceTree = ""; }; + 99BD44EA0561B5CE9F0F17331D6086DF /* GoogleDataTransport-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GoogleDataTransport-dummy.m"; sourceTree = ""; }; + 99F0C019D3C879F3942E5D425FAEB1A4 /* FBLPromiseError.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBLPromiseError.m; path = Sources/FBLPromises/FBLPromiseError.m; sourceTree = ""; }; + 9A08E0231CF2A46E1CAADFD0BF70218E /* db_impl.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = db_impl.cc; path = db/db_impl.cc; sourceTree = ""; }; + 9A6AEEDC723439C1699E7CF8FCCD9CA8 /* GDTCCTUploadOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCCTUploadOperation.h; path = GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h; sourceTree = ""; }; + 9A8E98FC9F43E3599FC43038D8F3A086 /* FIRServerValue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRServerValue.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h; sourceTree = ""; }; + 9AAD55BD4ADB6669E2A7308808EDF999 /* FRepo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRepo.h; path = FirebaseDatabase/Sources/Core/FRepo.h; sourceTree = ""; }; + 9AD42284107F66CA7E461B6E4D3455BF /* Pods-saraWhatsUp-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-saraWhatsUp-frameworks.sh"; sourceTree = ""; }; + 9B1977B027A730291BFC8865A04CCC89 /* GTMSessionUploadFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionUploadFetcher.m; path = Source/GTMSessionUploadFetcher.m; sourceTree = ""; }; + 9B3073A4C243406F1A0F8ECB78D00C96 /* FViewProcessorResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FViewProcessorResult.m; path = FirebaseDatabase/Sources/FViewProcessorResult.m; sourceTree = ""; }; + 9BBBA5BA7566D21A1AA9929A5E96F5D8 /* FIRFacebookAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFacebookAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h; sourceTree = ""; }; + 9C112FFED625306176513F53215AE57A /* FIRRetryHelper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRRetryHelper.h; path = FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h; sourceTree = ""; }; + 9C8A2339EA1A42BEC98EB1E8282BC101 /* FTupleObjectNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleObjectNode.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.m; sourceTree = ""; }; + 9CAFBE8E892174EFAEA29FCBD9318A38 /* FChange.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FChange.m; path = FirebaseDatabase/Sources/Core/View/FChange.m; sourceTree = ""; }; + 9CCC54EEE3F4DC8C1F48E8CBA72E1888 /* FViewCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FViewCache.m; path = FirebaseDatabase/Sources/Core/View/FViewCache.m; sourceTree = ""; }; + 9CF8FA5F01F446F01AAC7331075452AD /* FirebaseStorage */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseStorage; path = FirebaseStorage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9D2D2CDA157BA843AC5E477C656AC3A5 /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Sources/Private/FIRComponentType.h; sourceTree = ""; }; + 9D5D02FA20F7768EBC412798CA562E0F /* GULNetworkURLSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkURLSession.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h; sourceTree = ""; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9F00695EF92C4DF50D63567271334E34 /* FIRStorageGetDownloadURLTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageGetDownloadURLTask.m; path = FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.m; sourceTree = ""; }; + 9F44676D510C821AA4FCBEB2EDC7C1A9 /* FWriteTree.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FWriteTree.h; path = FirebaseDatabase/Sources/Core/FWriteTree.h; sourceTree = ""; }; + 9F9B40A1541FA2FB2FD430EC3320EA58 /* GDTCOREventDataObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREventDataObject.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h; sourceTree = ""; }; + 9FAD94001809AEFE8281F5B87506A581 /* FNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FNode.h; path = FirebaseDatabase/Sources/Snapshot/FNode.h; sourceTree = ""; }; + A028346C0A515F7539EB33C42B3D0DF5 /* GDTCORStorageProtocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORStorageProtocol.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h; sourceTree = ""; }; + A0D696069DC52E2EA049543F7F8A9256 /* c.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = c.h; path = include/leveldb/c.h; sourceTree = ""; }; + A0E6A648E4E14D6B21A0F8DF95C04F9C /* FIRSetAccountInfoResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSetAccountInfoResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h; sourceTree = ""; }; + A10858F9FD018F9DF1B20B62C3C26C77 /* FTupleUserCallback.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleUserCallback.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h; sourceTree = ""; }; + A13E5ECB9FF3870B0D27C2277B9EEF55 /* FTree.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTree.h; path = FirebaseDatabase/Sources/Core/Utilities/FTree.h; sourceTree = ""; }; + A13F6D7C44A5A2A6597076C8707DBA66 /* dumpfile.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = dumpfile.h; path = include/leveldb/dumpfile.h; sourceTree = ""; }; + A18052F86CDC309B984F2A072E0B8350 /* FIRAuthRPCResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthRPCResponse.h; path = FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h; sourceTree = ""; }; + A1BFD9AE542728E653ADC18E3BB48638 /* iterator.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = iterator.cc; path = table/iterator.cc; sourceTree = ""; }; + A1F163BCAE7863A12A99F71053BC2965 /* PromisesObjC-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "PromisesObjC-Info.plist"; sourceTree = ""; }; + A23BCDA5AC206E7CB756611195DEA81D /* FChildrenNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FChildrenNode.h; path = FirebaseDatabase/Sources/Snapshot/FChildrenNode.h; sourceTree = ""; }; + A24B571815B03F78DBFCF213BC206922 /* hash.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = hash.cc; path = util/hash.cc; sourceTree = ""; }; + A257F86718127C656BABAC72ADFFFD7D /* nanopb-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "nanopb-Info.plist"; sourceTree = ""; }; + A27989CBB3630E8519D5EF0AF4D86AC3 /* GDTCORClock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORClock.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORClock.m; sourceTree = ""; }; + A28C5B0EEC2339F327C24C1DEED5DF14 /* FIRUser.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUser.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h; sourceTree = ""; }; + A291D7F492A527067349C061395FCE5A /* FirebaseCore.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseCore.modulemap; sourceTree = ""; }; + A2A67198D2ECE2676C622E472F2E7450 /* FIRLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRLogger.m; path = FirebaseCore/Sources/FIRLogger.m; sourceTree = ""; }; + A2B257ECEC088990E9CDCDBCB30CC867 /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Sources/Private/FirebaseCoreInternal.h; sourceTree = ""; }; + A362684A637B06059850B849A03F1349 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; + A38345444096C985E3396DA12EEA60C5 /* FOverwrite.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FOverwrite.m; path = FirebaseDatabase/Sources/Core/Operation/FOverwrite.m; sourceTree = ""; }; + A3B520AC90F216E89C6A144E34C7B728 /* FBLPromise+Await.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Await.h"; path = "Sources/FBLPromises/include/FBLPromise+Await.h"; sourceTree = ""; }; + A41EFA62EBC841BCB7E78DB7374FFDDC /* FIREmailAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIREmailAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h; sourceTree = ""; }; + A47B0B236ECF15DBE883A4F85C21E999 /* FSnapshotUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSnapshotUtilities.m; path = FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.m; sourceTree = ""; }; + A523A418D4F79A8D9FA56B6A3EDAF69C /* FLimitedFilter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLimitedFilter.m; path = FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.m; sourceTree = ""; }; + A56068F39B274E2B955D1D4B80323F59 /* FBLPromise+Wrap.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Wrap.h"; path = "Sources/FBLPromises/include/FBLPromise+Wrap.h"; sourceTree = ""; }; + A571F592B22AE0BF6EAFD0953CC336D5 /* nanopb.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = nanopb.modulemap; sourceTree = ""; }; + A5760DF131877B2B89137DEBFEF1A3C1 /* GDTCCTUploader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCCTUploader.h; path = GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h; sourceTree = ""; }; + A5921FBD031DE0BA0224527B5D044FCF /* FIndexedFilter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIndexedFilter.m; path = FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.m; sourceTree = ""; }; + A5EE7C10193DBDDADE98DC3A19921624 /* FBLPromise+Reduce.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Reduce.h"; path = "Sources/FBLPromises/include/FBLPromise+Reduce.h"; sourceTree = ""; }; + A694F59813CCC4BC2AC445313784F0F2 /* format.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = format.h; path = table/format.h; sourceTree = ""; }; + A7133D98A56EE451D8DD163BAB3BBB28 /* FirebaseStorage.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseStorage.release.xcconfig; sourceTree = ""; }; + A7164E84783F2E49EAEC72DB3D512690 /* GULNSData+zlib.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GULNSData+zlib.m"; path = "GoogleUtilities/NSData+zlib/GULNSData+zlib.m"; sourceTree = ""; }; + A723A7F93D474EA6452E32D7F163FEA5 /* FIRAuthAPNSTokenManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthAPNSTokenManager.m; path = FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.m; sourceTree = ""; }; + A7281F8592B9D881F237AD35C3339C04 /* NSData+SRB64Additions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+SRB64Additions.h"; path = "FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h"; sourceTree = ""; }; + A75A814253FC19978642F5B98FBE1C54 /* FIRAuthURLPresenter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthURLPresenter.m; path = FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.m; sourceTree = ""; }; + A7FA416AE84B24927DEE30CC26F89422 /* GTMSessionFetcher.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = GTMSessionFetcher.modulemap; sourceTree = ""; }; + A8F96448F361676D974EF9A55C032F1F /* FIRAuthTokenResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthTokenResult.m; path = FirebaseAuth/Sources/Auth/FIRAuthTokenResult.m; sourceTree = ""; }; + A978F386557998E5D34EB6BB8A499A13 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; }; + A9B2E8CE344E4A43DE5471284EB56977 /* FClock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FClock.h; path = FirebaseDatabase/Sources/FClock.h; sourceTree = ""; }; + AA9244E063FD307DF5A1C224EFF32D86 /* FirebaseCore-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseCore-dummy.m"; sourceTree = ""; }; + AB2EF60C16B7021A14AE4954EF2F717B /* FIRAuthDefaultUIDelegate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthDefaultUIDelegate.m; path = FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.m; sourceTree = ""; }; + AB5E508280625F1411B9EFB92FE8198F /* format.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = format.cc; path = table/format.cc; sourceTree = ""; }; + AB7DB6EF23B9761561E1598918C90693 /* FIRStartMFASignInRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStartMFASignInRequest.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h; sourceTree = ""; }; + AB906146CF850CAF5331097EACEF462C /* FPersistenceManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPersistenceManager.h; path = FirebaseDatabase/Sources/Persistence/FPersistenceManager.h; sourceTree = ""; }; + ABA74436D35D18B787BA88238D23AF32 /* FCancelEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCancelEvent.h; path = FirebaseDatabase/Sources/Core/View/FCancelEvent.h; sourceTree = ""; }; + ABE44E0B7E460C06F92D3D1CE8AF490B /* FIRMultiFactor+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMultiFactor+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h"; sourceTree = ""; }; + ABEFDEDD9204F734E8CF7156DB34EAC2 /* FIRConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRConfiguration.m; path = FirebaseCore/Sources/FIRConfiguration.m; sourceTree = ""; }; + ABF88EF97C5E5AAC2CA3410AF223A810 /* FIRStorageListResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageListResult.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageListResult.h; sourceTree = ""; }; + AC9918E2FAE139C78CDF7F9F674FFA1F /* FIRStorageDownloadTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageDownloadTask.m; path = FirebaseStorage/Sources/FIRStorageDownloadTask.m; sourceTree = ""; }; + ACD4A4491817F56E21D0F68271612C7D /* GTMSessionFetcherService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherService.m; path = Source/GTMSessionFetcherService.m; sourceTree = ""; }; + ACE8DCECAAD1F5B7F9D2031B60201FE3 /* FIRFirebaseUserAgent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFirebaseUserAgent.m; path = FirebaseCore/Sources/FIRFirebaseUserAgent.m; sourceTree = ""; }; + ACFA9A512528EAD2FCC4355818A33CD3 /* PromisesObjC.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PromisesObjC.release.xcconfig; sourceTree = ""; }; + AD619B86153088B111D40A2840C799F4 /* FMaxNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FMaxNode.m; path = FirebaseDatabase/Sources/FMaxNode.m; sourceTree = ""; }; + AEFAC1E7E8D13CF3F8C80D787FC8EA68 /* pb_decode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb_decode.h; sourceTree = ""; }; + AF73E4F33B65F69FB06DB662B11DE607 /* GDTCORUploadCoordinator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORUploadCoordinator.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m; sourceTree = ""; }; + AFC22D41599A2CA8D184D8CF956E77FB /* FClock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FClock.m; path = FirebaseDatabase/Sources/FClock.m; sourceTree = ""; }; + B17EC1FDC566D6EE01633B7220A39230 /* FIRComponentType.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRComponentType.m; path = FirebaseCore/Sources/FIRComponentType.m; sourceTree = ""; }; + B17F92A2601314D41826CAB86DA61688 /* FCacheNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FCacheNode.m; path = FirebaseDatabase/Sources/Core/View/FCacheNode.m; sourceTree = ""; }; + B1905F81A71DDC3422570810765B92E4 /* FEmptyNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEmptyNode.h; path = FirebaseDatabase/Sources/Snapshot/FEmptyNode.h; sourceTree = ""; }; + B1E900E5749E319AC8DD9C2AA0A26B7A /* FIRGetProjectConfigResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetProjectConfigResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h; sourceTree = ""; }; + B205E2A02343B83399E353E5848FB22C /* FIRVerifyAssertionResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyAssertionResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.m; sourceTree = ""; }; + B20A9D1B2E1FF259990B121B18078B8B /* FirebaseStorage-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseStorage-Info.plist"; sourceTree = ""; }; + B23BBEB7E4D6A74D7D47CE8C255EB839 /* FIRLoggerLevel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLoggerLevel.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h; sourceTree = ""; }; + B23EC38971E21F4A29F30D17FB217E7D /* GDTCOREvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCOREvent.m; path = GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m; sourceTree = ""; }; + B251FA096ACFF51E3C472B66C3246C5E /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Sources/Private/FIRComponent.h; sourceTree = ""; }; + B271E16961C347079CB7026341CA75D0 /* FSnapshotHolder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSnapshotHolder.m; path = FirebaseDatabase/Sources/Core/FSnapshotHolder.m; sourceTree = ""; }; + B291863611DA98B373B9B2EB0CD48177 /* version_set.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = version_set.h; path = db/version_set.h; sourceTree = ""; }; + B2ADA563135B97021B2C1F71DF0405B8 /* FQueryParams.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FQueryParams.h; path = FirebaseDatabase/Sources/Core/FQueryParams.h; sourceTree = ""; }; + B2D5A80CA37F8BD29B4EAF0D339F38F7 /* FIRAuthProtoMFAEnrollment.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProtoMFAEnrollment.m; path = FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.m; sourceTree = ""; }; + B2D9BB15B65A8F9774E2C2D7FA9C5A52 /* FIRAuthProtoStartMFAPhoneResponseInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProtoStartMFAPhoneResponseInfo.m; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.m; sourceTree = ""; }; + B305CFA4A65CC751131EB86AA4DB3ED7 /* FPersistenceManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPersistenceManager.m; path = FirebaseDatabase/Sources/Persistence/FPersistenceManager.m; sourceTree = ""; }; + B3125D500C1F70AC85CA5401A1F25E6A /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + B34CAD0C7390089C50B4AECD381D8AC5 /* FCacheNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCacheNode.h; path = FirebaseDatabase/Sources/Core/View/FCacheNode.h; sourceTree = ""; }; + B351FCC097D07CD16092C31C2CA42839 /* FIRAuthWebUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthWebUtils.m; path = FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.m; sourceTree = ""; }; + B3A4EA889B8F6E87EFD595D77588F34C /* FIRAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/FIRAuthCredential.m; sourceTree = ""; }; + B3AD7AA0EA6D0ACE1BE4E5D12C5F2869 /* FPath.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPath.h; path = FirebaseDatabase/Sources/Core/Utilities/FPath.h; sourceTree = ""; }; + B3F239DE45C16ECA602453788681BAAE /* FIRCoreDiagnosticsConnector.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCoreDiagnosticsConnector.h; path = FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h; sourceTree = ""; }; + B43874C6CBB50E7134FBEC24BABFE14F /* GoogleUtilities */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = GoogleUtilities; path = GoogleUtilities.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B4653519E5F123F81CEF7260656B7E0B /* FTrackedQuery.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTrackedQuery.m; path = FirebaseDatabase/Sources/Persistence/FTrackedQuery.m; sourceTree = ""; }; + B48A5067D93FC5220DF1348412F02223 /* GTMSessionUploadFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionUploadFetcher.h; path = Source/GTMSessionUploadFetcher.h; sourceTree = ""; }; + B4F8D21D4F75C7ACFB902F78724ADF00 /* FIRComponentContainerInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainerInternal.h; path = FirebaseCore/Sources/FIRComponentContainerInternal.h; sourceTree = ""; }; + B4FF56EBCE0455EE942F1411CAD7E3B4 /* GDTCOREvent_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREvent_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h; sourceTree = ""; }; + B53B4F47E785737B058E7A4C89B15D48 /* FIROptions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIROptions.m; path = FirebaseCore/Sources/FIROptions.m; sourceTree = ""; }; + B613B172469E17F497E9203011CE9EA6 /* FTreeNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTreeNode.m; path = FirebaseDatabase/Sources/Core/Utilities/FTreeNode.m; sourceTree = ""; }; + B619FA3B200C111A548E62024E1C5A0A /* FValidation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FValidation.h; path = FirebaseDatabase/Sources/Utilities/FValidation.h; sourceTree = ""; }; + B67EF49828FB87A7A9D76CFCE913F31F /* FSparseSnapshotTree.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSparseSnapshotTree.m; path = FirebaseDatabase/Sources/Core/FSparseSnapshotTree.m; sourceTree = ""; }; + B6A063636D2C9CF47A66A3A4D96EB2A2 /* two_level_iterator.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = two_level_iterator.cc; path = table/two_level_iterator.cc; sourceTree = ""; }; + B6B8C36C9A9595FB83246E705A636C10 /* FImmutableTree.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FImmutableTree.h; path = FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h; sourceTree = ""; }; + B6FFCD446AFFF8D411EFD5BBB944A1BE /* FIRVerifyClientResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyClientResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h; sourceTree = ""; }; + B792817C5B5886C0147589470D6CCB0B /* FIRUserInfoImpl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUserInfoImpl.h; path = FirebaseAuth/Sources/User/FIRUserInfoImpl.h; sourceTree = ""; }; + B8032A0DB492656E1C113353FB6D43DE /* GULHeartbeatDateStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULHeartbeatDateStorage.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h; sourceTree = ""; }; + B80FA25AA1ED7576FF55175F0718FB6F /* FBLPromise+Retry.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Retry.m"; path = "Sources/FBLPromises/FBLPromise+Retry.m"; sourceTree = ""; }; + B81795EFF3756C6009403EB7B9A9868C /* NSURLSession+GULPromises.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSURLSession+GULPromises.h"; path = "GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h"; sourceTree = ""; }; + B827A66AEACAE0FAE2795D9338925F12 /* FRepo_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRepo_Private.h; path = FirebaseDatabase/Sources/Core/FRepo_Private.h; sourceTree = ""; }; + B83D5E64ACCD27EE28AEF71FBD036120 /* FIRActionCodeSettings.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRActionCodeSettings.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h; sourceTree = ""; }; + B8481B7DCD916B592B3296314358DC65 /* FIRDatabase_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabase_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h; sourceTree = ""; }; + B89A3C3BE57CFAFD85B24D321FD6BF7C /* FIRCoreDiagnosticsConnector.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCoreDiagnosticsConnector.h; path = FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h; sourceTree = ""; }; + B8B222728C3FF9B9FD14A76423A49B1B /* FIRComponent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRComponent.m; path = FirebaseCore/Sources/FIRComponent.m; sourceTree = ""; }; + B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + B936B1C80480FC87F5447A70D6AD27EC /* options.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = options.h; path = include/leveldb/options.h; sourceTree = ""; }; + B95010BC3EBD9FC0909725BDB3ABF4D9 /* FIRDeleteAccountRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDeleteAccountRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h; sourceTree = ""; }; + B981E34571A9050A1158813B45ABAA57 /* FIRDependency.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDependency.h; path = FirebaseCore/Sources/Private/FIRDependency.h; sourceTree = ""; }; + B98C573562E1874BD238096257145128 /* FIRDatabaseReference.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabaseReference.m; path = FirebaseDatabase/Sources/FIRDatabaseReference.m; sourceTree = ""; }; + B9DF6D4C0C68854AF972C290CF88B7A0 /* GoogleUtilities.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleUtilities.release.xcconfig; sourceTree = ""; }; + B9E907CA9588C9B9F242488583AC812D /* FIRStoragePath.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStoragePath.h; path = FirebaseStorage/Sources/FIRStoragePath.h; sourceTree = ""; }; + BA0C130C5AD4E78EF53F155ED1EEBDC5 /* FIROAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h; sourceTree = ""; }; + BA511F39EE0137DB4B0ACAA4F2EB5714 /* block.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = block.cc; path = table/block.cc; sourceTree = ""; }; + BB265518B2679102E1A6CCB3C247F6BE /* FUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FUtilities.m; path = FirebaseDatabase/Sources/Utilities/FUtilities.m; sourceTree = ""; }; + BBAF527ADC6259102C1FC8064BB26450 /* FIRAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthCredential.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h; sourceTree = ""; }; + BBBA3A61F8609CF2D274B58E72304564 /* FIRMultiFactorInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMultiFactorInfo.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h; sourceTree = ""; }; + BC0887BB80201541368EB5158D171A30 /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Sources/Private/FIRComponent.h; sourceTree = ""; }; + BC69DBAD903AA8D81D0899406634F740 /* FIRStorageGetMetadataTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageGetMetadataTask.h; path = FirebaseStorage/Sources/FIRStorageGetMetadataTask.h; sourceTree = ""; }; + BCA1C279CD7AB01391FC73FF502E99AD /* FIRDeleteAccountResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDeleteAccountResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h; sourceTree = ""; }; + BCE449A532CA88DFB2BC752B06041EC5 /* GULHeartbeatDateStorageUserDefaults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULHeartbeatDateStorageUserDefaults.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h; sourceTree = ""; }; + BD613FA63F113B835232228E5415A586 /* FIRAuthWebViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthWebViewController.m; path = FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.m; sourceTree = ""; }; + BD7E408A6A285E49DF1591FCF1591362 /* FBLPromise+Delay.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Delay.m"; path = "Sources/FBLPromises/FBLPromise+Delay.m"; sourceTree = ""; }; + BE74BCE8877C97E09DCE08D7221FFDFD /* FCompoundWrite.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FCompoundWrite.m; path = FirebaseDatabase/Sources/Snapshot/FCompoundWrite.m; sourceTree = ""; }; + BF7B94731C7027BE19E68D31F0CDEBEA /* FBLPromise+All.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+All.h"; path = "Sources/FBLPromises/include/FBLPromise+All.h"; sourceTree = ""; }; + BF8645293BD84FC36ED2B54D4E52D0AF /* FBLPromise+Validate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Validate.m"; path = "Sources/FBLPromises/FBLPromise+Validate.m"; sourceTree = ""; }; + BFF584623DAE6086D9A916D16C35507D /* FIRAuthBackend.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthBackend.h; path = FirebaseAuth/Sources/Backend/FIRAuthBackend.h; sourceTree = ""; }; + C00C0C9FE788D4BEAEE1CD97C5B7CA54 /* log_reader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = log_reader.h; path = db/log_reader.h; sourceTree = ""; }; + C04D966A10440A875CD3413E6B4B651C /* FIRGameCenterAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGameCenterAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m; sourceTree = ""; }; + C0924D6996644371910F4B789323F05F /* FIRMultiFactor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMultiFactor.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h; sourceTree = ""; }; + C0A5DA5FFD9B0E3136640EFCA7795031 /* FIRTwitterAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRTwitterAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h; sourceTree = ""; }; + C0D33B98DFBE8B633825E3A7B7AD1632 /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Sources/Private/FIRLibrary.h; sourceTree = ""; }; + C0D982FA616BAFDFC5F2ADA6D865ACEE /* FBLPromises.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromises.h; path = Sources/FBLPromises/include/FBLPromises.h; sourceTree = ""; }; + C17F19ED839D7947EFCF4E484C64AF60 /* FIROptions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptions.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h; sourceTree = ""; }; + C1998E0D8085221AD87F89B614C10E52 /* GTMSessionFetcher */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = GTMSessionFetcher; path = GTMSessionFetcher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C228A639A3A804038FCAFE0D56A11E97 /* FIRStorageTokenAuthorizer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageTokenAuthorizer.m; path = FirebaseStorage/Sources/FIRStorageTokenAuthorizer.m; sourceTree = ""; }; + C2DCA7FCB2F1AA7E5182524022DDFAC9 /* FIRAuth.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuth.m; path = FirebaseAuth/Sources/Auth/FIRAuth.m; sourceTree = ""; }; + C2EC8C6C780C5860481702B4A1E37E4B /* FIRTwitterAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRTwitterAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.m; sourceTree = ""; }; + C379D2DA2D639963933E2B6BD2FBF6D1 /* FIRVerifyPasswordRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyPasswordRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.m; sourceTree = ""; }; + C3B84167E1CB948B5A68D8197312567B /* FTupleTransaction.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleTransaction.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.m; sourceTree = ""; }; + C3ED5F9B71BB5AB9B21AD796059C1958 /* FIndex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIndex.h; path = FirebaseDatabase/Sources/FIndex.h; sourceTree = ""; }; + C3FDDBCAD63AD6C646361AF484324D5D /* FirebaseStorage-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseStorage-umbrella.h"; sourceTree = ""; }; + C41052FC02AEECA1AEEB044D099DF29E /* GTMSessionFetcher-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GTMSessionFetcher-umbrella.h"; sourceTree = ""; }; + C49A0050512E4D846C5B20571F192808 /* SafariServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SafariServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/SafariServices.framework; sourceTree = DEVELOPER_DIR; }; + C49ED58E11F92CAF3C06EC8A74B9BC36 /* FIRTwitterAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRTwitterAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthProvider.m; sourceTree = ""; }; + C4CC188B7B93B535D5F12913B4B2F37E /* db_impl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = db_impl.h; path = db/db_impl.h; sourceTree = ""; }; + C4E35116F3D5249AB4E261D67CDF74A6 /* FIRStorageReference.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageReference.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h; sourceTree = ""; }; + C532F2EFDCFDAA9E763A5DAB92A56843 /* FLevelDBStorageEngine.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLevelDBStorageEngine.m; path = FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.m; sourceTree = ""; }; + C57780199E3F445CA56E1EF2ADA32EB1 /* FIRVerifyAssertionRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyAssertionRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h; sourceTree = ""; }; + C59EBCCA53061961256AE11C24B8DA68 /* FIREmailLinkSignInRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIREmailLinkSignInRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h; sourceTree = ""; }; + C60545B543575471D5F2B720681B8F4F /* FIRMutableData_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMutableData_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h; sourceTree = ""; }; + C61B106681E3099B5B9744CA4BD8C8BB /* GTMSessionFetcher.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GTMSessionFetcher.release.xcconfig; sourceTree = ""; }; + C63E288BFEA73AB13BADC975423E2506 /* FIRFacebookAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFacebookAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthProvider.m; sourceTree = ""; }; + C661AC8E9FEAADAC1C40F825A2137419 /* GoogleUtilities.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleUtilities.debug.xcconfig; sourceTree = ""; }; + C6BE8F46BEE35DA8571C06A26A640632 /* FIRWithdrawMFARequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRWithdrawMFARequest.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.m; sourceTree = ""; }; + C7251F3F7533A9A216EFD0FF18A7FEA5 /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Sources/Private/FIRComponentType.h; sourceTree = ""; }; + C74C1F1761112ECCEAF3300A37403DDD /* FIRMultiFactorResolver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMultiFactorResolver.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h; sourceTree = ""; }; + C7583A00EFC7FC0517BD69D6D09B32E2 /* FIRMultiFactorConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactorConstants.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactorConstants.m; sourceTree = ""; }; + C75BC3FDB221D20BFF8AC4B4906E6172 /* FTupleNodePath.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleNodePath.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.m; sourceTree = ""; }; + C7FAFE3089E9D23C2B1DBED2289F4CBC /* FIRStorageDeleteTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageDeleteTask.m; path = FirebaseStorage/Sources/FIRStorageDeleteTask.m; sourceTree = ""; }; + C86A046017B5D5FA14470F7B2E9392BC /* FIRStorageDownloadTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageDownloadTask.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageDownloadTask.h; sourceTree = ""; }; + C97ED48F534DAB71C30E29D42CE0C347 /* block.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = block.h; path = table/block.h; sourceTree = ""; }; + C999B82DC40782937B995EB4447F67C1 /* table.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = table.cc; path = table/table.cc; sourceTree = ""; }; + C9B8B71643A846CA2ADA132AD852A522 /* FIRPhoneAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRPhoneAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential.m; sourceTree = ""; }; + C9B9793C13F569DADCC8C8F0E04F16A5 /* FServerValues.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FServerValues.m; path = FirebaseDatabase/Sources/Core/FServerValues.m; sourceTree = ""; }; + C9FFBCDFEBF380E250E116854F608812 /* FirebaseAuth.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseAuth.release.xcconfig; sourceTree = ""; }; + CA348D76247362411205819BEBAE4021 /* FTupleSetIdPath.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleSetIdPath.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h; sourceTree = ""; }; + CA5DF7383A09BA07C99F52E2965F0A2E /* GULAppEnvironmentUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULAppEnvironmentUtil.m; path = GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m; sourceTree = ""; }; + CB0BECAA820EA39FDA6E794C088A9F72 /* FQuerySpec.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FQuerySpec.m; path = FirebaseDatabase/Sources/Core/FQuerySpec.m; sourceTree = ""; }; + CB1E13E7998204FCB479D758BE566FDE /* FIRStartMFAEnrollmentResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStartMFAEnrollmentResponse.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h; sourceTree = ""; }; + CB962D67899B3AA299F65B98309061FB /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Sources/Private/FIRLibrary.h; sourceTree = ""; }; + CBBEF9A24FDDF05863D1B193EB0592AA /* FSnapshotHolder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSnapshotHolder.h; path = FirebaseDatabase/Sources/Core/FSnapshotHolder.h; sourceTree = ""; }; + CBE24A706CEBF7649A1C7B1E338AA52C /* FIRUser.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRUser.m; path = FirebaseAuth/Sources/User/FIRUser.m; sourceTree = ""; }; + CC269863983FDEAD924D5FBE3FD87236 /* FAckUserWrite.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FAckUserWrite.h; path = FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h; sourceTree = ""; }; + CC53772094E8CA6243B6A7930C6D7E99 /* FChildrenNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FChildrenNode.m; path = FirebaseDatabase/Sources/Snapshot/FChildrenNode.m; sourceTree = ""; }; + CC9F05108D2A9DE51B409B2429608A48 /* export.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = export.h; path = include/leveldb/export.h; sourceTree = ""; }; + CD698ABE83B63A4FDBC7C167D924FA4F /* Pods-saraWhatsUp-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-saraWhatsUp-acknowledgements.markdown"; sourceTree = ""; }; + CDEC520DB3D5CC6139576078A00C1FCD /* FIRMultiFactorAssertion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMultiFactorAssertion.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h; sourceTree = ""; }; + CDF8AC51DB6AC1BF9C30A265F6670B60 /* FIRTransactionResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRTransactionResult.m; path = FirebaseDatabase/Sources/Api/FIRTransactionResult.m; sourceTree = ""; }; + CE5BA5A1C569D1F8BED18C2C5EC763C1 /* skiplist.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = skiplist.h; path = db/skiplist.h; sourceTree = ""; }; + CEA0532B6963DB6C4B82B68B1AEEDAFE /* nanopb-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "nanopb-dummy.m"; sourceTree = ""; }; + CEB8FBCE6B02585240FAEBCEF664AFEF /* GULNetworkConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetworkConstants.m; path = GoogleUtilities/Network/GULNetworkConstants.m; sourceTree = ""; }; + CED377BFBEA5C61B77385FC87D617E93 /* FTreeSortedDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTreeSortedDictionary.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h; sourceTree = ""; }; + CED836F5AB275798DF1EF9CEDBAFD697 /* FIRFirebaseUserAgent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFirebaseUserAgent.h; path = FirebaseCore/Sources/FIRFirebaseUserAgent.h; sourceTree = ""; }; + CF352B6F70E09752E60EF9E4B1A9FDD3 /* random.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = random.h; path = util/random.h; sourceTree = ""; }; + CFA9A98B0E39FA0EEA43D511B134FC95 /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Sources/Private/FIRComponentType.h; sourceTree = ""; }; + CFB14EC1E12FD320A96E0F01E8E89EB2 /* FIRConfigurationInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRConfigurationInternal.h; path = FirebaseCore/Sources/FIRConfigurationInternal.h; sourceTree = ""; }; + CFE231493E8C735456EE5EE7B5E7B915 /* FIRAuthProtoStartMFAPhoneResponseInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProtoStartMFAPhoneResponseInfo.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h; sourceTree = ""; }; + D023DA0E20514A607A76BF8E49A6BD1E /* FIRVerifyClientResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyClientResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.m; sourceTree = ""; }; + D05CC9584CA83D98144C21E350DFBE48 /* FPendingPut.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPendingPut.h; path = FirebaseDatabase/Sources/Persistence/FPendingPut.h; sourceTree = ""; }; + D0925C8787A05CA82DB6EEA81561F989 /* FIRStorageReference.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageReference.m; path = FirebaseStorage/Sources/FIRStorageReference.m; sourceTree = ""; }; + D09720D9CE5B015636E0BF2DF73B40A2 /* FIRSecureTokenService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSecureTokenService.m; path = FirebaseAuth/Sources/SystemService/FIRSecureTokenService.m; sourceTree = ""; }; + D1284A968E76C7AB80F7D25481E15AED /* GDTCOREventTransformer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREventTransformer.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h; sourceTree = ""; }; + D26AF22ECA5F16578D950CF2E197D91C /* GDTCORRegistrar.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORRegistrar.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m; sourceTree = ""; }; + D2752476EEBD2EB1C3C03EB7D629DE55 /* GULSceneDelegateSwizzler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULSceneDelegateSwizzler.h; path = GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h; sourceTree = ""; }; + D2E8DEE67BD4C3A24D7C052314CDDAA6 /* FIRPhoneAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h; sourceTree = ""; }; + D2EC0D304F2E147D3F387897C17F1887 /* FIRApp.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRApp.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h; sourceTree = ""; }; + D30116979AF35FC25111CDB0F39355B5 /* FIRGetAccountInfoRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetAccountInfoRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h; sourceTree = ""; }; + D30D1AD3D4C298E46ACC5D9738D366E7 /* FIRServerValue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRServerValue.m; path = FirebaseDatabase/Sources/Api/FIRServerValue.m; sourceTree = ""; }; + D32FC791A2013E36F3CDA08B9612433B /* FIRAuthSerialTaskQueue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthSerialTaskQueue.h; path = FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h; sourceTree = ""; }; + D3331DD7FCAE6B40EB649D6941B9148C /* arena.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = arena.cc; path = util/arena.cc; sourceTree = ""; }; + D3342AFD54F753153E244BABE9B38DFF /* FSyncPoint.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSyncPoint.m; path = FirebaseDatabase/Sources/Core/FSyncPoint.m; sourceTree = ""; }; + D3357AC70DA0AB1A2DBC4B94318BA7F5 /* filter_policy.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = filter_policy.cc; path = util/filter_policy.cc; sourceTree = ""; }; + D3C31E13AF424AADDB899510E6244150 /* FIRMultiFactorInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactorInfo.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo.m; sourceTree = ""; }; + D3D10DEEC9195C5E381FF9C71A38D7D0 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProtoFinalizeMFAPhoneResponseInfo.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h; sourceTree = ""; }; + D4D60F9F02A0480B7DC03CCF3A8E0078 /* pb_common.c */ = {isa = PBXFileReference; includeInIndex = 1; path = pb_common.c; sourceTree = ""; }; + D51B00D1359AF39D419D7B0DD5CF6526 /* FIRSignUpNewUserResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSignUpNewUserResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.m; sourceTree = ""; }; + D51CE1651DCD28277901923BB6345C4B /* FRepoInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRepoInfo.h; path = FirebaseDatabase/Sources/Core/FRepoInfo.h; sourceTree = ""; }; + D5A4E78107B016AF69DC439FF2711A08 /* FChildEventRegistration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FChildEventRegistration.m; path = FirebaseDatabase/Sources/Core/View/FChildEventRegistration.m; sourceTree = ""; }; + D5E1524A0256E64E49CDA88A4D9F15F0 /* FChildEventRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FChildEventRegistration.h; path = FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h; sourceTree = ""; }; + D605890E41506261712FA9D98D2E022D /* FBLPromise+Then.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Then.m"; path = "Sources/FBLPromises/FBLPromise+Then.m"; sourceTree = ""; }; + D67D2536574B85AAEE67A9876A505335 /* FIRSetAccountInfoRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSetAccountInfoRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.m; sourceTree = ""; }; + D6CC30E2B10C146529670C215CCFE97F /* FIRStorageLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageLogger.h; path = FirebaseStorage/Sources/FIRStorageLogger.h; sourceTree = ""; }; + D75A71D6B0932410BBBF7B7C7ED86CF9 /* coding.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = coding.cc; path = util/coding.cc; sourceTree = ""; }; + D772660D348EDA152D9FA9274A4FD651 /* NSData+FIRBase64.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+FIRBase64.h"; path = "FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h"; sourceTree = ""; }; + D77FC63C6A5F4F440E4C6041694A5B6A /* nanopb.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = nanopb.debug.xcconfig; sourceTree = ""; }; + D795AE629879BC01531BB9102F646DB3 /* FIRGetAccountInfoRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetAccountInfoRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.m; sourceTree = ""; }; + D82232D321C3210F5B247FF6E16F7766 /* FIRHeartbeatInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatInfo.h; path = FirebaseCore/Sources/Private/FIRHeartbeatInfo.h; sourceTree = ""; }; + D83CA594DD91D43406561F75B2FF9BAF /* FIRAuthProtoStartMFAPhoneRequestInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProtoStartMFAPhoneRequestInfo.m; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.m; sourceTree = ""; }; + D84A34181EF2D407DFCDDACAA34AEB56 /* FWebSocketConnection.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FWebSocketConnection.m; path = FirebaseDatabase/Sources/Realtime/FWebSocketConnection.m; sourceTree = ""; }; + D881285A593D28B3D30B443110BFD856 /* db_iter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = db_iter.h; path = db/db_iter.h; sourceTree = ""; }; + D8BFA0DF95EDE6A4BA5277DE642A52D9 /* FIRVerifyPhoneNumberResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyPhoneNumberResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h; sourceTree = ""; }; + D93608706A00D31B0997B306A4075DC8 /* FIRMultiFactorSession.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactorSession.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession.m; sourceTree = ""; }; + D938E13F6F589C189B60C4CA4465EB1D /* GULSceneDelegateSwizzler.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULSceneDelegateSwizzler.m; path = GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m; sourceTree = ""; }; + D96ED13249834AE23DF273A121C5C859 /* FQueryParams.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FQueryParams.m; path = FirebaseDatabase/Sources/Core/FQueryParams.m; sourceTree = ""; }; + DA37457479E7EB67EA481AD09874D1CE /* FViewProcessor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FViewProcessor.m; path = FirebaseDatabase/Sources/FViewProcessor.m; sourceTree = ""; }; + DAE9BAEEBABE76B47CF2BD6325FC5602 /* FIRStorageConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageConstants.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageConstants.h; sourceTree = ""; }; + DB475D8D0ED92EA291952E540077A838 /* dbformat.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = dbformat.cc; path = db/dbformat.cc; sourceTree = ""; }; + DB8D7034E56B68DBD3E4DF5A74D8239E /* FirebaseCoreDiagnostics-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseCoreDiagnostics-Info.plist"; sourceTree = ""; }; + DBE09261FF79AE8E86F6A6F51D71B3AB /* FIRAuthAppCredentialManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthAppCredentialManager.h; path = FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h; sourceTree = ""; }; + DC1E3CB165C3CBF81DF3C343B01BF719 /* FIRGetProjectConfigRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetProjectConfigRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.m; sourceTree = ""; }; + DC228939E4F3D2C027921DDE205BF92A /* FTupleOnDisconnect.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleOnDisconnect.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.m; sourceTree = ""; }; + DC38D0C9D92FB77059573CB698BE8E0D /* FIRDataSnapshot_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDataSnapshot_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h; sourceTree = ""; }; + DC734172FD9BB1B7FA869203F23EC521 /* GDTCCTCompressionHelper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCCTCompressionHelper.h; path = GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h; sourceTree = ""; }; + DC7F516FF78C44446D8D2E2CFABA526E /* GULKeychainStorage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULKeychainStorage.m; path = GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m; sourceTree = ""; }; + DCAAF3DC536CEC5BF8DFB1152DF8240C /* GoogleDataTransport.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = GoogleDataTransport.modulemap; sourceTree = ""; }; + DD426E865FC8F06B2B303FB46EDD4415 /* FIRVerifyAssertionResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyAssertionResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h; sourceTree = ""; }; + DD4864542B99534D826884212D610051 /* no_destructor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = no_destructor.h; path = util/no_destructor.h; sourceTree = ""; }; + DD4A6114C542A0B76FFE2CD9F298C74B /* FirebaseDatabase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseDatabase.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FirebaseDatabase.h; sourceTree = ""; }; + DD5351F61E4051917ECC0C45DF0E5F8D /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Sources/Private/FIRAppInternal.h; sourceTree = ""; }; + DD69A621B862C551477417091A95F91C /* FTrackedQuery.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTrackedQuery.h; path = FirebaseDatabase/Sources/Persistence/FTrackedQuery.h; sourceTree = ""; }; + DE506671538C7408F5B08E892EA3B6B4 /* GDTCORPlatform.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORPlatform.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m; sourceTree = ""; }; + DF15EFABC8CF646F9AB391F67075A420 /* FIRStorageTaskSnapshot.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageTaskSnapshot.m; path = FirebaseStorage/Sources/FIRStorageTaskSnapshot.m; sourceTree = ""; }; + DF67656B1014EB5D0F8C31628A0F8D40 /* GDTCOREndpoints_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREndpoints_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h; sourceTree = ""; }; + DF7510634B456A9A5EB9BB8C7D93BEE9 /* FIRStorageListResult_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageListResult_Private.h; path = FirebaseStorage/Sources/FIRStorageListResult_Private.h; sourceTree = ""; }; + DF92A3DC3872C2E019717A99ABFC4BAF /* FirebaseCore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCore.h; path = FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h; sourceTree = ""; }; + DFB0AF5D8FA934148999A8DE9E242912 /* FirebaseDatabase.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseDatabase.modulemap; sourceTree = ""; }; + DFE085E90848700012D4C7E2953F5CB7 /* env_posix.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = env_posix.cc; path = util/env_posix.cc; sourceTree = ""; }; + DFEB773E723D577BD5E2FCEEA9EF8BBC /* FWriteTreeRef.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FWriteTreeRef.h; path = FirebaseDatabase/Sources/Core/FWriteTreeRef.h; sourceTree = ""; }; + E0070AA5B17F5B089940E9DF9C7EAEBB /* FWriteTreeRef.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FWriteTreeRef.m; path = FirebaseDatabase/Sources/Core/FWriteTreeRef.m; sourceTree = ""; }; + E00A4986CBE1E251A2DFE3F3701905E7 /* FIRSendVerificationCodeResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSendVerificationCodeResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.m; sourceTree = ""; }; + E034F1CE93125D1722311B3DE473783A /* leveldb-library-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "leveldb-library-dummy.m"; sourceTree = ""; }; + E05A9C8A4A5E398CC84792414886CFDF /* comparator.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = comparator.cc; path = util/comparator.cc; sourceTree = ""; }; + E0600815FC2D83CC6D9B07E29B47A629 /* table_builder.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = table_builder.cc; path = table/table_builder.cc; sourceTree = ""; }; + E1B4086F8CC23FC6345F410D5A962EE8 /* FPersistentConnection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPersistentConnection.h; path = FirebaseDatabase/Sources/Core/FPersistentConnection.h; sourceTree = ""; }; + E1EA944496A2573E7E46DDFBCACDB6C7 /* FEventRaiser.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FEventRaiser.m; path = FirebaseDatabase/Sources/Core/View/FEventRaiser.m; sourceTree = ""; }; + E1F13E99D5CDC9053C648E227DB5A99B /* FIRWithdrawMFAResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRWithdrawMFAResponse.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.m; sourceTree = ""; }; + E20C20D7FAB01BCCA3A30E6B08C36B35 /* GULNetwork.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetwork.m; path = GoogleUtilities/Network/GULNetwork.m; sourceTree = ""; }; + E20F0CE3E9E3B51A9C596A24A248E86A /* histogram.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = histogram.h; path = util/histogram.h; sourceTree = ""; }; + E24707A940249750B09DC979B64197AB /* GULKeychainStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULKeychainStorage.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h; sourceTree = ""; }; + E25806EF4D31B0F9738F7B89249DE5D0 /* FBLPromise+Wrap.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Wrap.m"; path = "Sources/FBLPromises/FBLPromise+Wrap.m"; sourceTree = ""; }; + E2B63D462DB7F827C4B11FD51E4F8E2D /* FirebaseCore */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseCore; path = FirebaseCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E2DCA620D3D076030DA2B13428F8DEA0 /* FBLPromise+Timeout.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Timeout.h"; path = "Sources/FBLPromises/include/FBLPromise+Timeout.h"; sourceTree = ""; }; + E35E50F5AA58D33E3A9E5B16C83258F2 /* FTrackedQueryManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTrackedQueryManager.m; path = FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.m; sourceTree = ""; }; + E36EDB3F233F4325954736D9BD031692 /* FIRPhoneMultiFactorGenerator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRPhoneMultiFactorGenerator.m; path = FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorGenerator.m; sourceTree = ""; }; + E3AA655918C94D7E5B6CD0A5049D1055 /* Pods-saraWhatsUp-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-saraWhatsUp-acknowledgements.plist"; sourceTree = ""; }; + E3CB1603F1188E8F482B76E8992658CA /* FIRFinalizeMFAEnrollmentResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFinalizeMFAEnrollmentResponse.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h; sourceTree = ""; }; + E3D37CD5FB23804B82EB8F6D3DA8919A /* FIRDatabaseQuery.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseQuery.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h; sourceTree = ""; }; + E4CAFFC2083A3EA3A2BD75F28233A4D2 /* FIRAuthInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthInterop.h; path = Interop/Auth/Public/FIRAuthInterop.h; sourceTree = ""; }; + E5692839611D88CB21196E1A6456DF29 /* nanopb-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "nanopb-prefix.pch"; sourceTree = ""; }; + E573656466A4A2CCC24C84FC97BBCE87 /* table_builder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = table_builder.h; path = include/leveldb/table_builder.h; sourceTree = ""; }; + E59A2BB16DF1C8DF51ED04E0F073F51B /* FIRAuthBackend.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthBackend.m; path = FirebaseAuth/Sources/Backend/FIRAuthBackend.m; sourceTree = ""; }; + E5E00737AB979B86E4AF9B01699CDFF3 /* GULNetworkLoggerProtocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkLoggerProtocol.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h; sourceTree = ""; }; + E66A45FDA42DCC78AC16BE6DAEFEBD90 /* FIRGoogleAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGoogleAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.m; sourceTree = ""; }; + E66BECCDBDAFF7F21FD65107CE127127 /* FBLPromise+Recover.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Recover.h"; path = "Sources/FBLPromises/include/FBLPromise+Recover.h"; sourceTree = ""; }; + E6B4F302F320A7E32801438DE388BEDE /* FTreeSortedDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTreeSortedDictionary.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.m; sourceTree = ""; }; + E71462E7A638DD8650951BF1796855AB /* hash.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = hash.h; path = util/hash.h; sourceTree = ""; }; + E7453502726C5BF4194ADE99C1058FDC /* FRepoInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FRepoInfo.m; path = FirebaseDatabase/Sources/Core/FRepoInfo.m; sourceTree = ""; }; + E783CB68946D7A9FD139DFCE6DCA7EFF /* FIRAuthAPNSTokenType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthAPNSTokenType.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h; sourceTree = ""; }; + E80F127499254D575F9567C7C18C951A /* FBLPromise+Catch.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Catch.m"; path = "Sources/FBLPromises/FBLPromise+Catch.m"; sourceTree = ""; }; + E82FD5AB387A0866240CEFF8BE02C4DD /* FRepoManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRepoManager.h; path = FirebaseDatabase/Sources/Core/FRepoManager.h; sourceTree = ""; }; + E839F6DD585A7A414970E839F31D2E7D /* port_stdcxx.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = port_stdcxx.h; path = port/port_stdcxx.h; sourceTree = ""; }; + E83C685792DEC69A5B185422B4AC2E7A /* FPathIndex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPathIndex.h; path = FirebaseDatabase/Sources/FPathIndex.h; sourceTree = ""; }; + E89944D89A09B02235F24FCB467AB808 /* FIRPhoneMultiFactorInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneMultiFactorInfo.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h; sourceTree = ""; }; + E8DB7C81B442901E0C90FBD3C7639CE1 /* FIRStorageMetadata.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageMetadata.m; path = FirebaseStorage/Sources/FIRStorageMetadata.m; sourceTree = ""; }; + E9047EE1297C3C54091D160DEE436716 /* leveldb-library-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "leveldb-library-prefix.pch"; sourceTree = ""; }; + E956BC1D004B2B30234ADA67B946DC7B /* GDTCORTransformer_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORTransformer_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h; sourceTree = ""; }; + E97BE04562F1B5A9A7E1E67C0AE0A3D2 /* FIRAdditionalUserInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAdditionalUserInfo.m; path = FirebaseAuth/Sources/User/FIRAdditionalUserInfo.m; sourceTree = ""; }; + E9A820561E869395EB1638CC40A12C05 /* FIRStorageDeleteTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageDeleteTask.h; path = FirebaseStorage/Sources/FIRStorageDeleteTask.h; sourceTree = ""; }; + E9ABCEAE642F047E5F947C694A613C72 /* FIRStorageListTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageListTask.h; path = FirebaseStorage/Sources/FIRStorageListTask.h; sourceTree = ""; }; + EA02B385FB2B4B2B9E246CA24BD2EF26 /* version_set.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = version_set.cc; path = db/version_set.cc; sourceTree = ""; }; + EA254A1DD38BCE10EC20E3DEB1B9E69F /* table_cache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = table_cache.h; path = db/table_cache.h; sourceTree = ""; }; + EA5CDBD4BB26A7AE9E17E18093DD93DD /* iterator_wrapper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = iterator_wrapper.h; path = table/iterator_wrapper.h; sourceTree = ""; }; + EAE2BBC91837C345D7F66F7B6DCB8D13 /* FirebaseCoreDiagnostics.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCoreDiagnostics.debug.xcconfig; sourceTree = ""; }; + EAF26E5359FBEEEBFA7845231AC4195A /* FBLPromise+Async.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Async.h"; path = "Sources/FBLPromises/include/FBLPromise+Async.h"; sourceTree = ""; }; + EB05B29EAFF925C4D8F7F10CFC02EBD4 /* FirebaseCore.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCore.release.xcconfig; sourceTree = ""; }; + EB97D7B83E06FEC9F876862742C3101F /* nanopb-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "nanopb-umbrella.h"; sourceTree = ""; }; + EBC6EA870A2561076AA0403C29B72C92 /* FIRAuthTokenResult_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthTokenResult_Internal.h; path = FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h; sourceTree = ""; }; + EBF684FC3AFCE3789A8D7312D9A91EF7 /* FParsedUrl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FParsedUrl.h; path = FirebaseDatabase/Sources/Utilities/FParsedUrl.h; sourceTree = ""; }; + EC19D3E58E78BDD743A8EFAD9BC684CD /* FKeepSyncedEventRegistration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FKeepSyncedEventRegistration.m; path = FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.m; sourceTree = ""; }; + EC25C893E42AF2D5B65AB06457AAC348 /* PromisesObjC.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PromisesObjC.debug.xcconfig; sourceTree = ""; }; + EC324A417D58FDC1DA10C0B10DD50D40 /* FTreeNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTreeNode.h; path = FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h; sourceTree = ""; }; + EC370A05FD4A8730435B4248870B1E34 /* FIndexedNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIndexedNode.m; path = FirebaseDatabase/Sources/Snapshot/FIndexedNode.m; sourceTree = ""; }; + EC42A40F3D6145F7FF3837DFE3B986C8 /* APLevelDB.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = APLevelDB.mm; path = "FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.mm"; sourceTree = ""; }; + ECAADF3C6E648C2ED2FE2BE67E6AA1A5 /* Pods-saraWhatsUp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-saraWhatsUp.release.xcconfig"; sourceTree = ""; }; + EDB91576C5DBF9C1A9EE8EA285461D1B /* GTMSessionFetcher-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GTMSessionFetcher-dummy.m"; sourceTree = ""; }; + EDC4641849E572F5723A6A116D0352EB /* FBLPromise+Catch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Catch.h"; path = "Sources/FBLPromises/include/FBLPromise+Catch.h"; sourceTree = ""; }; + EE23D8515841BDBE32E6EAC54862B5F0 /* FIRPhoneMultiFactorGenerator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneMultiFactorGenerator.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h; sourceTree = ""; }; + EE320D6805F4B2836B7394747D3FCD01 /* FIRAdditionalUserInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAdditionalUserInfo.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h; sourceTree = ""; }; + EF6A924BD6D1FE28BB9EEFD69CAE7638 /* FIRCreateAuthURIRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCreateAuthURIRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h; sourceTree = ""; }; + EFB4F1F9A60522154D72062A7EBC8106 /* FIRGetProjectConfigRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetProjectConfigRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h; sourceTree = ""; }; + F0BC27D6656FB79C7E72378BE364E49F /* FIRAuthBackend+MultiFactor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRAuthBackend+MultiFactor.h"; path = "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h"; sourceTree = ""; }; + F0C3D851DBEE7696D21526FF5443A526 /* FPersistentConnection.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPersistentConnection.m; path = FirebaseDatabase/Sources/Core/FPersistentConnection.m; sourceTree = ""; }; + F1389AE7281393EE724613BC5D251B38 /* FIRStorageLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageLogger.m; path = FirebaseStorage/Sources/FIRStorageLogger.m; sourceTree = ""; }; + F15CFAD5BAA65469E2657BD24D8EFA9F /* GDTCORStorageEventSelector.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORStorageEventSelector.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h; sourceTree = ""; }; + F23127FE4B314F0651762F66488965CB /* FSRWebSocket.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSRWebSocket.m; path = FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m; sourceTree = ""; }; + F2598F081516F4371B1C222199738340 /* leveldb-library-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "leveldb-library-umbrella.h"; sourceTree = ""; }; + F31C47663C2AFC318F0350B2FEF78F1B /* FirebaseStorage.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseStorage.modulemap; sourceTree = ""; }; + F3554235FC742EA63269C8BB2F6568B6 /* FIRGitHubAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGitHubAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h; sourceTree = ""; }; + F3E6618C894D10C116BC2F0FD09C91F0 /* FTupleCallbackStatus.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleCallbackStatus.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.m; sourceTree = ""; }; + F5089FA76BD0882F080BDA39DD2EDED3 /* GDTCORTransport.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORTransport.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m; sourceTree = ""; }; + F567C2F9688D82CA1EBA475DB0D1A069 /* FIRPhoneMultiFactorInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRPhoneMultiFactorInfo.m; path = FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo.m; sourceTree = ""; }; + F697F7EA92D4F5BEA9A9ED3F7DB01CA5 /* db.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = db.h; path = include/leveldb/db.h; sourceTree = ""; }; + F6AC2404030727486B0D2FBBED6A41F4 /* FArraySortedDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FArraySortedDictionary.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.m; sourceTree = ""; }; + F6C91B026962F7836CFEC9875EB678D7 /* FIRStorageListTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStorageListTask.m; path = FirebaseStorage/Sources/FIRStorageListTask.m; sourceTree = ""; }; + F7041D7B7DBE5353E7092A9A3BC10198 /* FIRStartMFASignInResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStartMFASignInResponse.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h; sourceTree = ""; }; + F70BCE209E6D671E54D0B43EC43C99DA /* FIRAuthInternalErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthInternalErrors.h; path = FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h; sourceTree = ""; }; + F7106C22A1E65102E4973A1912985F17 /* FIRStartMFAEnrollmentResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStartMFAEnrollmentResponse.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.m; sourceTree = ""; }; + F7DC7FA75B31D1254763C9DD27879B6B /* FEventGenerator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEventGenerator.h; path = FirebaseDatabase/Sources/FEventGenerator.h; sourceTree = ""; }; + F7DF3DE181967DAF4B834E4565CE8C52 /* FEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEvent.h; path = FirebaseDatabase/Sources/Core/View/FEvent.h; sourceTree = ""; }; + F83254030B3331F8B9250016B3E90536 /* FIRAuthWebView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthWebView.h; path = FirebaseAuth/Sources/Utilities/FIRAuthWebView.h; sourceTree = ""; }; + F8639C05F1651B89D57F11600A798BAA /* posix_logger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = posix_logger.h; path = util/posix_logger.h; sourceTree = ""; }; + F8EE5397CAFFDE0ED6DFFBECF96F4DA8 /* FIRAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/FIRAuthProvider.m; sourceTree = ""; }; + F9261B348836363F87E4E2D8EAF2156F /* firebasecore.nanopb.c */ = {isa = PBXFileReference; includeInIndex = 1; name = firebasecore.nanopb.c; path = Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c; sourceTree = ""; }; + F94E060978237A794872573025EA4BAA /* FEventEmitter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FEventEmitter.m; path = FirebaseDatabase/Sources/Utilities/FEventEmitter.m; sourceTree = ""; }; + F9A27AB3D82A79375F5B1A39D4C39E51 /* FIRDataEventType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDataEventType.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h; sourceTree = ""; }; + F9B99A9DE81C98F23A7956ADBB6AAA44 /* FTrackedQueryManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTrackedQueryManager.h; path = FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h; sourceTree = ""; }; + F9F04272698BB7D889AA4AF0525CEC7E /* FIRFederatedAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFederatedAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h; sourceTree = ""; }; + FA2E91A9425BE6BC994203B17F986063 /* GDTCOREvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREvent.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h; sourceTree = ""; }; + FA52D7A5FF113ACBFD33CBBC3183A141 /* GDTCORLifecycle.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORLifecycle.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h; sourceTree = ""; }; + FA57C47826950D4B1DDB1508EB0E38BA /* FIRDatabaseQuery.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabaseQuery.m; path = FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m; sourceTree = ""; }; + FA5E2A052EEFA5DAC5C85689BC871BD0 /* FIRMultiFactorResolver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactorResolver.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver.m; sourceTree = ""; }; + FAA49E2FDC1193C1C227B4B4A414812E /* FIRStorageObservableTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStorageObservableTask.h; path = FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageObservableTask.h; sourceTree = ""; }; + FABDF831904EB454A599B7FFBF8ABE65 /* filename.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = filename.h; path = db/filename.h; sourceTree = ""; }; + FADB445B0D83108D24457A1573E4CA4A /* FRepo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FRepo.m; path = FirebaseDatabase/Sources/Core/FRepo.m; sourceTree = ""; }; + FADE0B752CA28920C36DFE5EBFBD2EAC /* FSRWebSocket.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSRWebSocket.h; path = FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h; sourceTree = ""; }; + FB49854CEFC41D4E42CC5C6356038058 /* PromisesObjC.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = PromisesObjC.modulemap; sourceTree = ""; }; + FBEE29B982D54AA103A5A271D98767DA /* FCompoundWrite.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCompoundWrite.h; path = FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h; sourceTree = ""; }; + FC00211162E51E19F5561AD38A113BEE /* FIRMultiFactorAssertion+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMultiFactorAssertion+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h"; sourceTree = ""; }; + FC108E601CFE8FE0A56A55196000DBAD /* FValidation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FValidation.m; path = FirebaseDatabase/Sources/Utilities/FValidation.m; sourceTree = ""; }; + FC3008FE520DAA1E2912594F5C522BFC /* GDTCCTNanopbHelpers.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCCTNanopbHelpers.h; path = GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h; sourceTree = ""; }; + FC4238AE7DE4CF32B916F6526C7E4208 /* version_edit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = version_edit.h; path = db/version_edit.h; sourceTree = ""; }; + FC4DA8C6D73E78C03EED1C783C61202E /* GULReachabilityChecker.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULReachabilityChecker.m; path = GoogleUtilities/Reachability/GULReachabilityChecker.m; sourceTree = ""; }; + FC53DDB0E8B2F43E1E0596009C054FDE /* GULReachabilityChecker+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GULReachabilityChecker+Internal.h"; path = "GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h"; sourceTree = ""; }; + FC88E5BA67478422684CEA9786F3440D /* FLevelDBStorageEngine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLevelDBStorageEngine.h; path = FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h; sourceTree = ""; }; + FC8A2FC61EA1CF1F1CE6168D12AD5BC2 /* GDTCORLifecycle.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORLifecycle.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m; sourceTree = ""; }; + FD2E6D7850FD2B0697176C4A6261522A /* FListenProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FListenProvider.h; path = FirebaseDatabase/Sources/Core/FListenProvider.h; sourceTree = ""; }; + FD44137A3A06146041EBB23278EDC30D /* FTupleRemovedQueriesEvents.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleRemovedQueriesEvents.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.m; sourceTree = ""; }; + FD493E804D720708FC542BCC08CBEB35 /* FIRAuthSettings.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthSettings.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h; sourceTree = ""; }; + FE04F0C80BC6BB55DA64201AB87C33F2 /* FValueEventRegistration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FValueEventRegistration.m; path = FirebaseDatabase/Sources/Core/View/FValueEventRegistration.m; sourceTree = ""; }; + FE92A8ADFFB2CD95AFE36381C008D8F2 /* FBLPromise+Testing.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Testing.m"; path = "Sources/FBLPromises/FBLPromise+Testing.m"; sourceTree = ""; }; + FEB354FDBF724286A5645BC99EB99BAB /* FIRDependency.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDependency.h; path = FirebaseCore/Sources/Private/FIRDependency.h; sourceTree = ""; }; + FED184F8D1B40AFEA217EA44E8B7422E /* FIRHeartbeatInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatInfo.h; path = FirebaseCore/Sources/Private/FIRHeartbeatInfo.h; sourceTree = ""; }; + FF4238AE1711F98CE953B5A47C7A908F /* FIRAuthAppCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthAppCredential.h; path = FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h; sourceTree = ""; }; + FF51B5689329B949790D00975C6F5130 /* FIRHeartbeatInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatInfo.h; path = FirebaseCore/Sources/Private/FIRHeartbeatInfo.h; sourceTree = ""; }; + FF81BE1C255D9D09005E15D96253E22B /* FIRDatabase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabase.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 152C907A1F1FAF87F99B2AC79739E3B7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6C037F0F700DC983738B413D71829682 /* Foundation.framework in Frameworks */, + 5A8449C256C7ED0DE9DE9CD8B90D312B /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CEF3767C3F33F673178AA043F90F95E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E7BE3488F8FC2E0281CC39C7F83E2E62 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 534071F6DE083B6FF89A3E1CC86615B4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BDE8C2DE7F3E69FABD65269D3C05F3EF /* Foundation.framework in Frameworks */, + 00203A52C038200C1CE201185075F72A /* Security.framework in Frameworks */, + E3C4DB21732FACFEF57CFAB786696223 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 72F2974253F0A1DB5DFFA14510B0AFD2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 92144C5729C6F1D3860886BE4F9B3A19 /* CoreTelephony.framework in Frameworks */, + D61B73C38B18C79EACE64318FDE63055 /* Foundation.framework in Frameworks */, + E5E9E6CCAA1C59C1E1A78C96A8E69404 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 78B2D764E2E0280FF991AFE2E1A70E02 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FDE74312FC2EF956F883236DEACF2B02 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7DED8332091610648ACB97C947E10BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ACF9FE54BA2F0156346E031B4EFD50EC /* Foundation.framework in Frameworks */, + E8E9459994F1D1F8679202672ECF412C /* UIKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D9D53A81613F7B96BE6AB1B80C7DEB0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E879D9A07D20613BE2289126ECDBBF3B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9F77C26EAC00504FB8C5C1BD89AEDBD8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DE6619D3FC39F975C2B469A346872302 /* Foundation.framework in Frameworks */, + 617FB4DD5E4E749392DBA95B82582F36 /* SafariServices.framework in Frameworks */, + D0BCD49FF240ED8289440F635CD424C1 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CCB8F503631ED2691B85432142C6C40E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 027F055BC8C56B06A7F4349AF2DEBF3C /* CFNetwork.framework in Frameworks */, + 4002B79502F640837CF88CA9C61F2BA8 /* Foundation.framework in Frameworks */, + F47775DDD768C9D734A3264CCC7ACCD3 /* Security.framework in Frameworks */, + 337E024887E032C72637550A413CC012 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EEE9A50601C26E070141DCBA88EAB039 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5B0A6CB985EB036BD563219410BDE55F /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F81E63C96CB5AB58F86960D32BE72E0D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BA5EF3BD647DEB3661D6E3116A574FCD /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FB12A9CE864E21F0D8393EA472DA5746 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 862645997A150ACCA48117A58C676B4C /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0D233F3E69FFDBC9975EDD6EA68557CC /* Support Files */ = { + isa = PBXGroup; + children = ( + FB49854CEFC41D4E42CC5C6356038058 /* PromisesObjC.modulemap */, + 4E5807D571718FEBFE488332153F41E0 /* PromisesObjC-dummy.m */, + A1F163BCAE7863A12A99F71053BC2965 /* PromisesObjC-Info.plist */, + 3B07424603BC0D2D1C7EED9F0FD930D9 /* PromisesObjC-umbrella.h */, + EC25C893E42AF2D5B65AB06457AAC348 /* PromisesObjC.debug.xcconfig */, + ACFA9A512528EAD2FCC4355818A33CD3 /* PromisesObjC.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/PromisesObjC"; + sourceTree = ""; + }; + 0FDD19D2F75DA10608578CFC8FE02768 /* Support Files */ = { + isa = PBXGroup; + children = ( + F31C47663C2AFC318F0350B2FEF78F1B /* FirebaseStorage.modulemap */, + 30F3823B8E8D7D7EF49EF692FEC92C49 /* FirebaseStorage-dummy.m */, + B20A9D1B2E1FF259990B121B18078B8B /* FirebaseStorage-Info.plist */, + C3FDDBCAD63AD6C646361AF484324D5D /* FirebaseStorage-umbrella.h */, + 044F6E5467DFFE0E5874B2368601CF31 /* FirebaseStorage.debug.xcconfig */, + A7133D98A56EE451D8DD163BAB3BBB28 /* FirebaseStorage.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseStorage"; + sourceTree = ""; + }; + 149300CCB564C36213FBD105A43F87B8 /* Support Files */ = { + isa = PBXGroup; + children = ( + 321DBB4C7DC419E9D6B93E9AF1BEF5EB /* FirebaseCoreDiagnostics.modulemap */, + 30C0F0FC7817DC60672EB31C8B7064E2 /* FirebaseCoreDiagnostics-dummy.m */, + DB8D7034E56B68DBD3E4DF5A74D8239E /* FirebaseCoreDiagnostics-Info.plist */, + 1F0C566769D33EBA1455071400D6E307 /* FirebaseCoreDiagnostics-umbrella.h */, + EAE2BBC91837C345D7F66F7B6DCB8D13 /* FirebaseCoreDiagnostics.debug.xcconfig */, + 2B98F9FAC4E46C99230030CD824F79A4 /* FirebaseCoreDiagnostics.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseCoreDiagnostics"; + sourceTree = ""; + }; + 1B604A1E2AC95163CD0CFFB0F36FDCF9 /* Support Files */ = { + isa = PBXGroup; + children = ( + 1BECDD459D9B73BE4F02893E75E11FE2 /* Firebase.debug.xcconfig */, + 70998E41522AEE00454C7810173EB2F3 /* Firebase.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/Firebase"; + sourceTree = ""; + }; + 3277FFEFE6F2810FBC5C796D93288BFE /* Support Files */ = { + isa = PBXGroup; + children = ( + A291D7F492A527067349C061395FCE5A /* FirebaseCore.modulemap */, + AA9244E063FD307DF5A1C224EFF32D86 /* FirebaseCore-dummy.m */, + 7997B21891AEA54D42E3DA56720D5EC5 /* FirebaseCore-Info.plist */, + 77B9E73A06A93EA6F9C153639F6C4AB7 /* FirebaseCore-umbrella.h */, + 00107F5D3773418497630039D598AABF /* FirebaseCore.debug.xcconfig */, + EB05B29EAFF925C4D8F7F10CFC02EBD4 /* FirebaseCore.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseCore"; + sourceTree = ""; + }; + 4081481F151F75D5AF30065AB006B195 /* FirebaseAuth */ = { + isa = PBXGroup; + children = ( + B83D5E64ACCD27EE28AEF71FBD036120 /* FIRActionCodeSettings.h */, + 5C470B429F1B0F7C5C9717C34523B5CD /* FIRActionCodeSettings.m */, + EE320D6805F4B2836B7394747D3FCD01 /* FIRAdditionalUserInfo.h */, + E97BE04562F1B5A9A7E1E67C0AE0A3D2 /* FIRAdditionalUserInfo.m */, + 41D26DFB51D254693004507B17D7B737 /* FIRAdditionalUserInfo_Internal.h */, + 919646B9BE59C2A4A31EE830A2CA8068 /* FIRAppInternal.h */, + 1C9AFD1F65D89843CF8C273F7BDCA6F7 /* FIRAuth.h */, + C2DCA7FCB2F1AA7E5182524022DDFAC9 /* FIRAuth.m */, + 74821EC035B4458507191FC713CFE43F /* FIRAuth_Internal.h */, + 4BC172B36355B2633118EA66E1485D28 /* FIRAuthAPNSToken.h */, + 03215B0ED3F49AAA67906E78ABBB23BB /* FIRAuthAPNSToken.m */, + 33B64A8F94A6603E23D737D56A9EFAC2 /* FIRAuthAPNSTokenManager.h */, + A723A7F93D474EA6452E32D7F163FEA5 /* FIRAuthAPNSTokenManager.m */, + E783CB68946D7A9FD139DFCE6DCA7EFF /* FIRAuthAPNSTokenType.h */, + FF4238AE1711F98CE953B5A47C7A908F /* FIRAuthAppCredential.h */, + 09C911FD759302267DF9A71825701EE0 /* FIRAuthAppCredential.m */, + DBE09261FF79AE8E86F6A6F51D71B3AB /* FIRAuthAppCredentialManager.h */, + 3548EDB27273E2BA2A7598B23531161F /* FIRAuthAppCredentialManager.m */, + BFF584623DAE6086D9A916D16C35507D /* FIRAuthBackend.h */, + E59A2BB16DF1C8DF51ED04E0F073F51B /* FIRAuthBackend.m */, + F0BC27D6656FB79C7E72378BE364E49F /* FIRAuthBackend+MultiFactor.h */, + 1A0BF52AE10A30F5BD8A7D2E4F4080E8 /* FIRAuthBackend+MultiFactor.m */, + BBAF527ADC6259102C1FC8064BB26450 /* FIRAuthCredential.h */, + B3A4EA889B8F6E87EFD595D77588F34C /* FIRAuthCredential.m */, + 2B55A91D7EFF5E8B052CBC046587F562 /* FIRAuthCredential_Internal.h */, + 7850D19620E2E98D2EA9DEBDC1D95704 /* FIRAuthDataResult.h */, + 4E1DBC7D23830F6FD970766C7D982680 /* FIRAuthDataResult.m */, + 393EC1FCE7664B19AE80AF8CAFF77554 /* FIRAuthDataResult_Internal.h */, + 46DA95FEB78C1157595667E76D6B019A /* FIRAuthDefaultUIDelegate.h */, + AB2EF60C16B7021A14AE4954EF2F717B /* FIRAuthDefaultUIDelegate.m */, + 7EB66E7098D9785F63022238AC94D1C3 /* FIRAuthDispatcher.h */, + 4BDFC31F2515C00C3EF1D1C333356F6C /* FIRAuthDispatcher.m */, + 5A9BE2440239D2864323211F1A7436E5 /* FIRAuthErrors.h */, + 2749E81E39B3205D93B88A62A6C4B8AA /* FIRAuthErrorUtils.h */, + 4A9B3935AD68926702185D93B9797C7E /* FIRAuthErrorUtils.m */, + 22A27923B3B28E3BBE217714A2394B13 /* FIRAuthExceptionUtils.h */, + 13334C7932E2839836F8564E47E5E95F /* FIRAuthExceptionUtils.m */, + 60309DD4339A47378854B0E21D2290C3 /* FIRAuthGlobalWorkQueue.h */, + 7FE6FE37825B435D47D4B08F2AD91685 /* FIRAuthGlobalWorkQueue.m */, + F70BCE209E6D671E54D0B43EC43C99DA /* FIRAuthInternalErrors.h */, + 6B3244BB9FA3011541F121A0ED25A91F /* FIRAuthInterop.h */, + 5A2F3C5553C76F538ABC392A606C5232 /* FIRAuthKeychainServices.h */, + 56C3364F87A61B16B7B80534FF7547C6 /* FIRAuthKeychainServices.m */, + 85396FA2E4FB7242703B77E534BB96FA /* FIRAuthNotificationManager.h */, + 6BD97CC4A3A756852B6EDC695CC98557 /* FIRAuthNotificationManager.m */, + 51605F4C50CB89A5269DD361E6A5009E /* FIRAuthOperationType.h */, + 210D3946C544D2F83F1556FD40016B78 /* FIRAuthProto.h */, + 330336A17C4F23BA8D30F48A6BD38303 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.h */, + 86670524310C3DA3D11768477D60665F /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.m */, + D3D10DEEC9195C5E381FF9C71A38D7D0 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.h */, + 83EADD4A625C351937A0DE2CD57B8951 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.m */, + 3EAA9F352B333A6C73F732D89352E248 /* FIRAuthProtoMFAEnrollment.h */, + B2D5A80CA37F8BD29B4EAF0D339F38F7 /* FIRAuthProtoMFAEnrollment.m */, + 6E633C1B4BD6DAA2E6890291D5FEF70A /* FIRAuthProtoStartMFAPhoneRequestInfo.h */, + D83CA594DD91D43406561F75B2FF9BAF /* FIRAuthProtoStartMFAPhoneRequestInfo.m */, + CFE231493E8C735456EE5EE7B5E7B915 /* FIRAuthProtoStartMFAPhoneResponseInfo.h */, + B2D9BB15B65A8F9774E2C2D7FA9C5A52 /* FIRAuthProtoStartMFAPhoneResponseInfo.m */, + F8EE5397CAFFDE0ED6DFFBECF96F4DA8 /* FIRAuthProvider.m */, + 5FE2B96A5E3FEAB7406E5F37AD224EBD /* FIRAuthRequestConfiguration.h */, + 7C81B5E725699C2DA74037AE3F016F3A /* FIRAuthRequestConfiguration.m */, + 68D36AB3BDFAE5C55B9C8F45A1A5CEBE /* FIRAuthRPCRequest.h */, + A18052F86CDC309B984F2A072E0B8350 /* FIRAuthRPCResponse.h */, + D32FC791A2013E36F3CDA08B9612433B /* FIRAuthSerialTaskQueue.h */, + 493F18C6B603AF3ADDFD8FB37F07FEC3 /* FIRAuthSerialTaskQueue.m */, + FD493E804D720708FC542BCC08CBEB35 /* FIRAuthSettings.h */, + 736E2A05989CEB2E4B585E5C7E684F45 /* FIRAuthSettings.m */, + 90A27BDCA5211C8EC45EA81FBF65E552 /* FIRAuthStoredUserManager.h */, + 44DB219B5956C07D686FB110044AB975 /* FIRAuthStoredUserManager.m */, + 454D3B693F062A52555CB025AF94F840 /* FIRAuthTokenResult.h */, + A8F96448F361676D974EF9A55C032F1F /* FIRAuthTokenResult.m */, + EBC6EA870A2561076AA0403C29B72C92 /* FIRAuthTokenResult_Internal.h */, + 640F8AEF999AB871A9CF0301174BAFB5 /* FIRAuthUIDelegate.h */, + 49DEF809FDF8A0305B56D6382AF927F3 /* FIRAuthURLPresenter.h */, + A75A814253FC19978642F5B98FBE1C54 /* FIRAuthURLPresenter.m */, + 5D52FE533230E7D91A995F0E70F0875C /* FIRAuthUserDefaults.h */, + 4F7C5E48CD0159B1D1C694CE8FEBCC3E /* FIRAuthUserDefaults.m */, + 2E55AF603E677DAB13AAF1DECCB0780A /* FIRAuthWebUtils.h */, + B351FCC097D07CD16092C31C2CA42839 /* FIRAuthWebUtils.m */, + F83254030B3331F8B9250016B3E90536 /* FIRAuthWebView.h */, + 49A179A28D55D47B136047F2D340ACD9 /* FIRAuthWebView.m */, + 4A6B7DA408335681D8EBB8E8A8195300 /* FIRAuthWebViewController.h */, + BD613FA63F113B835232228E5415A586 /* FIRAuthWebViewController.m */, + 53DEF33906E89381205BFC84CE2B334E /* FIRComponent.h */, + 83F8C1112535F34E3B6D933899281A7C /* FIRComponentContainer.h */, + 26E785FC337EA22790808439DD1A5CD5 /* FIRComponentType.h */, + B89A3C3BE57CFAFD85B24D321FD6BF7C /* FIRCoreDiagnosticsConnector.h */, + EF6A924BD6D1FE28BB9EEFD69CAE7638 /* FIRCreateAuthURIRequest.h */, + 2CD4ED2472BA0526FFE6C73D576523AE /* FIRCreateAuthURIRequest.m */, + 5F46401767E51CCF943E45AC97804AFD /* FIRCreateAuthURIResponse.h */, + 80FDC76D3FBAC817FFB275752A4E8648 /* FIRCreateAuthURIResponse.m */, + B95010BC3EBD9FC0909725BDB3ABF4D9 /* FIRDeleteAccountRequest.h */, + 883F3061318EB3429FEE92B8E6EF94D5 /* FIRDeleteAccountRequest.m */, + BCA1C279CD7AB01391FC73FF502E99AD /* FIRDeleteAccountResponse.h */, + 09E760765D90D676A6B6F9E9B69247F7 /* FIRDeleteAccountResponse.m */, + 851ED6E275B5A08DA28258677A801BFA /* FIRDependency.h */, + 59E834E72180D1D0389618CEE6D091AD /* FirebaseAuth.h */, + A2B257ECEC088990E9CDCDBCB30CC867 /* FirebaseCoreInternal.h */, + A41EFA62EBC841BCB7E78DB7374FFDDC /* FIREmailAuthProvider.h */, + 59038A4766E4CC1722C7B60EEC4B33B7 /* FIREmailAuthProvider.m */, + C59EBCCA53061961256AE11C24B8DA68 /* FIREmailLinkSignInRequest.h */, + 855AA4953460F88C0D00DB72B639F3BD /* FIREmailLinkSignInRequest.m */, + 074B1506E54F170E9D971DFA65A05BAE /* FIREmailLinkSignInResponse.h */, + 822565DDCACE4B6CBA1EB346E3375B8E /* FIREmailLinkSignInResponse.m */, + 1FCE4B4A66E84892717EF5F2F0CC8516 /* FIREmailPasswordAuthCredential.h */, + 4243357DACC2D3FCD431CCAB131AA063 /* FIREmailPasswordAuthCredential.m */, + 9BBBA5BA7566D21A1AA9929A5E96F5D8 /* FIRFacebookAuthCredential.h */, + 03E1CE3EB6A65FC8FD5A092AADD594C1 /* FIRFacebookAuthCredential.m */, + 55F190ACA77146C5187A0BB15DA6EAF5 /* FIRFacebookAuthProvider.h */, + C63E288BFEA73AB13BADC975423E2506 /* FIRFacebookAuthProvider.m */, + F9F04272698BB7D889AA4AF0525CEC7E /* FIRFederatedAuthProvider.h */, + 7809E5411EAED2D217B878048273E546 /* FIRFinalizeMFAEnrollmentRequest.h */, + 16AA4D274A47351AFC341E2F1303F464 /* FIRFinalizeMFAEnrollmentRequest.m */, + E3CB1603F1188E8F482B76E8992658CA /* FIRFinalizeMFAEnrollmentResponse.h */, + 8797BE5BA0ED09CCC332EA884D1440E0 /* FIRFinalizeMFAEnrollmentResponse.m */, + 65E647C1250D83FF8B141CDD6D7AB22D /* FIRFinalizeMFASignInRequest.h */, + 1527CD4FCB8B349B9F014B7A2E846416 /* FIRFinalizeMFASignInRequest.m */, + 2ACC62B04F7F295C6F38A2DD14219DAA /* FIRFinalizeMFASignInResponse.h */, + 84D3910738ACD998D1901C556AB4335C /* FIRFinalizeMFASignInResponse.m */, + 3541E5F8A62C143380AFE1A197B39A4C /* FIRGameCenterAuthCredential.h */, + 896724F78E9E336F7C61BAA5D7FDA1C1 /* FIRGameCenterAuthCredential.m */, + 147C429D780487E0278FCBF69F77608C /* FIRGameCenterAuthProvider.h */, + C04D966A10440A875CD3413E6B4B651C /* FIRGameCenterAuthProvider.m */, + D30116979AF35FC25111CDB0F39355B5 /* FIRGetAccountInfoRequest.h */, + D795AE629879BC01531BB9102F646DB3 /* FIRGetAccountInfoRequest.m */, + 34BDBD173CB4896EB12F2BD922D4F0FB /* FIRGetAccountInfoResponse.h */, + 24166623AEBAC71E3A602781955498B7 /* FIRGetAccountInfoResponse.m */, + 8C49AB2D1242CB4AEE03BD5D1FDAD050 /* FIRGetOOBConfirmationCodeRequest.h */, + 7E0500670DA9C6B6BB264619E4475ED6 /* FIRGetOOBConfirmationCodeRequest.m */, + 3EC5810CCA6032CB4BD0F14A8BD60522 /* FIRGetOOBConfirmationCodeResponse.h */, + 2F43048B9E301D69301AEBFC0D7CA811 /* FIRGetOOBConfirmationCodeResponse.m */, + EFB4F1F9A60522154D72062A7EBC8106 /* FIRGetProjectConfigRequest.h */, + DC1E3CB165C3CBF81DF3C343B01BF719 /* FIRGetProjectConfigRequest.m */, + B1E900E5749E319AC8DD9C2AA0A26B7A /* FIRGetProjectConfigResponse.h */, + 7133273F65616CB95FFF840F84F09E70 /* FIRGetProjectConfigResponse.m */, + F3554235FC742EA63269C8BB2F6568B6 /* FIRGitHubAuthCredential.h */, + 01BFBDF82820583C2FB719EBC08FF100 /* FIRGitHubAuthCredential.m */, + 6577A54ABE028DEF2E168EC3A7B37FCA /* FIRGitHubAuthProvider.h */, + 27232BB0E72527AA10C5843D2372057F /* FIRGitHubAuthProvider.m */, + 89F007636FBF9CE37E8E53001CC953CF /* FIRGoogleAuthCredential.h */, + E66A45FDA42DCC78AC16BE6DAEFEBD90 /* FIRGoogleAuthCredential.m */, + 7A7D82FD36D69E637ED2F86EA9CCCFC6 /* FIRGoogleAuthProvider.h */, + 056C7AA7E700ABF039F5DB1D2E516E59 /* FIRGoogleAuthProvider.m */, + D82232D321C3210F5B247FF6E16F7766 /* FIRHeartbeatInfo.h */, + 4562E63F64CA70681763C3716BE3EF3D /* FIRIdentityToolkitRequest.h */, + 35818AD85F2784E8B89CB71D38ACD3F1 /* FIRIdentityToolkitRequest.m */, + C0D33B98DFBE8B633825E3A7B7AD1632 /* FIRLibrary.h */, + 7BEBE0B8B4A3E59166D06E1963A6E893 /* FIRLogger.h */, + C0924D6996644371910F4B789323F05F /* FIRMultiFactor.h */, + 7274EC13DBD95E1A1FA081BC43E5B66A /* FIRMultiFactor.m */, + ABE44E0B7E460C06F92D3D1CE8AF490B /* FIRMultiFactor+Internal.h */, + CDEC520DB3D5CC6139576078A00C1FCD /* FIRMultiFactorAssertion.h */, + 2DAB47641886E577CCFD751778C9F2CB /* FIRMultiFactorAssertion.m */, + FC00211162E51E19F5561AD38A113BEE /* FIRMultiFactorAssertion+Internal.h */, + C7583A00EFC7FC0517BD69D6D09B32E2 /* FIRMultiFactorConstants.m */, + BBBA3A61F8609CF2D274B58E72304564 /* FIRMultiFactorInfo.h */, + D3C31E13AF424AADDB899510E6244150 /* FIRMultiFactorInfo.m */, + 0786F5F9A30289D84FD9C66F9D05C9BF /* FIRMultiFactorInfo+Internal.h */, + C74C1F1761112ECCEAF3300A37403DDD /* FIRMultiFactorResolver.h */, + FA5E2A052EEFA5DAC5C85689BC871BD0 /* FIRMultiFactorResolver.m */, + 0C2B3391E6BB1E5093C9FD919D7CF549 /* FIRMultiFactorResolver+Internal.h */, + 1B61E1F94800DA4E1CC5D0C0EE897345 /* FIRMultiFactorSession.h */, + D93608706A00D31B0997B306A4075DC8 /* FIRMultiFactorSession.m */, + 33B69E4645D853E9D3C1AE7C7736CA58 /* FIRMultiFactorSession+Internal.h */, + 8C78EC07E7A21AED745FCFE8199BD2B7 /* FIROAuthCredential.h */, + 932BDA2F912838F24A80D4B9D69D594B /* FIROAuthCredential.m */, + 49517E3675D59087A341DEDAB824FAB3 /* FIROAuthCredential_Internal.h */, + BA0C130C5AD4E78EF53F155ED1EEBDC5 /* FIROAuthProvider.h */, + 89D4A7CF292E75C9E41386A232050E33 /* FIROAuthProvider.m */, + 1DEC7CA169AF37FBEE1A5945F3D3241B /* FIROptionsInternal.h */, + 1FC1446EF19FFFB8FD40DA8AD3896B58 /* FIRPhoneAuthCredential.h */, + C9B8B71643A846CA2ADA132AD852A522 /* FIRPhoneAuthCredential.m */, + 4F06531259055A8A9A7BB2EB37E8FEB6 /* FIRPhoneAuthCredential_Internal.h */, + D2E8DEE67BD4C3A24D7C052314CDDAA6 /* FIRPhoneAuthProvider.h */, + 28DDBFE577910A14716DE2BB33652A6C /* FIRPhoneAuthProvider.m */, + 02A800184212263B2434BD36BD5C4123 /* FIRPhoneMultiFactorAssertion.h */, + 16712385BBD6EFD20F637BE0027D43BD /* FIRPhoneMultiFactorAssertion.m */, + 8BC31B25EBCB529134F8A560ECCD3E6B /* FIRPhoneMultiFactorAssertion+Internal.h */, + EE23D8515841BDBE32E6EAC54862B5F0 /* FIRPhoneMultiFactorGenerator.h */, + E36EDB3F233F4325954736D9BD031692 /* FIRPhoneMultiFactorGenerator.m */, + E89944D89A09B02235F24FCB467AB808 /* FIRPhoneMultiFactorInfo.h */, + F567C2F9688D82CA1EBA475DB0D1A069 /* FIRPhoneMultiFactorInfo.m */, + 0940FE6F9786A2811E51E5B2AE96BF6F /* FIRPhoneMultiFactorInfo+Internal.h */, + 046A1A8B23BD286D6422499C9BC42BC5 /* FIRResetPasswordRequest.h */, + 16321AB5E9D6A5632ECCD98C46E259C1 /* FIRResetPasswordRequest.m */, + 8D36F7FBE8A5B0A49ADB656C0A724B5D /* FIRResetPasswordResponse.h */, + 4369B16C386867CF042633E43E33BE17 /* FIRResetPasswordResponse.m */, + 2A33E05B62B2DDAEABACB7EE4520E03A /* FIRSecureTokenRequest.h */, + 0B90DF6FA77A19EB3BAD0E1750EA2D94 /* FIRSecureTokenRequest.m */, + 21C565281E8122CD546FCFA1BF68DBA0 /* FIRSecureTokenResponse.h */, + 4422077BBC9F62B127CFA81DA71D3004 /* FIRSecureTokenResponse.m */, + 495A1CBF66ED76B976B4117DD6223B93 /* FIRSecureTokenService.h */, + D09720D9CE5B015636E0BF2DF73B40A2 /* FIRSecureTokenService.m */, + 22C0B9849699E858234B44466DE39EC9 /* FIRSendVerificationCodeRequest.h */, + 2C404889F379D8E72FFA595E06698BE4 /* FIRSendVerificationCodeRequest.m */, + 3839B8982A1F73C34171ED3275C50F6C /* FIRSendVerificationCodeResponse.h */, + E00A4986CBE1E251A2DFE3F3701905E7 /* FIRSendVerificationCodeResponse.m */, + 16BF111B8E55C4502E51954BA7333CCF /* FIRSetAccountInfoRequest.h */, + D67D2536574B85AAEE67A9876A505335 /* FIRSetAccountInfoRequest.m */, + A0E6A648E4E14D6B21A0F8DF95C04F9C /* FIRSetAccountInfoResponse.h */, + 88F1093AF881820A5E667EC0F12F47EF /* FIRSetAccountInfoResponse.m */, + 0B90799188BF45540C038E6AD9774A36 /* FIRSignInWithGameCenterRequest.h */, + 1A4F9E7A0915ED7FBEC30A8F71AD07C5 /* FIRSignInWithGameCenterRequest.m */, + 649B129D8BEEA4D78AF895FF4FB20EA9 /* FIRSignInWithGameCenterResponse.h */, + 113B2DB0C57859DE9BA3B3D6280DF261 /* FIRSignInWithGameCenterResponse.m */, + 91F64E407B7C5996C15B0EA7E2CC6D8D /* FIRSignUpNewUserRequest.h */, + 2003FCD7C349868CB3AAB8389B0A816A /* FIRSignUpNewUserRequest.m */, + 39BE74A01BE5634F38B2B443E9F408E3 /* FIRSignUpNewUserResponse.h */, + D51B00D1359AF39D419D7B0DD5CF6526 /* FIRSignUpNewUserResponse.m */, + 5431265B4569BAA9C924F890E9684329 /* FIRStartMFAEnrollmentRequest.h */, + 6DA191F722C849464E09ED0BF996686F /* FIRStartMFAEnrollmentRequest.m */, + CB1E13E7998204FCB479D758BE566FDE /* FIRStartMFAEnrollmentResponse.h */, + F7106C22A1E65102E4973A1912985F17 /* FIRStartMFAEnrollmentResponse.m */, + AB7DB6EF23B9761561E1598918C90693 /* FIRStartMFASignInRequest.h */, + 2307F3C89639D9D2EE17E026359A8CB2 /* FIRStartMFASignInRequest.m */, + F7041D7B7DBE5353E7092A9A3BC10198 /* FIRStartMFASignInResponse.h */, + 2075D1CE05FA37BC5327F25CBE420441 /* FIRStartMFASignInResponse.m */, + 253DAA1F6C666E88A854BEA3ADC06CBE /* FIRTwitterAuthCredential.h */, + C2EC8C6C780C5860481702B4A1E37E4B /* FIRTwitterAuthCredential.m */, + C0A5DA5FFD9B0E3136640EFCA7795031 /* FIRTwitterAuthProvider.h */, + C49ED58E11F92CAF3C06EC8A74B9BC36 /* FIRTwitterAuthProvider.m */, + A28C5B0EEC2339F327C24C1DEED5DF14 /* FIRUser.h */, + CBE24A706CEBF7649A1C7B1E338AA52C /* FIRUser.m */, + 2321555A80BE5C47A7147561FDF2F40E /* FIRUser_Internal.h */, + 39A02C6A98117D425B34FD66D0FE409D /* FIRUserInfo.h */, + B792817C5B5886C0147589470D6CCB0B /* FIRUserInfoImpl.h */, + 7A7C906E5F537583800EE44AA0B4F724 /* FIRUserInfoImpl.m */, + 983164803595694315F7F6A1821F52FB /* FIRUserMetadata.h */, + 12BDC2F59494AAB3007671C257F6E5DA /* FIRUserMetadata.m */, + 634E95BC4CB95F90015C87024F41037B /* FIRUserMetadata_Internal.h */, + C57780199E3F445CA56E1EF2ADA32EB1 /* FIRVerifyAssertionRequest.h */, + 41421C071CA3739A258EC0BA5CF15BD7 /* FIRVerifyAssertionRequest.m */, + DD426E865FC8F06B2B303FB46EDD4415 /* FIRVerifyAssertionResponse.h */, + B205E2A02343B83399E353E5848FB22C /* FIRVerifyAssertionResponse.m */, + 53E41845656DD3E593FDD4F6F3339B32 /* FIRVerifyClientRequest.h */, + 887930CE266A149A0909951039008F18 /* FIRVerifyClientRequest.m */, + B6FFCD446AFFF8D411EFD5BBB944A1BE /* FIRVerifyClientResponse.h */, + D023DA0E20514A607A76BF8E49A6BD1E /* FIRVerifyClientResponse.m */, + 201D6B608DE3FFE2C2B74490C3F4004C /* FIRVerifyCustomTokenRequest.h */, + 1610050E12683DE6BCCC39B25A37C034 /* FIRVerifyCustomTokenRequest.m */, + 315FFAA5751909C6D0C74C10F003C319 /* FIRVerifyCustomTokenResponse.h */, + 3A148D6148ECB9DE570FBC7207973EB8 /* FIRVerifyCustomTokenResponse.m */, + 47C6C963C21CCD40BCDAED4F0971499A /* FIRVerifyPasswordRequest.h */, + C379D2DA2D639963933E2B6BD2FBF6D1 /* FIRVerifyPasswordRequest.m */, + 6E783914DD89D8CE4F5851BF32F1F3AD /* FIRVerifyPasswordResponse.h */, + 47E1657B953672DCE7012A9F6150D4BE /* FIRVerifyPasswordResponse.m */, + 334F251C2F070D6DB3EB649734DB97B4 /* FIRVerifyPhoneNumberRequest.h */, + 08A9BE54D383AFB306E187521BE6F953 /* FIRVerifyPhoneNumberRequest.m */, + D8BFA0DF95EDE6A4BA5277DE642A52D9 /* FIRVerifyPhoneNumberResponse.h */, + 2EA1CB32F3E439672046D86007DE8A31 /* FIRVerifyPhoneNumberResponse.m */, + 2AB58E982FA948803C8BFFFE072A8FA7 /* FIRWithdrawMFARequest.h */, + C6BE8F46BEE35DA8571C06A26A640632 /* FIRWithdrawMFARequest.m */, + 648736713307A30F715716CC0D7E6610 /* FIRWithdrawMFAResponse.h */, + E1F13E99D5CDC9053C648E227DB5A99B /* FIRWithdrawMFAResponse.m */, + D772660D348EDA152D9FA9274A4FD651 /* NSData+FIRBase64.h */, + 07C17F9E595A3429B033D37E557FFA35 /* NSData+FIRBase64.m */, + F65A8D72B764DE727CE70947889FBD3D /* Support Files */, + ); + name = FirebaseAuth; + path = FirebaseAuth; + sourceTree = ""; + }; + 46C5CEBA314C8B5CD538D869F0ECCC03 /* AppDelegateSwizzler */ = { + isa = PBXGroup; + children = ( + 6978362BA33830B7AD0B5DB7A2947616 /* GULAppDelegateSwizzler.h */, + 91F8FFEB623B614F5EDF8885F5E8C780 /* GULAppDelegateSwizzler.m */, + 13FE74E1B86265EF9348F21E3F3E09D9 /* GULAppDelegateSwizzler_Private.h */, + 0219F46A3DB232BA4625B09FCAC5F422 /* GULApplication.h */, + 43F82C12F24B532F8411A78ACE0EAC72 /* GULLoggerCodes.h */, + D2752476EEBD2EB1C3C03EB7D629DE55 /* GULSceneDelegateSwizzler.h */, + D938E13F6F589C189B60C4CA4465EB1D /* GULSceneDelegateSwizzler.m */, + 938BD4E24A0851466BAFC3F07E2FF33F /* GULSceneDelegateSwizzler_Private.h */, + ); + name = AppDelegateSwizzler; + sourceTree = ""; + }; + 499EB8D1A22052C8C6DEE60D1191786F /* Logger */ = { + isa = PBXGroup; + children = ( + 56F81CBD795E02ECA8269A503DA73162 /* GULLogger.h */, + 876CF2F8FB95158F946B9DEA3869F659 /* GULLogger.m */, + 28E8C18EF9243B01130C42F9F7FF6092 /* GULLoggerLevel.h */, + ); + name = Logger; + sourceTree = ""; + }; + 5059F4FBAA3D48EB0A23E1B5904940EB /* Products */ = { + isa = PBXGroup; + children = ( + 43B1E4CD7B30B9FD278100133C2AC788 /* FirebaseAuth */, + E2B63D462DB7F827C4B11FD51E4F8E2D /* FirebaseCore */, + 8CC9178C366942FD6FF6A115604EAD58 /* FirebaseCoreDiagnostics */, + 51671C73F008B5C0C3751B3855999213 /* FirebaseDatabase */, + 9CF8FA5F01F446F01AAC7331075452AD /* FirebaseStorage */, + 856B5CD56F194FAD26EA91620B66D614 /* GoogleDataTransport */, + B43874C6CBB50E7134FBEC24BABFE14F /* GoogleUtilities */, + C1998E0D8085221AD87F89B614C10E52 /* GTMSessionFetcher */, + 0A9F46A999C47653013D3AD854352507 /* leveldb-library */, + 06FC5C9CF96D60C50FCD47D339C91951 /* nanopb */, + 5C321A8D9A1BFC778344F7F211DE5680 /* Pods-saraWhatsUp */, + 3347A1AB6546F0A3977529B8F199DC41 /* PromisesObjC */, + ); + name = Products; + sourceTree = ""; + }; + 513B91983445AAAC07501CC98D83ECD5 /* FirebaseDatabase */ = { + isa = PBXGroup; + children = ( + 7140D4B6712D57946886774F209BB1F6 /* APLevelDB.h */, + EC42A40F3D6145F7FF3837DFE3B986C8 /* APLevelDB.mm */, + CC269863983FDEAD924D5FBE3FD87236 /* FAckUserWrite.h */, + 3AADA268A54385BD84C98DA9A5DE30EA /* FAckUserWrite.m */, + 744F3A29E3170CC5C41C864DAC5D4235 /* FArraySortedDictionary.h */, + F6AC2404030727486B0D2FBBED6A41F4 /* FArraySortedDictionary.m */, + 74CB9232E11BC701A20AA685EB0A9152 /* FAtomicNumber.h */, + 3459404751ACFD08EDD0BDFD7ED39B97 /* FAtomicNumber.m */, + 34065017EC1BF5B0A3A4A05A2FF0D861 /* fbase64.c */, + 1F288DCDC36134E8DCCFE23B9B0A5552 /* fbase64.h */, + B34CAD0C7390089C50B4AECD381D8AC5 /* FCacheNode.h */, + B17F92A2601314D41826CAB86DA61688 /* FCacheNode.m */, + 0496FD94D83CBCCC1DB7ECDDC894B162 /* FCachePolicy.h */, + 771D448D527F0ED9A6589CFA7D620F5B /* FCachePolicy.m */, + ABA74436D35D18B787BA88238D23AF32 /* FCancelEvent.h */, + 7082914B8A3D20F7FA5BB89F2ABA8DB2 /* FCancelEvent.m */, + 4EB924A201604AACBB961E583E190D7A /* FChange.h */, + 9CAFBE8E892174EFAEA29FCBD9318A38 /* FChange.m */, + 63B3501F8CDAFD84E1E6CFBDF3AB5A1A /* FChildChangeAccumulator.h */, + 0653C3E0475AAA695FF29332FB69418C /* FChildChangeAccumulator.m */, + D5E1524A0256E64E49CDA88A4D9F15F0 /* FChildEventRegistration.h */, + D5A4E78107B016AF69DC439FF2711A08 /* FChildEventRegistration.m */, + A23BCDA5AC206E7CB756611195DEA81D /* FChildrenNode.h */, + CC53772094E8CA6243B6A7930C6D7E99 /* FChildrenNode.m */, + A9B2E8CE344E4A43DE5471284EB56977 /* FClock.h */, + AFC22D41599A2CA8D184D8CF956E77FB /* FClock.m */, + 139C0CF3E0B177E20E8F3550A4DEA5DD /* FCompleteChildSource.h */, + 6E4E4F4AC0B704BEE2F5186BA1744611 /* FCompoundHash.h */, + 89475AC8A6957A1C6B79D64857558539 /* FCompoundHash.m */, + FBEE29B982D54AA103A5A271D98767DA /* FCompoundWrite.h */, + BE74BCE8877C97E09DCE08D7221FFDFD /* FCompoundWrite.m */, + 0C30D81E6407995A697635D198C8DDDF /* FConnection.h */, + 83E2E567BD461A1E4963298CA03E1F4F /* FConnection.m */, + 93ED49D06A2C2D3717C9989F17DC95E2 /* FConstants.h */, + 04D67BEA48283ED3EBBC32F2CE1FB54D /* FConstants.m */, + 45AF18302FA22D80E5512B30C06C4070 /* FDataEvent.h */, + 0CFA82C57837B7BB75C48CEDB9A28159 /* FDataEvent.m */, + B1905F81A71DDC3422570810765B92E4 /* FEmptyNode.h */, + 22A2C5A6D778216B937ECDD7C4907FE6 /* FEmptyNode.m */, + F7DF3DE181967DAF4B834E4565CE8C52 /* FEvent.h */, + 7B14F659A087AA73A15A2172FDD72057 /* FEventEmitter.h */, + F94E060978237A794872573025EA4BAA /* FEventEmitter.m */, + F7DC7FA75B31D1254763C9DD27879B6B /* FEventGenerator.h */, + 6C9AF37FA21020C49EB931FE36D6FBD5 /* FEventGenerator.m */, + 820A9143A1B34097FC8811A6824024EE /* FEventRaiser.h */, + E1EA944496A2573E7E46DDFBCACDB6C7 /* FEventRaiser.m */, + 4DC1248939AA214A9B49EF4F744EA070 /* FEventRegistration.h */, + 056885DA57DFF38866F1836927203DB2 /* FImmutableSortedDictionary.h */, + 013A9B84A0D24B29F424C2D7B299946B /* FImmutableSortedDictionary.m */, + 6DAC3C48DBA947FB36971090D8CC75A0 /* FImmutableSortedSet.h */, + 1A27E89E002CAEE5D35D573EA0401CF0 /* FImmutableSortedSet.m */, + B6B8C36C9A9595FB83246E705A636C10 /* FImmutableTree.h */, + 154C7482FFED67A2563A3F0107E9E0C1 /* FImmutableTree.m */, + C3ED5F9B71BB5AB9B21AD796059C1958 /* FIndex.h */, + 24E003B576B1D07E80E0F3159C8D80AA /* FIndex.m */, + 2D928F363DB19E4AFCF00059587BBEA8 /* FIndexedFilter.h */, + A5921FBD031DE0BA0224527B5D044FCF /* FIndexedFilter.m */, + 36E0D2029C3DAB914F381E3957231419 /* FIndexedNode.h */, + EC370A05FD4A8730435B4248870B1E34 /* FIndexedNode.m */, + 81EEAF592B74F318B32710ADCF9E91B1 /* FIRAppCheckInterop.h */, + 52473D87AE13917BE131E5B55A668691 /* FIRAppCheckTokenResultInterop.h */, + 966A1DBDE4EC817C40A7AA5C8B1ABE0A /* FIRAppInternal.h */, + E4CAFFC2083A3EA3A2BD75F28233A4D2 /* FIRAuthInterop.h */, + BC0887BB80201541368EB5158D171A30 /* FIRComponent.h */, + 507EA49345E185C0EF9E6311E5748B3F /* FIRComponentContainer.h */, + C7251F3F7533A9A216EFD0FF18A7FEA5 /* FIRComponentType.h */, + 6BD5FF574F7F2B568DF85ED53271EC97 /* FIRCoreDiagnosticsConnector.h */, + FF81BE1C255D9D09005E15D96253E22B /* FIRDatabase.h */, + 405D1DB51D9EF49A3D1757A17D0FA23F /* FIRDatabase.m */, + B8481B7DCD916B592B3296314358DC65 /* FIRDatabase_Private.h */, + 89E31E2A96FD20D003BF0BCAA06EA6AE /* FIRDatabaseComponent.h */, + 4881E794C59369CE1B4F97ED9D5EE21E /* FIRDatabaseComponent.m */, + 74F3BD0F4A31AD80E7C2313A180504CC /* FIRDatabaseConfig.h */, + 4465D325944B7C664432A0C8703A429D /* FIRDatabaseConfig.m */, + 0421C48DDFB0098D497DCD3542BB99DA /* FIRDatabaseConfig_Private.h */, + 7A438F609CFC9332E652AAE024EE6EB4 /* FIRDatabaseConnectionContextProvider.h */, + 0E0B842AE076438EDED02B289F208B47 /* FIRDatabaseConnectionContextProvider.m */, + E3D37CD5FB23804B82EB8F6D3DA8919A /* FIRDatabaseQuery.h */, + FA57C47826950D4B1DDB1508EB0E38BA /* FIRDatabaseQuery.m */, + 08FBB509F7F005C11D635808E7C3B594 /* FIRDatabaseQuery_Private.h */, + 1157C2EB85FDBA73F430398032A06509 /* FIRDatabaseReference.h */, + B98C573562E1874BD238096257145128 /* FIRDatabaseReference.m */, + 2905F41AAD3BA1F44F8213EB56CF38DC /* FIRDatabaseReference_Private.h */, + F9A27AB3D82A79375F5B1A39D4C39E51 /* FIRDataEventType.h */, + 3729170399646C0750A1FF4A324422C7 /* FIRDataSnapshot.h */, + 9023A0DEA45F88CB202B8E8DB8ADE4D2 /* FIRDataSnapshot.m */, + DC38D0C9D92FB77059573CB698BE8E0D /* FIRDataSnapshot_Private.h */, + B981E34571A9050A1158813B45ABAA57 /* FIRDependency.h */, + 692F12FCE20BD05DF9A601125B760F1F /* FirebaseCoreInternal.h */, + DD4A6114C542A0B76FFE2CD9F298C74B /* FirebaseDatabase.h */, + FED184F8D1B40AFEA217EA44E8B7422E /* FIRHeartbeatInfo.h */, + 30F697CA73EBB0310B4076303AC5B7A8 /* FIRLibrary.h */, + 23BE7FAC4E42333FA445C40033DA4A17 /* FIRLogger.h */, + 41458221673789BB327991D743219EDC /* FIRMutableData.h */, + 8BCF37B07E3507CC4E49BC6EB62D2AFE /* FIRMutableData.m */, + C60545B543575471D5F2B720681B8F4F /* FIRMutableData_Private.h */, + 7B9CBE9C4D930B497C1A0FF04203D438 /* FIROptionsInternal.h */, + 9C112FFED625306176513F53215AE57A /* FIRRetryHelper.h */, + 5A08BEE1730CF35A6FC437448ABA4FE9 /* FIRRetryHelper.m */, + 9A8E98FC9F43E3599FC43038D8F3A086 /* FIRServerValue.h */, + D30D1AD3D4C298E46ACC5D9738D366E7 /* FIRServerValue.m */, + 1D037AF2BB90F895A3501FFF67FAD5C1 /* FIRTransactionResult.h */, + CDF8AC51DB6AC1BF9C30A265F6670B60 /* FIRTransactionResult.m */, + 18459382C69E8CE80FF371CDA0344FE1 /* FIRTransactionResult_Private.h */, + 893755B5174475866FE50238A792D3D4 /* FKeepSyncedEventRegistration.h */, + EC19D3E58E78BDD743A8EFAD9BC684CD /* FKeepSyncedEventRegistration.m */, + 1668C7B0D52CEFD7E0B83C5A403D1F50 /* FKeyIndex.h */, + 653F3E17804F6B21D223272C94E3141E /* FKeyIndex.m */, + 1C351DF20BBDB7C2D3D122CDE9CECB69 /* FLeafNode.h */, + 650A616FFDB77F03EEF97D722373AC34 /* FLeafNode.m */, + FC88E5BA67478422684CEA9786F3440D /* FLevelDBStorageEngine.h */, + C532F2EFDCFDAA9E763A5DAB92A56843 /* FLevelDBStorageEngine.m */, + 49144B923E72023870AA11B1320F1F4D /* FLimitedFilter.h */, + A523A418D4F79A8D9FA56B6A3EDAF69C /* FLimitedFilter.m */, + 95EF2C77F4AF7EEB9D7C7F24A0662678 /* FListenComplete.h */, + 46E0D19B44DD2105DB3A82048DF5D5B3 /* FListenComplete.m */, + FD2E6D7850FD2B0697176C4A6261522A /* FListenProvider.h */, + 658D0800BC15A31285C173FA8D9CB733 /* FListenProvider.m */, + 3F249B6371F8719C64CA57FC11118CC4 /* FLLRBEmptyNode.h */, + 33CEE7A426306395DC3DC59B63FD36AB /* FLLRBEmptyNode.m */, + 39411F7390CCE0DB18B3C0435CA92BB0 /* FLLRBNode.h */, + 69BC8DBB9DB5918FB6B6612E7F3B8B24 /* FLLRBValueNode.h */, + 77F60AEC184F86B601A6887F1210545B /* FLLRBValueNode.m */, + 656498BDC1CD14E38CB662D4FC560689 /* FMaxNode.h */, + AD619B86153088B111D40A2840C799F4 /* FMaxNode.m */, + 476FDE8C0ED7BDCEDFCF04830CE7F6D9 /* FMerge.h */, + 80D9586B150ABF4E1C652803A8C8420B /* FMerge.m */, + 197C1470CE81C5D575279D2F7040971D /* FNamedNode.h */, + 859B86587165B2DCC9980C52B661009A /* FNamedNode.m */, + 27F950C7EE4B76D2428D26EF8510C489 /* FNextPushId.h */, + 0D62E8B3886374A1220D5ED548497AB3 /* FNextPushId.m */, + 9FAD94001809AEFE8281F5B87506A581 /* FNode.h */, + 3B53883A091A5CB2C1CF6564AF14CE4B /* FNodeFilter.h */, + 1EC729ED3D4FBA1AF83B8B5321C688EF /* FOperation.h */, + 35E92455A3DBBF14B5F80114EDBC5BF3 /* FOperationSource.h */, + 4B4CAA944EC31C6A4379E65C073335EF /* FOperationSource.m */, + 4355106D4E229F6C43EFA4F9DCF22898 /* FOverwrite.h */, + A38345444096C985E3396DA12EEA60C5 /* FOverwrite.m */, + EBF684FC3AFCE3789A8D7312D9A91EF7 /* FParsedUrl.h */, + 3DCE0B526350A606F7712387B591E2D9 /* FParsedUrl.m */, + B3AD7AA0EA6D0ACE1BE4E5D12C5F2869 /* FPath.h */, + 08A8ED18BAADFDE9B7B3D9B70CFE0AEA /* FPath.m */, + E83C685792DEC69A5B185422B4AC2E7A /* FPathIndex.h */, + 097A3DBCD1FEDB6F15FC566B8F6EBB4D /* FPathIndex.m */, + D05CC9584CA83D98144C21E350DFBE48 /* FPendingPut.h */, + 5893F46AF93CDDCFE5279B6FCCF0030A /* FPendingPut.m */, + AB906146CF850CAF5331097EACEF462C /* FPersistenceManager.h */, + B305CFA4A65CC751131EB86AA4DB3ED7 /* FPersistenceManager.m */, + E1B4086F8CC23FC6345F410D5A962EE8 /* FPersistentConnection.h */, + F0C3D851DBEE7696D21526FF5443A526 /* FPersistentConnection.m */, + 86EBBD605D3354FDA906B9F9C13C7F23 /* FPriorityIndex.h */, + 0EB4424F6DC448437D09153671506EF7 /* FPriorityIndex.m */, + 1235ADB2B49B751EFEAF8A7A2CC2C36F /* FPruneForest.h */, + 610635289C0D10AC1C508932A13F5139 /* FPruneForest.m */, + B2ADA563135B97021B2C1F71DF0405B8 /* FQueryParams.h */, + D96ED13249834AE23DF273A121C5C859 /* FQueryParams.m */, + 6CD22871E7B3423E28E68F9F67339019 /* FQuerySpec.h */, + CB0BECAA820EA39FDA6E794C088A9F72 /* FQuerySpec.m */, + 39B80F6F5EC765ED2536E876CFA12A6A /* FRangedFilter.h */, + 98440E5E33E773D89A33711F76183D1B /* FRangedFilter.m */, + 08349AC39718E09B5546C61A59E2FDB6 /* FRangeMerge.h */, + 0C5B7637C35100D4E00B41FB959B5377 /* FRangeMerge.m */, + 9AAD55BD4ADB6669E2A7308808EDF999 /* FRepo.h */, + FADB445B0D83108D24457A1573E4CA4A /* FRepo.m */, + B827A66AEACAE0FAE2795D9338925F12 /* FRepo_Private.h */, + D51CE1651DCD28277901923BB6345C4B /* FRepoInfo.h */, + E7453502726C5BF4194ADE99C1058FDC /* FRepoInfo.m */, + E82FD5AB387A0866240CEFF8BE02C4DD /* FRepoManager.h */, + 208565AD245BDE529154ACE5F559D5AB /* FRepoManager.m */, + 01333A9556B2952D3BF8EF47FE063E14 /* FServerValues.h */, + C9B9793C13F569DADCC8C8F0E04F16A5 /* FServerValues.m */, + CBBEF9A24FDDF05863D1B193EB0592AA /* FSnapshotHolder.h */, + B271E16961C347079CB7026341CA75D0 /* FSnapshotHolder.m */, + 0391475D50E27C2921D0D820540DBF77 /* FSnapshotUtilities.h */, + A47B0B236ECF15DBE883A4F85C21E999 /* FSnapshotUtilities.m */, + 234E03B7B8FE3DD5EF2526A5EAF9FDE1 /* FSparseSnapshotTree.h */, + B67EF49828FB87A7A9D76CFCE913F31F /* FSparseSnapshotTree.m */, + FADE0B752CA28920C36DFE5EBFBD2EAC /* FSRWebSocket.h */, + F23127FE4B314F0651762F66488965CB /* FSRWebSocket.m */, + 6AF3DE1BF05C1C5CC8171AF15BF8E4AC /* FStorageEngine.h */, + 78DB71C20DCE241E1C54F53EFAC77530 /* FStringUtilities.h */, + 870F25C34E7DB23FF55A93605E9D93D1 /* FStringUtilities.m */, + 70E16CDF231339A38CEFC419256AF4B6 /* FSyncPoint.h */, + D3342AFD54F753153E244BABE9B38DFF /* FSyncPoint.m */, + 690301B45D9E8D31056AE28BE54B2A32 /* FSyncTree.h */, + 2500B7FB71DA82CBFDDDB4822D95A314 /* FSyncTree.m */, + DD69A621B862C551477417091A95F91C /* FTrackedQuery.h */, + B4653519E5F123F81CEF7260656B7E0B /* FTrackedQuery.m */, + F9B99A9DE81C98F23A7956ADBB6AAA44 /* FTrackedQueryManager.h */, + E35E50F5AA58D33E3A9E5B16C83258F2 /* FTrackedQueryManager.m */, + 1370B793664C2C3E3CE6DDC3053F7618 /* FTransformedEnumerator.h */, + 41BE35522F50B182192D5DC520C3216C /* FTransformedEnumerator.m */, + A13E5ECB9FF3870B0D27C2277B9EEF55 /* FTree.h */, + 02EF7686404E69DBF2E3EB1866181B14 /* FTree.m */, + EC324A417D58FDC1DA10C0B10DD50D40 /* FTreeNode.h */, + B613B172469E17F497E9203011CE9EA6 /* FTreeNode.m */, + CED377BFBEA5C61B77385FC87D617E93 /* FTreeSortedDictionary.h */, + E6B4F302F320A7E32801438DE388BEDE /* FTreeSortedDictionary.m */, + 553C71FD43D0F02F1FEC498375086661 /* FTreeSortedDictionaryEnumerator.h */, + 2B3B105917EE8719FEB00E3C8D4DFA56 /* FTreeSortedDictionaryEnumerator.m */, + 9319464784A2E9CF7514BBF5FB7DE52B /* FTupleBoolBlock.h */, + 78510B2DAF0836E51218B1E6D69962F7 /* FTupleBoolBlock.m */, + 05102F03FEA97AD55CCDD5D1FB4A90E3 /* FTupleCallbackStatus.h */, + F3E6618C894D10C116BC2F0FD09C91F0 /* FTupleCallbackStatus.m */, + 50C162F8A131149A66AA8D00EB16FD47 /* FTupleFirebase.h */, + 051169EAD8CE8968374F95BB47451BBA /* FTupleFirebase.m */, + 873B7FE9A7FFF50DB78D82AE2BB1692A /* FTupleNodePath.h */, + C75BC3FDB221D20BFF8AC4B4906E6172 /* FTupleNodePath.m */, + 54514D86CB405814FAC52602DC28EFF2 /* FTupleObjectNode.h */, + 9C8A2339EA1A42BEC98EB1E8282BC101 /* FTupleObjectNode.m */, + 1782CB220CA1344F5845A55A1A958C8C /* FTupleObjects.h */, + 65432ABDB449B9A041385A9150D9C1F9 /* FTupleObjects.m */, + 442329955158D6F017C4BE628CC72663 /* FTupleOnDisconnect.h */, + DC228939E4F3D2C027921DDE205BF92A /* FTupleOnDisconnect.m */, + 22563121E7EF6298E5CECCE8FF24294E /* FTuplePathValue.h */, + 96C114DA8C3BF81BDD0DE26B97B6754A /* FTuplePathValue.m */, + 40C49E450975211339D6732631127E8B /* FTupleRemovedQueriesEvents.h */, + FD44137A3A06146041EBB23278EDC30D /* FTupleRemovedQueriesEvents.m */, + CA348D76247362411205819BEBAE4021 /* FTupleSetIdPath.h */, + 52B93F9A3FDAF910EB354BCC66677B36 /* FTupleSetIdPath.m */, + 42DDF78AE884D504E56DD3D1843DD15F /* FTupleStringNode.h */, + 1F6E3155820E7453FEBBF8026C3B8DE6 /* FTupleStringNode.m */, + 454FA5FBE52280258D0A13B8B42FC8B0 /* FTupleTransaction.h */, + C3B84167E1CB948B5A68D8197312567B /* FTupleTransaction.m */, + 7642C814801983526EC7A772DD7CB903 /* FTupleTSN.h */, + 407581F15079BCCB5BC45C24943E6FD2 /* FTupleTSN.m */, + A10858F9FD018F9DF1B20B62C3C26C77 /* FTupleUserCallback.h */, + 05A833BF83229902996FDD783BD650CC /* FTupleUserCallback.m */, + 2224951413E013BC93CDFA9F58D26A34 /* FTypedefs.h */, + 3E9B301EABBEF76F916373F59140BDB7 /* FTypedefs_Private.h */, + 0FDA8FF09D2555F381F370A0422B2983 /* FUtilities.h */, + BB265518B2679102E1A6CCB3C247F6BE /* FUtilities.m */, + B619FA3B200C111A548E62024E1C5A0A /* FValidation.h */, + FC108E601CFE8FE0A56A55196000DBAD /* FValidation.m */, + 53BCB33DFFBC9068A6596EBFC554C15B /* FValueEventRegistration.h */, + FE04F0C80BC6BB55DA64201AB87C33F2 /* FValueEventRegistration.m */, + 133C88D736DA8CED133F999B0912796E /* FValueIndex.h */, + 21D511E9F4CC3BC909ACE2417E6EEEB7 /* FValueIndex.m */, + 4F1E284083A40C9553A9E065850B8A1C /* FView.h */, + 6AA3FC4AAA0E5EBF67505C5E0EA20BCB /* FView.m */, + 32CCD9D69D9B4F40FDDB4FD5B8C08322 /* FViewCache.h */, + 9CCC54EEE3F4DC8C1F48E8CBA72E1888 /* FViewCache.m */, + 7D845130CEB654D57DB488C212CDA7DF /* FViewProcessor.h */, + DA37457479E7EB67EA481AD09874D1CE /* FViewProcessor.m */, + 70252C7F4F088EF4BFE7BC92EA6FB86D /* FViewProcessorResult.h */, + 9B3073A4C243406F1A0F8ECB78D00C96 /* FViewProcessorResult.m */, + 90CAAB7C291E0685B9F1381EE7D4BFE7 /* FWebSocketConnection.h */, + D84A34181EF2D407DFCDDACAA34AEB56 /* FWebSocketConnection.m */, + 1BE3361A3F0C14B7DEFD6AF4BC8765A8 /* FWriteRecord.h */, + 0C7BF91AA178CDB48E76323D48504F27 /* FWriteRecord.m */, + 9F44676D510C821AA4FCBEB2EDC7C1A9 /* FWriteTree.h */, + 6CC5392A5C437F2EB22C9AEEE9E80264 /* FWriteTree.m */, + DFEB773E723D577BD5E2FCEEA9EF8BBC /* FWriteTreeRef.h */, + E0070AA5B17F5B089940E9DF9C7EAEBB /* FWriteTreeRef.m */, + A7281F8592B9D881F237AD35C3339C04 /* NSData+SRB64Additions.h */, + 2422BB9F3FEE8E73CD7604E104FB6565 /* NSData+SRB64Additions.m */, + 55BACE3DE47E002D6ABC0F0AD28E7281 /* Support Files */, + ); + name = FirebaseDatabase; + path = FirebaseDatabase; + sourceTree = ""; + }; + 51EF2911CFA91698549955266AA4A609 /* NSData+zlib */ = { + isa = PBXGroup; + children = ( + 7A884E90C80E2A19BF969865E5AFB5AC /* GULNSData+zlib.h */, + A7164E84783F2E49EAEC72DB3D512690 /* GULNSData+zlib.m */, + ); + name = "NSData+zlib"; + sourceTree = ""; + }; + 55BACE3DE47E002D6ABC0F0AD28E7281 /* Support Files */ = { + isa = PBXGroup; + children = ( + DFB0AF5D8FA934148999A8DE9E242912 /* FirebaseDatabase.modulemap */, + 36757A52A1527757F814CD6DF5597901 /* FirebaseDatabase-dummy.m */, + 1BB4D7A6FFFF742F2E980F08A9EA3AF3 /* FirebaseDatabase-Info.plist */, + 65C9D3135B91FB7527D0EA93EE04C9F7 /* FirebaseDatabase-umbrella.h */, + 8A19AACF745587E8B91E0E6FACA7BF1E /* FirebaseDatabase.debug.xcconfig */, + 173AF725A61B69DB8626BC934E56526F /* FirebaseDatabase.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseDatabase"; + sourceTree = ""; + }; + 577C17BB5578321E8F0FD9A52EC80756 /* CoreOnly */ = { + isa = PBXGroup; + children = ( + 7370EFBF89FC3CF254734605FBB4493B /* Firebase.h */, + ); + name = CoreOnly; + sourceTree = ""; + }; + 5A2055A292C8E9351C5C4006D9072762 /* Firebase */ = { + isa = PBXGroup; + children = ( + 577C17BB5578321E8F0FD9A52EC80756 /* CoreOnly */, + 1B604A1E2AC95163CD0CFFB0F36FDCF9 /* Support Files */, + ); + name = Firebase; + path = Firebase; + sourceTree = ""; + }; + 79CC46E79D64C3272A059E0E79BB78D3 /* leveldb-library */ = { + isa = PBXGroup; + children = ( + D3331DD7FCAE6B40EB649D6941B9148C /* arena.cc */, + 288E61A06D7AA62E0EC62D1A11CE0FEA /* arena.h */, + BA511F39EE0137DB4B0ACAA4F2EB5714 /* block.cc */, + C97ED48F534DAB71C30E29D42CE0C347 /* block.h */, + 8242A9A4631DC19F5D16EA6821C81ACE /* block_builder.cc */, + 305D63F18BFD331E7B6F6CDBAE3A86E6 /* block_builder.h */, + 6178C9FA032D52D1A34C47D97B5C12D5 /* bloom.cc */, + 1BAC185425DBFA92432FC48DC8E975D5 /* builder.cc */, + 10FE76B048D51686FA8712B5F472ECE3 /* builder.h */, + 33DB693963458E6D16D408C4E387BBA6 /* c.cc */, + A0D696069DC52E2EA049543F7F8A9256 /* c.h */, + 902BFA8AA57755F097F4A2314A70024E /* cache.cc */, + 6C28C18AE3A3486767C01ED576BFB6E2 /* cache.h */, + D75A71D6B0932410BBBF7B7C7ED86CF9 /* coding.cc */, + 5EF7576689BC01D4194E19EF9A62732C /* coding.h */, + E05A9C8A4A5E398CC84792414886CFDF /* comparator.cc */, + 67AC37415B5E0F60D1AB77E62E71BCE2 /* comparator.h */, + 999D8DF2DEB3C92825F53ACD82C3DB9C /* crc32c.cc */, + 088B296CBACE0AC12047F6B7A5570A89 /* crc32c.h */, + F697F7EA92D4F5BEA9A9ED3F7DB01CA5 /* db.h */, + 9A08E0231CF2A46E1CAADFD0BF70218E /* db_impl.cc */, + C4CC188B7B93B535D5F12913B4B2F37E /* db_impl.h */, + 794B727CDE156C67F0B60B8D474D20C7 /* db_iter.cc */, + D881285A593D28B3D30B443110BFD856 /* db_iter.h */, + DB475D8D0ED92EA291952E540077A838 /* dbformat.cc */, + 4B9919D2A47D4A51AA0F110EA67FACAB /* dbformat.h */, + 3530277F290B77EE13F89290A41E04C4 /* dumpfile.cc */, + A13F6D7C44A5A2A6597076C8707DBA66 /* dumpfile.h */, + 404EFB07CB1339C320835C4EDA1ED913 /* env.cc */, + 3A1F060899EF16D3F61A63082A459A58 /* env.h */, + DFE085E90848700012D4C7E2953F5CB7 /* env_posix.cc */, + 035DB386647B61CA504DED882F157E0E /* env_posix_test_helper.h */, + 17B17FDF8C1411944C7BAF3A650948E1 /* env_windows_test_helper.h */, + CC9F05108D2A9DE51B409B2429608A48 /* export.h */, + 80CDF9EB8D8F9AC9F7C8BF0A0F2D50B3 /* filename.cc */, + FABDF831904EB454A599B7FFBF8ABE65 /* filename.h */, + 895057CB8373A1993247A9B6D4D8115C /* filter_block.cc */, + 7FE96EDA64C9137D9B8CCBCA2E2B050C /* filter_block.h */, + D3357AC70DA0AB1A2DBC4B94318BA7F5 /* filter_policy.cc */, + 811110CD8732C07CA742FCB28DD59DAF /* filter_policy.h */, + AB5E508280625F1411B9EFB92FE8198F /* format.cc */, + A694F59813CCC4BC2AC445313784F0F2 /* format.h */, + A24B571815B03F78DBFCF213BC206922 /* hash.cc */, + E71462E7A638DD8650951BF1796855AB /* hash.h */, + 98624617DE7BFE80191230F4C3EA8C8F /* histogram.cc */, + E20F0CE3E9E3B51A9C596A24A248E86A /* histogram.h */, + A1BFD9AE542728E653ADC18E3BB48638 /* iterator.cc */, + 3CAA0FD11D8FBE058FA3A8121AEA112E /* iterator.h */, + EA5CDBD4BB26A7AE9E17E18093DD93DD /* iterator_wrapper.h */, + 6737C17420EC2B9B78FD01C46864F7D7 /* log_format.h */, + 17B6C9AB660C7ED9F3CDAA1F45F4D9EC /* log_reader.cc */, + C00C0C9FE788D4BEAEE1CD97C5B7CA54 /* log_reader.h */, + 971E8724264AB745B9E5A5BCF8718493 /* log_writer.cc */, + 79882FAC0E130E92163100F2906DC9EE /* log_writer.h */, + 304757A5D03E8A05E64E70D59C041A7D /* logging.cc */, + 51F316E9BA48B7969E95F23475DAF6CE /* logging.h */, + 55306428FD4A4CD23EE65BE697D86C37 /* memtable.cc */, + 36FA3C599D68ACB54C990556F1DFB016 /* memtable.h */, + 24D69FACD4B23716EBCD5F309571F61A /* merger.cc */, + 366AEC787A39A50848D53D417F5F40BA /* merger.h */, + 4054C2CE5E6C42242A0D1ED848DB68B4 /* mutexlock.h */, + DD4864542B99534D826884212D610051 /* no_destructor.h */, + 8B80F50DB73B1D0034621B3CDB16BE58 /* options.cc */, + B936B1C80480FC87F5447A70D6AD27EC /* options.h */, + 5104C396E6DF2C443D0D8078264E91FF /* port.h */, + 597E0977016E0C422EE40E3D6BFECCA0 /* port_example.h */, + E839F6DD585A7A414970E839F31D2E7D /* port_stdcxx.h */, + F8639C05F1651B89D57F11600A798BAA /* posix_logger.h */, + CF352B6F70E09752E60EF9E4B1A9FDD3 /* random.h */, + 033F4C2158EF7093260D0330792F029F /* repair.cc */, + CE5BA5A1C569D1F8BED18C2C5EC763C1 /* skiplist.h */, + 5CD8E0EADF4EE6B3E91C089CE16D4F17 /* slice.h */, + 201E994E5AB33B9C4F084310F0262E87 /* snapshot.h */, + 06026367C0383ADE30C5100DC880F6FD /* status.cc */, + 76C2FA149D8C26F195DE9762321A1920 /* status.h */, + C999B82DC40782937B995EB4447F67C1 /* table.cc */, + 5A3CB08CA78834D9A4E195F7E0FE927A /* table.h */, + E0600815FC2D83CC6D9B07E29B47A629 /* table_builder.cc */, + E573656466A4A2CCC24C84FC97BBCE87 /* table_builder.h */, + 63E1D53A4B14B4142DC4D4E2EBE46EF3 /* table_cache.cc */, + EA254A1DD38BCE10EC20E3DEB1B9E69F /* table_cache.h */, + 2362DA688BE060908187030599778FF2 /* testharness.cc */, + 0A77E7C65037F8961C4FAE7B34A6CB32 /* testharness.h */, + 85CE11515F2C205F76C8BFC8719857B2 /* testutil.h */, + 74E042EA7A7F096AF1B67AA3C772EBF5 /* thread_annotations.h */, + B6A063636D2C9CF47A66A3A4D96EB2A2 /* two_level_iterator.cc */, + 5CD4886842838E480318693C78559A41 /* two_level_iterator.h */, + 5D877752182A2E5845173CA3BF342E8F /* version_edit.cc */, + FC4238AE7DE4CF32B916F6526C7E4208 /* version_edit.h */, + EA02B385FB2B4B2B9E246CA24BD2EF26 /* version_set.cc */, + B291863611DA98B373B9B2EB0CD48177 /* version_set.h */, + 301EA6A4343640583F1D76E4D3FDB21C /* windows_logger.h */, + 949794C45F737460830D38D5C890CD72 /* write_batch.cc */, + 3955A3844EE1F657DC3F3734E0E90A45 /* write_batch.h */, + 91B88E934D122F562EFA30F1738C3C2A /* write_batch_internal.h */, + B9D8321417981FB66478F63106BF928D /* Support Files */, + ); + name = "leveldb-library"; + path = "leveldb-library"; + sourceTree = ""; + }; + 7BC0FB856084F3FA93C70CF7297C8ED0 /* Core */ = { + isa = PBXGroup; + children = ( + 35079459556846DC42E6BAD6EF998A09 /* GTMSessionFetcher.h */, + 70C515513B0530D479DEC11A0222821F /* GTMSessionFetcher.m */, + 4F8EDD5168E6EE7045D53755BA6ACE3B /* GTMSessionFetcherLogging.h */, + 94235ABB6F648EA86DBC2A05160618EA /* GTMSessionFetcherLogging.m */, + 81117FB9C9B2BBBD3119E04D9F265A56 /* GTMSessionFetcherService.h */, + ACD4A4491817F56E21D0F68271612C7D /* GTMSessionFetcherService.m */, + B48A5067D93FC5220DF1348412F02223 /* GTMSessionUploadFetcher.h */, + 9B1977B027A730291BFC8865A04CCC89 /* GTMSessionUploadFetcher.m */, + ); + name = Core; + sourceTree = ""; + }; + 81E31054029CB80671C8BEE97F7B2502 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + D13FA67A9BDE54D8B32BD948D3CE76D7 /* Pods-saraWhatsUp */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 8275CCB4E8732497B1021FCBC240F3C2 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8B6747F3DF88A04902E036A33818C878 /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + 837E70109D03CD71FD278A48346BF595 /* Support Files */ = { + isa = PBXGroup; + children = ( + A571F592B22AE0BF6EAFD0953CC336D5 /* nanopb.modulemap */, + CEA0532B6963DB6C4B82B68B1AEEDAFE /* nanopb-dummy.m */, + A257F86718127C656BABAC72ADFFFD7D /* nanopb-Info.plist */, + E5692839611D88CB21196E1A6456DF29 /* nanopb-prefix.pch */, + EB97D7B83E06FEC9F876862742C3101F /* nanopb-umbrella.h */, + D77FC63C6A5F4F440E4C6041694A5B6A /* nanopb.debug.xcconfig */, + 28E9C68290B23C26900DBEA3E551D14E /* nanopb.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/nanopb"; + sourceTree = ""; + }; + 8750C5998951631700C3C872AE74D408 /* Pods */ = { + isa = PBXGroup; + children = ( + 5A2055A292C8E9351C5C4006D9072762 /* Firebase */, + 4081481F151F75D5AF30065AB006B195 /* FirebaseAuth */, + C5874E907BD9F671F56AF09EE65F6991 /* FirebaseCore */, + A348227958FB54DC5FEA856771A74BCE /* FirebaseCoreDiagnostics */, + 513B91983445AAAC07501CC98D83ECD5 /* FirebaseDatabase */, + E2CBE803AF1F96486B1E563071282D01 /* FirebaseStorage */, + BCEE7680A3EE1254DF75D0D327FB45B0 /* GoogleDataTransport */, + 8B28CC4BAA6B6FC9584D84216EA65EBD /* GoogleUtilities */, + B5AE1CB62D48185CEB14075514C39ACA /* GTMSessionFetcher */, + 79CC46E79D64C3272A059E0E79BB78D3 /* leveldb-library */, + AC8FB8C0D30B0F3DFA35564A3A25DE42 /* nanopb */, + CC84C2689EF477DF70B1D92C754D4032 /* PromisesObjC */, + ); + name = Pods; + sourceTree = ""; + }; + 8B28CC4BAA6B6FC9584D84216EA65EBD /* GoogleUtilities */ = { + isa = PBXGroup; + children = ( + 46C5CEBA314C8B5CD538D869F0ECCC03 /* AppDelegateSwizzler */, + 938E3D54FB60F245D40B8152AB50880E /* Environment */, + 499EB8D1A22052C8C6DEE60D1191786F /* Logger */, + A9B3A3214494E97594E25505C6AB6079 /* Network */, + 51EF2911CFA91698549955266AA4A609 /* NSData+zlib */, + E26FF5A3C9A7E1AF18AD8353434ADFE3 /* Reachability */, + FAF73B1DFA1FE0C751B293B195D2A562 /* Support Files */, + ); + name = GoogleUtilities; + path = GoogleUtilities; + sourceTree = ""; + }; + 8B6747F3DF88A04902E036A33818C878 /* iOS */ = { + isa = PBXGroup; + children = ( + A362684A637B06059850B849A03F1349 /* CFNetwork.framework */, + 3EB45EC81F9E789E892AA3B0F212BD9B /* CoreTelephony.framework */, + B90CCE98F435BF9D39003628B965E001 /* Foundation.framework */, + C49A0050512E4D846C5B20571F192808 /* SafariServices.framework */, + B3125D500C1F70AC85CA5401A1F25E6A /* Security.framework */, + A978F386557998E5D34EB6BB8A499A13 /* SystemConfiguration.framework */, + 900BF383BC85BE28DB45649BAB939A60 /* UIKit.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 938E3D54FB60F245D40B8152AB50880E /* Environment */ = { + isa = PBXGroup; + children = ( + 30F3F1287E0C40F9E4C1D4DDD5807784 /* GULAppEnvironmentUtil.h */, + CA5DF7383A09BA07C99F52E2965F0A2E /* GULAppEnvironmentUtil.m */, + 38DE2A3494BE61EDB0B876D18D0A55E0 /* GULHeartbeatDateStorable.h */, + B8032A0DB492656E1C113353FB6D43DE /* GULHeartbeatDateStorage.h */, + 925BD1DFC24947B884372F9062E7A526 /* GULHeartbeatDateStorage.m */, + BCE449A532CA88DFB2BC752B06041EC5 /* GULHeartbeatDateStorageUserDefaults.h */, + 87AE30E463E767DF440624B241B3A6A4 /* GULHeartbeatDateStorageUserDefaults.m */, + E24707A940249750B09DC979B64197AB /* GULKeychainStorage.h */, + DC7F516FF78C44446D8D2E2CFABA526E /* GULKeychainStorage.m */, + 132E0228BE7AC8D19E9CF7E085EE282D /* GULKeychainUtils.h */, + 93DD3C0ECA96FFC0C58657AFB6F07DE0 /* GULKeychainUtils.m */, + 7E907B698BBF0F9109ABFC14AC18417C /* GULSecureCoding.h */, + 3C3A935A0E1C775C388B504E26363B9D /* GULSecureCoding.m */, + 15FC3AC6278487A52B2F5A7FEEF30FAC /* GULURLSessionDataResponse.h */, + 5F749420BEE22809423074866B4C77F2 /* GULURLSessionDataResponse.m */, + B81795EFF3756C6009403EB7B9A9868C /* NSURLSession+GULPromises.h */, + 1E69939A365088C66AD857717FF633A8 /* NSURLSession+GULPromises.m */, + ); + name = Environment; + sourceTree = ""; + }; + 9FF2346EAC17496E831346D6865E14E7 /* Support Files */ = { + isa = PBXGroup; + children = ( + A7FA416AE84B24927DEE30CC26F89422 /* GTMSessionFetcher.modulemap */, + EDB91576C5DBF9C1A9EE8EA285461D1B /* GTMSessionFetcher-dummy.m */, + 298ED93877CC4D1E87C81BA2A07083D5 /* GTMSessionFetcher-Info.plist */, + 3ABA0E9A7429B48D6B8C6BF47DF70702 /* GTMSessionFetcher-prefix.pch */, + C41052FC02AEECA1AEEB044D099DF29E /* GTMSessionFetcher-umbrella.h */, + 22ACFD8A65A5EDB477F1472FAB19B5DC /* GTMSessionFetcher.debug.xcconfig */, + C61B106681E3099B5B9744CA4BD8C8BB /* GTMSessionFetcher.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/GTMSessionFetcher"; + sourceTree = ""; + }; + A348227958FB54DC5FEA856771A74BCE /* FirebaseCoreDiagnostics */ = { + isa = PBXGroup; + children = ( + 456A00DB744DF00FBD9B147C646D1639 /* FIRCoreDiagnostics.h */, + 70C8399F3F73FA8401A82FF892984E39 /* FIRCoreDiagnostics.m */, + 451F026B97D69D675820DFD19C8B211B /* FIRCoreDiagnosticsData.h */, + 453E14DB73F09FBD36D1DB25E717FB5C /* FIRCoreDiagnosticsInterop.h */, + F9261B348836363F87E4E2D8EAF2156F /* firebasecore.nanopb.c */, + 85DF2F3A1C45FB8F162B24BEA791AF80 /* firebasecore.nanopb.h */, + 149300CCB564C36213FBD105A43F87B8 /* Support Files */, + ); + name = FirebaseCoreDiagnostics; + path = FirebaseCoreDiagnostics; + sourceTree = ""; + }; + A9B3A3214494E97594E25505C6AB6079 /* Network */ = { + isa = PBXGroup; + children = ( + 159393C33349F60D4E04328017F2B565 /* GULMutableDictionary.h */, + 4CCB2BF6F6A5EB6D04951F3D60060A14 /* GULMutableDictionary.m */, + 87B50EC0E9EE9E6ECA780B6E21840EA0 /* GULNetwork.h */, + E20C20D7FAB01BCCA3A30E6B08C36B35 /* GULNetwork.m */, + 32D828B5EF58C384892390572BC508C4 /* GULNetworkConstants.h */, + CEB8FBCE6B02585240FAEBCEF664AFEF /* GULNetworkConstants.m */, + 5C3CFCB3EEDDF72A8350385FABE6EED2 /* GULNetworkInternal.h */, + E5E00737AB979B86E4AF9B01699CDFF3 /* GULNetworkLoggerProtocol.h */, + 172F05B85B5EC79590698D2BEECF63CE /* GULNetworkMessageCode.h */, + 9D5D02FA20F7768EBC412798CA562E0F /* GULNetworkURLSession.h */, + 531AD53C3115F7F7EB5D782FD9813823 /* GULNetworkURLSession.m */, + ); + name = Network; + sourceTree = ""; + }; + AC8FB8C0D30B0F3DFA35564A3A25DE42 /* nanopb */ = { + isa = PBXGroup; + children = ( + 332156AC66B8A5BE893815856DA94D3C /* pb.h */, + D4D60F9F02A0480B7DC03CCF3A8E0078 /* pb_common.c */, + 8FF27683F341192130EB44D127CBA99A /* pb_common.h */, + 56EE34A46421CDFB2307136C2B5B76C8 /* pb_decode.c */, + AEFAC1E7E8D13CF3F8C80D787FC8EA68 /* pb_decode.h */, + 27D1CAC99D5E7E545C7793FED2EC6FAC /* pb_encode.c */, + 86C7CA6595BF223D4051F9ACD7821516 /* pb_encode.h */, + EC2DCA7BBB098771525BC5CBBDCFFDB8 /* decode */, + EEC4F9310C80C73A412007AAA4CABCEF /* encode */, + 837E70109D03CD71FD278A48346BF595 /* Support Files */, + ); + name = nanopb; + path = nanopb; + sourceTree = ""; + }; + B5AE1CB62D48185CEB14075514C39ACA /* GTMSessionFetcher */ = { + isa = PBXGroup; + children = ( + 7BC0FB856084F3FA93C70CF7297C8ED0 /* Core */, + 9FF2346EAC17496E831346D6865E14E7 /* Support Files */, + ); + name = GTMSessionFetcher; + path = GTMSessionFetcher; + sourceTree = ""; + }; + B9D8321417981FB66478F63106BF928D /* Support Files */ = { + isa = PBXGroup; + children = ( + 84DD600E57DB8E6E08CD086A2207EC82 /* leveldb-library.modulemap */, + E034F1CE93125D1722311B3DE473783A /* leveldb-library-dummy.m */, + 5E9476011EBE9536D02B60D647D208FF /* leveldb-library-Info.plist */, + E9047EE1297C3C54091D160DEE436716 /* leveldb-library-prefix.pch */, + F2598F081516F4371B1C222199738340 /* leveldb-library-umbrella.h */, + 355434705FF7B7073A4B9D11E25224D7 /* leveldb-library.debug.xcconfig */, + 663C76ADAD38564E75D41755802032D1 /* leveldb-library.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/leveldb-library"; + sourceTree = ""; + }; + BCEE7680A3EE1254DF75D0D327FB45B0 /* GoogleDataTransport */ = { + isa = PBXGroup; + children = ( + 925E43A65D1F0FB87B5EFE7FC554BA86 /* cct.nanopb.c */, + 71EE8EAC0D7B50883AEF17DADF5767A2 /* cct.nanopb.h */, + DC734172FD9BB1B7FA869203F23EC521 /* GDTCCTCompressionHelper.h */, + 9292823C54252CB8B2596AC4FCB873ED /* GDTCCTCompressionHelper.m */, + FC3008FE520DAA1E2912594F5C522BFC /* GDTCCTNanopbHelpers.h */, + 7479F6204A3F34CDEC48DB0D5C66BAF3 /* GDTCCTNanopbHelpers.m */, + A5760DF131877B2B89137DEBFEF1A3C1 /* GDTCCTUploader.h */, + 9984587BC159E07ADBA1CBAFAF7A0DC4 /* GDTCCTUploader.m */, + 9A6AEEDC723439C1699E7CF8FCCD9CA8 /* GDTCCTUploadOperation.h */, + 37529818565A88B7EA068C0B2810EB6B /* GDTCCTUploadOperation.m */, + 5B631A61906DC5D2C67D668AC690D0F0 /* GDTCORAssert.h */, + 331A7C3422670ECCDF077EDA8C5B0FB7 /* GDTCORAssert.m */, + 3A0B3E5EA3F8111247486DB742BB6DB7 /* GDTCORClock.h */, + A27989CBB3630E8519D5EF0AF4D86AC3 /* GDTCORClock.m */, + 2EB0CDD50EC9532DC424B2BE44B2FE29 /* GDTCORConsoleLogger.h */, + 6E327D29008B38CAD50251DFE43B0910 /* GDTCORConsoleLogger.m */, + 50CB80E6E0BEAE2308EE795D8EFF0E61 /* GDTCORDirectorySizeTracker.h */, + 5EADB06838DAC9C43A23D0F1CA0C0AD1 /* GDTCORDirectorySizeTracker.m */, + 8016DF8549B631F0298ACC705E2FEB07 /* GDTCOREndpoints.h */, + 8A665156BBF095A8DAE862B03D76D49E /* GDTCOREndpoints.m */, + DF67656B1014EB5D0F8C31628A0F8D40 /* GDTCOREndpoints_Private.h */, + FA2E91A9425BE6BC994203B17F986063 /* GDTCOREvent.h */, + B23EC38971E21F4A29F30D17FB217E7D /* GDTCOREvent.m */, + 01E75FBC9C58CDC564AC74535ABAF369 /* GDTCOREvent+GDTCCTSupport.h */, + 17F669B599B173989CB4B85439CACA8B /* GDTCOREvent+GDTCCTSupport.m */, + B4FF56EBCE0455EE942F1411CAD7E3B4 /* GDTCOREvent_Private.h */, + 9F9B40A1541FA2FB2FD430EC3320EA58 /* GDTCOREventDataObject.h */, + D1284A968E76C7AB80F7D25481E15AED /* GDTCOREventTransformer.h */, + 7DA865334FCBB6542CCD3A0506BFD36A /* GDTCORFlatFileStorage.h */, + 68045793108BA0560D877E755265EF7B /* GDTCORFlatFileStorage.m */, + 796FC6CF1B3D7E3AC02697E08E2EA1F6 /* GDTCORFlatFileStorage+Promises.h */, + 3C83E99C8390879BAAE9ED2AE7E505CA /* GDTCORFlatFileStorage+Promises.m */, + FA52D7A5FF113ACBFD33CBBC3183A141 /* GDTCORLifecycle.h */, + FC8A2FC61EA1CF1F1CE6168D12AD5BC2 /* GDTCORLifecycle.m */, + 2B660D391F0513F69F3840BAF34FAF6A /* GDTCORPlatform.h */, + DE506671538C7408F5B08E892EA3B6B4 /* GDTCORPlatform.m */, + 01770DBB442B8AC1A2AA89A8B06AE1CD /* GDTCORReachability.h */, + 865CD6958FFE2BBE6CAAB27A454D920E /* GDTCORReachability.m */, + 031CCD2F09059BB876AEF36C4CCA549D /* GDTCORReachability_Private.h */, + 7990098C6933A9C3ACFD403877E938CC /* GDTCORRegistrar.h */, + D26AF22ECA5F16578D950CF2E197D91C /* GDTCORRegistrar.m */, + 4C54003B69296239A18EDF3744A8DF41 /* GDTCORRegistrar_Private.h */, + F15CFAD5BAA65469E2657BD24D8EFA9F /* GDTCORStorageEventSelector.h */, + 757945FA220DFAC917470EC142BCAC20 /* GDTCORStorageEventSelector.m */, + A028346C0A515F7539EB33C42B3D0DF5 /* GDTCORStorageProtocol.h */, + 090C4DF6889DD5CE158AF416BFE28E37 /* GDTCORTargets.h */, + 54F92AA596420F49A8CE62BF16ACD771 /* GDTCORTransformer.h */, + 2BBAE436FDDBE0D788ED31A281A08436 /* GDTCORTransformer.m */, + E956BC1D004B2B30234ADA67B946DC7B /* GDTCORTransformer_Private.h */, + 0238C971BE9A0CA5EF77CBFB630D350F /* GDTCORTransport.h */, + F5089FA76BD0882F080BDA39DD2EDED3 /* GDTCORTransport.m */, + 3162E87790D20F6130A7D9273AD557D3 /* GDTCORTransport_Private.h */, + 3EB166DE4F074F3497F8F11DEA37944A /* GDTCORUploadBatch.h */, + 368E3E5C4EF9356A8DA1ECE19D07E518 /* GDTCORUploadBatch.m */, + 6B560758433B7E849C46B3873B69351A /* GDTCORUploadCoordinator.h */, + AF73E4F33B65F69FB06DB662B11DE607 /* GDTCORUploadCoordinator.m */, + 845238B4F985C6B229BBD312689D4F16 /* GDTCORUploader.h */, + 378C8AD124FDA4F23AECAD552687460A /* GoogleDataTransport.h */, + CECC7C28B2D4A820EF4894AE4646BA35 /* Support Files */, + ); + name = GoogleDataTransport; + path = GoogleDataTransport; + sourceTree = ""; + }; + C5874E907BD9F671F56AF09EE65F6991 /* FirebaseCore */ = { + isa = PBXGroup; + children = ( + 60308EFBF8231E4B777992DB527F71E9 /* FIRAnalyticsConfiguration.h */, + 0E25132C2CD03254F7E2A6E3C4F929F7 /* FIRAnalyticsConfiguration.m */, + D2EC0D304F2E147D3F387897C17F1887 /* FIRApp.h */, + 286D39398D1A765422E97AAAFD146BDB /* FIRApp.m */, + 65CC113A8D6258FFC99A804308B6D18E /* FIRAppAssociationRegistration.h */, + 68E626CB79A2ADC613582CCD54AF80C3 /* FIRAppAssociationRegistration.m */, + 923643A2605DC868E971C64C0BF28726 /* FIRAppInternal.h */, + 64198B298948BC8CF0170A0327736352 /* FIRBundleUtil.h */, + 659FED812C988A2D8BF2D7E6F39661B8 /* FIRBundleUtil.m */, + B251FA096ACFF51E3C472B66C3246C5E /* FIRComponent.h */, + B8B222728C3FF9B9FD14A76423A49B1B /* FIRComponent.m */, + 5AED10E896523AA3351EAC775C0DA052 /* FIRComponentContainer.h */, + 0BD69D14E151B50FC47885567CC1F00A /* FIRComponentContainer.m */, + B4F8D21D4F75C7ACFB902F78724ADF00 /* FIRComponentContainerInternal.h */, + 9D2D2CDA157BA843AC5E477C656AC3A5 /* FIRComponentType.h */, + B17EC1FDC566D6EE01633B7220A39230 /* FIRComponentType.m */, + 0063F6261147793EDA01C98F131EE381 /* FIRConfiguration.h */, + ABEFDEDD9204F734E8CF7156DB34EAC2 /* FIRConfiguration.m */, + CFB14EC1E12FD320A96E0F01E8E89EB2 /* FIRConfigurationInternal.h */, + 7B51D95619BDA00B9016FAE302AD53F5 /* FIRCoreDiagnosticsConnector.h */, + 625B9F40AF5A3D6B6AFD638EB4F9A610 /* FIRCoreDiagnosticsConnector.m */, + 4266E39FA9DD1D55C7E5F79F7F3BCEE6 /* FIRCoreDiagnosticsData.h */, + 7E7CDABFB608D65FEE43A17EB8C75B0A /* FIRCoreDiagnosticsInterop.h */, + 4225BD34B5EB613DF261A853B2DE3A60 /* FIRDependency.h */, + 7381E483AC0125ADF1E57858686F50A4 /* FIRDependency.m */, + 462FEA23E29047E8A7CA6843CA61F009 /* FIRDiagnosticsData.h */, + 8090F51A62764AFD707E8DC587EFBD37 /* FIRDiagnosticsData.m */, + DF92A3DC3872C2E019717A99ABFC4BAF /* FirebaseCore.h */, + 7A46A292823A650C8E22CF1315EB369A /* FirebaseCoreInternal.h */, + CED836F5AB275798DF1EF9CEDBAFD697 /* FIRFirebaseUserAgent.h */, + ACE8DCECAAD1F5B7F9D2031B60201FE3 /* FIRFirebaseUserAgent.m */, + FF51B5689329B949790D00975C6F5130 /* FIRHeartbeatInfo.h */, + 75483AC2AE9B94CA4D4431712A9E010F /* FIRHeartbeatInfo.m */, + 771B1D692CD92E2E80BCF92ADE963A96 /* FIRLibrary.h */, + 291B38DFC54C1CE23A2902F96EEB66D7 /* FIRLogger.h */, + A2A67198D2ECE2676C622E472F2E7450 /* FIRLogger.m */, + B23BBEB7E4D6A74D7D47CE8C255EB839 /* FIRLoggerLevel.h */, + C17F19ED839D7947EFCF4E484C64AF60 /* FIROptions.h */, + B53B4F47E785737B058E7A4C89B15D48 /* FIROptions.m */, + 2AF60A6D52FE8EBEB70B6B9CC52A6B3B /* FIROptionsInternal.h */, + 1123E7A9203EDCC45A75D4C556249693 /* FIRVersion.h */, + 7B7B7C27019F0E6D7ED6C457C4FEFCB5 /* FIRVersion.m */, + 3277FFEFE6F2810FBC5C796D93288BFE /* Support Files */, + ); + name = FirebaseCore; + path = FirebaseCore; + sourceTree = ""; + }; + CC84C2689EF477DF70B1D92C754D4032 /* PromisesObjC */ = { + isa = PBXGroup; + children = ( + 0DCE8B190588AF201D9521AFDEC1A12A /* FBLPromise.h */, + 7ABAB0517BE907A3D48AA8FAC13726E3 /* FBLPromise.m */, + BF7B94731C7027BE19E68D31F0CDEBEA /* FBLPromise+All.h */, + 2DEBB1A11CC1186F9865672E1A758722 /* FBLPromise+All.m */, + 856378CC2E53007A66BBB5C102C82AE8 /* FBLPromise+Always.h */, + 872149127BBFF2A884E7375618BF435F /* FBLPromise+Always.m */, + 443546F817B6B0439A3F4A59985CD4B7 /* FBLPromise+Any.h */, + 5607EBC07C127505AD967D102AE1952C /* FBLPromise+Any.m */, + EAF26E5359FBEEEBFA7845231AC4195A /* FBLPromise+Async.h */, + 0C0983B32DB733B5AAA3960177D9F143 /* FBLPromise+Async.m */, + A3B520AC90F216E89C6A144E34C7B728 /* FBLPromise+Await.h */, + 355AACCB7DBED4FAC573C5B11C78B4FD /* FBLPromise+Await.m */, + EDC4641849E572F5723A6A116D0352EB /* FBLPromise+Catch.h */, + E80F127499254D575F9567C7C18C951A /* FBLPromise+Catch.m */, + 62B3358312776954E31DF7EED58885A5 /* FBLPromise+Delay.h */, + BD7E408A6A285E49DF1591FCF1591362 /* FBLPromise+Delay.m */, + 5AC2B509956CCDD9C8BED734854FE77A /* FBLPromise+Do.h */, + 1F64C372A6E12EF616E2930965FB8336 /* FBLPromise+Do.m */, + 1A49AC9D79084068C17D46C29FA998AA /* FBLPromise+Race.h */, + 63546985BB72619AA1BD5BF3034999D8 /* FBLPromise+Race.m */, + E66BECCDBDAFF7F21FD65107CE127127 /* FBLPromise+Recover.h */, + 1BFDCC2F82C100448FE007F05AC497C7 /* FBLPromise+Recover.m */, + A5EE7C10193DBDDADE98DC3A19921624 /* FBLPromise+Reduce.h */, + 7B7777FBCD8B1C6CFD56B64CACAFF882 /* FBLPromise+Reduce.m */, + 4DD222A708C236933A0C9863252657F2 /* FBLPromise+Retry.h */, + B80FA25AA1ED7576FF55175F0718FB6F /* FBLPromise+Retry.m */, + 5E340A1BB7B1090345005734CE131B8D /* FBLPromise+Testing.h */, + FE92A8ADFFB2CD95AFE36381C008D8F2 /* FBLPromise+Testing.m */, + 64CEE3E2D4A19A53504FB2177D8059B5 /* FBLPromise+Then.h */, + D605890E41506261712FA9D98D2E022D /* FBLPromise+Then.m */, + E2DCA620D3D076030DA2B13428F8DEA0 /* FBLPromise+Timeout.h */, + 5FA17DB98BC67108253D4D33E6EA8312 /* FBLPromise+Timeout.m */, + 56793ED84A5687D192F21FFE912AFD81 /* FBLPromise+Validate.h */, + BF8645293BD84FC36ED2B54D4E52D0AF /* FBLPromise+Validate.m */, + A56068F39B274E2B955D1D4B80323F59 /* FBLPromise+Wrap.h */, + E25806EF4D31B0F9738F7B89249DE5D0 /* FBLPromise+Wrap.m */, + 49529F7D99AFC203DC55C22A66EF500E /* FBLPromiseError.h */, + 99F0C019D3C879F3942E5D425FAEB1A4 /* FBLPromiseError.m */, + 76BEE430E44B481CB97A3647B5104EE7 /* FBLPromisePrivate.h */, + C0D982FA616BAFDFC5F2ADA6D865ACEE /* FBLPromises.h */, + 0D233F3E69FFDBC9975EDD6EA68557CC /* Support Files */, + ); + name = PromisesObjC; + path = PromisesObjC; + sourceTree = ""; + }; + CECC7C28B2D4A820EF4894AE4646BA35 /* Support Files */ = { + isa = PBXGroup; + children = ( + DCAAF3DC536CEC5BF8DFB1152DF8240C /* GoogleDataTransport.modulemap */, + 99BD44EA0561B5CE9F0F17331D6086DF /* GoogleDataTransport-dummy.m */, + 4009389C08D129836F4FBC79F341D4AB /* GoogleDataTransport-Info.plist */, + 40F5FBEE90FA0FAA88EBC934B01FF63B /* GoogleDataTransport-umbrella.h */, + 51DADC6EA95F8D9FE2935B2D17FFF724 /* GoogleDataTransport.debug.xcconfig */, + 2F6B0DD02D0223F2F0DD71412C7EB585 /* GoogleDataTransport.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/GoogleDataTransport"; + sourceTree = ""; + }; + CF1408CF629C7361332E53B88F7BD30C = { + isa = PBXGroup; + children = ( + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + 8275CCB4E8732497B1021FCBC240F3C2 /* Frameworks */, + 8750C5998951631700C3C872AE74D408 /* Pods */, + 5059F4FBAA3D48EB0A23E1B5904940EB /* Products */, + 81E31054029CB80671C8BEE97F7B2502 /* Targets Support Files */, + ); + sourceTree = ""; + }; + D13FA67A9BDE54D8B32BD948D3CE76D7 /* Pods-saraWhatsUp */ = { + isa = PBXGroup; + children = ( + 10726F9298E233D645FE70928D347C8E /* Pods-saraWhatsUp.modulemap */, + CD698ABE83B63A4FDBC7C167D924FA4F /* Pods-saraWhatsUp-acknowledgements.markdown */, + E3AA655918C94D7E5B6CD0A5049D1055 /* Pods-saraWhatsUp-acknowledgements.plist */, + 7F94EBAB96F11BB0CEA8C3C329A569C6 /* Pods-saraWhatsUp-dummy.m */, + 9AD42284107F66CA7E461B6E4D3455BF /* Pods-saraWhatsUp-frameworks.sh */, + 5BE7A17DB0DB60B1B5B2023B4EEE3911 /* Pods-saraWhatsUp-Info.plist */, + 3F05777D1035F3FD490D2B67C497F1D7 /* Pods-saraWhatsUp-umbrella.h */, + 6E38458165FD4E6AD15616E1CA142196 /* Pods-saraWhatsUp.debug.xcconfig */, + ECAADF3C6E648C2ED2FE2BE67E6AA1A5 /* Pods-saraWhatsUp.release.xcconfig */, + ); + name = "Pods-saraWhatsUp"; + path = "Target Support Files/Pods-saraWhatsUp"; + sourceTree = ""; + }; + E26FF5A3C9A7E1AF18AD8353434ADFE3 /* Reachability */ = { + isa = PBXGroup; + children = ( + 827DDBDAFAD49886E84E1065A72F70CC /* GULReachabilityChecker.h */, + FC4DA8C6D73E78C03EED1C783C61202E /* GULReachabilityChecker.m */, + FC53DDB0E8B2F43E1E0596009C054FDE /* GULReachabilityChecker+Internal.h */, + 5B6ED693CFD0B6CC4D958CF81650ED80 /* GULReachabilityMessageCode.h */, + ); + name = Reachability; + sourceTree = ""; + }; + E2CBE803AF1F96486B1E563071282D01 /* FirebaseStorage */ = { + isa = PBXGroup; + children = ( + 017EFF960BB5DB0C88DEA74292152B14 /* FIRAppCheckInterop.h */, + 5C8C7273435FEBC73D2074E6266738FF /* FIRAppCheckTokenResultInterop.h */, + DD5351F61E4051917ECC0C45DF0E5F8D /* FIRAppInternal.h */, + 4E18993DAD8C46A4A4E3A64FF7677CC5 /* FIRAuthInterop.h */, + 2D84B1B010E37FBC800DEA3F33B0C3B9 /* FIRComponent.h */, + 22C249A29BE5C894E90F84F5C51D9ACE /* FIRComponentContainer.h */, + CFA9A98B0E39FA0EEA43D511B134FC95 /* FIRComponentType.h */, + B3F239DE45C16ECA602453788681BAAE /* FIRCoreDiagnosticsConnector.h */, + FEB354FDBF724286A5645BC99EB99BAB /* FIRDependency.h */, + 1E907A35C1DEDA93701504221E550A28 /* FirebaseCoreInternal.h */, + 0D3EF6641CC688F9E7B716DA42049B1C /* FirebaseStorage.h */, + 4E6A08E5885D93950E50FCD40CF9F022 /* FIRHeartbeatInfo.h */, + CB962D67899B3AA299F65B98309061FB /* FIRLibrary.h */, + 33AC8DDC34080E0C8F6B67968DBCD4E2 /* FIRLogger.h */, + 693831C5F92916966D1C6D6E899EB871 /* FIROptionsInternal.h */, + 032DF10AB85867F30E7D46A814B88652 /* FIRStorage.h */, + 765D98B1AC54CE64FBC591B6AFCC533E /* FIRStorage.m */, + 83A802E95D84E016849CCD84A2FA5A5E /* FIRStorage_Private.h */, + 75EAD854551E311C33A9678D3417E4B3 /* FIRStorageComponent.h */, + 711156AE176D1D7C9932201F14669A1D /* FIRStorageComponent.m */, + DAE9BAEEBABE76B47CF2BD6325FC5602 /* FIRStorageConstants.h */, + 2D6DD1667F0E2BB21268B5CC194CA594 /* FIRStorageConstants.m */, + 2CE46C58D06DFEBA5227D7A202DEE514 /* FIRStorageConstants_Private.h */, + E9A820561E869395EB1638CC40A12C05 /* FIRStorageDeleteTask.h */, + C7FAFE3089E9D23C2B1DBED2289F4CBC /* FIRStorageDeleteTask.m */, + C86A046017B5D5FA14470F7B2E9392BC /* FIRStorageDownloadTask.h */, + AC9918E2FAE139C78CDF7F9F674FFA1F /* FIRStorageDownloadTask.m */, + 253F33B4DBFD01CAA5A4802942933E2A /* FIRStorageDownloadTask_Private.h */, + 69A1FF88AB4CE2399AC22479042C14C0 /* FIRStorageErrors.h */, + 5D28BF6F99FC527C5CAF3B8CE13E578A /* FIRStorageErrors.m */, + 21E7374CA2BAFFE4EC6CCE7724CF719C /* FIRStorageGetDownloadURLTask.h */, + 9F00695EF92C4DF50D63567271334E34 /* FIRStorageGetDownloadURLTask.m */, + 75CC991F7C85A64C9B896F9778873BE2 /* FIRStorageGetDownloadURLTask_Private.h */, + BC69DBAD903AA8D81D0899406634F740 /* FIRStorageGetMetadataTask.h */, + 5F3CD1B9DAD528B29819D6C23F49BDD7 /* FIRStorageGetMetadataTask.m */, + ABF88EF97C5E5AAC2CA3410AF223A810 /* FIRStorageListResult.h */, + 408EE725ADF5418AEB303B645FEFECE1 /* FIRStorageListResult.m */, + DF7510634B456A9A5EB9BB8C7D93BEE9 /* FIRStorageListResult_Private.h */, + E9ABCEAE642F047E5F947C694A613C72 /* FIRStorageListTask.h */, + F6C91B026962F7836CFEC9875EB678D7 /* FIRStorageListTask.m */, + D6CC30E2B10C146529670C215CCFE97F /* FIRStorageLogger.h */, + F1389AE7281393EE724613BC5D251B38 /* FIRStorageLogger.m */, + 60A8C73A7FD90C1255E0B6EFF7A2E47C /* FIRStorageMetadata.h */, + E8DB7C81B442901E0C90FBD3C7639CE1 /* FIRStorageMetadata.m */, + 563A9C1C12ED779F8A95FBF46C9A61B9 /* FIRStorageMetadata_Private.h */, + FAA49E2FDC1193C1C227B4B4A414812E /* FIRStorageObservableTask.h */, + 1BB3746D9D29A0B4A79E4F46A7FB50BF /* FIRStorageObservableTask.m */, + 3A79C412D90BBA0C242A6222476E3C0F /* FIRStorageObservableTask_Private.h */, + B9E907CA9588C9B9F242488583AC812D /* FIRStoragePath.h */, + 694A67A5D2B3C84DB25148DB4DCB6DA1 /* FIRStoragePath.m */, + C4E35116F3D5249AB4E261D67CDF74A6 /* FIRStorageReference.h */, + D0925C8787A05CA82DB6EEA81561F989 /* FIRStorageReference.m */, + 17CA14733B2F2512D271981AC3222251 /* FIRStorageReference_Private.h */, + 1D5503EED647D08F5A54F1B20F33761C /* FIRStorageTask.h */, + 77994AF3EB2E00C13B79A21F6BCF9CBE /* FIRStorageTask.m */, + 0F7FE598826DA18D6CAB2AE10119075A /* FIRStorageTask_Private.h */, + 1A824F119286E0C31278A847591BB786 /* FIRStorageTaskSnapshot.h */, + DF15EFABC8CF646F9AB391F67075A420 /* FIRStorageTaskSnapshot.m */, + 340A99536CB0153ECB0A771942C373CE /* FIRStorageTaskSnapshot_Private.h */, + 2EAFE0E8FC6D0A618CC1951440D5D862 /* FIRStorageTokenAuthorizer.h */, + C228A639A3A804038FCAFE0D56A11E97 /* FIRStorageTokenAuthorizer.m */, + 568CCC590C28D73A8937CC57C00DC09E /* FIRStorageUpdateMetadataTask.h */, + 8AE9920117FF484590C20A61903F5796 /* FIRStorageUpdateMetadataTask.m */, + 4FB87C0E75DE3B5B7C9A8E0BAB0197F3 /* FIRStorageUploadTask.h */, + 4933D04D038FAE70992539991986C709 /* FIRStorageUploadTask.m */, + 184FB4DAC7ECA7641F9F273B2C2EE276 /* FIRStorageUploadTask_Private.h */, + 6C1CC4F20E09860CA4DC1D7D915C1D73 /* FIRStorageUtils.h */, + 2BA2D1D9C6E20FA4187ECDEB666F5808 /* FIRStorageUtils.m */, + 0FDD19D2F75DA10608578CFC8FE02768 /* Support Files */, + ); + name = FirebaseStorage; + path = FirebaseStorage; + sourceTree = ""; + }; + EC2DCA7BBB098771525BC5CBBDCFFDB8 /* decode */ = { + isa = PBXGroup; + children = ( + ); + name = decode; + sourceTree = ""; + }; + EEC4F9310C80C73A412007AAA4CABCEF /* encode */ = { + isa = PBXGroup; + children = ( + ); + name = encode; + sourceTree = ""; + }; + F65A8D72B764DE727CE70947889FBD3D /* Support Files */ = { + isa = PBXGroup; + children = ( + 65C8D8B0C48090B294FF04FE3E6DC375 /* FirebaseAuth.modulemap */, + 3FF417F53059E610CCEF3ABB2470DDD8 /* FirebaseAuth-dummy.m */, + 88C693850F5DD1C8C6CF617B4A4686A4 /* FirebaseAuth-Info.plist */, + 60AAFFD70875A35BF0E1C81AD8D50ACD /* FirebaseAuth-umbrella.h */, + 77E9E4BDDA17F583BD30ED9F9BD9E915 /* FirebaseAuth.debug.xcconfig */, + C9FFBCDFEBF380E250E116854F608812 /* FirebaseAuth.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseAuth"; + sourceTree = ""; + }; + FAF73B1DFA1FE0C751B293B195D2A562 /* Support Files */ = { + isa = PBXGroup; + children = ( + 65DD11E9D029D8A94119F4C9657DD571 /* GoogleUtilities.modulemap */, + 92C8D3FC28E367731EFA7DA60B5B2769 /* GoogleUtilities-dummy.m */, + 8F6D8A5072C17C800028473C1B8DF4C8 /* GoogleUtilities-Info.plist */, + 4DAE27593E4EA4BA28B1EFE6B4235D25 /* GoogleUtilities-umbrella.h */, + C661AC8E9FEAADAC1C40F825A2137419 /* GoogleUtilities.debug.xcconfig */, + B9DF6D4C0C68854AF972C290CF88B7A0 /* GoogleUtilities.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/GoogleUtilities"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 0BB6D10539AC49B11373729E65F37C36 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 2D3BF3C7FB1A02253E78885F5674579D /* Pods-saraWhatsUp-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1488159A9B9D000DDA80B32C5E6E21F9 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3B7C49B121C9879013EB6BED44F3B1A3 /* FBLPromise.h in Headers */, + 583954BFD701D58D6A1B93FE23089483 /* FBLPromise+All.h in Headers */, + 0F42E644A4435879EE2BFFA259E74272 /* FBLPromise+Always.h in Headers */, + 15CE9AD5A2BDF7359CC549311CCBBB86 /* FBLPromise+Any.h in Headers */, + A61F472DE3BEB12D7C83FB9C4D6B72BB /* FBLPromise+Async.h in Headers */, + DD52C95627433F57E34DEDE919094B61 /* FBLPromise+Await.h in Headers */, + CF3B4720A3C872F0AF839839BA3F82E8 /* FBLPromise+Catch.h in Headers */, + 11D0C54A62BA81A431F433D9AB4917AE /* FBLPromise+Delay.h in Headers */, + B3F50D04804292AD05F78547D620A900 /* FBLPromise+Do.h in Headers */, + 687C49AC74D75C7064C4BCD1FEF165A2 /* FBLPromise+Race.h in Headers */, + AD59610EE5CA729018A039AAEB6EED27 /* FBLPromise+Recover.h in Headers */, + 1A2BEC4B5875E4BE2425808D1D2EE0A2 /* FBLPromise+Reduce.h in Headers */, + 508A180F40CFD02AE17D220BDFDCD08D /* FBLPromise+Retry.h in Headers */, + BF1740ADD46742AD919219C6F7871B64 /* FBLPromise+Testing.h in Headers */, + A982B39A61FF5A33A02F3D6242ED68F2 /* FBLPromise+Then.h in Headers */, + B885B226B693B0E4EE91BE442B1F1F64 /* FBLPromise+Timeout.h in Headers */, + FF58BBB0D998FE73A97B7B3499824ABA /* FBLPromise+Validate.h in Headers */, + 9A3DF0E0712125EF260817821D6F3906 /* FBLPromise+Wrap.h in Headers */, + 20DE19C0C85296A461424DF0000A9012 /* FBLPromiseError.h in Headers */, + 1E37AAD1C8D636541BAC26BDF5FDF902 /* FBLPromisePrivate.h in Headers */, + 2B988C83446ACDC57A51250BC631168A /* FBLPromises.h in Headers */, + AA9029987BA6BD3CFC6BD3F6370E26CA /* PromisesObjC-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1D12DBB47BAA9DE2D8ECA7E37DC15272 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 9CBAC2F3BA42653FD0A59B84C661FE42 /* APLevelDB.h in Headers */, + 459FFE1AC91BBE48BA56F12747343557 /* FAckUserWrite.h in Headers */, + FB6DEA4AEA597F3BC2F9294C593B2CA2 /* FArraySortedDictionary.h in Headers */, + 3E9658324B66B119A40D7851B6F1BB3A /* FAtomicNumber.h in Headers */, + 0802D6A8E0B4C610EBAF894E8CE2ABA1 /* fbase64.h in Headers */, + 1F84E91268E0BC381F6CA02F637C37A9 /* FCacheNode.h in Headers */, + AC2CB1EA26FFDEB7A9F152416D7E3466 /* FCachePolicy.h in Headers */, + D5FFA49A70CE9337ECB5F4CE91D59065 /* FCancelEvent.h in Headers */, + 380DC670ED5FB081A38FF031692D9BCF /* FChange.h in Headers */, + 4ADAC66A365D665F495CD73CD98D3C36 /* FChildChangeAccumulator.h in Headers */, + BF071C51C6DDC89D5C83A4CBBFF6E7BA /* FChildEventRegistration.h in Headers */, + EF8B926D831C87D3592A1EEAD326E946 /* FChildrenNode.h in Headers */, + AEEF9EA0FF80C36AA368A47603D40E41 /* FClock.h in Headers */, + 24C99BF35233726D8353F4F01C5C6785 /* FCompleteChildSource.h in Headers */, + 4EB0800AA06AAD774619AF4B6E6F3393 /* FCompoundHash.h in Headers */, + 012125DA48E713D2C1699D28A8A6CC80 /* FCompoundWrite.h in Headers */, + DCD352BF594C668193B293354AA4B5AC /* FConnection.h in Headers */, + 76598E46A0503077124CDABA6A6ADEA6 /* FConstants.h in Headers */, + 919D6CD31FF106A4CF8B8F4DF20AC772 /* FDataEvent.h in Headers */, + 31FCC6057730A3324E31FE25673F5258 /* FEmptyNode.h in Headers */, + 20892A665BEC3104E996528D3F00EA4D /* FEvent.h in Headers */, + 28B0C95AE52879CB167AC1435ABED7CE /* FEventEmitter.h in Headers */, + 1AA55A0C66508AB5BDFE721BF39B7CC6 /* FEventGenerator.h in Headers */, + F947986DEE834871DDAFA1BC57DBFB6A /* FEventRaiser.h in Headers */, + 1B601DC0C23710DA8BF2CB6483E582C2 /* FEventRegistration.h in Headers */, + 36672556635EB9CE0D1161CAE8DC1BE0 /* FImmutableSortedDictionary.h in Headers */, + 6951325278388C26E3AC2560642800E8 /* FImmutableSortedSet.h in Headers */, + 39B928D2B64C00E7E11A020C6F1DAAFD /* FImmutableTree.h in Headers */, + 67AC814AB27FF6C1E884EE473F9D47F1 /* FIndex.h in Headers */, + 94DD516831437C2320440D0EC212CC7E /* FIndexedFilter.h in Headers */, + 0B73B7A94F807C465D7CE32E1208D5B5 /* FIndexedNode.h in Headers */, + FC768D07C0AA62AF339CF13F0ACEA358 /* FIRAppCheckInterop.h in Headers */, + 71061B2E67F8751EF2EEF89DB2DF51D9 /* FIRAppCheckTokenResultInterop.h in Headers */, + FFF620F49ED2780182A3F1B1DBB28B1C /* FIRAppInternal.h in Headers */, + 39D906658BA6F799F716F3E6FD18F15A /* FIRAuthInterop.h in Headers */, + 09DD61B576FEC57FB31A52B8B0E11E37 /* FIRComponent.h in Headers */, + 49F4E17FC3D3F69C33BBBB101A94D69A /* FIRComponentContainer.h in Headers */, + 8CA7CC4B775AE20BF05D8FF2FD4D9C50 /* FIRComponentType.h in Headers */, + 4CF229992D5C19643BEC8E2B10DB0F3F /* FIRCoreDiagnosticsConnector.h in Headers */, + B4EBF2714763916DA75F6EBDFE90B519 /* FIRDatabase.h in Headers */, + 9A3768AF9A2672E527D21C02951F429F /* FIRDatabase_Private.h in Headers */, + F85431750FFA77723656EEE949F74503 /* FIRDatabaseComponent.h in Headers */, + 528453DA9A9FA271085D4FC82DD3F870 /* FIRDatabaseConfig.h in Headers */, + 4CBFCFFCE73FE33BF2793C9FFBE698A4 /* FIRDatabaseConfig_Private.h in Headers */, + 16579A7E550864A3D752BFC07ED5F0AB /* FIRDatabaseConnectionContextProvider.h in Headers */, + E6120B2B605040F43A888737A69188BE /* FIRDatabaseQuery.h in Headers */, + 69F4290E7823430720A47749DC834A66 /* FIRDatabaseQuery_Private.h in Headers */, + 954381EDA4655CC7F6DB05DCECFE2304 /* FIRDatabaseReference.h in Headers */, + 9A6E94B1D1A2358210F733A8E496F8A0 /* FIRDatabaseReference_Private.h in Headers */, + 962BA17595BF9C8593F20FA476C14B63 /* FIRDataEventType.h in Headers */, + 1760A120E6269179BDE56F874468EB0B /* FIRDataSnapshot.h in Headers */, + 33162FD30D3F82CBC9D92371B09B0ACA /* FIRDataSnapshot_Private.h in Headers */, + AB487380FD00FCDAA86BC950F7AABF4A /* FIRDependency.h in Headers */, + 114563114C0901A942488FAD4CAD7B00 /* FirebaseCoreInternal.h in Headers */, + 1B5335738488AC6BD3971955DA2F6568 /* FirebaseDatabase.h in Headers */, + 7B2F9EEA7062C0B40A50D13A0BF27BA6 /* FirebaseDatabase-umbrella.h in Headers */, + F34F0C3F59D1284F845DC2CD2D140E41 /* FIRHeartbeatInfo.h in Headers */, + 0922964D8333D1C15A7ECEA7C6DEDADF /* FIRLibrary.h in Headers */, + F88537120E41C136B1EE60FE5D54CA78 /* FIRLogger.h in Headers */, + 5AFA49633DF5CD52228123D0A40FEF61 /* FIRMutableData.h in Headers */, + FA30A98124EF6F3559022A7FE0B4B5F1 /* FIRMutableData_Private.h in Headers */, + 494D189EC4E6A6A063946C0D4AE7F1B0 /* FIROptionsInternal.h in Headers */, + 8D57BA44161FEE21D99506D077456B7F /* FIRRetryHelper.h in Headers */, + 58E33604E98B48869C2342DD27515367 /* FIRServerValue.h in Headers */, + F642A4B2D3D8562AF1D5A27419B79011 /* FIRTransactionResult.h in Headers */, + 502A1FD7AF817552FE2D5C8353DBF016 /* FIRTransactionResult_Private.h in Headers */, + 7ADFF49C61F88C284EBC3F8F3BFC7E70 /* FKeepSyncedEventRegistration.h in Headers */, + ADB42C6F214D308DEC02B4314C456BCE /* FKeyIndex.h in Headers */, + BCBDBBE502C6F0BB4E0460BBA12FAF36 /* FLeafNode.h in Headers */, + EE524090F6836405CDED5B68AE70CD18 /* FLevelDBStorageEngine.h in Headers */, + 555C4E07D98A783FB5980901900350FC /* FLimitedFilter.h in Headers */, + 573B7B99F444E3A73999FC84FC79440D /* FListenComplete.h in Headers */, + C525285F2BAFE7FF68FA51BECC0B234A /* FListenProvider.h in Headers */, + C102B48CF761B1706D9566805FD656B2 /* FLLRBEmptyNode.h in Headers */, + 2BA5FA4D6D55E436E5B0C3455DD44316 /* FLLRBNode.h in Headers */, + 9C2C06E8ABD475C6118E5E86CC54B713 /* FLLRBValueNode.h in Headers */, + BC62E8C20DB20E06D369EBE8CB5EABD3 /* FMaxNode.h in Headers */, + CD79651074CA9C1C344D7FD6B744D183 /* FMerge.h in Headers */, + 33EA40A4CEA003C0F73E7BD267135FD4 /* FNamedNode.h in Headers */, + 82FB76596854911C8990D63666D960AE /* FNextPushId.h in Headers */, + 2ED628469B135D0219D5AF2C53461CD4 /* FNode.h in Headers */, + B66E7B15E38E793C6549E94508D919BB /* FNodeFilter.h in Headers */, + 81E4C37AC1B89BC2F316636CD0D4481C /* FOperation.h in Headers */, + 444108C4CCFCEC6AA785F6380E31FB80 /* FOperationSource.h in Headers */, + E18DFABCF8FCF7E7903EDB94CDE350FB /* FOverwrite.h in Headers */, + 8A71B72D50C8320631C8BF80018502DD /* FParsedUrl.h in Headers */, + ACEAFD5A113B324C7495335ADD47E09E /* FPath.h in Headers */, + FF8F64995C8D9DE5A6436742B340C075 /* FPathIndex.h in Headers */, + 4B2DFE5E5C7FFC7A7B9BA57C82DC0171 /* FPendingPut.h in Headers */, + 40AF4F48135996792818E09341F587F2 /* FPersistenceManager.h in Headers */, + EE7F44F0BB5BE6ABFDC653436231FE6E /* FPersistentConnection.h in Headers */, + DDCE00601F5E710E85D7A6C9CF863D06 /* FPriorityIndex.h in Headers */, + 5608A77DEA4AD864171308E65D3DE826 /* FPruneForest.h in Headers */, + 29F33F50160C2150EFDA1E88B186861F /* FQueryParams.h in Headers */, + F49754B4A9604F7B6232D876B7A13EDF /* FQuerySpec.h in Headers */, + 83CA89EB2806F46C872FF1551D0ED171 /* FRangedFilter.h in Headers */, + 547C7A4FBAF369AA9F54C479836FDE25 /* FRangeMerge.h in Headers */, + AA7396B6A63C43B7178BB91B97C65F05 /* FRepo.h in Headers */, + 4160033A7F659B11F088A28FF13EBD23 /* FRepo_Private.h in Headers */, + 580464CFB9172044A7B5FECE112921F4 /* FRepoInfo.h in Headers */, + 1D7C4CA4082EC479BF83F8C3C2C61ADD /* FRepoManager.h in Headers */, + 7AB306C95D7D95B57430E1D8097D448C /* FServerValues.h in Headers */, + 1A5D812605F3B4FCE14860AC51EA5B68 /* FSnapshotHolder.h in Headers */, + 3618F3039E3260EC1C7FA0D3695B4364 /* FSnapshotUtilities.h in Headers */, + 9F7F90E44AFE3A5D85810CE12C55C7CA /* FSparseSnapshotTree.h in Headers */, + 5D479C5ACA7CD9A038502936898ADAD5 /* FSRWebSocket.h in Headers */, + E9F86F2E14D4C9C645FBCB3ECCB64C57 /* FStorageEngine.h in Headers */, + B622904A4E718D7597D72C8BEC372E82 /* FStringUtilities.h in Headers */, + 7D6065C88C5BDF90AB8F00CD1BF6C276 /* FSyncPoint.h in Headers */, + 5EDD5B50DD1356EF677C687409FE0853 /* FSyncTree.h in Headers */, + 50A19B7DD718B38490B672612AFF3372 /* FTrackedQuery.h in Headers */, + 22F5C879CD61751CA8CABE6CB582E361 /* FTrackedQueryManager.h in Headers */, + D988B762510FBF565BE6F6196DCA7908 /* FTransformedEnumerator.h in Headers */, + BCC14122E551CCC35044E9556D8EFEA7 /* FTree.h in Headers */, + 5529BE079D4B59388ED9AC5471DC5D96 /* FTreeNode.h in Headers */, + 2362318B122BBE59D1948C20815B9D8E /* FTreeSortedDictionary.h in Headers */, + 9867E35C8A464F28432A045E347E6E1F /* FTreeSortedDictionaryEnumerator.h in Headers */, + 6E48076C21BE60B79C6CD1FD27A7D7CC /* FTupleBoolBlock.h in Headers */, + A9F12F228547516954D393968C536101 /* FTupleCallbackStatus.h in Headers */, + 61DB8504F985F28E725F9C3AD6ADB4CA /* FTupleFirebase.h in Headers */, + 107E1A5608CABF3C09F93816F8DFDA44 /* FTupleNodePath.h in Headers */, + 20ACFAA65648768E8A14490D7956B105 /* FTupleObjectNode.h in Headers */, + 84E620F824D728AEB6D3786457B951E5 /* FTupleObjects.h in Headers */, + 716E198B020891EEF1D43C2C48C1E4F5 /* FTupleOnDisconnect.h in Headers */, + A4231C94CE4FF52E27891A416233DFE1 /* FTuplePathValue.h in Headers */, + FA5D554F9F4670EAD6E7828911A5C15E /* FTupleRemovedQueriesEvents.h in Headers */, + 9017C1C93750182F2A32736B460C699A /* FTupleSetIdPath.h in Headers */, + 5821A1ED0B68A385E3C1E907E69D4BB0 /* FTupleStringNode.h in Headers */, + 7E5CE79823249FC02E6F9F0BCD720E30 /* FTupleTransaction.h in Headers */, + 0AE96C77ACA19C7D020DF69A79C1293A /* FTupleTSN.h in Headers */, + 553439CF8D1DA0324EEFB78B3DCD2D3F /* FTupleUserCallback.h in Headers */, + 8B4A58C4EFA72BCD77996DBC7BEB8982 /* FTypedefs.h in Headers */, + E055EA1332DC10E277EA2CA3F5F05D2E /* FTypedefs_Private.h in Headers */, + 0A4CD8859C6A1F2ADA7A566661F41AEB /* FUtilities.h in Headers */, + 77590AB689347900DF0F519AF3B0F2F6 /* FValidation.h in Headers */, + 361D8F8960D2F7B33B83FE77BF44FE75 /* FValueEventRegistration.h in Headers */, + 08115A4E09DBD7C3D86DBCED9933A036 /* FValueIndex.h in Headers */, + 41F0F520F05EDA9798A6D7ED82DB697D /* FView.h in Headers */, + A7DF2F55597EEE231E653DA5134B45A1 /* FViewCache.h in Headers */, + B7DC9F344D21854AAB027B5AAE167C69 /* FViewProcessor.h in Headers */, + CD088DBB485A8B3A5596B476CDF32EB3 /* FViewProcessorResult.h in Headers */, + ED48733738C7B0E42B7BEF11BDA94641 /* FWebSocketConnection.h in Headers */, + 190E2C2A181DA99098B238220E368C59 /* FWriteRecord.h in Headers */, + E374EC108F866C2E59DFDC69AC76D352 /* FWriteTree.h in Headers */, + 4F27AA54C609AD6FABA4A5FC12BBBC25 /* FWriteTreeRef.h in Headers */, + 82A04219A742044F706375B21F507E28 /* NSData+SRB64Additions.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 20672DD68847F185DC042E313A859B52 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + BB9FF975D160432407D7AB68F140FE9B /* FIRAnalyticsConfiguration.h in Headers */, + 9479CCD356F14DE6D7FC3D887F0754BB /* FIRApp.h in Headers */, + 742AB4CF041E58979F850575F0E1C633 /* FIRAppAssociationRegistration.h in Headers */, + CA72344D2EDA5DB6077582CC8BC03782 /* FIRAppInternal.h in Headers */, + 166A023F8E2E7D06058547066461DE60 /* FIRBundleUtil.h in Headers */, + 76F3760E8A249FBEE27DF68F81073F39 /* FIRComponent.h in Headers */, + 29C91BC3C328FD3DEDF61995A58D0194 /* FIRComponentContainer.h in Headers */, + 66B6AE4725AC401C60EF58C089F8A881 /* FIRComponentContainerInternal.h in Headers */, + 699224F417B88B9E5ED92E5DE4EE3A2D /* FIRComponentType.h in Headers */, + 44427C44D0B0466B7059B032C914F33E /* FIRConfiguration.h in Headers */, + 082FE8AC51D5B3FFC3E5905BF007A8FF /* FIRConfigurationInternal.h in Headers */, + 846CCCD44A615EB057E9117834B3D044 /* FIRCoreDiagnosticsConnector.h in Headers */, + D5C16683C91904C6C571736F1E4DBCC5 /* FIRCoreDiagnosticsData.h in Headers */, + 2D03E5F83ED6B8D5C86FD2D21A1C16D1 /* FIRCoreDiagnosticsInterop.h in Headers */, + 4F77FB5B9F98A2AC10EAB9C0D47CF062 /* FIRDependency.h in Headers */, + 55A4789FB986581A2FEA0BFBF275A352 /* FIRDiagnosticsData.h in Headers */, + FEFE957B39AA88C9760C2B8ECC8F3780 /* FirebaseCore.h in Headers */, + FDBFA8572C4EA56E9A77D2680DE48E11 /* FirebaseCore-umbrella.h in Headers */, + 2B00B63E31CE509578C64831FA9ECC06 /* FirebaseCoreInternal.h in Headers */, + FD29C1D724C822E2D8DACC9619355C09 /* FIRFirebaseUserAgent.h in Headers */, + 08E84CEF4C496BA696F88CE29419B3E0 /* FIRHeartbeatInfo.h in Headers */, + 73ADD3668F2482196FC451065E2B46F7 /* FIRLibrary.h in Headers */, + 5501A1D079AA938AB2D3B1120B519F0D /* FIRLogger.h in Headers */, + ABBAF1AF392C10314861702CFDE0C755 /* FIRLoggerLevel.h in Headers */, + 6440AAEB698149F1076ABD1C2EB7728C /* FIROptions.h in Headers */, + 08675D31F229AD82CB72555D60B690F5 /* FIROptionsInternal.h in Headers */, + 67CD5BEC3720F441D6EB28B07A42C7B4 /* FIRVersion.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 47A85167F39588C93A68FFC26CC0223F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 7D77834592C464F004194603DE79FFED /* nanopb-umbrella.h in Headers */, + 54E53FF8B3F78D30C731D56DC7FD86B9 /* pb.h in Headers */, + 5D5898632CD8963E3FA4682EE2702BBA /* pb_common.h in Headers */, + 561DDF8E056C94C867FEA95C1C5FD196 /* pb_decode.h in Headers */, + 89C77D7AE3380CE0141805EC830108BB /* pb_encode.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5C4015169A8F37E18D58EC812445DF6F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8960245F1AC80306C58DD9D2ECC80EDD /* cct.nanopb.h in Headers */, + BA7A212B29E1823D0C8197CC961A21F8 /* GDTCCTCompressionHelper.h in Headers */, + C418761AEB68F5EC72E5DDDF109470CB /* GDTCCTNanopbHelpers.h in Headers */, + DAACE24070F232857EB6CD2969FD2485 /* GDTCCTUploader.h in Headers */, + 60DAF5108D66A54C3CB0A05E7C3E0D61 /* GDTCCTUploadOperation.h in Headers */, + 45C12B64C2E4BB5400AF0F137DB6D127 /* GDTCORAssert.h in Headers */, + BEA2F4D80157029982D56B9393BF8473 /* GDTCORClock.h in Headers */, + D4BC3EA08275D757E3BDCF11318112E8 /* GDTCORConsoleLogger.h in Headers */, + A4618E1F90D7B02D624DCEAF3F627C7A /* GDTCORDirectorySizeTracker.h in Headers */, + 437548A50764EA3E328987360A34E839 /* GDTCOREndpoints.h in Headers */, + 3DB07976E0E7822B1F0E0F64847F30A9 /* GDTCOREndpoints_Private.h in Headers */, + 0F43D4A86955BDEDD38662D2D48A5F2B /* GDTCOREvent.h in Headers */, + 64458AFBFBE0268F3136FD2249AEE654 /* GDTCOREvent+GDTCCTSupport.h in Headers */, + D61C497480BD1BC00C0AAB970049A9F4 /* GDTCOREvent_Private.h in Headers */, + 30F7C9B2C72A1411739797FF218E86E6 /* GDTCOREventDataObject.h in Headers */, + 84D9680CC81C18ADEDBBAFF0FFD5A373 /* GDTCOREventTransformer.h in Headers */, + 4C3A2D99DF80874FAF4E3A656D44851D /* GDTCORFlatFileStorage.h in Headers */, + 7A752A831BAEC391DA358C31B9B5AB45 /* GDTCORFlatFileStorage+Promises.h in Headers */, + F745EE6A5ADA4EFDBB3B8E6C59D80C3E /* GDTCORLifecycle.h in Headers */, + 6C3C85FACFD8BA5961C50A7D613C375C /* GDTCORPlatform.h in Headers */, + 477FF7E782971D6C63093C2C8AF03367 /* GDTCORReachability.h in Headers */, + 62DE02710C62D6496823D1B88364634A /* GDTCORReachability_Private.h in Headers */, + 683D61CDFA54C10A91D7128E05A707F0 /* GDTCORRegistrar.h in Headers */, + 48A8A0B879F894F4F893891CA84BCCAF /* GDTCORRegistrar_Private.h in Headers */, + 3480AED45250B4E730F013DA855C2EA0 /* GDTCORStorageEventSelector.h in Headers */, + 9224B111DC38D2B9FCB47095C27DEE63 /* GDTCORStorageProtocol.h in Headers */, + BFB28739975EBEE8A1746207CCF23A05 /* GDTCORTargets.h in Headers */, + 5A89BBC727393C7C9A2930885172A577 /* GDTCORTransformer.h in Headers */, + 9194640A5BA4E355C067A4E4AE1F6AE3 /* GDTCORTransformer_Private.h in Headers */, + 04F09B4EF37F6D607E7728C0DEC587B0 /* GDTCORTransport.h in Headers */, + B2E756461CC6A5BD2B8606CC644B265B /* GDTCORTransport_Private.h in Headers */, + 2325EA10FFE47768B016BC8C50E0D155 /* GDTCORUploadBatch.h in Headers */, + 831E11B569812416126CC430EB44832F /* GDTCORUploadCoordinator.h in Headers */, + 56EC819E759B8E5CD45AC0897CD0817F /* GDTCORUploader.h in Headers */, + 0CFDC69D49F64438AFA9E3E6759E5278 /* GoogleDataTransport.h in Headers */, + FEC68219ED7543FB9D5E99CC7ACBBA85 /* GoogleDataTransport-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 898615E79129CFA6E4B59743FF377D38 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 910D87141418C7D0A20563D926EE51EA /* GTMSessionFetcher.h in Headers */, + 31FF175ECC67FEA8FFE92EF5DE720495 /* GTMSessionFetcher-umbrella.h in Headers */, + 4D187759F8D1ADDF7083B4B6AA242641 /* GTMSessionFetcherLogging.h in Headers */, + DE1288E9B67BADB1CEA4C4AEC4E971EC /* GTMSessionFetcherService.h in Headers */, + 0EFFA97BE71ACD272028C81539AEFDB3 /* GTMSessionUploadFetcher.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AE76A4CB7D2A1031F0F281AE045EE3A2 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D1ED8FFED3E8D3E7808F85AC5AB07397 /* arena.h in Headers */, + 0FB6B58DB914156D801A025D499934C2 /* block.h in Headers */, + 9830E352C83DB50348E3D0D881A325C3 /* block_builder.h in Headers */, + F833AB8826B1B846DC77605FBC603A1D /* builder.h in Headers */, + 724F47B500A1B5067FF0C83F91800FB6 /* c.h in Headers */, + 4C782F3642F126D0A2A58466B9F08F4D /* cache.h in Headers */, + 60481150898E4F0010B3E2D167AA4A62 /* coding.h in Headers */, + 2A1AD3F7D09D799885439138BE268C7F /* comparator.h in Headers */, + AFB8C112E07196E7F75B5DF77A71F0C0 /* crc32c.h in Headers */, + 6F53C577E5D2BB146AFD3363832D2BEF /* db.h in Headers */, + FDFE6C98DB63331DE9AF23C835A8950E /* db_impl.h in Headers */, + 7622B5ED0A4FB6DCD78A15CAC63027F6 /* db_iter.h in Headers */, + D2AC8A997825E8AE897EED8EF1EA1164 /* dbformat.h in Headers */, + A900D4217CF53FDA3F8F3D553B25F2A9 /* dumpfile.h in Headers */, + 14F22A663551AB534BFEBD41D8556A1A /* env.h in Headers */, + CA826459C93EC48AE5582E8BFD65109D /* env_posix_test_helper.h in Headers */, + 8BDDC7BAFF8F9398888B59D7CC24CEEC /* env_windows_test_helper.h in Headers */, + 7BE9BFF47CD87967D9BFB28966CC9F26 /* export.h in Headers */, + CC2CFD1D05BC58D5D8FB0A3681ADFFD4 /* filename.h in Headers */, + 6D4F24F8F42A4EF2DC3725A798398213 /* filter_block.h in Headers */, + 71F58DD428B816B771DDC1E0AB9C5E89 /* filter_policy.h in Headers */, + 47E7B25D201A7C6C56A87415B725A5D2 /* format.h in Headers */, + CB415C77247CFD4E364CD24C16958F0D /* hash.h in Headers */, + C6E58F6D8D0E4AEE8D9F085A1A50178F /* histogram.h in Headers */, + 7FA7C0F81141C2CB9A7B998AF7D9E9C8 /* iterator.h in Headers */, + CDAC97BF51759B8CE575D84AF040B480 /* iterator_wrapper.h in Headers */, + 95E4525FEDACD00BF456ED9CD7576AE7 /* leveldb-library-umbrella.h in Headers */, + 2A7228197434FA6CA7FFE183C763F8D2 /* log_format.h in Headers */, + 4DCB33A7DB6E96D4866ED2B2646B91CD /* log_reader.h in Headers */, + 26968B09D99EE5492D2CECDE9EFD0B06 /* log_writer.h in Headers */, + 15E63ED85B9CDE39662B77B16B34EB8A /* logging.h in Headers */, + 9DAC647A3322128CCE17A1791F69A994 /* memtable.h in Headers */, + 8DA1AE4EACC98378C44DBC65DFB282B1 /* merger.h in Headers */, + FA4F8353D59E5A188F487D06AF00DA77 /* mutexlock.h in Headers */, + 706232F8C368B5471D7101E2848CF38B /* no_destructor.h in Headers */, + B46BBAAE5DA7EF5E935FECCCD06C75E2 /* options.h in Headers */, + 6C9859DECFAC995CDA6D055CC454EB1A /* port.h in Headers */, + 6C1E37DF84299791836DF45885744CBA /* port_example.h in Headers */, + CAD1D04F06D5BF83530988BD89042E11 /* port_stdcxx.h in Headers */, + 37839D72126B75880996A624A52EA48A /* posix_logger.h in Headers */, + D0933029DF3B4C4D162A112AFE46DFF3 /* random.h in Headers */, + CE16ACD45316BE13DC49A139E0C22348 /* skiplist.h in Headers */, + 9C987C18401657468C5F525822AC6A84 /* slice.h in Headers */, + 0E820CB9B7AB02BCC2A703F49B6A6D09 /* snapshot.h in Headers */, + DA8FB749210D21FFC114D2742EF9F937 /* status.h in Headers */, + 616B2E89D32FD69F07E92AB1B11D2CBC /* table.h in Headers */, + C730C445099A2487F6757A413534B5AE /* table_builder.h in Headers */, + 42543BA65C0125AEC372C1C0C6FAE1CE /* table_cache.h in Headers */, + A8D659AA923AF2B46E3C49BD3550BE77 /* testharness.h in Headers */, + 668D655F32BA7A18033B1F19266C28FE /* testutil.h in Headers */, + C20F33C7CCC33D585B948D3CD5FCCD14 /* thread_annotations.h in Headers */, + 3377C22543E182655A05B7614263CC08 /* two_level_iterator.h in Headers */, + 6979B7B344E7603BC52FA8BD0FEA6205 /* version_edit.h in Headers */, + C3882C73D5566E24F1F6272E0D22BCFF /* version_set.h in Headers */, + 9F855716602F307970A8EF9075F89470 /* windows_logger.h in Headers */, + D3B7D0731E8F8449D4E19F62FF712313 /* write_batch.h in Headers */, + F390066B1BD3328086F242BE4552C15B /* write_batch_internal.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AFB481D2053ABBFE15721BAC0FFA2456 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3C1A098456FE8892D2AB50774E7378D3 /* GoogleUtilities-umbrella.h in Headers */, + 998C42C051A9F25D40DC5655B2C22699 /* GULAppDelegateSwizzler.h in Headers */, + E75FA822B3BF50E4A0FBB8D61E4333E2 /* GULAppDelegateSwizzler_Private.h in Headers */, + B8FB2090DCAE05BE7C3F7A2930F34C34 /* GULAppEnvironmentUtil.h in Headers */, + 7D0188C317EF3E96695742D4E163DD8A /* GULApplication.h in Headers */, + 9B033FEB7AC385C943AA6DF22C7BC21D /* GULHeartbeatDateStorable.h in Headers */, + C58878BE15065DD13399FFC43BBF9190 /* GULHeartbeatDateStorage.h in Headers */, + A175967AB93B855356D5AE3D0E823868 /* GULHeartbeatDateStorageUserDefaults.h in Headers */, + C6834D2615A8F126B9213F90852AFB08 /* GULKeychainStorage.h in Headers */, + B9C2451354D749B3A325F6118C8993B6 /* GULKeychainUtils.h in Headers */, + 01A6C557909CAE5AEBD1FA6DDA823EB8 /* GULLogger.h in Headers */, + EB71967B8DFC8099E0B414067D99A0FD /* GULLoggerCodes.h in Headers */, + 85FF342CC7BFC4625D7ABF6102E106F6 /* GULLoggerLevel.h in Headers */, + 37BA637B794968750B48D22ACC59091C /* GULMutableDictionary.h in Headers */, + 1AC831FB9A5BDDCDC53B2E6CE19CE345 /* GULNetwork.h in Headers */, + C73612CBD6B206416D4610074A8919F9 /* GULNetworkConstants.h in Headers */, + A45AC11ED4BFD423B03444A242AA1701 /* GULNetworkInternal.h in Headers */, + CBDA17A4CDF98B881ECA098998AF1748 /* GULNetworkLoggerProtocol.h in Headers */, + B31CB8B76A17C1FB22E8699181911418 /* GULNetworkMessageCode.h in Headers */, + D82CC806256F9A36104BA01C5EFCAB8E /* GULNetworkURLSession.h in Headers */, + CACEA5D18E4B9D0FDE6AEBAC1288BAA3 /* GULNSData+zlib.h in Headers */, + A7363B8B2B99FAE5371CAFBE1CDF1C98 /* GULReachabilityChecker.h in Headers */, + 278B5061DF66CE0EDC5B36BF924494F0 /* GULReachabilityChecker+Internal.h in Headers */, + 48221D69CE4E8000F85D00E3555E0BE8 /* GULReachabilityMessageCode.h in Headers */, + FB6B518F0FC056ABABAA42355E6B4B0A /* GULSceneDelegateSwizzler.h in Headers */, + AAA432F7101046D3317CFEBD825F04D3 /* GULSceneDelegateSwizzler_Private.h in Headers */, + 8EBBE1DE3E49C903EBFE8B2AF59D6CFC /* GULSecureCoding.h in Headers */, + 355BF6E13C02002EC27761C3B789826B /* GULURLSessionDataResponse.h in Headers */, + E43DF6F8DE107CCEF4B6CC66DD731794 /* NSURLSession+GULPromises.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B2A876CDF35581F2938B4D9F32CEAD06 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E66621BE38D05EB8E972C7F230CB475B /* FIRAppCheckInterop.h in Headers */, + 91AED5DBBD2528772364BA8B702366D9 /* FIRAppCheckTokenResultInterop.h in Headers */, + 3C5CC104B3D20A2AFF430228DF095FA8 /* FIRAppInternal.h in Headers */, + 5459DE085ED7C4A66DB23115757E2A9E /* FIRAuthInterop.h in Headers */, + D0B3526CF455B9D4413E7B36CABA0C39 /* FIRComponent.h in Headers */, + 9490844671235A0D95556CB1BA93C23E /* FIRComponentContainer.h in Headers */, + DA9D9277224DB2B1842CB36671C1B652 /* FIRComponentType.h in Headers */, + 048C7DD0F80749D50084C32B02A0DF76 /* FIRCoreDiagnosticsConnector.h in Headers */, + 25C89D35C18013A381A5B0A9635914E6 /* FIRDependency.h in Headers */, + 076C5BC197E05230BEF99B0083072439 /* FirebaseCoreInternal.h in Headers */, + 23102BA0EF95DF55764B795739FD989E /* FirebaseStorage.h in Headers */, + 0C07FE7898CF52FE71E7B1EAF5F50FC6 /* FirebaseStorage-umbrella.h in Headers */, + D6FF6BF5F8218696F0A74D6377691F63 /* FIRHeartbeatInfo.h in Headers */, + 2DB5CA3709377942B66D88362231A3EB /* FIRLibrary.h in Headers */, + 5CFD98A13822F82EDB38A762D3CD1DBF /* FIRLogger.h in Headers */, + CD210BBFAEEB890616D971AED87950BF /* FIROptionsInternal.h in Headers */, + 98D2915ED1960931C77A97E81308E382 /* FIRStorage.h in Headers */, + 7585FB9893C47574C714EC0CD2504C97 /* FIRStorage_Private.h in Headers */, + E2F18677E67B604C0777E83C0C5C478D /* FIRStorageComponent.h in Headers */, + CEE667501017D637317753CBEEC3FB5A /* FIRStorageConstants.h in Headers */, + 58C93368ED6F500E21548239C62979D0 /* FIRStorageConstants_Private.h in Headers */, + 17FABFD8F4FAB1214C0759EB0798CDD6 /* FIRStorageDeleteTask.h in Headers */, + 0F4E913099947B1E8D9D7ACCCEB82A59 /* FIRStorageDownloadTask.h in Headers */, + 614A388909C3449BDDFFA0DA220A12C0 /* FIRStorageDownloadTask_Private.h in Headers */, + C544C2B25329C18043D7AECF1DF694D2 /* FIRStorageErrors.h in Headers */, + D6A103007C2AB29EAC8101085D4F81E1 /* FIRStorageGetDownloadURLTask.h in Headers */, + E6A967ACA9DA5AD23C8AE3338F0C9086 /* FIRStorageGetDownloadURLTask_Private.h in Headers */, + 44600199E64B23381555EEADAEBA6296 /* FIRStorageGetMetadataTask.h in Headers */, + 1804BB9F80D4AA5447BE4694A937C92C /* FIRStorageListResult.h in Headers */, + E1E26E23A30A3592F8710792945C6B4B /* FIRStorageListResult_Private.h in Headers */, + 39EDFA71AA87C5ED0804701D77887585 /* FIRStorageListTask.h in Headers */, + F176AF70E20F4C6E7D504E0413D9779E /* FIRStorageLogger.h in Headers */, + 0C68FA06A72B4A4E52E0A993D84FC669 /* FIRStorageMetadata.h in Headers */, + E232D23ECC2F1C664A6E2A6727FB369F /* FIRStorageMetadata_Private.h in Headers */, + 541E5DC7C13CF8E8D896D2716203FCA6 /* FIRStorageObservableTask.h in Headers */, + 75E819D7151D7CCE92C79AE2DDA1F95F /* FIRStorageObservableTask_Private.h in Headers */, + 0BD146AFD406DAD1F05068752B709894 /* FIRStoragePath.h in Headers */, + 7306ED79AC4A8B9425C5880284AB780A /* FIRStorageReference.h in Headers */, + 9DF82C7BA9CD423B35691FD6324B8AA1 /* FIRStorageReference_Private.h in Headers */, + B89AC9425E84B0E196D73C0B9F7B37B4 /* FIRStorageTask.h in Headers */, + ABFE736014A60F960ABB80269549A344 /* FIRStorageTask_Private.h in Headers */, + A0435254199DE6EA39E2BC07447DE789 /* FIRStorageTaskSnapshot.h in Headers */, + E6A4EF24DA64A4DAFE707341ACF1A4EE /* FIRStorageTaskSnapshot_Private.h in Headers */, + FA5A3FDC4ECDCE3D754B050F40BD8AFE /* FIRStorageTokenAuthorizer.h in Headers */, + 1ED666F1BA37880ADD5D627FB74B0A70 /* FIRStorageUpdateMetadataTask.h in Headers */, + 759B15456E9CA9130BEE3022AFC10F49 /* FIRStorageUploadTask.h in Headers */, + 6ED6CB026B6CE440864EF27A2C6A30A2 /* FIRStorageUploadTask_Private.h in Headers */, + BCB7DA75FCCCCCF265BDC85802F1BD7F /* FIRStorageUtils.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C2B13132CF7950F3F1916C9EFA0317CF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F9637896E08E6D4C4420DE7FCCD8172 /* FIRActionCodeSettings.h in Headers */, + 778DC5CEEB3B4DD44DD01DCE7A2B439F /* FIRAdditionalUserInfo.h in Headers */, + DBA96093F6297C3EBAA4039933CE6160 /* FIRAdditionalUserInfo_Internal.h in Headers */, + 844FA7C3837151A737442BD27727B428 /* FIRAppInternal.h in Headers */, + D906AB3695DB3EEDD49AD7FCB873D2E3 /* FIRAuth.h in Headers */, + 19E7D9479B59A26D0D12E9E19E1475B5 /* FIRAuth_Internal.h in Headers */, + A298FA59BD8627CE99CCFDB3C7DC25A3 /* FIRAuthAPNSToken.h in Headers */, + D031957FCE83D94F33D8D37815702565 /* FIRAuthAPNSTokenManager.h in Headers */, + 06AB1E0106C4611D37E4CD64459E6374 /* FIRAuthAPNSTokenType.h in Headers */, + 8301D0F695FF1765CDAD6EB734E42EE1 /* FIRAuthAppCredential.h in Headers */, + 129EE9819D846904937054067888B78B /* FIRAuthAppCredentialManager.h in Headers */, + A68B6CC82203D8A16467CF424E3811A7 /* FIRAuthBackend.h in Headers */, + 7AB54867E38488F0C42A6601C1DA6208 /* FIRAuthBackend+MultiFactor.h in Headers */, + E25CB13A772897B1185B8C1AE0D6DFF2 /* FIRAuthCredential.h in Headers */, + D64E86413E22E49040D5B01142065FBB /* FIRAuthCredential_Internal.h in Headers */, + 270CF8EAFE4DC66E0CB73B177578FEAF /* FIRAuthDataResult.h in Headers */, + C0E00E871F12EE2A24BF42E0E8DEDCD4 /* FIRAuthDataResult_Internal.h in Headers */, + BC4C03A39AC31AD6FBA78B7A67C27323 /* FIRAuthDefaultUIDelegate.h in Headers */, + B49260928D40C22AAD88457E25E20AF2 /* FIRAuthDispatcher.h in Headers */, + B7C45D6E0E1EB8D02E3B775C47EB2BEE /* FIRAuthErrors.h in Headers */, + 37DF2AD96AB9BD9518253AC14700DE1F /* FIRAuthErrorUtils.h in Headers */, + BB2B28EC729D847F2799663DC2D607E2 /* FIRAuthExceptionUtils.h in Headers */, + 5C06F048ED12F3A8C551E8D67739C9DC /* FIRAuthGlobalWorkQueue.h in Headers */, + 7D785B8DD4B6471135EE117CFA4300BC /* FIRAuthInternalErrors.h in Headers */, + 0ECD56A94543C55E2324ED27A027FBEC /* FIRAuthInterop.h in Headers */, + 29A6D7D6D45DD8EAED318BB51BFBF514 /* FIRAuthKeychainServices.h in Headers */, + 7BE47D6D30ACA7C520E2AAE337DDE6E4 /* FIRAuthNotificationManager.h in Headers */, + 39C00A2F5368CE4CE4885C727A2349A5 /* FIRAuthOperationType.h in Headers */, + 0C9E95296CE1998832C22199DCA3153C /* FIRAuthProto.h in Headers */, + B6F992FC08FB0ED6273F7B46068D759D /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.h in Headers */, + 7172A6567FC9674DB16DEE23677E36AF /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.h in Headers */, + D1D230A0D628080378C66C2C2F044AAC /* FIRAuthProtoMFAEnrollment.h in Headers */, + 39C69069F1CB85D187824BBD7E4E4841 /* FIRAuthProtoStartMFAPhoneRequestInfo.h in Headers */, + 62A83818CD40006D6BA70CBED6490D29 /* FIRAuthProtoStartMFAPhoneResponseInfo.h in Headers */, + 7AFAE54E97C44681D98FC93CD357912F /* FIRAuthRequestConfiguration.h in Headers */, + B6771332A6FC860E5EE45C46992E5200 /* FIRAuthRPCRequest.h in Headers */, + FAA6A295C4B9EBEE073C6CB253577F5F /* FIRAuthRPCResponse.h in Headers */, + 8C44314F95042D95380E7F1F84A7649C /* FIRAuthSerialTaskQueue.h in Headers */, + 2D5C78721BB459B078D801294DBE11D6 /* FIRAuthSettings.h in Headers */, + 518F84055CAD670D7120F5B79849A576 /* FIRAuthStoredUserManager.h in Headers */, + 06F4EA32D50A1182187E39227D41B542 /* FIRAuthTokenResult.h in Headers */, + 842596B7741229FA10A6C0FE65968239 /* FIRAuthTokenResult_Internal.h in Headers */, + 7DD314CFB3E341990B3E317139A123D0 /* FIRAuthUIDelegate.h in Headers */, + 95D70E62A632D2A32C3BA4EFBD64A64B /* FIRAuthURLPresenter.h in Headers */, + 905DA99BAB170BC93513360519722DA8 /* FIRAuthUserDefaults.h in Headers */, + 42D688F55A84AD8DEE4773BC15B5EE61 /* FIRAuthWebUtils.h in Headers */, + 838BB38C313133CBE50C29C938E94F58 /* FIRAuthWebView.h in Headers */, + 9085186086C8E31DE65E85131737F2B6 /* FIRAuthWebViewController.h in Headers */, + 0AD692D6D421F7E455D2FF45326EF715 /* FIRComponent.h in Headers */, + 2EB68F33E95F742138F9AFD04747CCE9 /* FIRComponentContainer.h in Headers */, + 240DE67DAA1EC1BF1CD3E45C2226FE85 /* FIRComponentType.h in Headers */, + 36F1762E563636B7ABE981D0662A7B44 /* FIRCoreDiagnosticsConnector.h in Headers */, + D33386E098005F5A61553F8274B2A5EE /* FIRCreateAuthURIRequest.h in Headers */, + DB07070680E837F75151B85E667F2A80 /* FIRCreateAuthURIResponse.h in Headers */, + F430C6D7960DAE857DC6EB878F54AF69 /* FIRDeleteAccountRequest.h in Headers */, + 449952E83715CFC4D0A7E4947C2856E2 /* FIRDeleteAccountResponse.h in Headers */, + 0D8CAA0FBDA1CC5A9C62B14FEC88CB89 /* FIRDependency.h in Headers */, + 4319E26000B6345DA43EC87429391531 /* FirebaseAuth.h in Headers */, + A209431E9F65430989E16A0CAFC0814D /* FirebaseAuth-umbrella.h in Headers */, + 32F644C584A752ED539E3187B40985F0 /* FirebaseCoreInternal.h in Headers */, + 80F4B66C43F64C2A05ED6245F69641BA /* FIREmailAuthProvider.h in Headers */, + 8C8B9AA671EE9F83E0C2ECD13F9E5306 /* FIREmailLinkSignInRequest.h in Headers */, + 15A4FA93FE3F877448AB1E59E4794471 /* FIREmailLinkSignInResponse.h in Headers */, + 2468760844B2A127A728022BCB13CF5E /* FIREmailPasswordAuthCredential.h in Headers */, + 4C995A985CAA266B79E5646A9B83C408 /* FIRFacebookAuthCredential.h in Headers */, + EF1F810E63261DCF91D30E4ECC047AFA /* FIRFacebookAuthProvider.h in Headers */, + AA6A220380568BBD8AF6E5685285C8C7 /* FIRFederatedAuthProvider.h in Headers */, + 95856B75ABD2C00249DCC69921C3308F /* FIRFinalizeMFAEnrollmentRequest.h in Headers */, + ABD53B75BFB346D62B25DAD08E896676 /* FIRFinalizeMFAEnrollmentResponse.h in Headers */, + 5B02A3E3FD1A87C4B23D46EE93866A80 /* FIRFinalizeMFASignInRequest.h in Headers */, + 247CC367E3F037FECC615F5CD3F8855B /* FIRFinalizeMFASignInResponse.h in Headers */, + A6637B7CE1805725D3E8D1A7EDA8BC2C /* FIRGameCenterAuthCredential.h in Headers */, + 9D95F0989A0963F06494FD5553237D53 /* FIRGameCenterAuthProvider.h in Headers */, + 090414BA9AFDD5A1B7170AD140FEBBFD /* FIRGetAccountInfoRequest.h in Headers */, + 0E3969B21A0155C85DD249CB5E7168ED /* FIRGetAccountInfoResponse.h in Headers */, + 5C73A188E56617C05C11BCF74984D3CC /* FIRGetOOBConfirmationCodeRequest.h in Headers */, + 0FC5F850C688112506AF13ACF5F15C79 /* FIRGetOOBConfirmationCodeResponse.h in Headers */, + 1B520A625131C937020B0BD49E11BC23 /* FIRGetProjectConfigRequest.h in Headers */, + D177E0DDD59B390EB73E0D6E18279DFF /* FIRGetProjectConfigResponse.h in Headers */, + 0FA2AD301EC5C86CB80B8281864B0ADB /* FIRGitHubAuthCredential.h in Headers */, + 70F1FD0154E875CA3B8EFACA8CA32E6A /* FIRGitHubAuthProvider.h in Headers */, + D51D33E2C449E5ECE30337BEF4A20739 /* FIRGoogleAuthCredential.h in Headers */, + 5F5099298A59B6F867A046EA0D1A2283 /* FIRGoogleAuthProvider.h in Headers */, + 96213AB03142B1DD9BB63FE042AB7C07 /* FIRHeartbeatInfo.h in Headers */, + F9A37700BD48A2C1CF21FB246E389C75 /* FIRIdentityToolkitRequest.h in Headers */, + 36D6F986C259D0296744DCDBEC4B6C52 /* FIRLibrary.h in Headers */, + 0F2A489C428CB5919CE1C743F319FFE2 /* FIRLogger.h in Headers */, + 4133B75C944C9093CE765E9C6A827FA1 /* FIRMultiFactor.h in Headers */, + 89DC919325A25CC1DE4B44094DA0A962 /* FIRMultiFactor+Internal.h in Headers */, + 22BE79CE0866A7C8D0FE3673FA1F2F35 /* FIRMultiFactorAssertion.h in Headers */, + 0275D6BB6D8357A70D80FA88FCD4D75E /* FIRMultiFactorAssertion+Internal.h in Headers */, + 84FB53E0059CA2D5C7A6ECE534229BCC /* FIRMultiFactorInfo.h in Headers */, + 1DC2508CFB04B32022E61560A5738481 /* FIRMultiFactorInfo+Internal.h in Headers */, + 7A2CA8D03EACFAAC906606B551F830A6 /* FIRMultiFactorResolver.h in Headers */, + E5263593CD4CBEF49D2CAFCAC3CDE6F9 /* FIRMultiFactorResolver+Internal.h in Headers */, + ACBDC7FCC6F8600B0271A6D2ED9DCD10 /* FIRMultiFactorSession.h in Headers */, + 4E3A26D6ED2332B474474099F7E27EF6 /* FIRMultiFactorSession+Internal.h in Headers */, + 8E117DDEF71D85E84D5C6C6F4CCF504D /* FIROAuthCredential.h in Headers */, + 7173ADD487449BB30C047AAF031EB41E /* FIROAuthCredential_Internal.h in Headers */, + D8A9620AD633A6ABDFE8515D7C51FDFF /* FIROAuthProvider.h in Headers */, + 6B16A68AC63ED6F5D3128DDDD407DE60 /* FIROptionsInternal.h in Headers */, + 651BD9FBA52511E2F13EB0DA9E563031 /* FIRPhoneAuthCredential.h in Headers */, + AF4A5F72481F3D76A53D5B1D4BA41B29 /* FIRPhoneAuthCredential_Internal.h in Headers */, + 180DAF37669451AA6451AC4401C81D4E /* FIRPhoneAuthProvider.h in Headers */, + 935BB5128361756AF5CC5B3650130A14 /* FIRPhoneMultiFactorAssertion.h in Headers */, + 34C1AF702FA358ED3D006277A9312B95 /* FIRPhoneMultiFactorAssertion+Internal.h in Headers */, + 9DAD3A85765D97A269EB2EAC99D718D7 /* FIRPhoneMultiFactorGenerator.h in Headers */, + D92144BBA6B27D4767881FFB77AC81F1 /* FIRPhoneMultiFactorInfo.h in Headers */, + 1F45A8D8097D8059298F1210E5CE440B /* FIRPhoneMultiFactorInfo+Internal.h in Headers */, + DDCD533E1D00FFFEBE01D45415ED1E8B /* FIRResetPasswordRequest.h in Headers */, + C24C75C71AC1DAB2432F95E03EE82863 /* FIRResetPasswordResponse.h in Headers */, + 5C92F3D83A17F078D0B42E92A1BA19BD /* FIRSecureTokenRequest.h in Headers */, + 2FE86192CEBBD515E8F2056A59879A82 /* FIRSecureTokenResponse.h in Headers */, + 7E41BFA699D5160081068728DD661040 /* FIRSecureTokenService.h in Headers */, + D61708EBC2CE36A7083910134C74D83E /* FIRSendVerificationCodeRequest.h in Headers */, + 9C490071CB4398966A66F174EB99002B /* FIRSendVerificationCodeResponse.h in Headers */, + BAC83030415DB61C8F2A72D3275FD0A2 /* FIRSetAccountInfoRequest.h in Headers */, + 139A4F1FFA65C5B8FFD58E58137DB58F /* FIRSetAccountInfoResponse.h in Headers */, + 2A9C04A41EA0F108D58E5458A8EDD7D8 /* FIRSignInWithGameCenterRequest.h in Headers */, + B4D3E1FFD0CA59374B88AE0EC1501AF0 /* FIRSignInWithGameCenterResponse.h in Headers */, + 6CBF35F4F530975DB66F9FD017473901 /* FIRSignUpNewUserRequest.h in Headers */, + 095785C9F47316B92925EDF9EFE641A4 /* FIRSignUpNewUserResponse.h in Headers */, + 91A136B8AD4777A463238ECB23804731 /* FIRStartMFAEnrollmentRequest.h in Headers */, + 01F16003BB6BAAC985F02EF2C694D86C /* FIRStartMFAEnrollmentResponse.h in Headers */, + F09DE2AA47714D5DC0AD93935920529F /* FIRStartMFASignInRequest.h in Headers */, + 885F224793EF37BF5179907F21F453B4 /* FIRStartMFASignInResponse.h in Headers */, + 47D4A624F2376E4D984804510C5851FE /* FIRTwitterAuthCredential.h in Headers */, + 36282A5956905D74BBAB02782A494B07 /* FIRTwitterAuthProvider.h in Headers */, + 2D9BA8A0B076740932B7B96CA7CD915C /* FIRUser.h in Headers */, + 8024622AE0E5CB515628DD4D344CFBBC /* FIRUser_Internal.h in Headers */, + DB4E927F6600C2D39A6D66933588496F /* FIRUserInfo.h in Headers */, + 3FC92D4827CF604044CBC62286BAC7AC /* FIRUserInfoImpl.h in Headers */, + BF28E6C7CA2213275AD07A5004BFC80F /* FIRUserMetadata.h in Headers */, + 162171383C10D2C1C52E01CDDEE80116 /* FIRUserMetadata_Internal.h in Headers */, + BF83BAC1BCD21156C30C7C08EFFA2C42 /* FIRVerifyAssertionRequest.h in Headers */, + C99CCBBF389F215B44BFEB1747F41FE3 /* FIRVerifyAssertionResponse.h in Headers */, + C7153BF71E3F492E3C70F66CE9703ACC /* FIRVerifyClientRequest.h in Headers */, + 44D331D1753DE918C661FE61E69B50DF /* FIRVerifyClientResponse.h in Headers */, + 1E75EEE40C4C1D14AA5FFCC6543DBB28 /* FIRVerifyCustomTokenRequest.h in Headers */, + 37DAA639FA4FAADA09F7970A7FE66248 /* FIRVerifyCustomTokenResponse.h in Headers */, + 0427C524142A2BAFD41071E205D50445 /* FIRVerifyPasswordRequest.h in Headers */, + DF80641143FD2B4E0B73B5488BF70E8A /* FIRVerifyPasswordResponse.h in Headers */, + DB2C57B40DE78EFA9D39CD99B54B21F4 /* FIRVerifyPhoneNumberRequest.h in Headers */, + AE0FE5E9ECDC9F7683BA6C708587B6F6 /* FIRVerifyPhoneNumberResponse.h in Headers */, + 773A7355F15490EA982DF17AE6676998 /* FIRWithdrawMFARequest.h in Headers */, + 9988E4C42954BF79A32A3F4FF4F46623 /* FIRWithdrawMFAResponse.h in Headers */, + 61BAD4B3AC092595A4DBD710410C78DD /* NSData+FIRBase64.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C84D29630238A1BFA0D9CC32A76F9B1D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 12FA59710EA94ACF21FB4436DD95867F /* FIRCoreDiagnostics.h in Headers */, + 760BA4FFAA6A2C1651C5673DB42095D4 /* FIRCoreDiagnosticsData.h in Headers */, + BC375D294E17AA52FAF84BEADB8EE59C /* FIRCoreDiagnosticsInterop.h in Headers */, + 076D9173EE944FB9E6101BB16FA6324B /* firebasecore.nanopb.h in Headers */, + C88BA30F71DD393322BAD9563C5B6340 /* FirebaseCoreDiagnostics-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 23E7C4A52360C026F97E4A96D91B03CE /* FirebaseStorage */ = { + isa = PBXNativeTarget; + buildConfigurationList = BA4EF57DE1E6A2DA36BFC921B39A085A /* Build configuration list for PBXNativeTarget "FirebaseStorage" */; + buildPhases = ( + B2A876CDF35581F2938B4D9F32CEAD06 /* Headers */, + 3CDA139BBB21CDB4D370AA725B42F730 /* Sources */, + FB12A9CE864E21F0D8393EA472DA5746 /* Frameworks */, + 5F13C32599A77FA940BBB457A396F29B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4654BF4CE1805B5DA618B081210CFB2F /* PBXTargetDependency */, + 04E3FEAA9108DBC5578CC3FE44DBFE66 /* PBXTargetDependency */, + ); + name = FirebaseStorage; + productName = FirebaseStorage; + productReference = 9CF8FA5F01F446F01AAC7331075452AD /* FirebaseStorage */; + productType = "com.apple.product-type.framework"; + }; + 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */ = { + isa = PBXNativeTarget; + buildConfigurationList = 87045C3ACA8836F42AED6B5CF7B938C4 /* Build configuration list for PBXNativeTarget "PromisesObjC" */; + buildPhases = ( + 1488159A9B9D000DDA80B32C5E6E21F9 /* Headers */, + FF2903366EFB7A36DEC66D583781A3E0 /* Copy . Private Headers */, + 6E2DAB853E8F090EA06FFBB8FBDD25F3 /* Copy . Public Headers */, + BB148065C5B367118820236ADD533EBB /* Sources */, + 78B2D764E2E0280FF991AFE2E1A70E02 /* Frameworks */, + 11C4D5F08081D5A3491422213C82AAA8 /* Resources */, + 2FE2229583A59190900A37048594BC29 /* Create Symlinks to Header Folders */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PromisesObjC; + productName = FBLPromises; + productReference = 3347A1AB6546F0A3977529B8F199DC41 /* PromisesObjC */; + productType = "com.apple.product-type.framework"; + }; + 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */ = { + isa = PBXNativeTarget; + buildConfigurationList = BA3465076324B082765EC249969C880E /* Build configuration list for PBXNativeTarget "FirebaseCore" */; + buildPhases = ( + 20672DD68847F185DC042E313A859B52 /* Headers */, + AA41EC178BB7671D18FBF918B7942780 /* Sources */, + 7DED8332091610648ACB97C947E10BE5 /* Frameworks */, + A6A0389EA2C53F843D779F9F98C235A1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 1D304EB5CA6B9AF59C604FA8C81FAD6C /* PBXTargetDependency */, + 365FC54401A0211CD260DEFB5F5BCCC9 /* PBXTargetDependency */, + ); + name = FirebaseCore; + productName = FirebaseCore; + productReference = E2B63D462DB7F827C4B11FD51E4F8E2D /* FirebaseCore */; + productType = "com.apple.product-type.framework"; + }; + 5C0371EE948D0357B8EE0E34ABB44BF0 /* GoogleDataTransport */ = { + isa = PBXNativeTarget; + buildConfigurationList = 986F1AA400CD9818F8136AABFA142C08 /* Build configuration list for PBXNativeTarget "GoogleDataTransport" */; + buildPhases = ( + 5C4015169A8F37E18D58EC812445DF6F /* Headers */, + 1157F0B9840FDB56E29B925579D70882 /* Sources */, + 72F2974253F0A1DB5DFFA14510B0AFD2 /* Frameworks */, + 2135F0F311AB758931433EFDE1078BE1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 40F4BB26427733FA9181463D32F4A523 /* PBXTargetDependency */, + 92CDC77EF8013E7CF3E7821256A1E556 /* PBXTargetDependency */, + 631692E880153D2CF3FFB622D6AD1648 /* PBXTargetDependency */, + ); + name = GoogleDataTransport; + productName = GoogleDataTransport; + productReference = 856B5CD56F194FAD26EA91620B66D614 /* GoogleDataTransport */; + productType = "com.apple.product-type.framework"; + }; + 620E05868772C10B4920DC7E324F2C87 /* FirebaseCoreDiagnostics */ = { + isa = PBXNativeTarget; + buildConfigurationList = B63C58730E117135DD12AD9D422458D4 /* Build configuration list for PBXNativeTarget "FirebaseCoreDiagnostics" */; + buildPhases = ( + C84D29630238A1BFA0D9CC32A76F9B1D /* Headers */, + 1A90623709CAD79BABF0960077965FF7 /* Sources */, + 3CEF3767C3F33F673178AA043F90F95E /* Frameworks */, + 03AAB14F1011965ACBD49C832A8311BA /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 2E970012EF70B1F30AE0A3B872FAE845 /* PBXTargetDependency */, + E856BB4009034B5E9FB68B65CF3B6355 /* PBXTargetDependency */, + 06E0185D8C8E3C8A158B8C3A5F269786 /* PBXTargetDependency */, + ); + name = FirebaseCoreDiagnostics; + productName = FirebaseCoreDiagnostics; + productReference = 8CC9178C366942FD6FF6A115604EAD58 /* FirebaseCoreDiagnostics */; + productType = "com.apple.product-type.framework"; + }; + 6AE4A3D573DED275B034E20506596C62 /* FirebaseAuth */ = { + isa = PBXNativeTarget; + buildConfigurationList = F47BD23AA5943D62A6EA20D71F803485 /* Build configuration list for PBXNativeTarget "FirebaseAuth" */; + buildPhases = ( + C2B13132CF7950F3F1916C9EFA0317CF /* Headers */, + 0292E9096956421B3D9E6C2A0127DEE9 /* Sources */, + 9F77C26EAC00504FB8C5C1BD89AEDBD8 /* Frameworks */, + 75B8C0D0197A3F8A079766B941B2D847 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + F6664C5F2396BFD8035EAD477E1DD87C /* PBXTargetDependency */, + D5FF9C0807CE1A53CF45849BBC3F74F8 /* PBXTargetDependency */, + 1DAF02A7444F79E7F34886AB98947102 /* PBXTargetDependency */, + ); + name = FirebaseAuth; + productName = FirebaseAuth; + productReference = 43B1E4CD7B30B9FD278100133C2AC788 /* FirebaseAuth */; + productType = "com.apple.product-type.framework"; + }; + 736AF68F6527ACF6B4A4C54728824A1C /* FirebaseDatabase */ = { + isa = PBXNativeTarget; + buildConfigurationList = D520B9DB9F6D9A03F3AF3E561A87DDD6 /* Build configuration list for PBXNativeTarget "FirebaseDatabase" */; + buildPhases = ( + 1D12DBB47BAA9DE2D8ECA7E37DC15272 /* Headers */, + 6D6811B124506D46F6C8EDF3409A50F3 /* Sources */, + CCB8F503631ED2691B85432142C6C40E /* Frameworks */, + D60EDDC45A2B8E2703F83D35C3302B57 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5A9BD4197B533664764E6318BA949347 /* PBXTargetDependency */, + 6F755F56BFA1B4D1973DB7DD4EEAFDB6 /* PBXTargetDependency */, + ); + name = FirebaseDatabase; + productName = FirebaseDatabase; + productReference = 51671C73F008B5C0C3751B3855999213 /* FirebaseDatabase */; + productType = "com.apple.product-type.framework"; + }; + 88B86622B055B944C18D2D29DE77A2B4 /* Pods-saraWhatsUp */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6F54AD43C735E58F79F4B5F731D63AEA /* Build configuration list for PBXNativeTarget "Pods-saraWhatsUp" */; + buildPhases = ( + 0BB6D10539AC49B11373729E65F37C36 /* Headers */, + E1D92C0D2D568335894CF224DF1EDFD2 /* Sources */, + F81E63C96CB5AB58F86960D32BE72E0D /* Frameworks */, + ACD1DDAB9B07EDEE6E84DFA95E48DDC1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + CF832150363A02D97AB0BF59BCB5421B /* PBXTargetDependency */, + 567468EE0FB2126B97D213CA5CE4B497 /* PBXTargetDependency */, + 3C06305162A11FE501B03032B5A80C84 /* PBXTargetDependency */, + 313E445DEA4F50A9991A18790CBEC815 /* PBXTargetDependency */, + 1F1D58F475282ED7D8B74E77816DA762 /* PBXTargetDependency */, + F9C5F9DE3BCD6C9993F1F78AC8E56FB7 /* PBXTargetDependency */, + 65673B1B86ECF9A3DB29FE2EE72C56B3 /* PBXTargetDependency */, + 9836C91E1910DD22BE569755415B25BE /* PBXTargetDependency */, + E19DE2AE1B3DFC7A3DC96B1F66BF01AD /* PBXTargetDependency */, + F25DA974AB9089B1C8C8C729256426F7 /* PBXTargetDependency */, + 535FB6010AA026EEA4482967FC0F4C0F /* PBXTargetDependency */, + CE8AD85CF057AC596368A8A93DBC58EA /* PBXTargetDependency */, + ); + name = "Pods-saraWhatsUp"; + productName = Pods_saraWhatsUp; + productReference = 5C321A8D9A1BFC778344F7F211DE5680 /* Pods-saraWhatsUp */; + productType = "com.apple.product-type.framework"; + }; + 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */ = { + isa = PBXNativeTarget; + buildConfigurationList = 11CF5C560B12D8F76442A91FAFDD07EB /* Build configuration list for PBXNativeTarget "GoogleUtilities" */; + buildPhases = ( + AFB481D2053ABBFE15721BAC0FFA2456 /* Headers */, + E8F9859A97DB0783FB16DE7A599209E5 /* Sources */, + 534071F6DE083B6FF89A3E1CC86615B4 /* Frameworks */, + 7964ED3EA90E099BD25A4FB6C37472AF /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 676F88BBFB075EF3B710F0A42509E57A /* PBXTargetDependency */, + ); + name = GoogleUtilities; + productName = GoogleUtilities; + productReference = B43874C6CBB50E7134FBEC24BABFE14F /* GoogleUtilities */; + productType = "com.apple.product-type.framework"; + }; + 9307B7A119490930CF70393AB529AAC1 /* leveldb-library */ = { + isa = PBXNativeTarget; + buildConfigurationList = EBF4DA5DA8DAA995C406178BDC05EDFA /* Build configuration list for PBXNativeTarget "leveldb-library" */; + buildPhases = ( + AE76A4CB7D2A1031F0F281AE045EE3A2 /* Headers */, + DCEC0841BA916251FCBE1A199CF9268F /* Sources */, + EEE9A50601C26E070141DCBA88EAB039 /* Frameworks */, + 84EDD803455CEA6F820C2E94952239AA /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "leveldb-library"; + productName = leveldb; + productReference = 0A9F46A999C47653013D3AD854352507 /* leveldb-library */; + productType = "com.apple.product-type.framework"; + }; + D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */ = { + isa = PBXNativeTarget; + buildConfigurationList = 68E7FD26B070FBFCEC3C556599258FC7 /* Build configuration list for PBXNativeTarget "nanopb" */; + buildPhases = ( + 47A85167F39588C93A68FFC26CC0223F /* Headers */, + BE3EBB685B04AF036B951B440D3EA9F8 /* Sources */, + 8D9D53A81613F7B96BE6AB1B80C7DEB0 /* Frameworks */, + 7D0B2816A07629B9DBFEC8129B6696B2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = nanopb; + productName = nanopb; + productReference = 06FC5C9CF96D60C50FCD47D339C91951 /* nanopb */; + productType = "com.apple.product-type.framework"; + }; + D676E21115185671D7258A56944ABE98 /* GTMSessionFetcher */ = { + isa = PBXNativeTarget; + buildConfigurationList = C9A3516B1C68CBE1587C9F50C2E1E7DE /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */; + buildPhases = ( + 898615E79129CFA6E4B59743FF377D38 /* Headers */, + CBE35D1A182A5B79E6DCEFD11E050663 /* Sources */, + 152C907A1F1FAF87F99B2AC79739E3B7 /* Frameworks */, + 53CBA00EEA09D94FF02D129A85E3B14E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GTMSessionFetcher; + productName = GTMSessionFetcher; + productReference = C1998E0D8085221AD87F89B614C10E52 /* GTMSessionFetcher */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFDFE7DC352907FC980B868725387E98 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1240; + LastUpgradeCheck = 1240; + }; + buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = CF1408CF629C7361332E53B88F7BD30C; + productRefGroup = 5059F4FBAA3D48EB0A23E1B5904940EB /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 072CEA044D2EF26F03496D5996BBF59F /* Firebase */, + 6AE4A3D573DED275B034E20506596C62 /* FirebaseAuth */, + 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */, + 620E05868772C10B4920DC7E324F2C87 /* FirebaseCoreDiagnostics */, + 736AF68F6527ACF6B4A4C54728824A1C /* FirebaseDatabase */, + 23E7C4A52360C026F97E4A96D91B03CE /* FirebaseStorage */, + 5C0371EE948D0357B8EE0E34ABB44BF0 /* GoogleDataTransport */, + 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */, + D676E21115185671D7258A56944ABE98 /* GTMSessionFetcher */, + 9307B7A119490930CF70393AB529AAC1 /* leveldb-library */, + D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */, + 88B86622B055B944C18D2D29DE77A2B4 /* Pods-saraWhatsUp */, + 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 03AAB14F1011965ACBD49C832A8311BA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 11C4D5F08081D5A3491422213C82AAA8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2135F0F311AB758931433EFDE1078BE1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53CBA00EEA09D94FF02D129A85E3B14E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F13C32599A77FA940BBB457A396F29B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 75B8C0D0197A3F8A079766B941B2D847 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7964ED3EA90E099BD25A4FB6C37472AF /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7D0B2816A07629B9DBFEC8129B6696B2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 84EDD803455CEA6F820C2E94952239AA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A6A0389EA2C53F843D779F9F98C235A1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + ACD1DDAB9B07EDEE6E84DFA95E48DDC1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D60EDDC45A2B8E2703F83D35C3302B57 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2FE2229583A59190900A37048594BC29 /* Create Symlinks to Header Folders */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Create Symlinks to Header Folders"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cd \"$CONFIGURATION_BUILD_DIR/$WRAPPER_NAME\" || exit 1\nif [ ! -d Versions ]; then\n # Not a versioned framework, so no need to do anything\n exit 0\nfi\n\npublic_path=\"${PUBLIC_HEADERS_FOLDER_PATH#$CONTENTS_FOLDER_PATH/}\"\nif [ ! -f \"$public_path\" ]; then\n ln -fs \"${PUBLIC_HEADERS_FOLDER_PATH#$WRAPPER_NAME/}\" \"$public_path\"\nfi\n\nprivate_path=\"${PRIVATE_HEADERS_FOLDER_PATH#$CONTENTS_FOLDER_PATH/}\"\nif [ ! -f \"$private_path\" ]; then\n ln -fs \"${PRIVATE_HEADERS_FOLDER_PATH#$WRAPPER_NAME/}\" \"$private_path\"\nfi\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0292E9096956421B3D9E6C2A0127DEE9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F717D60CB93C2CCB02B839D89521DA7A /* FIRActionCodeSettings.m in Sources */, + 983063CD03376A95785053451C780F79 /* FIRAdditionalUserInfo.m in Sources */, + C2942C7F216D4AA42ACFACB52AA86464 /* FIRAuth.m in Sources */, + 82421185BFECC0330891863B6C6B9E1A /* FIRAuthAPNSToken.m in Sources */, + A5AE02E69658A425C1B01230F4C8FA14 /* FIRAuthAPNSTokenManager.m in Sources */, + 77B0BDB698070CCA95A70089BAC23AF4 /* FIRAuthAppCredential.m in Sources */, + 8B40C2853D08740082E7D01F5320B46E /* FIRAuthAppCredentialManager.m in Sources */, + 7D0CEB45C774DBD9AED7942C23E8D100 /* FIRAuthBackend.m in Sources */, + 83D72576BFB730F7EA50FE092466BEEF /* FIRAuthBackend+MultiFactor.m in Sources */, + 324EDD65C041C1AE8D1A84ECF3C291BC /* FIRAuthCredential.m in Sources */, + 16D8E7082DEF7B79F60863C3E0230276 /* FIRAuthDataResult.m in Sources */, + 08FFF6697B510E557E32009456A0E0E8 /* FIRAuthDefaultUIDelegate.m in Sources */, + 4D419E2528582F83F93AAEDD8DA82CF7 /* FIRAuthDispatcher.m in Sources */, + F4873A6E8872E9742B0617AE89AEC464 /* FIRAuthErrorUtils.m in Sources */, + 63764E43C4E5B8288446633D0A055AFC /* FIRAuthExceptionUtils.m in Sources */, + 0896582AFC794FF74E50CBA0DCB78FB7 /* FIRAuthGlobalWorkQueue.m in Sources */, + E3908B4FB5DC3976FDF132C9A2B7C4B8 /* FIRAuthKeychainServices.m in Sources */, + C290897AE33B258A9108AE01766F9B1F /* FIRAuthNotificationManager.m in Sources */, + 1F19AD338B9B9016B92A22CB78423BF7 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.m in Sources */, + 36871998D4FD1B26426B968CC19E4641 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.m in Sources */, + C3AC3E4E5967BACA1EEEE37CB9F52C59 /* FIRAuthProtoMFAEnrollment.m in Sources */, + 4E8471B03FB2B976EAEE1A0FA58E27F5 /* FIRAuthProtoStartMFAPhoneRequestInfo.m in Sources */, + C8E1E5A7D28FE6F8395FDD6872EDD268 /* FIRAuthProtoStartMFAPhoneResponseInfo.m in Sources */, + 1B7003D24D814169EF33A559EF2C4400 /* FIRAuthProvider.m in Sources */, + 9950B0D533276E07A93A0128E073772A /* FIRAuthRequestConfiguration.m in Sources */, + CEAF992BEDADDBA5FFC72B74BB08AC15 /* FIRAuthSerialTaskQueue.m in Sources */, + 49A49F4A2C0E68AF62BC963531922CF9 /* FIRAuthSettings.m in Sources */, + 2C4D1F5D50253C77429C2C5B0D6334D7 /* FIRAuthStoredUserManager.m in Sources */, + 36F62E55B71C819BDCC44B7D5FD22B6B /* FIRAuthTokenResult.m in Sources */, + FD4C2A53F7E0A9F1AB92B058D3C443DA /* FIRAuthURLPresenter.m in Sources */, + DABA54962787244E9B239EFF0C9FA7CF /* FIRAuthUserDefaults.m in Sources */, + 080AC7F5EB28B130A20F6A28DDD22996 /* FIRAuthWebUtils.m in Sources */, + 9A282E7CF0544BFD51A2B3A85DF3D497 /* FIRAuthWebView.m in Sources */, + 44B9E396D8F40BDDD0BF3A8B07491D59 /* FIRAuthWebViewController.m in Sources */, + 2FE42BEEB04A6D0628AA86B43DEEE61C /* FIRCreateAuthURIRequest.m in Sources */, + FDB2A038E79C965885210DE71FD289B8 /* FIRCreateAuthURIResponse.m in Sources */, + DBA1765E03F6D0686D5F2B6BD6D1C9C1 /* FIRDeleteAccountRequest.m in Sources */, + 241EEA15A7F02455B11B817D09591753 /* FIRDeleteAccountResponse.m in Sources */, + 1DF76C978674C0A91F03CB4F0B6A189B /* FirebaseAuth-dummy.m in Sources */, + E083913AA645AA88506806BF99854FB6 /* FIREmailAuthProvider.m in Sources */, + 32BCBC79AA92404253EE80219E3A4AD4 /* FIREmailLinkSignInRequest.m in Sources */, + 08AA505683FEE5F1E61A52D3B675846F /* FIREmailLinkSignInResponse.m in Sources */, + 34B5550B70CEAC67308C32D9271B51E2 /* FIREmailPasswordAuthCredential.m in Sources */, + 08ED6191618A3D731FCE86CCB04F97A9 /* FIRFacebookAuthCredential.m in Sources */, + 82858EA79C6545989FD16116DC1046E2 /* FIRFacebookAuthProvider.m in Sources */, + 7B00D6A4319C96E8C195A62236AAE45D /* FIRFinalizeMFAEnrollmentRequest.m in Sources */, + EDAA92E3A8D3731C13A0C2743909267D /* FIRFinalizeMFAEnrollmentResponse.m in Sources */, + AEBED04183009BCB8FE00B797BAA5C10 /* FIRFinalizeMFASignInRequest.m in Sources */, + 7AADF931BA9247F31B1D59A864D1BD2D /* FIRFinalizeMFASignInResponse.m in Sources */, + D059406F02D5BEB2BD9E08AF105CB626 /* FIRGameCenterAuthCredential.m in Sources */, + FFA4A408774EC7345E0684BC1CD37F5D /* FIRGameCenterAuthProvider.m in Sources */, + 1C6FF185F54442D54E0F8443A58D6169 /* FIRGetAccountInfoRequest.m in Sources */, + CD7844100B03C3662B63E3ACA3AF355A /* FIRGetAccountInfoResponse.m in Sources */, + B988F8276ED672315FFAE905F52BF82B /* FIRGetOOBConfirmationCodeRequest.m in Sources */, + 3BB69CF0EAD9B2F0119D6E159D3C9976 /* FIRGetOOBConfirmationCodeResponse.m in Sources */, + 3EDE237CF1424F8E7221DD100E531D05 /* FIRGetProjectConfigRequest.m in Sources */, + 155952A152951A07D66363290E3BA9BD /* FIRGetProjectConfigResponse.m in Sources */, + D0D624770FBC61B098ADCBF66B8AEA3D /* FIRGitHubAuthCredential.m in Sources */, + B546014D2EA0A30EB6773AF2DC7061AC /* FIRGitHubAuthProvider.m in Sources */, + 0E1B862378B4F1E49A1D5B9D63F0F510 /* FIRGoogleAuthCredential.m in Sources */, + 52E0327EF9892E5401A79C084C0F15CA /* FIRGoogleAuthProvider.m in Sources */, + 6C4C3AF66F2F27E39972465C10D5FED8 /* FIRIdentityToolkitRequest.m in Sources */, + 19DAE70F41E72B60CBB195E9C44F6670 /* FIRMultiFactor.m in Sources */, + 6674DEE755366B1AA3BC1C8DA72EE0BB /* FIRMultiFactorAssertion.m in Sources */, + 2906F6A4ADBECD6C8DE3C3D7E7F90FEC /* FIRMultiFactorConstants.m in Sources */, + 7B5A0F99CB075CCFC9BA1EEFE29ED77F /* FIRMultiFactorInfo.m in Sources */, + 85571F0848D48FC93C449C1986C012C9 /* FIRMultiFactorResolver.m in Sources */, + 34773FD7E47A7A26FAA8F6EA4F577F7C /* FIRMultiFactorSession.m in Sources */, + E2AE6DDEC4BD3DC6C1FC6E80D179C236 /* FIROAuthCredential.m in Sources */, + B0CB1B155C99B22C97F45E0ADA5D4618 /* FIROAuthProvider.m in Sources */, + 07B1DA9DB16424D0809ADA36F48FF480 /* FIRPhoneAuthCredential.m in Sources */, + 47C62EEB8B69C5CD508E366A67CF2729 /* FIRPhoneAuthProvider.m in Sources */, + 27DC29F6794F7616897180491C1A7D1E /* FIRPhoneMultiFactorAssertion.m in Sources */, + 0A49F2C5C977CD8F4A47A05EAE2E8BF8 /* FIRPhoneMultiFactorGenerator.m in Sources */, + E34BD8F0410576B6F7B3947447474943 /* FIRPhoneMultiFactorInfo.m in Sources */, + 6033F62A41BBCEAA7BFA756FEE021418 /* FIRResetPasswordRequest.m in Sources */, + 655EBDF94BCD02187A918254978A1034 /* FIRResetPasswordResponse.m in Sources */, + 4D4C74A2E9E4C5B50A98AE5C94D70D58 /* FIRSecureTokenRequest.m in Sources */, + B0B39BE500B9567B25B71977881DA1EC /* FIRSecureTokenResponse.m in Sources */, + 8F1D38C0AD2AB9C132D750E6A0453312 /* FIRSecureTokenService.m in Sources */, + 0255589F47915265239B430239BB154D /* FIRSendVerificationCodeRequest.m in Sources */, + 16F4CF8087DC60B0730FC5BEB0FB578E /* FIRSendVerificationCodeResponse.m in Sources */, + 6F520679C3B53DCA82460DE364BDC4CC /* FIRSetAccountInfoRequest.m in Sources */, + 39F7BE218E2CFCE951F5A0E4B3B8DE7A /* FIRSetAccountInfoResponse.m in Sources */, + C416FFC65F0BA38BF7B7044352F0AC33 /* FIRSignInWithGameCenterRequest.m in Sources */, + 4B9FB8FD9006135B9F1847CD1F274058 /* FIRSignInWithGameCenterResponse.m in Sources */, + 4203BCA824BCE9A3942DFC20304EC053 /* FIRSignUpNewUserRequest.m in Sources */, + AFADBEBF673D850D8622C156A12E6CE3 /* FIRSignUpNewUserResponse.m in Sources */, + 609B53B50AD2672F4805D60C2B47DD39 /* FIRStartMFAEnrollmentRequest.m in Sources */, + 32AE0A7150E1CA915BFE3D0EB4D5D582 /* FIRStartMFAEnrollmentResponse.m in Sources */, + A9F9A7D04BA928EDD35F54A6F6972460 /* FIRStartMFASignInRequest.m in Sources */, + 33094CF89EBEA0CFE4E55E5E714A2A31 /* FIRStartMFASignInResponse.m in Sources */, + BA65ACA1F5302B5BDD840CF54AE66381 /* FIRTwitterAuthCredential.m in Sources */, + CFB23CC4B1823197B18A2ECC2CD31393 /* FIRTwitterAuthProvider.m in Sources */, + 41B04D6909FEB1A696ABF27698BCF6F5 /* FIRUser.m in Sources */, + F9FCEC45422BBCCE393D9E3A563FD9E5 /* FIRUserInfoImpl.m in Sources */, + 97BBC5F4455ED893A97241B577B1F730 /* FIRUserMetadata.m in Sources */, + 24B9CAC7D15EFBB66DAC206218DC9D45 /* FIRVerifyAssertionRequest.m in Sources */, + 6635A1592B385FE08057D0186B149966 /* FIRVerifyAssertionResponse.m in Sources */, + D3C82A51CC1481C9C0C4D0186733797D /* FIRVerifyClientRequest.m in Sources */, + 994339AA7CCBEFBED50F5BC63DCF5BA3 /* FIRVerifyClientResponse.m in Sources */, + 0F5FF6B726D791FB48A21F3FCF3BE75D /* FIRVerifyCustomTokenRequest.m in Sources */, + 32B7A27422654270432FC648B965BF39 /* FIRVerifyCustomTokenResponse.m in Sources */, + 51D758558CFDE52A847FB8E00A855F79 /* FIRVerifyPasswordRequest.m in Sources */, + 68C7362E00FFE0E070F04E6BB537E5E9 /* FIRVerifyPasswordResponse.m in Sources */, + B032E00F4C4DF04F459DAE54F536B967 /* FIRVerifyPhoneNumberRequest.m in Sources */, + 9A94706483A056C0330BDEE4CD5BCAEE /* FIRVerifyPhoneNumberResponse.m in Sources */, + 5B0FEB83A4F5F7CF12CB78B28EEEAF3D /* FIRWithdrawMFARequest.m in Sources */, + 08989AE18374AA69F9740CC95C33B373 /* FIRWithdrawMFAResponse.m in Sources */, + 868FF3395EE1C4FCC3004281B340E1EB /* NSData+FIRBase64.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1157F0B9840FDB56E29B925579D70882 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0CD03BBFD9C64C56B2DA1D8C4EA7FD3E /* cct.nanopb.c in Sources */, + 6670345A52E74A2A2CFD531CD287E190 /* GDTCCTCompressionHelper.m in Sources */, + 81A6E9D26B117B3E7E9E9042C8AC5BC7 /* GDTCCTNanopbHelpers.m in Sources */, + 30BEC42B24D859F5B892955C63165FEE /* GDTCCTUploader.m in Sources */, + 10D1C792F4AB82496BC9156BAC561182 /* GDTCCTUploadOperation.m in Sources */, + 0E0644E775491C0D19300244E7AC3930 /* GDTCORAssert.m in Sources */, + 87509592DC4D483D79B5ECFBAED06C94 /* GDTCORClock.m in Sources */, + 4F376635FBD32FE1FDE8E645219D64DD /* GDTCORConsoleLogger.m in Sources */, + A21A4177EDFA1C529D9DB22B64C0C746 /* GDTCORDirectorySizeTracker.m in Sources */, + B63B5F33C0685A724FBC3AD8E23506CC /* GDTCOREndpoints.m in Sources */, + 92E2001590E01893E9512EE4B749966E /* GDTCOREvent.m in Sources */, + CC8296CE73D7B0B4A0C5F339AEC0F21F /* GDTCOREvent+GDTCCTSupport.m in Sources */, + DF69EACB95BF1F1ABB752B5CE347D2BE /* GDTCORFlatFileStorage.m in Sources */, + ABD508BD058D25EFFC469A55D18F3338 /* GDTCORFlatFileStorage+Promises.m in Sources */, + 2F09B0729F8F48F217140937F1363954 /* GDTCORLifecycle.m in Sources */, + 096F3C656D1C98DCFEF6BD074C105C35 /* GDTCORPlatform.m in Sources */, + 0CC252D2D453B1029E504E7C718AE318 /* GDTCORReachability.m in Sources */, + BC14302FF04BFD07C8B67121AC2B029E /* GDTCORRegistrar.m in Sources */, + AB4E9A49AD1EE8933D81C93FD442A80D /* GDTCORStorageEventSelector.m in Sources */, + 948EC119E467DCC735AF49A4636925A0 /* GDTCORTransformer.m in Sources */, + EAE37CF4772BAFD674FAEFEC92CB00F6 /* GDTCORTransport.m in Sources */, + 1301C1E90A36990079C201D51E94FE5A /* GDTCORUploadBatch.m in Sources */, + 527C5C9A44B32B8644E964996742D7D2 /* GDTCORUploadCoordinator.m in Sources */, + F7C8FF0DDF61B71E4B3BA2A79F0BFF1F /* GoogleDataTransport-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1A90623709CAD79BABF0960077965FF7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DF5BD1E9663A16B3F87DF6AAEBF6A8D9 /* FIRCoreDiagnostics.m in Sources */, + 76AE78B5CBE2112303D0B9CD1D4A5D85 /* firebasecore.nanopb.c in Sources */, + 03A2245681DDE936EFED41C4EC4E2413 /* FirebaseCoreDiagnostics-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CDA139BBB21CDB4D370AA725B42F730 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2271AECE865036AE13A3ED9736FB06E8 /* FirebaseStorage-dummy.m in Sources */, + C3FBE3E8B32D8563D2BA5755EE507762 /* FIRStorage.m in Sources */, + B02FB6DB95132E1D42F318F4E612B974 /* FIRStorageComponent.m in Sources */, + 7397DFEC139CDABF8CB5789951BDD66E /* FIRStorageConstants.m in Sources */, + 017FC76A8CAAD3A39931B5EFAEE8F881 /* FIRStorageDeleteTask.m in Sources */, + AD764AB0D5391E74186C7FFD145AB61D /* FIRStorageDownloadTask.m in Sources */, + F4BB4F154F7744A7D223165024CA476A /* FIRStorageErrors.m in Sources */, + BAB6B2212BFB6894F97DD45C157F82EC /* FIRStorageGetDownloadURLTask.m in Sources */, + 56220FCC40302B7D54214F0E8871880B /* FIRStorageGetMetadataTask.m in Sources */, + D6DD92622533BA664AF231CABBFECC6B /* FIRStorageListResult.m in Sources */, + 0BE6F49DC5D49B5120727BC3DD4AEB77 /* FIRStorageListTask.m in Sources */, + 3105ECCF3D4F52E7930D9A34EAB09E4F /* FIRStorageLogger.m in Sources */, + 70A52996349B60E0C637D744305677C3 /* FIRStorageMetadata.m in Sources */, + A962CC9503BC18B8D19D8558B72742F7 /* FIRStorageObservableTask.m in Sources */, + 964ABA6B10275C7E330A0D309950289D /* FIRStoragePath.m in Sources */, + 9EAEC5A0C55761EF5A63A372673A78E3 /* FIRStorageReference.m in Sources */, + D2AE1D75C11C565C8DD366CC7733E668 /* FIRStorageTask.m in Sources */, + 0DBA0C8D5C80C009FA5BFF953DCC786F /* FIRStorageTaskSnapshot.m in Sources */, + 90C2795D5858544C6636A77AE6BB9088 /* FIRStorageTokenAuthorizer.m in Sources */, + C7CD10F59FD55CF5279D11DADB5E1E27 /* FIRStorageUpdateMetadataTask.m in Sources */, + 330F4E68C30A3B7FBE048A09D3193376 /* FIRStorageUploadTask.m in Sources */, + 9F76C947C77B8723023D491F27C9F0D6 /* FIRStorageUtils.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6D6811B124506D46F6C8EDF3409A50F3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 765F1A85400A99B67576382E569A9972 /* APLevelDB.mm in Sources */, + 0BFDCA8A93CE5D68C3B133E904258E87 /* FAckUserWrite.m in Sources */, + A032C28EE93C9DF961E1FA7BC1F33526 /* FArraySortedDictionary.m in Sources */, + A17B06B481158F43A12DD588A6ECF79D /* FAtomicNumber.m in Sources */, + 2C41315DBB9CE0D68B3AB4317D260D89 /* fbase64.c in Sources */, + 7E3600898B2058A29ACC86B5A6013B5F /* FCacheNode.m in Sources */, + 7D813D99BD9C92C5CD4129300C5AC498 /* FCachePolicy.m in Sources */, + 404163498D0820368DEA729341FA7C11 /* FCancelEvent.m in Sources */, + 19F751AA15289FCBB3B7383A538BEA07 /* FChange.m in Sources */, + 575446EDA5833B9BFB7996F3450101CD /* FChildChangeAccumulator.m in Sources */, + E065D09B532FC0101947B7995808A409 /* FChildEventRegistration.m in Sources */, + 845C86D673765B84369EA75ED1C27476 /* FChildrenNode.m in Sources */, + AF62E045B3D6B1D77B0C924A0425C7A2 /* FClock.m in Sources */, + F1071EDACCB6BA39951ADE36C88C8A01 /* FCompoundHash.m in Sources */, + 46F87315A3677964D8B9C2DA2CE41CFA /* FCompoundWrite.m in Sources */, + F271C03971AC5CE29FADBA38397BD038 /* FConnection.m in Sources */, + 6253AB48F6EC0AE958CA1B9469A64C71 /* FConstants.m in Sources */, + 3372B0AA899112C0E54EA42D202A35E9 /* FDataEvent.m in Sources */, + FDEE3281E745802214A26F1EEB91A414 /* FEmptyNode.m in Sources */, + D7B239A33F49499F91052059EEE0DB61 /* FEventEmitter.m in Sources */, + E5BBF211DB1D35E120279AF32B411374 /* FEventGenerator.m in Sources */, + D8220CF3253C9D0B3B3A47CEF7A4AC3A /* FEventRaiser.m in Sources */, + FD7FDDB9112DDE055134DFD0241426AA /* FImmutableSortedDictionary.m in Sources */, + 18F29E47671D54D44ED42A2AFE479FC3 /* FImmutableSortedSet.m in Sources */, + 9B6E962EB5B8EF07974D3E49CA7136E1 /* FImmutableTree.m in Sources */, + 83E4DF34F5C45E17F19AE7215F8ECD48 /* FIndex.m in Sources */, + C15048B150D27AC9A2911992961F0D19 /* FIndexedFilter.m in Sources */, + 14D0F96DBEF7812AD6955EB2E7295BC1 /* FIndexedNode.m in Sources */, + 997C6F4200D2C4B6D9448E2D03348CCE /* FIRDatabase.m in Sources */, + 3E6B4D3C66796EB7765B8C1E8DB4E5B9 /* FIRDatabaseComponent.m in Sources */, + 434E2B0D588A666BACCB686DEA2B41DD /* FIRDatabaseConfig.m in Sources */, + 896F863E67F27EAA3DFF0D1549F76F6F /* FIRDatabaseConnectionContextProvider.m in Sources */, + 8C75B4E09A6E9E6E3668E763066434FA /* FIRDatabaseQuery.m in Sources */, + 88FCE7252AB682CC6F73DD96624930A8 /* FIRDatabaseReference.m in Sources */, + 82FB414CA71D1A4977412181A6C8668C /* FIRDataSnapshot.m in Sources */, + 7F6A49312DE0FEEA8670C33BB7C8FCD7 /* FirebaseDatabase-dummy.m in Sources */, + 7C9FB6475EDF8467952C11002E43B5C1 /* FIRMutableData.m in Sources */, + 0DCAD134935C2C1F89B399FE3A174A8F /* FIRRetryHelper.m in Sources */, + 4690F1FED12CEC922DDB6BE8EBF6A73B /* FIRServerValue.m in Sources */, + 14004F9876E592CF3971A3FB0413585D /* FIRTransactionResult.m in Sources */, + 9526755F9FD25D5080DF620EA5A1FC5B /* FKeepSyncedEventRegistration.m in Sources */, + C8BCABB8A2D71683AC3A7B9E3EEE3DB7 /* FKeyIndex.m in Sources */, + 68C9F99D0E1EB247247E7CC741EDCE29 /* FLeafNode.m in Sources */, + D1986F0BBE69E4BFE273DBF515E54786 /* FLevelDBStorageEngine.m in Sources */, + 2302A161C2E053F44ECA86B69F579336 /* FLimitedFilter.m in Sources */, + 7C36F8DD3064D160FB7149D357F3CD87 /* FListenComplete.m in Sources */, + C9402F165499D55858F5C915929A4AC0 /* FListenProvider.m in Sources */, + CB50B470D6EBE84A11C92E3280C0436C /* FLLRBEmptyNode.m in Sources */, + 39655CFB325519B069E4F520C4918852 /* FLLRBValueNode.m in Sources */, + 3570758C30D862D40FB420A986C9939E /* FMaxNode.m in Sources */, + 25C3E2A6B7FED090018299891019A38A /* FMerge.m in Sources */, + D7100BF0D1835C402E4DFFB82DAEF21F /* FNamedNode.m in Sources */, + 1E17B461DE251C9B6F1FA562DC7A8458 /* FNextPushId.m in Sources */, + 3C989AB29293B1AE39987F7B10D50C12 /* FOperationSource.m in Sources */, + B1E22EFBE7A18A107CB8B080CCEF3C45 /* FOverwrite.m in Sources */, + 5AB0712C9E382FA2433264E108A3A25F /* FParsedUrl.m in Sources */, + 032F415D2387802BB88D8D8B7E762006 /* FPath.m in Sources */, + DC9B237AFA813047F87DB936973435FE /* FPathIndex.m in Sources */, + 3CB5719F46E10DEE2058AD808BE6D9B1 /* FPendingPut.m in Sources */, + E16954B672CF8317F31A5D91D9D3C565 /* FPersistenceManager.m in Sources */, + DBB0561A746EFF3AFC734E061D0AC32C /* FPersistentConnection.m in Sources */, + 8D4A065A5FE18A77C437F63675CE5BC6 /* FPriorityIndex.m in Sources */, + 7B982C6250B9F6A3033B02685F010590 /* FPruneForest.m in Sources */, + 4932F067F6F168B31D602D275969A184 /* FQueryParams.m in Sources */, + 75824117DB3AEA2D0E30E6157B4654CB /* FQuerySpec.m in Sources */, + AF1EC2D893B1469BD782FD2D9DB48A28 /* FRangedFilter.m in Sources */, + DF2F9FEB4F4019602C85B9DA0CDEEC64 /* FRangeMerge.m in Sources */, + 2D4526FBB219EF8BD8E3B044466EF591 /* FRepo.m in Sources */, + 84B9473B74CE8DD54941D7A03B160895 /* FRepoInfo.m in Sources */, + 359C4AFAB4CB12A50BD17CD32F0B702F /* FRepoManager.m in Sources */, + 41FA6A18DB6685F8A2E288D3E5510C47 /* FServerValues.m in Sources */, + 087074B8503FF61B5BA51AC409255283 /* FSnapshotHolder.m in Sources */, + 8A8908AA3F89244EFF01B5C6CFC2B4AE /* FSnapshotUtilities.m in Sources */, + 8D626225F9AE2D98416282F2BDEA26C3 /* FSparseSnapshotTree.m in Sources */, + 9A475899EBC2C5CBEC957510DC7F1D80 /* FSRWebSocket.m in Sources */, + AEB4611A733BD69C755AEA8B9DA27DB8 /* FStringUtilities.m in Sources */, + 3F19D09BDB49AB424E546489835ECDAB /* FSyncPoint.m in Sources */, + 8A3ACA70369FD7CD07746EB652CBF841 /* FSyncTree.m in Sources */, + 1E140DDC2E8894E371E778AC3120DE9A /* FTrackedQuery.m in Sources */, + BD305E0759965D608D0E31B92349F585 /* FTrackedQueryManager.m in Sources */, + E74F94588B8C7F5B7AB3986D7ABC96E4 /* FTransformedEnumerator.m in Sources */, + 98A2F4537B02F1D78E793955B8DBEF28 /* FTree.m in Sources */, + ACDD46248AC4A90760036423CF1F8A56 /* FTreeNode.m in Sources */, + A30466BAA21728774E49A960C85F7B9A /* FTreeSortedDictionary.m in Sources */, + B61D69DCFAD6E8012B0579E17504C8DD /* FTreeSortedDictionaryEnumerator.m in Sources */, + 63CA3834470B3A2EDE6EC9143A4AEEF1 /* FTupleBoolBlock.m in Sources */, + F29FF6369D8D010F9ADF4CFFAB600FDC /* FTupleCallbackStatus.m in Sources */, + 82A793EAA095E4ECDCEAFACE9FD08C6F /* FTupleFirebase.m in Sources */, + 6D6A2333C5E7DD95CE37F1DDAC75FD06 /* FTupleNodePath.m in Sources */, + 4AEBC6ECFAE24CF92AA8FFA5E34FEF6A /* FTupleObjectNode.m in Sources */, + 182F5009696A6603F30EE00CE08F56EA /* FTupleObjects.m in Sources */, + 8D5D3323F9C4566FCA2CC7C6500CB7DD /* FTupleOnDisconnect.m in Sources */, + DF1C0C13094591C04536CC2881E673B4 /* FTuplePathValue.m in Sources */, + B72F55435B9C6CB06083E13D6665F40A /* FTupleRemovedQueriesEvents.m in Sources */, + AC3EF2A397AF4C794642F1C5C8A25671 /* FTupleSetIdPath.m in Sources */, + F7FAAE40AFA76716EE0B4EA4657FEC5F /* FTupleStringNode.m in Sources */, + B2BC0CD6B278E9320C111E67490609EB /* FTupleTransaction.m in Sources */, + 72C5FBC8B9ED1885E1E7CE2DD89ADDFF /* FTupleTSN.m in Sources */, + 3A2F0C67E9233CC78F946499B0A8A217 /* FTupleUserCallback.m in Sources */, + 72F4F980A56274C51D938593FDE57EDF /* FUtilities.m in Sources */, + 94F4C13BDBFFB1CA1E8F8B9DC83D60C6 /* FValidation.m in Sources */, + 95A247CC80E3EB7AC11BCF40F0834F7E /* FValueEventRegistration.m in Sources */, + 12E6CEEB0D6E10BA1C3E75D613609C03 /* FValueIndex.m in Sources */, + D5B6B157E13AA27ADB87E34A3339E67D /* FView.m in Sources */, + BD7D262468B0C6C4E0AD0C6E8D0A9D39 /* FViewCache.m in Sources */, + A6056E88E32AD462E6BED36F9564BC30 /* FViewProcessor.m in Sources */, + AB8234A3C959B0965FAE3C29D86DCE16 /* FViewProcessorResult.m in Sources */, + 543F33C26FF8B3B22D1EBA874B7B8D15 /* FWebSocketConnection.m in Sources */, + E192AAE3C2E9C093F032A3C97B3EAD5D /* FWriteRecord.m in Sources */, + 41EA43D95F45177AA1BC1AEEE89C81B5 /* FWriteTree.m in Sources */, + 81AB97AF31AF1535F743922CBB797777 /* FWriteTreeRef.m in Sources */, + C55B5EF82F094F12A583069B9EBA9B70 /* NSData+SRB64Additions.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AA41EC178BB7671D18FBF918B7942780 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BCCB46EB32A9E24902524A998C4B5584 /* FIRAnalyticsConfiguration.m in Sources */, + 2F97631700959223AE6EBFD09AB344EB /* FIRApp.m in Sources */, + 7AE56FDB079D733CB05F64F0E662E9F5 /* FIRAppAssociationRegistration.m in Sources */, + 6F57C9DEBE484729475F1DEC6154B4E6 /* FIRBundleUtil.m in Sources */, + 00441B1F2F7E37B3F539A558956EFBF5 /* FIRComponent.m in Sources */, + E76C5D45261CCB5439F7F863F5F7CD04 /* FIRComponentContainer.m in Sources */, + F2FACCE09C3F3900E03111D4A942EBF2 /* FIRComponentType.m in Sources */, + 60BA97B8834498ADE5023FC7DAD2EBCD /* FIRConfiguration.m in Sources */, + 0C5317CF34D88C5F27BC8A41B17D9CC4 /* FIRCoreDiagnosticsConnector.m in Sources */, + D4FB0D111E3FCD4CC9DF4C2B5CD03885 /* FIRDependency.m in Sources */, + 3B9841EBFA524494AF3C7CCD7300825D /* FIRDiagnosticsData.m in Sources */, + E11ED6EE81AD639DAA965CB3BE20B446 /* FirebaseCore-dummy.m in Sources */, + 1A5C03846C5719D86BCAE60F1F6A785D /* FIRFirebaseUserAgent.m in Sources */, + F22B5419E9003421796BCFE4BE3306B5 /* FIRHeartbeatInfo.m in Sources */, + 09D63733A04735D72560A28859B32A8E /* FIRLogger.m in Sources */, + 5B1372FE89C5FD1CE1FC20060EB7B0DA /* FIROptions.m in Sources */, + 3F8CF7CBEF48B8FFA875E0EC4A521C6C /* FIRVersion.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BB148065C5B367118820236ADD533EBB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D4C5D302824251B2B21AE98658F328C0 /* FBLPromise.m in Sources */, + BBCFF4694A34B0BC29020592E3C5E91A /* FBLPromise+All.m in Sources */, + 2A72AC548CBABC42B601AFB8BC4163CB /* FBLPromise+Always.m in Sources */, + B8D1B1A447AC953BF707719698BE4F24 /* FBLPromise+Any.m in Sources */, + FA94D9DC939A04D35D1634AC721E87F4 /* FBLPromise+Async.m in Sources */, + 6D061BDBC2E0310C7648D3417594E229 /* FBLPromise+Await.m in Sources */, + 69DC2A9F6509B50FDF64F9C216069134 /* FBLPromise+Catch.m in Sources */, + 478BE3B492B4F334DA5B0AAF7580BD96 /* FBLPromise+Delay.m in Sources */, + C40A24EC73BA5696B23A9EE559F2EBAD /* FBLPromise+Do.m in Sources */, + BB6C989703542377BA56A5B8659C7C95 /* FBLPromise+Race.m in Sources */, + A8D7F7255B740EE0753FA6B5C5116976 /* FBLPromise+Recover.m in Sources */, + 4B2DAC9546BCDCD5FF1BE8A47C6DAC8D /* FBLPromise+Reduce.m in Sources */, + 86CC8FA2A361B3AC6266A57E7013AB7E /* FBLPromise+Retry.m in Sources */, + CF2AD4472ACC9EC61D962CC6B6265DD5 /* FBLPromise+Testing.m in Sources */, + D32D19A4DCDEE3E3C0E64880A091B011 /* FBLPromise+Then.m in Sources */, + 03CB74334AA7FFA8BF44063D2D39EEBE /* FBLPromise+Timeout.m in Sources */, + F1E78E4BE10C1B0FA712035CDF29E63B /* FBLPromise+Validate.m in Sources */, + 5352601D1BA065C5DF9C6448EC197595 /* FBLPromise+Wrap.m in Sources */, + CF9359A9819113A07B6258E3DFDE0780 /* FBLPromiseError.m in Sources */, + 1C3A93DF5071A40B5896A1442F81FDE5 /* PromisesObjC-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BE3EBB685B04AF036B951B440D3EA9F8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A9A7BC87548A483EBCB078708A62D14F /* nanopb-dummy.m in Sources */, + 167E2ED6C3D82E1176811283BA2094F5 /* pb_common.c in Sources */, + 17CC1D21750D15D3B526CF6D8F17E291 /* pb_decode.c in Sources */, + AFFBBA38004514281DFBE8BCCDBFC499 /* pb_encode.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CBE35D1A182A5B79E6DCEFD11E050663 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 079AADE89F4CAB46622CA4A8A865D34A /* GTMSessionFetcher.m in Sources */, + 6962B76E990566CA13B470EE1130E7C2 /* GTMSessionFetcher-dummy.m in Sources */, + 21436097817C9C7C2E0ED524C5C9B25E /* GTMSessionFetcherLogging.m in Sources */, + 3AA7566EEC0DC99AA661AC7BFB5BF31A /* GTMSessionFetcherService.m in Sources */, + 43A30D94083E44E1F1C93C359017E2C8 /* GTMSessionUploadFetcher.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DCEC0841BA916251FCBE1A199CF9268F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 191D3D7482F908A17BE973DB5B225661 /* arena.cc in Sources */, + 89103EC97A6B11F06DFFF3AEC331E05B /* block.cc in Sources */, + EBCBFBBCD3C06237EA6012DF9EB06182 /* block_builder.cc in Sources */, + 1CAD0A2C66E9A998AC818F7F4786FB8E /* bloom.cc in Sources */, + 5B0A142FDBF995D8E4AC243E0D1ED7D5 /* builder.cc in Sources */, + C134C09ACCA380020449862BDE7A0027 /* c.cc in Sources */, + 8D2DE777CC28353B240AD75391B5719A /* cache.cc in Sources */, + 3011994272318F5D1752BE484A812CE4 /* coding.cc in Sources */, + 5F551BF53EDDC2F198AC908DBC42E1F6 /* comparator.cc in Sources */, + 63AB34CB59ACAEDDA595EDF91BF8FDB1 /* crc32c.cc in Sources */, + 24699FD4161536D8449EDBB1E26100A9 /* db_impl.cc in Sources */, + 21DA0ED052218D23C276E23533319493 /* db_iter.cc in Sources */, + 2A4371FC7470C816E2D4F27401598109 /* dbformat.cc in Sources */, + F7ED8CD914AE49A13627556BD0A4F3A3 /* dumpfile.cc in Sources */, + 047D57E0721FF5ED4C3764B03F9B0032 /* env.cc in Sources */, + 680C99CBF3FFA946B0D6573BCA10A097 /* env_posix.cc in Sources */, + 41581AA344EA604C1A6E05A66770AB34 /* filename.cc in Sources */, + C7014B9B704B62751CB17B9A92036CE7 /* filter_block.cc in Sources */, + F331A2E53F59CA601620F3A75C80276D /* filter_policy.cc in Sources */, + 4BDC5BEB880CB70824A5BF415D1B4AE7 /* format.cc in Sources */, + 5B0EFE0A8BD311854B7E7DA6CF087198 /* hash.cc in Sources */, + C07C128E45C881057605D65DE7B3C7B8 /* histogram.cc in Sources */, + 35C9EAA14ED0932DEA18768DE71266B1 /* iterator.cc in Sources */, + 555190201D020AD45D745A0A3E088714 /* leveldb-library-dummy.m in Sources */, + 1DB975BA292FF3A41E3A113F94A2D594 /* log_reader.cc in Sources */, + 5594EB3D40CA11ACC2260C04E09A57F5 /* log_writer.cc in Sources */, + 5EDCFF0B8FF8BAC118B97D7A0C9EE4D2 /* logging.cc in Sources */, + E2806B51DBD95AC52C85D27E8FC92974 /* memtable.cc in Sources */, + A5B26244F8DF411FE1941B6B250887A2 /* merger.cc in Sources */, + 1FB4FE2D9F2F1F551798C360FAB20486 /* options.cc in Sources */, + 5BA4AEB9ACF731DB33AA25C7C0BA6420 /* repair.cc in Sources */, + 37F80B7AC810422C50AE42F80AE285A7 /* status.cc in Sources */, + 4712C4518C8F4EA3B14A783D24E60F96 /* table.cc in Sources */, + 29A67806B9BFEEB878F609E756B6289A /* table_builder.cc in Sources */, + 311B84FEC2C6165AF25B7B772BE18338 /* table_cache.cc in Sources */, + 92D78842802FAAEBD807246D070DDD9E /* testharness.cc in Sources */, + 74F74F232328099A92DBE70AD8D5B008 /* two_level_iterator.cc in Sources */, + 0A9141E06052B3C07F8083DA193FF6F2 /* version_edit.cc in Sources */, + E9D78DB10436001DC5906559BDA7345D /* version_set.cc in Sources */, + C93FF0CD7824C73523BF9D0317A0E4B6 /* write_batch.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E1D92C0D2D568335894CF224DF1EDFD2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 740135820DB418029232BACB1470FDFB /* Pods-saraWhatsUp-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E8F9859A97DB0783FB16DE7A599209E5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 62BC134F5E129851682E2B83446C82CE /* GoogleUtilities-dummy.m in Sources */, + DEF75A559FA8171C4661C1ABF27387C6 /* GULAppDelegateSwizzler.m in Sources */, + 70DEF84DC8BEF8FB292EF9E29C5A0F0F /* GULAppEnvironmentUtil.m in Sources */, + 0DA4DA5443A4A6CD5F0CC3A16EC22146 /* GULHeartbeatDateStorage.m in Sources */, + 049C8EA5F88E7C3DE6F510974196ADDF /* GULHeartbeatDateStorageUserDefaults.m in Sources */, + 97E3E024B11C53FBEA9C7E479C3AB5F7 /* GULKeychainStorage.m in Sources */, + 8861C1ECE26C3BB7606E1E749D322F21 /* GULKeychainUtils.m in Sources */, + B6E11C1ABF52EE75E6ED6912FCF2E0C0 /* GULLogger.m in Sources */, + 61E2DB574A18AE2C6D301B9FF657AEBB /* GULMutableDictionary.m in Sources */, + 02639C151CC5091634FA1BB5BA99B8CD /* GULNetwork.m in Sources */, + C950A66489D14C17FB5E9A46229F2935 /* GULNetworkConstants.m in Sources */, + C53BD5B9468D548C9F321DB406A2AAD3 /* GULNetworkURLSession.m in Sources */, + 56724F131CDCE6B877F2CC89195FD352 /* GULNSData+zlib.m in Sources */, + 4035F77D3A22F98815F808BEA74B2D0A /* GULReachabilityChecker.m in Sources */, + EA41CD95E22020D58A4C5FCF022FC174 /* GULSceneDelegateSwizzler.m in Sources */, + 6C84AB2FE56227E3CB6D7B77C85AB3D0 /* GULSecureCoding.m in Sources */, + 514DC3B501DCAB3718AEFA9542482B47 /* GULURLSessionDataResponse.m in Sources */, + C0EB9A1236CDA0B8873DB61249666620 /* NSURLSession+GULPromises.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 04E3FEAA9108DBC5578CC3FE44DBFE66 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GTMSessionFetcher; + target = D676E21115185671D7258A56944ABE98 /* GTMSessionFetcher */; + targetProxy = FECBB6C757065DC08E79F3662B8F88A4 /* PBXContainerItemProxy */; + }; + 06E0185D8C8E3C8A158B8C3A5F269786 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = nanopb; + target = D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */; + targetProxy = F18E7FBF39FF9F9F1EDA2644DA483EAC /* PBXContainerItemProxy */; + }; + 1D304EB5CA6B9AF59C604FA8C81FAD6C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCoreDiagnostics; + target = 620E05868772C10B4920DC7E324F2C87 /* FirebaseCoreDiagnostics */; + targetProxy = 1F6166552149452762F1E1B5F99C25ED /* PBXContainerItemProxy */; + }; + 1DAF02A7444F79E7F34886AB98947102 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 91F232AD1BA09F4868F0E4904046F26E /* PBXContainerItemProxy */; + }; + 1F1D58F475282ED7D8B74E77816DA762 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseDatabase; + target = 736AF68F6527ACF6B4A4C54728824A1C /* FirebaseDatabase */; + targetProxy = C6E808461B0093E1F31C36B97E1EC639 /* PBXContainerItemProxy */; + }; + 1FAD10F2ADDA7371BE117ED09AE8A2C2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAuth; + target = 6AE4A3D573DED275B034E20506596C62 /* FirebaseAuth */; + targetProxy = D63595C6316C71F11E47E6C6141EBD2B /* PBXContainerItemProxy */; + }; + 2E970012EF70B1F30AE0A3B872FAE845 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleDataTransport; + target = 5C0371EE948D0357B8EE0E34ABB44BF0 /* GoogleDataTransport */; + targetProxy = C55870D10A2B6A8AFC8F92B1AE79A411 /* PBXContainerItemProxy */; + }; + 313E445DEA4F50A9991A18790CBEC815 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCoreDiagnostics; + target = 620E05868772C10B4920DC7E324F2C87 /* FirebaseCoreDiagnostics */; + targetProxy = 21FF479D036F39B4A377FCAB253F6FDF /* PBXContainerItemProxy */; + }; + 365FC54401A0211CD260DEFB5F5BCCC9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 6EE7768875FA3C3DA32788B5154C2542 /* PBXContainerItemProxy */; + }; + 3C06305162A11FE501B03032B5A80C84 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = B3ADDF90A3EEE0CBAE2BA87E3A2FE1F1 /* PBXContainerItemProxy */; + }; + 40F4BB26427733FA9181463D32F4A523 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 5B459D35C2F52F6CAB89E2AFF8E67681 /* PBXContainerItemProxy */; + }; + 4654BF4CE1805B5DA618B081210CFB2F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = 068109FB101AF2DF8EFB1D2B0BFD9FC1 /* PBXContainerItemProxy */; + }; + 4A85BEA2E67123EF3ECBA12CB1E92C67 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseStorage; + target = 23E7C4A52360C026F97E4A96D91B03CE /* FirebaseStorage */; + targetProxy = 8B24FC45F289EBE4D7BDD409C070D853 /* PBXContainerItemProxy */; + }; + 535FB6010AA026EEA4482967FC0F4C0F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "leveldb-library"; + target = 9307B7A119490930CF70393AB529AAC1 /* leveldb-library */; + targetProxy = 0039D1FC45AE117EFAC3EA76115AA794 /* PBXContainerItemProxy */; + }; + 567468EE0FB2126B97D213CA5CE4B497 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAuth; + target = 6AE4A3D573DED275B034E20506596C62 /* FirebaseAuth */; + targetProxy = 55C5159A2E28785F579342492CF8CB4A /* PBXContainerItemProxy */; + }; + 5A9BD4197B533664764E6318BA949347 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = E2D756F966650B368D3D2843C66A1A3B /* PBXContainerItemProxy */; + }; + 631692E880153D2CF3FFB622D6AD1648 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = nanopb; + target = D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */; + targetProxy = 1B4D34C5D204EE17B15C4BB0E90E4977 /* PBXContainerItemProxy */; + }; + 65673B1B86ECF9A3DB29FE2EE72C56B3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GTMSessionFetcher; + target = D676E21115185671D7258A56944ABE98 /* GTMSessionFetcher */; + targetProxy = 618532CFB81B9E8D6011AB704FFC6E1F /* PBXContainerItemProxy */; + }; + 676F88BBFB075EF3B710F0A42509E57A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PromisesObjC; + target = 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */; + targetProxy = 943DE89A070FEE11065D1A77CD396E61 /* PBXContainerItemProxy */; + }; + 67B7F8D7F211D4673775E9B7BBDB9CFC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = 77C27BFD921CF2C54EBF77F5011AACB6 /* PBXContainerItemProxy */; + }; + 6F755F56BFA1B4D1973DB7DD4EEAFDB6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "leveldb-library"; + target = 9307B7A119490930CF70393AB529AAC1 /* leveldb-library */; + targetProxy = 9B9016F1CFBF6136DDD385802B8500A1 /* PBXContainerItemProxy */; + }; + 92CDC77EF8013E7CF3E7821256A1E556 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PromisesObjC; + target = 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */; + targetProxy = 0DC214B31BED7E8AFD6FCD8F29B5F7E8 /* PBXContainerItemProxy */; + }; + 96A4979FD7D11C6142FB66F6FE62AAA0 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseDatabase; + target = 736AF68F6527ACF6B4A4C54728824A1C /* FirebaseDatabase */; + targetProxy = 4AFF0692751D81CF6C455BE917797094 /* PBXContainerItemProxy */; + }; + 9836C91E1910DD22BE569755415B25BE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleDataTransport; + target = 5C0371EE948D0357B8EE0E34ABB44BF0 /* GoogleDataTransport */; + targetProxy = E7DDC8831E140251F0308321E8DC7DF1 /* PBXContainerItemProxy */; + }; + CE8AD85CF057AC596368A8A93DBC58EA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = nanopb; + target = D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */; + targetProxy = 47DE645704CB21514D16F705FFE571DA /* PBXContainerItemProxy */; + }; + CF832150363A02D97AB0BF59BCB5421B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Firebase; + target = 072CEA044D2EF26F03496D5996BBF59F /* Firebase */; + targetProxy = FD4F0BD27C60009A5D24D74ECEB38198 /* PBXContainerItemProxy */; + }; + D5FF9C0807CE1A53CF45849BBC3F74F8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GTMSessionFetcher; + target = D676E21115185671D7258A56944ABE98 /* GTMSessionFetcher */; + targetProxy = 7471C818C9AC163CF1477F4D461FCFBE /* PBXContainerItemProxy */; + }; + E19DE2AE1B3DFC7A3DC96B1F66BF01AD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = EB214D8092C459994B327B14448BFAA7 /* PBXContainerItemProxy */; + }; + E856BB4009034B5E9FB68B65CF3B6355 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 7C82CCF17BB0C84E09F48FFA457AC415 /* PBXContainerItemProxy */; + }; + F25DA974AB9089B1C8C8C729256426F7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PromisesObjC; + target = 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */; + targetProxy = 2727A0893CA5320676761CF88ADECCE1 /* PBXContainerItemProxy */; + }; + F6664C5F2396BFD8035EAD477E1DD87C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = DFF7FFF85F84655DCDAADCB5A3129EE6 /* PBXContainerItemProxy */; + }; + F9C5F9DE3BCD6C9993F1F78AC8E56FB7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseStorage; + target = 23E7C4A52360C026F97E4A96D91B03CE /* FirebaseStorage */; + targetProxy = AEB825C55B5967AB91433DE739FAC516 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 0A5E6A10E2977DD3B5422063713EF41D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 22ACFD8A65A5EDB477F1472FAB19B5DC /* GTMSessionFetcher.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap"; + PRODUCT_MODULE_NAME = GTMSessionFetcher; + PRODUCT_NAME = GTMSessionFetcher; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 0C0F8B9C60399D46F61D5AC32E718E9B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 00107F5D3773418497630039D598AABF /* FirebaseCore.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseCore/FirebaseCore-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCore/FirebaseCore.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCore; + PRODUCT_NAME = FirebaseCore; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 32FED417944A0FF5DD64582C56CCA725 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 77E9E4BDDA17F583BD30ED9F9BD9E915 /* FirebaseAuth.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseAuth/FirebaseAuth-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseAuth/FirebaseAuth.modulemap"; + PRODUCT_MODULE_NAME = FirebaseAuth; + PRODUCT_NAME = FirebaseAuth; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 35446697282B601B950218FC59B931FD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1BECDD459D9B73BE4F02893E75E11FE2 /* Firebase.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 37A21290DC61B629DF1213DD0DFF2953 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2F6B0DD02D0223F2F0DD71412C7EB585 /* GoogleDataTransport.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap"; + PRODUCT_MODULE_NAME = GoogleDataTransport; + PRODUCT_NAME = GoogleDataTransport; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 3E36B8A363A210501D62056109A36096 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8A19AACF745587E8B91E0E6FACA7BF1E /* FirebaseDatabase.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseDatabase/FirebaseDatabase-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseDatabase/FirebaseDatabase.modulemap"; + PRODUCT_MODULE_NAME = FirebaseDatabase; + PRODUCT_NAME = FirebaseDatabase; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 3FC68984CFFB1B36597052F947A9ADD8 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6E38458165FD4E6AD15616E1CA142196 /* Pods-saraWhatsUp.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 49F36D40148ED84C4B961B78A7A19D7C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EB05B29EAFF925C4D8F7F10CFC02EBD4 /* FirebaseCore.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseCore/FirebaseCore-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCore/FirebaseCore.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCore; + PRODUCT_NAME = FirebaseCore; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 4A46C15F78A76D883AC00DF00BFE9760 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 28E9C68290B23C26900DBEA3E551D14E /* nanopb.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/nanopb/nanopb-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/nanopb/nanopb-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/nanopb/nanopb.modulemap"; + PRODUCT_MODULE_NAME = nanopb; + PRODUCT_NAME = nanopb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 56762CBB4597619A257171BF0A27B747 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 355434705FF7B7073A4B9D11E25224D7 /* leveldb-library.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/leveldb-library/leveldb-library-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/leveldb-library/leveldb-library-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/leveldb-library/leveldb-library.modulemap"; + PRODUCT_MODULE_NAME = leveldb; + PRODUCT_NAME = leveldb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 5D42586E843D7488AB82AE40846D8C8A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 51DADC6EA95F8D9FE2935B2D17FFF724 /* GoogleDataTransport.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap"; + PRODUCT_MODULE_NAME = GoogleDataTransport; + PRODUCT_NAME = GoogleDataTransport; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 63A331C5F84C5C42E64E7BF004C78BA2 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EAE2BBC91837C345D7F66F7B6DCB8D13 /* FirebaseCoreDiagnostics.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCoreDiagnostics; + PRODUCT_NAME = FirebaseCoreDiagnostics; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 702BE0BFB8C7B86CE2BC91D443F932AB /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D77FC63C6A5F4F440E4C6041694A5B6A /* nanopb.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/nanopb/nanopb-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/nanopb/nanopb-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/nanopb/nanopb.modulemap"; + PRODUCT_MODULE_NAME = nanopb; + PRODUCT_NAME = nanopb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 73E0CD04B1C27093A044A506C976E0B2 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 044F6E5467DFFE0E5874B2368601CF31 /* FirebaseStorage.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseStorage/FirebaseStorage-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseStorage/FirebaseStorage.modulemap"; + PRODUCT_MODULE_NAME = FirebaseStorage; + PRODUCT_NAME = FirebaseStorage; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 7534D8CFD6FC8C479BA58BA9B6AEC297 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ECAADF3C6E648C2ED2FE2BE67E6AA1A5 /* Pods-saraWhatsUp.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 83F724F2AB40FC0B9A23CBEAA1C42DE0 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ACFA9A512528EAD2FCC4355818A33CD3 /* PromisesObjC.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/PromisesObjC/PromisesObjC-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/PromisesObjC/PromisesObjC.modulemap"; + PRODUCT_MODULE_NAME = FBLPromises; + PRODUCT_NAME = FBLPromises; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 84DF175ACF4AE2393BCD885D01B96868 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C661AC8E9FEAADAC1C40F825A2137419 /* GoogleUtilities.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities.modulemap"; + PRODUCT_MODULE_NAME = GoogleUtilities; + PRODUCT_NAME = GoogleUtilities; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 858CCC0B7B2C7B2AD3FBF1EFC128F845 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C61B106681E3099B5B9744CA4BD8C8BB /* GTMSessionFetcher.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap"; + PRODUCT_MODULE_NAME = GTMSessionFetcher; + PRODUCT_NAME = GTMSessionFetcher; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 90D4D09BCB6A4660E43ACBE9ECB6FE9A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 95092B019D0F7174B54A0A29B7281207 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C9FFBCDFEBF380E250E116854F608812 /* FirebaseAuth.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseAuth/FirebaseAuth-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseAuth/FirebaseAuth.modulemap"; + PRODUCT_MODULE_NAME = FirebaseAuth; + PRODUCT_NAME = FirebaseAuth; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 9553C89E183877A5CB2F3C6801BEC129 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Release; + }; + A9D7DFE832E1FD5F3E6AA70380EC8F50 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 663C76ADAD38564E75D41755802032D1 /* leveldb-library.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/leveldb-library/leveldb-library-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/leveldb-library/leveldb-library-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/leveldb-library/leveldb-library.modulemap"; + PRODUCT_MODULE_NAME = leveldb; + PRODUCT_NAME = leveldb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + D0FDC05001B087C8D54C720E3F9C1D9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 173AF725A61B69DB8626BC934E56526F /* FirebaseDatabase.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseDatabase/FirebaseDatabase-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseDatabase/FirebaseDatabase.modulemap"; + PRODUCT_MODULE_NAME = FirebaseDatabase; + PRODUCT_NAME = FirebaseDatabase; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + DDCF2EB12E4C919832D4FE847D531DB6 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A7133D98A56EE451D8DD163BAB3BBB28 /* FirebaseStorage.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseStorage/FirebaseStorage-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseStorage/FirebaseStorage.modulemap"; + PRODUCT_MODULE_NAME = FirebaseStorage; + PRODUCT_NAME = FirebaseStorage; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + E3FE6477EEEE4166AFF4CA02DDE9B1AF /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EC25C893E42AF2D5B65AB06457AAC348 /* PromisesObjC.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/PromisesObjC/PromisesObjC-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/PromisesObjC/PromisesObjC.modulemap"; + PRODUCT_MODULE_NAME = FBLPromises; + PRODUCT_NAME = FBLPromises; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + E7CAA0AA46AC5C3EA670B685EB6B0D37 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2B98F9FAC4E46C99230030CD824F79A4 /* FirebaseCoreDiagnostics.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCoreDiagnostics; + PRODUCT_NAME = FirebaseCoreDiagnostics; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + F1349F0545F70B5A904570DF46F0B04C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B9DF6D4C0C68854AF972C290CF88B7A0 /* GoogleUtilities.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities.modulemap"; + PRODUCT_MODULE_NAME = GoogleUtilities; + PRODUCT_NAME = GoogleUtilities; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + FF5AE1A9487EA62F9260F79C907E6BC5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 70998E41522AEE00454C7810173EB2F3 /* Firebase.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 11CF5C560B12D8F76442A91FAFDD07EB /* Build configuration list for PBXNativeTarget "GoogleUtilities" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 84DF175ACF4AE2393BCD885D01B96868 /* Debug */, + F1349F0545F70B5A904570DF46F0B04C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 90D4D09BCB6A4660E43ACBE9ECB6FE9A /* Debug */, + 9553C89E183877A5CB2F3C6801BEC129 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6733F52BE3660369DC2674736EE30AB5 /* Build configuration list for PBXAggregateTarget "Firebase" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 35446697282B601B950218FC59B931FD /* Debug */, + FF5AE1A9487EA62F9260F79C907E6BC5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 68E7FD26B070FBFCEC3C556599258FC7 /* Build configuration list for PBXNativeTarget "nanopb" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 702BE0BFB8C7B86CE2BC91D443F932AB /* Debug */, + 4A46C15F78A76D883AC00DF00BFE9760 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6F54AD43C735E58F79F4B5F731D63AEA /* Build configuration list for PBXNativeTarget "Pods-saraWhatsUp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3FC68984CFFB1B36597052F947A9ADD8 /* Debug */, + 7534D8CFD6FC8C479BA58BA9B6AEC297 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 87045C3ACA8836F42AED6B5CF7B938C4 /* Build configuration list for PBXNativeTarget "PromisesObjC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E3FE6477EEEE4166AFF4CA02DDE9B1AF /* Debug */, + 83F724F2AB40FC0B9A23CBEAA1C42DE0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 986F1AA400CD9818F8136AABFA142C08 /* Build configuration list for PBXNativeTarget "GoogleDataTransport" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5D42586E843D7488AB82AE40846D8C8A /* Debug */, + 37A21290DC61B629DF1213DD0DFF2953 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B63C58730E117135DD12AD9D422458D4 /* Build configuration list for PBXNativeTarget "FirebaseCoreDiagnostics" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 63A331C5F84C5C42E64E7BF004C78BA2 /* Debug */, + E7CAA0AA46AC5C3EA670B685EB6B0D37 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BA3465076324B082765EC249969C880E /* Build configuration list for PBXNativeTarget "FirebaseCore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0C0F8B9C60399D46F61D5AC32E718E9B /* Debug */, + 49F36D40148ED84C4B961B78A7A19D7C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BA4EF57DE1E6A2DA36BFC921B39A085A /* Build configuration list for PBXNativeTarget "FirebaseStorage" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 73E0CD04B1C27093A044A506C976E0B2 /* Debug */, + DDCF2EB12E4C919832D4FE847D531DB6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C9A3516B1C68CBE1587C9F50C2E1E7DE /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0A5E6A10E2977DD3B5422063713EF41D /* Debug */, + 858CCC0B7B2C7B2AD3FBF1EFC128F845 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D520B9DB9F6D9A03F3AF3E561A87DDD6 /* Build configuration list for PBXNativeTarget "FirebaseDatabase" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3E36B8A363A210501D62056109A36096 /* Debug */, + D0FDC05001B087C8D54C720E3F9C1D9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EBF4DA5DA8DAA995C406178BDC05EDFA /* Build configuration list for PBXNativeTarget "leveldb-library" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 56762CBB4597619A257171BF0A27B747 /* Debug */, + A9D7DFE832E1FD5F3E6AA70380EC8F50 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F47BD23AA5943D62A6EA20D71F803485 /* Build configuration list for PBXNativeTarget "FirebaseAuth" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 32FED417944A0FF5DD64582C56CCA725 /* Debug */, + 95092B019D0F7174B54A0A29B7281207 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; +} diff --git a/saraWhatsUp/Pods/PromisesObjC/LICENSE b/saraWhatsUp/Pods/PromisesObjC/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/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/saraWhatsUp/Pods/PromisesObjC/README.md b/saraWhatsUp/Pods/PromisesObjC/README.md new file mode 100644 index 0000000..e0e65b7 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/README.md @@ -0,0 +1,60 @@ +[![Apache +License](https://img.shields.io/github/license/google/promises.svg)](LICENSE) +[![Travis](https://api.travis-ci.org/google/promises.svg?branch=master)](https://travis-ci.org/google/promises) +[![Gitter Chat](https://badges.gitter.im/google/promises.svg)](https://gitter.im/google/promises) + +![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20iOS%20%7C%20tvOS%20%7C%20watchOS-blue.svg?longCache=true&style=flat) +![Languages](https://img.shields.io/badge/languages-Swift%20%7C%20ObjC-orange.svg?longCache=true&style=flat) +![Package Managers](https://img.shields.io/badge/supports-Bazel%20%7C%20SwiftPM%20%7C%20CocoaPods%20%7C%20Carthage-yellow.svg?longCache=true&style=flat) + +# Promises + +Promises is a modern framework that provides a synchronization construct for +Objective-C and Swift to facilitate writing asynchronous code. + +* [Introduction](g3doc/index.md) + * [The problem with async + code](g3doc/index.md#the-problem-with-async-code) + * [Promises to the rescue](g3doc/index.md#promises-to-the-rescue) + * [What is a promise?](g3doc/index.md#what-is-a-promise) +* [Framework](g3doc/index.md#framework) + * [Features](g3doc/index.md#features) + * [Benchmark](g3doc/index.md#benchmark) +* [Getting started](g3doc/index.md#getting-started) + * [Add dependency](g3doc/index.md#add-dependency) + * [Import](g3doc/index.md#import) + * [Adopt](g3doc/index.md#adopt) +* [Basics](g3doc/index.md#basics) + * [Creating promises](g3doc/index.md#creating-promises) + * [Async](g3doc/index.md#async) + * [Do](g3doc/index.md#do) + * [Pending](g3doc/index.md#pending) + * [Resolved](g3doc/index.md#create-a-resolved-promise) + * [Observing fulfillment](g3doc/index.md#observing-fulfillment) + * [Then](g3doc/index.md#then) + * [Observing rejection](g3doc/index.md#observing-rejection) + * [Catch](g3doc/index.md#catch) +* [Extensions](g3doc/index.md#extensions) + * [All](g3doc/index.md#all) + * [Always](g3doc/index.md#always) + * [Any](g3doc/index.md#any) + * [AwaitPromise](g3doc/index.md#awaitpromise) + * [Delay](g3doc/index.md#delay) + * [Race](g3doc/index.md#race) + * [Recover](g3doc/index.md#recover) + * [Reduce](g3doc/index.md#reduce) + * [Retry](g3doc/index.md#retry) + * [Timeout](g3doc/index.md#timeout) + * [Validate](g3doc/index.md#validate) + * [Wrap](g3doc/index.md#wrap) +* [Advanced topics](g3doc/index.md#advanced-topics) + * [Default dispatch queue](g3doc/index.md#default-dispatch-queue) + * [Ownership and retain + cycles](g3doc/index.md#ownership-and-retain-cycles) + * [Testing](g3doc/index.md#testing) + * [Objective-C <-> Swift + interoperability](g3doc/index.md#objective-c---swift-interoperability) + * [Dot-syntax in Objective-C](g3doc/index.md#dot-syntax-in-objective-c) +* [Anti-patterns](g3doc/index.md#anti-patterns) + * [Broken chain](g3doc/index.md#broken-chain) + * [Nested promises](g3doc/index.md#nested-promises) diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m new file mode 100644 index 0000000..c21f30e --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m @@ -0,0 +1,86 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+All.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AllAdditions) + ++ (FBLPromise *)all:(NSArray *)promises { + return [self onQueue:self.defaultDispatchQueue all:promises]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue all:(NSArray *)allPromises { + NSParameterAssert(queue); + NSParameterAssert(allPromises); + + if (allPromises.count == 0) { + return [[FBLPromise alloc] initWithResolution:@[]]; + } + NSMutableArray *promises = [allPromises mutableCopy]; + return [FBLPromise + onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (NSUInteger i = 0; i < promises.count; ++i) { + id promise = promises[i]; + if ([promise isKindOfClass:self]) { + continue; + } else if ([promise isKindOfClass:[NSError class]]) { + reject(promise); + return; + } else { + [promises replaceObjectAtIndex:i + withObject:[[FBLPromise alloc] initWithResolution:promise]]; + } + } + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue + fulfill:^(id __unused _) { + // Wait until all are fulfilled. + for (FBLPromise *promise in promises) { + if (!promise.isFulfilled) { + return; + } + } + // If called multiple times, only the first one affects the result. + fulfill([promises valueForKey:NSStringFromSelector(@selector(value))]); + } + reject:^(NSError *error) { + reject(error); + }]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AllAdditions) + ++ (FBLPromise * (^)(NSArray *))all { + return ^(NSArray *promises) { + return [self all:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))allOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue all:promises]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m new file mode 100644 index 0000000..6927442 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m @@ -0,0 +1,58 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Always.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AlwaysAdditions) + +- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue always:work]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue always:(FBLPromiseAlwaysWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self chainOnQueue:queue + chainedFulfill:^id(id value) { + work(); + return value; + } + chainedReject:^id(NSError *error) { + work(); + return error; + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AlwaysAdditions) + +- (FBLPromise * (^)(FBLPromiseAlwaysWorkBlock))always { + return ^(FBLPromiseAlwaysWorkBlock work) { + return [self always:work]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseAlwaysWorkBlock))alwaysOn { + return ^(dispatch_queue_t queue, FBLPromiseAlwaysWorkBlock work) { + return [self onQueue:queue always:work]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m new file mode 100644 index 0000000..e101c98 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m @@ -0,0 +1,112 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Any.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +static NSArray *FBLPromiseCombineValuesAndErrors(NSArray *promises) { + NSMutableArray *combinedValuesAndErrors = [[NSMutableArray alloc] init]; + for (FBLPromise *promise in promises) { + if (promise.isFulfilled) { + [combinedValuesAndErrors addObject:promise.value ?: [NSNull null]]; + continue; + } + if (promise.isRejected) { + [combinedValuesAndErrors addObject:promise.error]; + continue; + } + assert(!promise.isPending); + }; + return combinedValuesAndErrors; +} + +@implementation FBLPromise (AnyAdditions) + ++ (FBLPromise *)any:(NSArray *)promises { + return [self onQueue:FBLPromise.defaultDispatchQueue any:promises]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue any:(NSArray *)anyPromises { + NSParameterAssert(queue); + NSParameterAssert(anyPromises); + + if (anyPromises.count == 0) { + return [[FBLPromise alloc] initWithResolution:@[]]; + } + NSMutableArray *promises = [anyPromises mutableCopy]; + return [FBLPromise + onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (NSUInteger i = 0; i < promises.count; ++i) { + id promise = promises[i]; + if ([promise isKindOfClass:self]) { + continue; + } else { + [promises replaceObjectAtIndex:i + withObject:[[FBLPromise alloc] initWithResolution:promise]]; + } + } + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue + fulfill:^(id __unused _) { + // Wait until all are resolved. + for (FBLPromise *promise in promises) { + if (promise.isPending) { + return; + } + } + // If called multiple times, only the first one affects the result. + fulfill(FBLPromiseCombineValuesAndErrors(promises)); + } + reject:^(NSError *error) { + BOOL atLeastOneIsFulfilled = NO; + for (FBLPromise *promise in promises) { + if (promise.isPending) { + return; + } + if (promise.isFulfilled) { + atLeastOneIsFulfilled = YES; + } + } + if (atLeastOneIsFulfilled) { + fulfill(FBLPromiseCombineValuesAndErrors(promises)); + } else { + reject(error); + } + }]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AnyAdditions) + ++ (FBLPromise * (^)(NSArray *))any { + return ^(NSArray *promises) { + return [self any:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))anyOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue any:promises]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m new file mode 100644 index 0000000..249158c --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m @@ -0,0 +1,70 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Async.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AsyncAdditions) + ++ (instancetype)async:(FBLPromiseAsyncWorkBlock)work { + return [self onQueue:self.defaultDispatchQueue async:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue async:(FBLPromiseAsyncWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[FBLPromise alloc] initPending]; + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + work( + ^(id __nullable value) { + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }, + ^(NSError *error) { + [promise reject:error]; + }); + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_AsyncAdditions) + ++ (FBLPromise* (^)(FBLPromiseAsyncWorkBlock))async { + return ^(FBLPromiseAsyncWorkBlock work) { + return [self async:work]; + }; +} + ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAsyncWorkBlock))asyncOn { + return ^(dispatch_queue_t queue, FBLPromiseAsyncWorkBlock work) { + return [self onQueue:queue async:work]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m new file mode 100644 index 0000000..ea3b87a --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m @@ -0,0 +1,48 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Await.h" + +#import "FBLPromisePrivate.h" + +id __nullable FBLPromiseAwait(FBLPromise *promise, NSError **outError) { + assert(promise); + + static dispatch_once_t onceToken; + static dispatch_queue_t queue; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.google.FBLPromises.Await", DISPATCH_QUEUE_CONCURRENT); + }); + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + id __block resolution; + NSError __block *blockError; + [promise chainOnQueue:queue + chainedFulfill:^id(id value) { + resolution = value; + dispatch_semaphore_signal(semaphore); + return value; + } + chainedReject:^id(NSError *error) { + blockError = error; + dispatch_semaphore_signal(semaphore); + return error; + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (outError) { + *outError = blockError; + } + return resolution; +} diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m new file mode 100644 index 0000000..25e8ce6 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m @@ -0,0 +1,55 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Catch.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (CatchAdditions) + +- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject { + return [self onQueue:FBLPromise.defaultDispatchQueue catch:reject]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue catch:(FBLPromiseCatchWorkBlock)reject { + NSParameterAssert(queue); + NSParameterAssert(reject); + + return [self chainOnQueue:queue + chainedFulfill:nil + chainedReject:^id(NSError *error) { + reject(error); + return error; + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_CatchAdditions) + +- (FBLPromise* (^)(FBLPromiseCatchWorkBlock))catch { + return ^(FBLPromiseCatchWorkBlock catch) { + return [self catch:catch]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseCatchWorkBlock))catchOn { + return ^(dispatch_queue_t queue, FBLPromiseCatchWorkBlock catch) { + return [self onQueue:queue catch:catch]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m new file mode 100644 index 0000000..ce94c33 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Delay.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (DelayAdditions) + +- (FBLPromise *)delay:(NSTimeInterval)interval { + return [self onQueue:FBLPromise.defaultDispatchQueue delay:interval]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue delay:(NSTimeInterval)interval { + NSParameterAssert(queue); + + FBLPromise *promise = [[FBLPromise alloc] initPending]; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + [promise fulfill:value]; + }); + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_DelayAdditions) + +- (FBLPromise * (^)(NSTimeInterval))delay { + return ^(NSTimeInterval interval) { + return [self delay:interval]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, NSTimeInterval))delayOn { + return ^(dispatch_queue_t queue, NSTimeInterval interval) { + return [self onQueue:queue delay:interval]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m new file mode 100644 index 0000000..eb7e10d --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Do.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (DoAdditions) + ++ (instancetype)do:(FBLPromiseDoWorkBlock)work { + return [self onQueue:self.defaultDispatchQueue do:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[FBLPromise alloc] initPending]; + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + id value = work(); + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_DoAdditions) + ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseDoWorkBlock))doOn { + return ^(dispatch_queue_t queue, FBLPromiseDoWorkBlock work) { + return [self onQueue:queue do:work]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m new file mode 100644 index 0000000..b5bd9f1 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m @@ -0,0 +1,65 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Race.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (RaceAdditions) + ++ (instancetype)race:(NSArray *)promises { + return [self onQueue:self.defaultDispatchQueue race:promises]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)racePromises { + NSParameterAssert(queue); + NSAssert(racePromises.count > 0, @"No promises to observe"); + + NSArray *promises = [racePromises copy]; + return [FBLPromise onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (id promise in promises) { + if (![promise isKindOfClass:self]) { + fulfill(promise); + return; + } + } + // Subscribe all, but only the first one to resolve will change + // the resulting promise's state. + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue fulfill:fulfill reject:reject]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_RaceAdditions) + ++ (FBLPromise * (^)(NSArray *))race { + return ^(NSArray *promises) { + return [self race:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))raceOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue race:promises]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m new file mode 100644 index 0000000..0c9326a --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m @@ -0,0 +1,54 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Recover.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (RecoverAdditions) + +- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery { + return [self onQueue:FBLPromise.defaultDispatchQueue recover:recovery]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue recover:(FBLPromiseRecoverWorkBlock)recovery { + NSParameterAssert(queue); + NSParameterAssert(recovery); + + return [self chainOnQueue:queue + chainedFulfill:nil + chainedReject:^id(NSError *error) { + return recovery(error); + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_RecoverAdditions) + +- (FBLPromise * (^)(FBLPromiseRecoverWorkBlock))recover { + return ^(FBLPromiseRecoverWorkBlock recovery) { + return [self recover:recovery]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRecoverWorkBlock))recoverOn { + return ^(dispatch_queue_t queue, FBLPromiseRecoverWorkBlock recovery) { + return [self onQueue:queue recover:recovery]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m new file mode 100644 index 0000000..1f3fc50 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m @@ -0,0 +1,61 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Reduce.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ReduceAdditions) + +- (FBLPromise *)reduce:(NSArray *)items combine:(FBLPromiseReducerBlock)reducer { + return [self onQueue:FBLPromise.defaultDispatchQueue reduce:items combine:reducer]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer { + NSParameterAssert(queue); + NSParameterAssert(items); + NSParameterAssert(reducer); + + FBLPromise *promise = self; + for (id item in items) { + promise = [promise chainOnQueue:queue + chainedFulfill:^id(id value) { + return reducer(value, item); + } + chainedReject:nil]; + } + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_ReduceAdditions) + +- (FBLPromise * (^)(NSArray *, FBLPromiseReducerBlock))reduce { + return ^(NSArray *items, FBLPromiseReducerBlock reducer) { + return [self reduce:items combine:reducer]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, NSArray *, FBLPromiseReducerBlock))reduceOn { + return ^(dispatch_queue_t queue, NSArray *items, FBLPromiseReducerBlock reducer) { + return [self onQueue:queue reduce:items combine:reducer]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m new file mode 100644 index 0000000..37c5576 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m @@ -0,0 +1,128 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Retry.h" + +#import "FBLPromisePrivate.h" + +NSInteger const FBLPromiseRetryDefaultAttemptsCount = 1; +NSTimeInterval const FBLPromiseRetryDefaultDelayInterval = 1.0; + +static void FBLPromiseRetryAttempt(FBLPromise *promise, dispatch_queue_t queue, NSInteger count, + NSTimeInterval interval, FBLPromiseRetryPredicateBlock predicate, + FBLPromiseRetryWorkBlock work) { + __auto_type retrier = ^(id __nullable value) { + if ([value isKindOfClass:[NSError class]]) { + if (count <= 0 || (predicate && !predicate(count, value))) { + [promise reject:value]; + } else { + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + FBLPromiseRetryAttempt(promise, queue, count - 1, interval, predicate, work); + }); + } + } else { + [promise fulfill:value]; + } + }; + id value = work(); + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue fulfill:retrier reject:retrier]; + } else { + retrier(value); + } +} + +@implementation FBLPromise (RetryAdditions) + ++ (FBLPromise *)retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue retry:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:queue attempts:FBLPromiseRetryDefaultAttemptsCount retry:work]; +} + ++ (FBLPromise *)attempts:(NSInteger)count retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue attempts:count retry:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:queue + attempts:count + delay:FBLPromiseRetryDefaultDelayInterval + condition:nil + retry:work]; +} + ++ (FBLPromise *)attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue + attempts:count + delay:interval + condition:predicate + retry:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[FBLPromise alloc] initPending]; + FBLPromiseRetryAttempt(promise, queue, count, interval, predicate, work); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_RetryAdditions) + ++ (FBLPromise * (^)(FBLPromiseRetryWorkBlock))retry { + return ^id(FBLPromiseRetryWorkBlock work) { + return [self retry:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRetryWorkBlock))retryOn { + return ^id(dispatch_queue_t queue, FBLPromiseRetryWorkBlock work) { + return [self onQueue:queue retry:work]; + }; +} + ++ (FBLPromise * (^)(NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock, + FBLPromiseRetryWorkBlock))retryAgain { + return ^id(NSInteger count, NSTimeInterval interval, FBLPromiseRetryPredicateBlock predicate, + FBLPromiseRetryWorkBlock work) { + return [self attempts:count delay:interval condition:predicate retry:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock, + FBLPromiseRetryWorkBlock))retryAgainOn { + return ^id(dispatch_queue_t queue, NSInteger count, NSTimeInterval interval, + FBLPromiseRetryPredicateBlock predicate, FBLPromiseRetryWorkBlock work) { + return [self onQueue:queue attempts:count delay:interval condition:predicate retry:work]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m new file mode 100644 index 0000000..33d3536 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m @@ -0,0 +1,55 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Testing.h" + +BOOL FBLWaitForPromisesWithTimeout(NSTimeInterval timeout) { + BOOL isTimedOut = NO; + NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout]; + static NSTimeInterval const minimalTimeout = 0.01; + static int64_t const minimalTimeToWait = (int64_t)(minimalTimeout * NSEC_PER_SEC); + dispatch_time_t waitTime = dispatch_time(DISPATCH_TIME_NOW, minimalTimeToWait); + dispatch_group_t dispatchGroup = FBLPromise.dispatchGroup; + NSRunLoop *runLoop = NSRunLoop.currentRunLoop; + while (dispatch_group_wait(dispatchGroup, waitTime)) { + isTimedOut = timeoutDate.timeIntervalSinceNow < 0.0; + if (isTimedOut) { + break; + } + [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:minimalTimeout]]; + } + return !isTimedOut; +} + +@implementation FBLPromise (TestingAdditions) + +// These properties are implemented in the FBLPromise class itself. +@dynamic isPending; +@dynamic isFulfilled; +@dynamic isRejected; +@dynamic value; +@dynamic error; + ++ (dispatch_group_t)dispatchGroup { + static dispatch_group_t gDispatchGroup; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gDispatchGroup = dispatch_group_create(); + }); + return gDispatchGroup; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m new file mode 100644 index 0000000..ab03bd1 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m @@ -0,0 +1,50 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Then.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ThenAdditions) + +- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue then:work]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue then:(FBLPromiseThenWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self chainOnQueue:queue chainedFulfill:work chainedReject:nil]; +} + +@end + +@implementation FBLPromise (DotSyntax_ThenAdditions) + +- (FBLPromise* (^)(FBLPromiseThenWorkBlock))then { + return ^(FBLPromiseThenWorkBlock work) { + return [self then:work]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseThenWorkBlock))thenOn { + return ^(dispatch_queue_t queue, FBLPromiseThenWorkBlock work) { + return [self onQueue:queue then:work]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m new file mode 100644 index 0000000..a2252e6 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m @@ -0,0 +1,64 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Timeout.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (TimeoutAdditions) + +- (FBLPromise *)timeout:(NSTimeInterval)interval { + return [self onQueue:FBLPromise.defaultDispatchQueue timeout:interval]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue timeout:(NSTimeInterval)interval { + NSParameterAssert(queue); + + FBLPromise *promise = [[FBLPromise alloc] initPending]; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + typeof(self) __weak weakPromise = promise; + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + NSError *timedOutError = [[NSError alloc] initWithDomain:FBLPromiseErrorDomain + code:FBLPromiseErrorCodeTimedOut + userInfo:nil]; + [weakPromise reject:timedOutError]; + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_TimeoutAdditions) + +- (FBLPromise* (^)(NSTimeInterval))timeout { + return ^(NSTimeInterval interval) { + return [self timeout:interval]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, NSTimeInterval))timeoutOn { + return ^(dispatch_queue_t queue, NSTimeInterval interval) { + return [self onQueue:queue timeout:interval]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m new file mode 100644 index 0000000..1e21e81 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m @@ -0,0 +1,56 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Validate.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ValidateAdditions) + +- (FBLPromise*)validate:(FBLPromiseValidateWorkBlock)predicate { + return [self onQueue:FBLPromise.defaultDispatchQueue validate:predicate]; +} + +- (FBLPromise*)onQueue:(dispatch_queue_t)queue validate:(FBLPromiseValidateWorkBlock)predicate { + NSParameterAssert(queue); + NSParameterAssert(predicate); + + FBLPromiseChainedFulfillBlock chainedFulfill = ^id(id value) { + return predicate(value) ? value : + [[NSError alloc] initWithDomain:FBLPromiseErrorDomain + code:FBLPromiseErrorCodeValidationFailure + userInfo:nil]; + }; + return [self chainOnQueue:queue chainedFulfill:chainedFulfill chainedReject:nil]; +} + +@end + +@implementation FBLPromise (DotSyntax_ValidateAdditions) + +- (FBLPromise* (^)(FBLPromiseValidateWorkBlock))validate { + return ^(FBLPromiseValidateWorkBlock predicate) { + return [self validate:predicate]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseValidateWorkBlock))validateOn { + return ^(dispatch_queue_t queue, FBLPromiseValidateWorkBlock predicate) { + return [self onQueue:queue validate:predicate]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m new file mode 100644 index 0000000..ee10951 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m @@ -0,0 +1,420 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Wrap.h" + +#import "FBLPromise+Async.h" + +@implementation FBLPromise (WrapAdditions) + ++ (instancetype)wrapCompletion:(void (^)(FBLPromiseCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapCompletion:(void (^)(FBLPromiseCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^{ + fulfill(nil); + }); + }]; +} + ++ (instancetype)wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapObjectCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(id __nullable value) { + fulfill(value); + }); + }]; +} + ++ (instancetype)wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapErrorCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(nil); + } + }); + }]; +} + ++ (instancetype)wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapObjectOrErrorCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(id __nullable value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(value); + } + }); + }]; +} + ++ (instancetype)wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapErrorOrObjectCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSError *__nullable error, id __nullable value) { + if (error) { + reject(error); + } else { + fulfill(value); + } + }); + }]; +} + ++ (FBLPromise *)wrap2ObjectsOrErrorCompletion: + (void (^)(FBLPromise2ObjectsOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrap2ObjectsOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrap2ObjectsOrErrorCompletion:(void (^)(FBLPromise2ObjectsOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(id __nullable value1, id __nullable value2, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@[ value1 ?: [NSNull null], value2 ?: [NSNull null] ]); + } + }); + }]; +} + ++ (FBLPromise *)wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapBoolCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(BOOL value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapBoolOrErrorCompletion: + (void (^)(FBLPromiseBoolOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapBoolOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapBoolOrErrorCompletion:(void (^)(FBLPromiseBoolOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(BOOL value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + ++ (FBLPromise *)wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapIntegerCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(NSInteger value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapIntegerOrErrorCompletion: + (void (^)(FBLPromiseIntegerOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapIntegerOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapIntegerOrErrorCompletion:(void (^)(FBLPromiseIntegerOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSInteger value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + ++ (FBLPromise *)wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapDoubleCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:(dispatch_queue_t)queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(double value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapDoubleOrErrorCompletion: + (void (^)(FBLPromiseDoubleOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapDoubleOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapDoubleOrErrorCompletion:(void (^)(FBLPromiseDoubleOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(double value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_WrapAdditions) + ++ (FBLPromise * (^)(void (^)(FBLPromiseCompletion)))wrapCompletion { + return ^(void (^work)(FBLPromiseCompletion)) { + return [self wrapCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseCompletion)))wrapCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseCompletion)) { + return [self onQueue:queue wrapCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletion { + return ^(void (^work)(FBLPromiseObjectCompletion)) { + return [self wrapObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseObjectCompletion)) { + return [self onQueue:queue wrapObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletion { + return ^(void (^work)(FBLPromiseErrorCompletion)) { + return [self wrapErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseErrorCompletion)) { + return [self onQueue:queue wrapErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletion { + return ^(void (^work)(FBLPromiseObjectOrErrorCompletion)) { + return [self wrapObjectOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseObjectOrErrorCompletion)) { + return [self onQueue:queue wrapObjectOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletion { + return ^(void (^work)(FBLPromiseErrorOrObjectCompletion)) { + return [self wrapErrorOrObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseErrorOrObjectCompletion)) { + return [self onQueue:queue wrapErrorOrObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletion { + return ^(void (^work)(FBLPromise2ObjectsOrErrorCompletion)) { + return [self wrap2ObjectsOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromise2ObjectsOrErrorCompletion)) { + return [self onQueue:queue wrap2ObjectsOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletion { + return ^(void (^work)(FBLPromiseBoolCompletion)) { + return [self wrapBoolCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseBoolCompletion)) { + return [self onQueue:queue wrapBoolCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseBoolOrErrorCompletion))) + wrapBoolOrErrorCompletion { + return ^(void (^work)(FBLPromiseBoolOrErrorCompletion)) { + return [self wrapBoolOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseBoolOrErrorCompletion))) + wrapBoolOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseBoolOrErrorCompletion)) { + return [self onQueue:queue wrapBoolOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletion { + return ^(void (^work)(FBLPromiseIntegerCompletion)) { + return [self wrapIntegerCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseIntegerCompletion)) { + return [self onQueue:queue wrapIntegerCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletion { + return ^(void (^work)(FBLPromiseIntegerOrErrorCompletion)) { + return [self wrapIntegerOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseIntegerOrErrorCompletion)) { + return [self onQueue:queue wrapIntegerOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletion { + return ^(void (^work)(FBLPromiseDoubleCompletion)) { + return [self wrapDoubleCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseDoubleCompletion)) { + return [self onQueue:queue wrapDoubleCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletion { + return ^(void (^work)(FBLPromiseDoubleOrErrorCompletion)) { + return [self wrapDoubleOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseDoubleOrErrorCompletion)) { + return [self onQueue:queue wrapDoubleOrErrorCompletion:work]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m new file mode 100644 index 0000000..c12ad32 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m @@ -0,0 +1,299 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromisePrivate.h" + +/** All states a promise can be in. */ +typedef NS_ENUM(NSInteger, FBLPromiseState) { + FBLPromiseStatePending = 0, + FBLPromiseStateFulfilled, + FBLPromiseStateRejected, +}; + +typedef void (^FBLPromiseObserver)(FBLPromiseState state, id __nullable resolution); + +static dispatch_queue_t gFBLPromiseDefaultDispatchQueue; + +@implementation FBLPromise { + /** Current state of the promise. */ + FBLPromiseState _state; + /** + Set of arbitrary objects to keep strongly while the promise is pending. + Becomes nil after the promise has been resolved. + */ + NSMutableSet *__nullable _pendingObjects; + /** + Value to fulfill the promise with. + Can be nil if the promise is still pending, was resolved with nil or after it has been rejected. + */ + id __nullable _value; + /** + Error to reject the promise with. + Can be nil if the promise is still pending or after it has been fulfilled. + */ + NSError *__nullable _error; + /** List of observers to notify when the promise gets resolved. */ + NSMutableArray *_observers; +} + ++ (void)initialize { + if (self == [FBLPromise class]) { + gFBLPromiseDefaultDispatchQueue = dispatch_get_main_queue(); + } +} + ++ (dispatch_queue_t)defaultDispatchQueue { + @synchronized(self) { + return gFBLPromiseDefaultDispatchQueue; + } +} + ++ (void)setDefaultDispatchQueue:(dispatch_queue_t)queue { + NSParameterAssert(queue); + + @synchronized(self) { + gFBLPromiseDefaultDispatchQueue = queue; + } +} + ++ (instancetype)pendingPromise { + return [[self alloc] initPending]; +} + ++ (instancetype)resolvedWith:(nullable id)resolution { + return [[self alloc] initWithResolution:resolution]; +} + +- (void)fulfill:(nullable id)value { + if ([value isKindOfClass:[NSError class]]) { + [self reject:(NSError *)value]; + } else { + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + _state = FBLPromiseStateFulfilled; + _value = value; + _pendingObjects = nil; + for (FBLPromiseObserver observer in _observers) { + observer(_state, _value); + } + _observers = nil; + dispatch_group_leave(FBLPromise.dispatchGroup); + } + } + } +} + +- (void)reject:(NSError *)error { + NSAssert([error isKindOfClass:[NSError class]], @"Invalid error type."); + + if (![error isKindOfClass:[NSError class]]) { + // Give up on invalid error type in Release mode. + @throw error; // NOLINT + } + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + _state = FBLPromiseStateRejected; + _error = error; + _pendingObjects = nil; + for (FBLPromiseObserver observer in _observers) { + observer(_state, _error); + } + _observers = nil; + dispatch_group_leave(FBLPromise.dispatchGroup); + } + } +} + +#pragma mark - NSObject + +- (NSString *)description { + if (self.isFulfilled) { + return [NSString stringWithFormat:@"<%@ %p> Fulfilled: %@", NSStringFromClass([self class]), + self, self.value]; + } + if (self.isRejected) { + return [NSString stringWithFormat:@"<%@ %p> Rejected: %@", NSStringFromClass([self class]), + self, self.error]; + } + return [NSString stringWithFormat:@"<%@ %p> Pending", NSStringFromClass([self class]), self]; +} + +#pragma mark - Private + +- (instancetype)initPending { + self = [super init]; + if (self) { + dispatch_group_enter(FBLPromise.dispatchGroup); + } + return self; +} + +- (instancetype)initWithResolution:(nullable id)resolution { + self = [super init]; + if (self) { + if ([resolution isKindOfClass:[NSError class]]) { + _state = FBLPromiseStateRejected; + _error = (NSError *)resolution; + } else { + _state = FBLPromiseStateFulfilled; + _value = resolution; + } + } + return self; +} + +- (void)dealloc { + if (_state == FBLPromiseStatePending) { + dispatch_group_leave(FBLPromise.dispatchGroup); + } +} + +- (BOOL)isPending { + @synchronized(self) { + return _state == FBLPromiseStatePending; + } +} + +- (BOOL)isFulfilled { + @synchronized(self) { + return _state == FBLPromiseStateFulfilled; + } +} + +- (BOOL)isRejected { + @synchronized(self) { + return _state == FBLPromiseStateRejected; + } +} + +- (nullable id)value { + @synchronized(self) { + return _value; + } +} + +- (NSError *__nullable)error { + @synchronized(self) { + return _error; + } +} + +- (void)addPendingObject:(id)object { + NSParameterAssert(object); + + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + if (!_pendingObjects) { + _pendingObjects = [[NSMutableSet alloc] init]; + } + [_pendingObjects addObject:object]; + } + } +} + +- (void)observeOnQueue:(dispatch_queue_t)queue + fulfill:(FBLPromiseOnFulfillBlock)onFulfill + reject:(FBLPromiseOnRejectBlock)onReject { + NSParameterAssert(queue); + NSParameterAssert(onFulfill); + NSParameterAssert(onReject); + + @synchronized(self) { + switch (_state) { + case FBLPromiseStatePending: { + if (!_observers) { + _observers = [[NSMutableArray alloc] init]; + } + [_observers addObject:^(FBLPromiseState state, id __nullable resolution) { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + switch (state) { + case FBLPromiseStatePending: + break; + case FBLPromiseStateFulfilled: + onFulfill(resolution); + break; + case FBLPromiseStateRejected: + onReject(resolution); + break; + } + }); + }]; + break; + } + case FBLPromiseStateFulfilled: { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + onFulfill(self->_value); + }); + break; + } + case FBLPromiseStateRejected: { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + onReject(self->_error); + }); + break; + } + } + } +} + +- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue + chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill + chainedReject:(FBLPromiseChainedRejectBlock)chainedReject { + NSParameterAssert(queue); + + FBLPromise *promise = [[FBLPromise alloc] initPending]; + __auto_type resolver = ^(id __nullable value) { + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + value = chainedFulfill ? chainedFulfill(value) : value; + resolver(value); + } + reject:^(NSError *error) { + id value = chainedReject ? chainedReject(error) : error; + resolver(value); + }]; + return promise; +} + +@end + +@implementation FBLPromise (DotSyntaxAdditions) + ++ (instancetype (^)(void))pending { + return ^(void) { + return [self pendingPromise]; + }; +} + ++ (instancetype (^)(id __nullable))resolved { + return ^(id resolution) { + return [self resolvedWith:resolution]; + }; +} + +@end diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m new file mode 100644 index 0000000..1cc181a --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m @@ -0,0 +1,19 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromiseError.h" + +NSErrorDomain const FBLPromiseErrorDomain = @"com.google.FBLPromises.Error"; diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h new file mode 100644 index 0000000..9c0090e --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h @@ -0,0 +1,63 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AllAdditions) + +/** + Wait until all of the given promises are fulfilled. + If one of the given promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param promises Promises to wait for. + @return Promise of an array containing the values of input promises in the same order. + */ ++ (FBLPromise *)all:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Wait until all of the given promises are fulfilled. + If one of the given promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected FBLPromise correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return Promise of an array containing the values of input promises in the same order. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + all:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `all` operators. + Usage: FBLPromise.all(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_AllAdditions) + ++ (FBLPromise * (^)(NSArray *))all FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))allOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h new file mode 100644 index 0000000..13000f5 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h @@ -0,0 +1,54 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AlwaysAdditions) + +typedef void (^FBLPromiseAlwaysWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block that always executes, no matter if the receiver is rejected or fulfilled. + @return A new pending promise to be resolved with same resolution as the receiver. + */ +- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to dispatch on. + @param work A block that always executes, no matter if the receiver is rejected or fulfilled. + @return A new pending promise to be resolved with same resolution as the receiver. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + always:(FBLPromiseAlwaysWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `always` operators. + Usage: promise.always(^{...}) + */ +@interface FBLPromise(DotSyntax_AlwaysAdditions) + +- (FBLPromise* (^)(FBLPromiseAlwaysWorkBlock))always FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAlwaysWorkBlock))alwaysOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h new file mode 100644 index 0000000..82875bf --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h @@ -0,0 +1,69 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AnyAdditions) + +/** + Waits until all of the given promises are either fulfilled or rejected. + If all promises are rejected, then the returned promise is rejected with same error + as the last one rejected. + If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array of + values or `NSErrors`, matching the original order of fulfilled or rejected promises respectively. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param promises Promises to wait for. + @return Promise of array containing the values or `NSError`s of input promises in the same order. + */ ++ (FBLPromise *)any:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Waits until all of the given promises are either fulfilled or rejected. + If all promises are rejected, then the returned promise is rejected with same error + as the last one rejected. + If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array of + values or `NSError`s, matching the original order of fulfilled or rejected promises respectively. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return Promise of array containing the values or `NSError`s of input promises in the same order. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + any:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `any` operators. + Usage: FBLPromise.any(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_AnyAdditions) + ++ (FBLPromise * (^)(NSArray *))any FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))anyOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h new file mode 100644 index 0000000..0588a9e --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AsyncAdditions) + +typedef void (^FBLPromiseFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseAsyncWorkBlock)(FBLPromiseFulfillBlock fulfill, + FBLPromiseRejectBlock reject) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously. + + @param work A block to perform any operations needed to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)async:(FBLPromiseAsyncWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously on the given queue. + + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + async:(FBLPromiseAsyncWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `async` operators. + Usage: FBLPromise.async(^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { ... }) + */ +@interface FBLPromise(DotSyntax_AsyncAdditions) + ++ (FBLPromise* (^)(FBLPromiseAsyncWorkBlock))async FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAsyncWorkBlock))asyncOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h new file mode 100644 index 0000000..c97a1ba --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h @@ -0,0 +1,32 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Waits for promise resolution. The current thread blocks until the promise is resolved. + + @param promise Promise to wait for. + @param error Error the promise was rejected with, or `nil` if the promise was fulfilled. + @return Value the promise was fulfilled with. If the promise was rejected, the return value + is always `nil`, but the error out arg is not. + */ +FOUNDATION_EXTERN id __nullable FBLPromiseAwait(FBLPromise *promise, + NSError **error) NS_REFINED_FOR_SWIFT; + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h new file mode 100644 index 0000000..a9ff170 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(CatchAdditions) + +typedef void (^FBLPromiseCatchWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with same resolution as the receiver. + If receiver is rejected, then `reject` block is executed asynchronously. + + @param reject A block to handle the error that receiver was rejected with. + @return A new pending promise. + */ +- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with same resolution as the receiver. + If receiver is rejected, then `reject` block is executed asynchronously on the given queue. + + @param queue A queue to invoke the `reject` block on. + @param reject A block to handle the error that receiver was rejected with. + @return A new pending promise. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + catch:(FBLPromiseCatchWorkBlock)reject NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `catch` operators. + Usage: promise.catch(^(NSError *error) { ... }) + */ +@interface FBLPromise(DotSyntax_CatchAdditions) + +- (FBLPromise* (^)(FBLPromiseCatchWorkBlock))catch FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseCatchWorkBlock))catchOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h new file mode 100644 index 0000000..557df48 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(DelayAdditions) + +/** + Creates a new pending promise that fulfills with the same value as `self` after the `delay`, or + rejects with the same error immediately. + + @param interval Time to wait in seconds. + @return A new pending promise that fulfills at least `delay` seconds later than `self`, or rejects + with the same error immediately. + */ +- (FBLPromise *)delay:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a new pending promise that fulfills with the same value as `self` after the `delay`, or + rejects with the same error immediately. + + @param queue A queue to dispatch on. + @param interval Time to wait in seconds. + @return A new pending promise that fulfills at least `delay` seconds later than `self`, or rejects + with the same error immediately. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + delay:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `delay` operators. + Usage: promise.delay(...) + */ +@interface FBLPromise(DotSyntax_DelayAdditions) + +- (FBLPromise * (^)(NSTimeInterval))delay FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, NSTimeInterval))delayOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h new file mode 100644 index 0000000..6838e0a --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h @@ -0,0 +1,55 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(DoAdditions) + +typedef id __nullable (^FBLPromiseDoWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously. + + @param work A block that returns a value or an error used to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)do:(FBLPromiseDoWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously on the given queue. + + @param queue A queue to invoke the `work` block on. + @param work A block that returns a value or an error used to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `do` operators. + Usage: FBLPromise.doOn(queue, ^(NSError *error) { ... }) + */ +@interface FBLPromise(DotSyntax_DoAdditions) + ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseDoWorkBlock))doOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h new file mode 100644 index 0000000..2f67258 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h @@ -0,0 +1,62 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(RaceAdditions) + +/** + Wait until any of the given promises are fulfilled. + If one of the promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + + @param promises Promises to wait for. + @return A new pending promise to be resolved with the same resolution as the first promise, among + the given ones, which was resolved. + */ ++ (instancetype)race:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Wait until any of the given promises are fulfilled. + If one of the promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return A new pending promise to be resolved with the same resolution as the first promise, among + the given ones, which was resolved. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `race` operators. + Usage: FBLPromise.race(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_RaceAdditions) + ++ (FBLPromise * (^)(NSArray *))race FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))raceOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h new file mode 100644 index 0000000..bb7df7e --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(RecoverAdditions) + +typedef id __nullable (^FBLPromiseRecoverWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); + +/** + Provides a new promise to recover in case the receiver gets rejected. + + @param recovery A block to handle the error that the receiver was rejected with. + @return A new pending promise to use instead of the rejected one that gets resolved with resolution + returned from `recovery` block. + */ +- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery NS_SWIFT_UNAVAILABLE(""); + +/** + Provides a new promise to recover in case the receiver gets rejected. + + @param queue A queue to dispatch on. + @param recovery A block to handle the error that the receiver was rejected with. + @return A new pending promise to use instead of the rejected one that gets resolved with resolution + returned from `recovery` block. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + recover:(FBLPromiseRecoverWorkBlock)recovery NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `recover` operators. + Usage: promise.recover(^id(NSError *error) {...}) + */ +@interface FBLPromise(DotSyntax_RecoverAdditions) + +- (FBLPromise * (^)(FBLPromiseRecoverWorkBlock))recover FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRecoverWorkBlock))recoverOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h new file mode 100644 index 0000000..5bb1eee --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h @@ -0,0 +1,71 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ReduceAdditions) + +typedef id __nullable (^FBLPromiseReducerBlock)(Value __nullable partial, id next) + NS_SWIFT_UNAVAILABLE(""); + +/** + Sequentially reduces a collection of values to a single promise using a given combining block + and the value `self` resolves with as initial value. + + @param items An array of values to process in order. + @param reducer A block to combine an accumulating value and an element of the sequence into + the new accumulating value or a promise resolved with it, to be used in the next + call of the `reducer` or returned to the caller. + @return A new pending promise returned from the last `reducer` invocation. + Or `self` if `items` is empty. + */ +- (FBLPromise *)reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE(""); + +/** + Sequentially reduces a collection of values to a single promise using a given combining block + and the value `self` resolves with as initial value. + + @param queue A queue to dispatch on. + @param items An array of values to process in order. + @param reducer A block to combine an accumulating value and an element of the sequence into + the new accumulating value or a promise resolved with it, to be used in the next + call of the `reducer` or returned to the caller. + @return A new pending promise returned from the last `reducer` invocation. + Or `self` if `items` is empty. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE(""); + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `reduce` operators. + Usage: promise.reduce(values, ^id(id partial, id next) { ... }) + */ +@interface FBLPromise(DotSyntax_ReduceAdditions) + +- (FBLPromise * (^)(NSArray *, FBLPromiseReducerBlock))reduce FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, NSArray *, FBLPromiseReducerBlock))reduceOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h new file mode 100644 index 0000000..98ef558 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h @@ -0,0 +1,165 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The default number of retry attempts is 1. */ +FOUNDATION_EXTERN NSInteger const FBLPromiseRetryDefaultAttemptsCount NS_REFINED_FOR_SWIFT; + +/** The default delay interval before making a retry attempt is 1.0 second. */ +FOUNDATION_EXTERN NSTimeInterval const FBLPromiseRetryDefaultDelayInterval NS_REFINED_FOR_SWIFT; + +@interface FBLPromise(RetryAdditions) + +typedef id __nullable (^FBLPromiseRetryWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); +typedef BOOL (^FBLPromiseRetryPredicateBlock)(NSInteger, NSError *) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. Defaults to `FBLPromiseRetryDefaultAttemptsCount` attempt(s) on rejection where the + `work` block is retried after a delay of `FBLPromiseRetryDefaultDelayInterval` second(s). + + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (FBLPromise *)retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. Defaults to `FBLPromiseRetryDefaultAttemptsCount` attempt(s) on + rejection where the `work` block is retried on the given `queue` after a delay of + `FBLPromiseRetryDefaultDelayInterval` second(s). + + @param queue A queue to invoke the `work` block on. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. + + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (FBLPromise *)attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. + + @param queue A queue to invoke the `work` block on. + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. On rejection, the `work` block is retried after the given delay `interval` and will + continue to retry until the number of specified attempts have been exhausted or will bail early if + the given condition is not met. + + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param interval Time to wait before the next retry attempt. + @param predicate Condition to check before the next retry attempt. The predicate block provides the + the number of remaining retry attempts and the error that the promise was rejected + with. + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted or if + the given condition is not met. + */ ++ (FBLPromise *)attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. On rejection, the `work` block is retried after the given + delay `interval` and will continue to retry until the number of specified attempts have been + exhausted or will bail early if the given condition is not met. + + @param queue A queue to invoke the `work` block on. + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param interval Time to wait before the next retry attempt. + @param predicate Condition to check before the next retry attempt. The predicate block provides the + the number of remaining retry attempts and the error that the promise was rejected + with. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted or if + the given condition is not met. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise+Retry` operators. + Usage: FBLPromise.retry(^id { ... }) + */ +@interface FBLPromise(DotSyntax_RetryAdditions) + ++ (FBLPromise * (^)(FBLPromiseRetryWorkBlock))retry FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRetryWorkBlock))retryOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock __nullable, + FBLPromiseRetryWorkBlock))retryAgain FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSInteger, NSTimeInterval, + FBLPromiseRetryPredicateBlock __nullable, + FBLPromiseRetryWorkBlock))retryAgainOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h new file mode 100644 index 0000000..8478ae2 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h @@ -0,0 +1,57 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Waits for all scheduled promises blocks. + + @param timeout Maximum time to wait. + @return YES if all promises blocks have completed before the timeout and NO otherwise. + */ +FOUNDATION_EXTERN BOOL FBLWaitForPromisesWithTimeout(NSTimeInterval timeout) NS_REFINED_FOR_SWIFT; + +@interface FBLPromise(TestingAdditions) + +/** + Dispatch group for promises that is typically used to wait for all scheduled blocks. + */ +@property(class, nonatomic, readonly) dispatch_group_t dispatchGroup NS_REFINED_FOR_SWIFT; + +/** + Properties to get the current state of the promise. + */ +@property(nonatomic, readonly) BOOL isPending NS_REFINED_FOR_SWIFT; +@property(nonatomic, readonly) BOOL isFulfilled NS_REFINED_FOR_SWIFT; +@property(nonatomic, readonly) BOOL isRejected NS_REFINED_FOR_SWIFT; + +/** + Value the promise was fulfilled with. + Can be nil if the promise is still pending, was resolved with nil or after it has been rejected. + */ +@property(nonatomic, readonly, nullable) Value value NS_REFINED_FOR_SWIFT; + +/** + Error the promise was rejected with. + Can be nil if the promise is still pending or after it has been fulfilled. + */ +@property(nonatomic, readonly, nullable) NSError *error NS_REFINED_FOR_SWIFT; + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h new file mode 100644 index 0000000..32027e6 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h @@ -0,0 +1,63 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ThenAdditions) + +typedef id __nullable (^FBLPromiseThenWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with resolution returned from `work` + block: either value, error or another promise. The `work` block is executed asynchronously only + when the receiver is fulfilled. If receiver is rejected, the returned promise is also rejected with + the same error. + + @param work A block to handle the value that receiver was fulfilled with. + @return A new pending promise to be resolved with resolution returned from the `work` block. + */ +- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with resolution returned from `work` + block: either value, error or another promise. The `work` block is executed asynchronously when the + receiver is fulfilled. If receiver is rejected, the returned promise is also rejected with the same + error. + + @param queue A queue to invoke the `work` block on. + @param work A block to handle the value that receiver was fulfilled with. + @return A new pending promise to be resolved with resolution returned from the `work` block. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + then:(FBLPromiseThenWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `then` operators. + Usage: promise.then(^id(id value) { ... }) + */ +@interface FBLPromise(DotSyntax_ThenAdditions) + +- (FBLPromise* (^)(FBLPromiseThenWorkBlock))then FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseThenWorkBlock))thenOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h new file mode 100644 index 0000000..184ba16 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h @@ -0,0 +1,57 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(TimeoutAdditions) + +/** + Waits for a promise with the specified `timeout`. + + @param interval Time to wait in seconds. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeTimedOut` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)timeout:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE(""); + +/** + Waits for a promise with the specified `timeout`. + + @param queue A queue to dispatch on. + @param interval Time to wait in seconds. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeTimedOut` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + timeout:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `timeout` operators. + Usage: promise.timeout(...) + */ +@interface FBLPromise(DotSyntax_TimeoutAdditions) + +- (FBLPromise* (^)(NSTimeInterval))timeout FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, NSTimeInterval))timeoutOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h new file mode 100644 index 0000000..9dfa2f1 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ValidateAdditions) + +typedef BOOL (^FBLPromiseValidateWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); + +/** + Validates a fulfilled value or rejects the value if it can not be validated. + + @param predicate An expression to validate. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeValidationFailure` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)validate:(FBLPromiseValidateWorkBlock)predicate NS_SWIFT_UNAVAILABLE(""); + +/** + Validates a fulfilled value or rejects the value if it can not be validated. + + @param queue A queue to dispatch on. + @param predicate An expression to validate. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeValidationFailure` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + validate:(FBLPromiseValidateWorkBlock)predicate NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `validate` operators. + Usage: promise.validate(^BOOL(id value) { ... }) + */ +@interface FBLPromise(DotSyntax_ValidateAdditions) + +- (FBLPromise * (^)(FBLPromiseValidateWorkBlock))validate FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseValidateWorkBlock))validateOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h new file mode 100644 index 0000000..664e1bb --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h @@ -0,0 +1,316 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Different types of completion handlers available to be wrapped with promise. + */ +typedef void (^FBLPromiseCompletion)(void) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseObjectCompletion)(id __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseErrorCompletion)(NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseObjectOrErrorCompletion)(id __nullable, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseErrorOrObjectCompletion)(NSError* __nullable, id __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromise2ObjectsOrErrorCompletion)(id __nullable, id __nullable, + NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseBoolCompletion)(BOOL) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseBoolOrErrorCompletion)(BOOL, NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseIntegerCompletion)(NSInteger) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseIntegerOrErrorCompletion)(NSInteger, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseDoubleCompletion)(double) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseDoubleOrErrorCompletion)(double, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); + +/** + Provides an easy way to convert methods that use common callback patterns into promises. + */ +@interface FBLPromise(WrapAdditions) + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with `nil` when completion handler is invoked. + */ ++ (instancetype)wrapCompletion:(void (^)(FBLPromiseCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with `nil` when completion handler is invoked. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapCompletion:(void (^)(FBLPromiseCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler. + */ ++ (instancetype)wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error provided by completion handler. + If error is `nil`, fulfills with `nil`, otherwise rejects with the error. + */ ++ (instancetype)wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error provided by completion handler. + If error is `nil`, fulfills with `nil`, otherwise rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler if error is `nil`. + Otherwise, rejects with the error. + */ ++ (instancetype)wrapObjectOrErrorCompletion: + (void (^)(FBLPromiseObjectOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler if error is `nil`. + Otherwise, rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error or object provided by completion handler. If error + is not `nil`, rejects with the error. + */ ++ (instancetype)wrapErrorOrObjectCompletion: + (void (^)(FBLPromiseErrorOrObjectCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error or object provided by completion handler. If error + is not `nil`, rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an array of objects provided by completion handler in order + if error is `nil`. Otherwise, rejects with the error. + */ ++ (FBLPromise*)wrap2ObjectsOrErrorCompletion: + (void (^)(FBLPromise2ObjectsOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an array of objects provided by completion handler in order + if error is `nil`. Otherwise, rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrap2ObjectsOrErrorCompletion:(void (^)(FBLPromise2ObjectsOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO. + */ ++ (FBLPromise*)wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapBoolOrErrorCompletion: + (void (^)(FBLPromiseBoolOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapBoolOrErrorCompletion:(void (^)(FBLPromiseBoolOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer. + */ ++ (FBLPromise*)wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapIntegerOrErrorCompletion: + (void (^)(FBLPromiseIntegerOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapIntegerOrErrorCompletion:(void (^)(FBLPromiseIntegerOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double. + */ ++ (FBLPromise*)wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapDoubleOrErrorCompletion: + (void (^)(FBLPromiseDoubleOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapDoubleOrErrorCompletion:(void (^)(FBLPromiseDoubleOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `wrap` operators. + Usage: FBLPromise.wrapCompletion(^(FBLPromiseCompletion handler) {...}) + */ +@interface FBLPromise(DotSyntax_WrapAdditions) + ++ (FBLPromise* (^)(void (^)(FBLPromiseCompletion)))wrapCompletion FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseCompletion)))wrapCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletion FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseBoolOrErrorCompletion)))wrapBoolOrErrorCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolOrErrorCompletion)))wrapBoolOrErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h new file mode 100644 index 0000000..b1380dc --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h @@ -0,0 +1,93 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromiseError.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Promises synchronization construct in Objective-C. + */ +@interface FBLPromise<__covariant Value> : NSObject + +/** + Default dispatch queue used for `FBLPromise`, which is `main` if a queue is not specified. + */ +@property(class) dispatch_queue_t defaultDispatchQueue NS_REFINED_FOR_SWIFT; + +/** + Creates a pending promise. + */ ++ (instancetype)pendingPromise NS_REFINED_FOR_SWIFT; + +/** + Creates a resolved promise. + + @param resolution An object to resolve the promise with: either a value or an error. + @return A new resolved promise. + */ ++ (instancetype)resolvedWith:(nullable id)resolution NS_REFINED_FOR_SWIFT; + +/** + Synchronously fulfills the promise with a value. + + @param value An arbitrary value to fulfill the promise with, including `nil`. + */ +- (void)fulfill:(nullable Value)value NS_REFINED_FOR_SWIFT; + +/** + Synchronously rejects the promise with an error. + + @param error An error to reject the promise with. + */ +- (void)reject:(NSError *)error NS_REFINED_FOR_SWIFT; + ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; +@end + +@interface FBLPromise() + +/** + Adds an object to the set of pending objects to keep strongly while the promise is pending. + Used by the Swift wrappers to keep them alive until the underlying ObjC promise is resolved. + + @param object An object to add. + */ +- (void)addPendingObject:(id)object NS_REFINED_FOR_SWIFT; + +@end + +#ifdef FBL_PROMISES_DOT_SYNTAX_IS_DEPRECATED +#define FBL_PROMISES_DOT_SYNTAX __attribute__((deprecated)) +#else +#define FBL_PROMISES_DOT_SYNTAX +#endif + +@interface FBLPromise(DotSyntaxAdditions) + +/** + Convenience dot-syntax wrappers for FBLPromise. + Usage: FBLPromise.pending() + FBLPromise.resolved(value) + + */ ++ (instancetype (^)(void))pending FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (instancetype (^)(id __nullable))resolved FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h new file mode 100644 index 0000000..d37af53 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h @@ -0,0 +1,43 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXTERN NSErrorDomain const FBLPromiseErrorDomain NS_REFINED_FOR_SWIFT; + +/** + Possible error codes in `FBLPromiseErrorDomain`. + */ +typedef NS_ENUM(NSInteger, FBLPromiseErrorCode) { + /** Promise failed to resolve in time. */ + FBLPromiseErrorCodeTimedOut = 1, + /** Validation predicate returned false. */ + FBLPromiseErrorCodeValidationFailure = 2, +} NS_REFINED_FOR_SWIFT; + +NS_INLINE BOOL FBLPromiseErrorIsTimedOut(NSError *error) NS_SWIFT_UNAVAILABLE("") { + return error.domain == FBLPromiseErrorDomain && + error.code == FBLPromiseErrorCodeTimedOut; +} + +NS_INLINE BOOL FBLPromiseErrorIsValidationFailure(NSError *error) NS_SWIFT_UNAVAILABLE("") { + return error.domain == FBLPromiseErrorDomain && + error.code == FBLPromiseErrorCodeValidationFailure; +} + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h new file mode 100644 index 0000000..7a132f2 --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h @@ -0,0 +1,66 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Testing.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Miscellaneous low-level private interfaces available to extend standard FBLPromise functionality. + */ +@interface FBLPromise() + +typedef void (^FBLPromiseOnFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseOnRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); +typedef id __nullable (^__nullable FBLPromiseChainedFulfillBlock)(Value __nullable value) + NS_SWIFT_UNAVAILABLE(""); +typedef id __nullable (^__nullable FBLPromiseChainedRejectBlock)(NSError *error) + NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise. + */ +- (instancetype)initPending NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a resolved promise. + + @param resolution An object to resolve the promise with: either a value or an error. + @return A new resolved promise. + */ +- (instancetype)initWithResolution:(nullable id)resolution NS_SWIFT_UNAVAILABLE(""); + +/** + Invokes `fulfill` and `reject` blocks on `queue` when the receiver gets either fulfilled or + rejected respectively. + */ +- (void)observeOnQueue:(dispatch_queue_t)queue + fulfill:(FBLPromiseOnFulfillBlock)onFulfill + reject:(FBLPromiseOnRejectBlock)onReject NS_SWIFT_UNAVAILABLE(""); + +/** + Returns a new promise which gets resolved with the return value of `chainedFulfill` or + `chainedReject` blocks respectively. The blocks are invoked when the receiver gets either + fulfilled or rejected. If `nil` is passed to either block arg, the returned promise is resolved + with the same resolution as the receiver. + */ +- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue + chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill + chainedReject:(FBLPromiseChainedRejectBlock)chainedReject NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h new file mode 100644 index 0000000..2d90bad --- /dev/null +++ b/saraWhatsUp/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h @@ -0,0 +1,32 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+All.h" +#import "FBLPromise+Always.h" +#import "FBLPromise+Any.h" +#import "FBLPromise+Async.h" +#import "FBLPromise+Await.h" +#import "FBLPromise+Catch.h" +#import "FBLPromise+Delay.h" +#import "FBLPromise+Do.h" +#import "FBLPromise+Race.h" +#import "FBLPromise+Recover.h" +#import "FBLPromise+Reduce.h" +#import "FBLPromise+Retry.h" +#import "FBLPromise+Then.h" +#import "FBLPromise+Timeout.h" +#import "FBLPromise+Validate.h" +#import "FBLPromise+Wrap.h" diff --git a/saraWhatsUp/Pods/Target Support Files/Firebase/Firebase.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/Firebase/Firebase.debug.xcconfig new file mode 100644 index 0000000..7c465a7 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Firebase/Firebase.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Firebase +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAuth" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseDatabase" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseStorage" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Firebase" "${PODS_ROOT}/Headers/Public" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Firebase +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/Firebase/Firebase.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/Firebase/Firebase.release.xcconfig new file mode 100644 index 0000000..7c465a7 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Firebase/Firebase.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Firebase +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAuth" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseDatabase" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseStorage" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Firebase" "${PODS_ROOT}/Headers/Public" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Firebase +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-Info.plist b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-Info.plist new file mode 100644 index 0000000..fe51ae9 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 8.9.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-dummy.m b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-dummy.m new file mode 100644 index 0000000..63dc459 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseAuth : NSObject +@end +@implementation PodsDummy_FirebaseAuth +@end diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-umbrella.h b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-umbrella.h new file mode 100644 index 0000000..6a6a150 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth-umbrella.h @@ -0,0 +1,49 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRActionCodeSettings.h" +#import "FIRAdditionalUserInfo.h" +#import "FIRAuth.h" +#import "FIRAuthAPNSTokenType.h" +#import "FIRAuthCredential.h" +#import "FIRAuthDataResult.h" +#import "FIRAuthErrors.h" +#import "FIRAuthSettings.h" +#import "FIRAuthTokenResult.h" +#import "FIRAuthUIDelegate.h" +#import "FirebaseAuth.h" +#import "FIREmailAuthProvider.h" +#import "FIRFacebookAuthProvider.h" +#import "FIRFederatedAuthProvider.h" +#import "FIRGameCenterAuthProvider.h" +#import "FIRGitHubAuthProvider.h" +#import "FIRGoogleAuthProvider.h" +#import "FIRMultiFactor.h" +#import "FIRMultiFactorAssertion.h" +#import "FIRMultiFactorInfo.h" +#import "FIRMultiFactorResolver.h" +#import "FIRMultiFactorSession.h" +#import "FIROAuthCredential.h" +#import "FIROAuthProvider.h" +#import "FIRPhoneAuthCredential.h" +#import "FIRPhoneAuthProvider.h" +#import "FIRPhoneMultiFactorAssertion.h" +#import "FIRPhoneMultiFactorGenerator.h" +#import "FIRPhoneMultiFactorInfo.h" +#import "FIRTwitterAuthProvider.h" +#import "FIRUser.h" +#import "FIRUserInfo.h" +#import "FIRUserMetadata.h" + +FOUNDATION_EXPORT double FirebaseAuthVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAuthVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.debug.xcconfig new file mode 100644 index 0000000..3a9bf6d --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAuth +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCore" -framework "Foundation" -framework "GTMSessionFetcher" -framework "GoogleUtilities" -framework "SafariServices" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseAuth +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.modulemap b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.modulemap new file mode 100644 index 0000000..7ee6c70 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseAuth { + umbrella header "FirebaseAuth-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.release.xcconfig new file mode 100644 index 0000000..3a9bf6d --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseAuth/FirebaseAuth.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAuth +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCore" -framework "Foundation" -framework "GTMSessionFetcher" -framework "GoogleUtilities" -framework "SafariServices" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseAuth +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-Info.plist b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-Info.plist new file mode 100644 index 0000000..fa0a316 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 8.9.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-dummy.m b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-dummy.m new file mode 100644 index 0000000..4f1eb27 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseCore : NSObject +@end +@implementation PodsDummy_FirebaseCore +@end diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-umbrella.h b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-umbrella.h new file mode 100644 index 0000000..0f96d94 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore-umbrella.h @@ -0,0 +1,22 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRApp.h" +#import "FIRConfiguration.h" +#import "FirebaseCore.h" +#import "FIRLoggerLevel.h" +#import "FIROptions.h" +#import "FIRVersion.h" + +FOUNDATION_EXPORT double FirebaseCoreVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseCoreVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.debug.xcconfig new file mode 100644 index 0000000..4446253 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 Firebase_VERSION=8.9.1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_CFLAGS = $(inherited) -fno-autolink +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCoreDiagnostics" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCore +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.modulemap b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.modulemap new file mode 100644 index 0000000..4c38b87 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseCore { + umbrella header "FirebaseCore-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.release.xcconfig new file mode 100644 index 0000000..4446253 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCore/FirebaseCore.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 Firebase_VERSION=8.9.1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_CFLAGS = $(inherited) -fno-autolink +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCoreDiagnostics" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCore +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-Info.plist b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-Info.plist new file mode 100644 index 0000000..fe51ae9 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 8.9.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-dummy.m b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-dummy.m new file mode 100644 index 0000000..224d263 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseCoreDiagnostics : NSObject +@end +@implementation PodsDummy_FirebaseCoreDiagnostics +@end diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-umbrella.h b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-umbrella.h new file mode 100644 index 0000000..a27569f --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics-umbrella.h @@ -0,0 +1,17 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRCoreDiagnostics.h" + +FOUNDATION_EXPORT double FirebaseCoreDiagnosticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseCoreDiagnosticsVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.debug.xcconfig new file mode 100644 index 0000000..e5b1e9a --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.debug.xcconfig @@ -0,0 +1,17 @@ +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +GCC_TREAT_WARNINGS_AS_ERRORS = YES +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCoreDiagnostics +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.modulemap b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.modulemap new file mode 100644 index 0000000..d9cad8b --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseCoreDiagnostics { + umbrella header "FirebaseCoreDiagnostics-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.release.xcconfig new file mode 100644 index 0000000..e5b1e9a --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.release.xcconfig @@ -0,0 +1,17 @@ +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +GCC_TREAT_WARNINGS_AS_ERRORS = YES +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCoreDiagnostics +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-Info.plist b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-Info.plist new file mode 100644 index 0000000..fe51ae9 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 8.9.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-dummy.m b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-dummy.m new file mode 100644 index 0000000..40813e7 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseDatabase : NSObject +@end +@implementation PodsDummy_FirebaseDatabase +@end diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-umbrella.h b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-umbrella.h new file mode 100644 index 0000000..b9b40ff --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase-umbrella.h @@ -0,0 +1,25 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRDatabase.h" +#import "FIRDatabaseQuery.h" +#import "FIRDatabaseReference.h" +#import "FIRDataEventType.h" +#import "FIRDataSnapshot.h" +#import "FirebaseDatabase.h" +#import "FIRMutableData.h" +#import "FIRServerValue.h" +#import "FIRTransactionResult.h" + +FOUNDATION_EXPORT double FirebaseDatabaseVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseDatabaseVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.debug.xcconfig new file mode 100644 index 0000000..97070d8 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseDatabase +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -l"c++" -l"icucore" -framework "CFNetwork" -framework "FirebaseCore" -framework "Foundation" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "leveldb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseDatabase +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.modulemap b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.modulemap new file mode 100644 index 0000000..7424a95 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseDatabase { + umbrella header "FirebaseDatabase-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.release.xcconfig new file mode 100644 index 0000000..97070d8 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseDatabase/FirebaseDatabase.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseDatabase +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -l"c++" -l"icucore" -framework "CFNetwork" -framework "FirebaseCore" -framework "Foundation" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "leveldb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseDatabase +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-Info.plist b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-Info.plist new file mode 100644 index 0000000..fe51ae9 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 8.9.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-dummy.m b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-dummy.m new file mode 100644 index 0000000..15945ee --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseStorage : NSObject +@end +@implementation PodsDummy_FirebaseStorage +@end diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-umbrella.h b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-umbrella.h new file mode 100644 index 0000000..40d6144 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage-umbrella.h @@ -0,0 +1,27 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FirebaseStorage.h" +#import "FIRStorage.h" +#import "FIRStorageConstants.h" +#import "FIRStorageDownloadTask.h" +#import "FIRStorageListResult.h" +#import "FIRStorageMetadata.h" +#import "FIRStorageObservableTask.h" +#import "FIRStorageReference.h" +#import "FIRStorageTask.h" +#import "FIRStorageTaskSnapshot.h" +#import "FIRStorageUploadTask.h" + +FOUNDATION_EXPORT double FirebaseStorageVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseStorageVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.debug.xcconfig new file mode 100644 index 0000000..4c6da88 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseStorage +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCore" -framework "Foundation" -framework "GTMSessionFetcher" -framework "Security" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseStorage +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.modulemap b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.modulemap new file mode 100644 index 0000000..627ff18 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseStorage { + umbrella header "FirebaseStorage-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.release.xcconfig new file mode 100644 index 0000000..4c6da88 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/FirebaseStorage/FirebaseStorage.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseStorage +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCore" -framework "Foundation" -framework "GTMSessionFetcher" -framework "Security" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseStorage +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-Info.plist b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-Info.plist new file mode 100644 index 0000000..fcedd03 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.7.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m new file mode 100644 index 0000000..13d68b3 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GTMSessionFetcher : NSObject +@end +@implementation PodsDummy_GTMSessionFetcher +@end diff --git a/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-umbrella.h b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-umbrella.h new file mode 100644 index 0000000..1c0b7b8 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher-umbrella.h @@ -0,0 +1,20 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "GTMSessionFetcher.h" +#import "GTMSessionFetcherLogging.h" +#import "GTMSessionFetcherService.h" +#import "GTMSessionUploadFetcher.h" + +FOUNDATION_EXPORT double GTMSessionFetcherVersionNumber; +FOUNDATION_EXPORT const unsigned char GTMSessionFetcherVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.debug.xcconfig new file mode 100644 index 0000000..b1f7629 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "Security" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GTMSessionFetcher +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap new file mode 100644 index 0000000..5121a4d --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap @@ -0,0 +1,6 @@ +framework module GTMSessionFetcher { + umbrella header "GTMSessionFetcher-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.release.xcconfig new file mode 100644 index 0000000..b1f7629 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GTMSessionFetcher/GTMSessionFetcher.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "Security" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GTMSessionFetcher +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist new file mode 100644 index 0000000..4be429b --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 9.1.2 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-dummy.m b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-dummy.m new file mode 100644 index 0000000..9a08ec3 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GoogleDataTransport : NSObject +@end +@implementation PodsDummy_GoogleDataTransport +@end diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-umbrella.h b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-umbrella.h new file mode 100644 index 0000000..53d9138 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-umbrella.h @@ -0,0 +1,25 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "GDTCORClock.h" +#import "GDTCORConsoleLogger.h" +#import "GDTCOREndpoints.h" +#import "GDTCOREvent.h" +#import "GDTCOREventDataObject.h" +#import "GDTCOREventTransformer.h" +#import "GDTCORTargets.h" +#import "GDTCORTransport.h" +#import "GoogleDataTransport.h" + +FOUNDATION_EXPORT double GoogleDataTransportVersionNumber; +FOUNDATION_EXPORT const unsigned char GoogleDataTransportVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.debug.xcconfig new file mode 100644 index 0000000..656e7c2 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 GDTCOR_VERSION=9.1.2 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}/" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleDataTransport +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap new file mode 100644 index 0000000..8a67414 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap @@ -0,0 +1,6 @@ +framework module GoogleDataTransport { + umbrella header "GoogleDataTransport-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.release.xcconfig new file mode 100644 index 0000000..656e7c2 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 GDTCOR_VERSION=9.1.2 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}/" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleDataTransport +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist new file mode 100644 index 0000000..98e56b3 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 7.6.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-dummy.m b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-dummy.m new file mode 100644 index 0000000..98ac4e9 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GoogleUtilities : NSObject +@end +@implementation PodsDummy_GoogleUtilities +@end diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-umbrella.h b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-umbrella.h new file mode 100644 index 0000000..465644a --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-umbrella.h @@ -0,0 +1,38 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "GULAppDelegateSwizzler.h" +#import "GULApplication.h" +#import "GULSceneDelegateSwizzler.h" +#import "GULAppEnvironmentUtil.h" +#import "GULHeartbeatDateStorable.h" +#import "GULHeartbeatDateStorage.h" +#import "GULHeartbeatDateStorageUserDefaults.h" +#import "GULKeychainStorage.h" +#import "GULKeychainUtils.h" +#import "GULSecureCoding.h" +#import "GULURLSessionDataResponse.h" +#import "NSURLSession+GULPromises.h" +#import "GULLogger.h" +#import "GULLoggerLevel.h" +#import "GULNSData+zlib.h" +#import "GULMutableDictionary.h" +#import "GULNetwork.h" +#import "GULNetworkConstants.h" +#import "GULNetworkLoggerProtocol.h" +#import "GULNetworkMessageCode.h" +#import "GULNetworkURLSession.h" +#import "GULReachabilityChecker.h" + +FOUNDATION_EXPORT double GoogleUtilitiesVersionNumber; +FOUNDATION_EXPORT const unsigned char GoogleUtilitiesVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.debug.xcconfig new file mode 100644 index 0000000..1136499 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "FBLPromises" -framework "Security" -framework "SystemConfiguration" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleUtilities +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.modulemap b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.modulemap new file mode 100644 index 0000000..491dd0a --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.modulemap @@ -0,0 +1,6 @@ +framework module GoogleUtilities { + umbrella header "GoogleUtilities-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.release.xcconfig new file mode 100644 index 0000000..1136499 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "FBLPromises" -framework "Security" -framework "SystemConfiguration" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleUtilities +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-Info.plist b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-acknowledgements.markdown b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-acknowledgements.markdown new file mode 100644 index 0000000..324eea9 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-acknowledgements.markdown @@ -0,0 +1,2163 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## Firebase + + + 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. + + +## FirebaseAuth + + + 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. + + +## FirebaseCore + + + 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. + + +## FirebaseCoreDiagnostics + + + 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. + + +## FirebaseDatabase + + + 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. + + +## FirebaseStorage + + + 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. + + +## GTMSessionFetcher + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## GoogleDataTransport + + + 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. + + +## GoogleUtilities + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +================================================================================ + +The following copyright from Landon J. Fuller applies to the isAppEncrypted +function in Environment/third_party/GULAppEnvironmentUtil.m. + +Copyright (c) 2017 Landon J. Fuller +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Comment from +iPhone Dev Wiki +Crack Prevention: App Store binaries are signed by both their developer +and Apple. This encrypts the binary so that decryption keys are needed in order +to make the binary readable. When iOS executes the binary, the decryption keys +are used to decrypt the binary into a readable state where it is then loaded +into memory and executed. iOS can tell the encryption status of a binary via the +cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is +a non-zero value then the binary is encrypted. + +'Cracking' works by letting the kernel decrypt the binary then siphoning the +decrypted data into a new binary file, resigning, and repackaging. This will +only work on jailbroken devices as codesignature validation has been removed. +Resigning takes place because while the codesignature doesn't have to be valid +thanks to the jailbreak, it does have to be in place unless you have AppSync or +similar to disable codesignature checks. + +More information at Landon +Fuller's blog + + +## PromisesObjC + + + 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. + + +## leveldb-library + +Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +## nanopb + +Copyright (c) 2011 Petteri Aimonen + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held liable +for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. + +Generated by CocoaPods - https://cocoapods.org diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-acknowledgements.plist b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-acknowledgements.plist new file mode 100644 index 0000000..db6bba9 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-acknowledgements.plist @@ -0,0 +1,2261 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + Firebase + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + FirebaseAuth + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + FirebaseCore + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + FirebaseCoreDiagnostics + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + FirebaseDatabase + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + FirebaseStorage + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + GTMSessionFetcher + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + GoogleDataTransport + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +================================================================================ + +The following copyright from Landon J. Fuller applies to the isAppEncrypted +function in Environment/third_party/GULAppEnvironmentUtil.m. + +Copyright (c) 2017 Landon J. Fuller <landon@landonf.org> +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Comment from +<a href="http://iphonedevwiki.net/index.php/Crack_prevention">iPhone Dev Wiki +Crack Prevention</a>: App Store binaries are signed by both their developer +and Apple. This encrypts the binary so that decryption keys are needed in order +to make the binary readable. When iOS executes the binary, the decryption keys +are used to decrypt the binary into a readable state where it is then loaded +into memory and executed. iOS can tell the encryption status of a binary via the +cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is +a non-zero value then the binary is encrypted. + +'Cracking' works by letting the kernel decrypt the binary then siphoning the +decrypted data into a new binary file, resigning, and repackaging. This will +only work on jailbroken devices as codesignature validation has been removed. +Resigning takes place because while the codesignature doesn't have to be valid +thanks to the jailbreak, it does have to be in place unless you have AppSync or +similar to disable codesignature checks. + +More information at <a href="http://landonf.org/2009/02/index.html">Landon +Fuller's blog</a> + + License + Apache + Title + GoogleUtilities + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache + Title + PromisesObjC + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + License + New BSD + Title + leveldb-library + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2011 Petteri Aimonen <jpa at nanopb.mail.kapsi.fi> + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held liable +for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. + + License + zlib + Title + nanopb + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-dummy.m b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-dummy.m new file mode 100644 index 0000000..7bf5739 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_saraWhatsUp : NSObject +@end +@implementation PodsDummy_Pods_saraWhatsUp +@end diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Debug-input-files.xcfilelist b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Debug-input-files.xcfilelist new file mode 100644 index 0000000..824d7e2 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Debug-input-files.xcfilelist @@ -0,0 +1,12 @@ +${PODS_ROOT}/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks.sh +${BUILT_PRODUCTS_DIR}/FirebaseAuth/FirebaseAuth.framework +${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework +${BUILT_PRODUCTS_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework +${BUILT_PRODUCTS_DIR}/FirebaseDatabase/FirebaseDatabase.framework +${BUILT_PRODUCTS_DIR}/FirebaseStorage/FirebaseStorage.framework +${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework +${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework +${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework +${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework +${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework +${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework \ No newline at end of file diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Debug-output-files.xcfilelist b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Debug-output-files.xcfilelist new file mode 100644 index 0000000..345a965 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Debug-output-files.xcfilelist @@ -0,0 +1,11 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAuth.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreDiagnostics.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseDatabase.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseStorage.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework \ No newline at end of file diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Release-input-files.xcfilelist b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Release-input-files.xcfilelist new file mode 100644 index 0000000..824d7e2 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Release-input-files.xcfilelist @@ -0,0 +1,12 @@ +${PODS_ROOT}/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks.sh +${BUILT_PRODUCTS_DIR}/FirebaseAuth/FirebaseAuth.framework +${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework +${BUILT_PRODUCTS_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework +${BUILT_PRODUCTS_DIR}/FirebaseDatabase/FirebaseDatabase.framework +${BUILT_PRODUCTS_DIR}/FirebaseStorage/FirebaseStorage.framework +${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework +${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework +${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework +${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework +${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework +${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework \ No newline at end of file diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Release-output-files.xcfilelist b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Release-output-files.xcfilelist new file mode 100644 index 0000000..345a965 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-Release-output-files.xcfilelist @@ -0,0 +1,11 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAuth.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreDiagnostics.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseDatabase.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseStorage.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework \ No newline at end of file diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks.sh b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks.sh new file mode 100755 index 0000000..fb1ae76 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks.sh @@ -0,0 +1,206 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + +if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then + # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy + # frameworks to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +BCSYMBOLMAP_DIR="BCSymbolMaps" + + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +# Copies and strips a vendored framework +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then + # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied + find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do + echo "Installing $f" + install_bcsymbolmap "$f" "$destination" + rm "$f" + done + rmdir "${source}/${BCSYMBOLMAP_DIR}" + fi + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + elif [ -L "${binary}" ]; then + echo "Destination binary is symlinked..." + dirname="$(dirname "${binary}")" + binary="${dirname}/$(readlink "${binary}")" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} +# Copies and strips a vendored dSYM +install_dsym() { + local source="$1" + warn_missing_arch=${2:-true} + if [ -r "$source" ]; then + # Copy the dSYM into the targets temp dir. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" + + local basename + basename="$(basename -s .dSYM "$source")" + binary_name="$(ls "$source/Contents/Resources/DWARF")" + binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" + + # Strip invalid architectures from the dSYM. + if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then + strip_invalid_archs "$binary" "$warn_missing_arch" + fi + if [[ $STRIP_BINARY_RETVAL == 0 ]]; then + # Move the stripped file into its final destination. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" + else + # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. + mkdir -p "${DWARF_DSYM_FOLDER_PATH}" + touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" + fi + fi +} + +# Used as a return value for each invocation of `strip_invalid_archs` function. +STRIP_BINARY_RETVAL=0 + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + warn_missing_arch=${2:-true} + # Get architectures for current target binary + binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" + # Intersect them with the architectures we are building for + intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" + # If there are no archs supported by this binary then warn the user + if [[ -z "$intersected_archs" ]]; then + if [[ "$warn_missing_arch" == "true" ]]; then + echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." + fi + STRIP_BINARY_RETVAL=1 + return + fi + stripped="" + for arch in $binary_archs; do + if ! [[ "${ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi + STRIP_BINARY_RETVAL=0 +} + +# Copies the bcsymbolmap files of a vendored framework +install_bcsymbolmap() { + local bcsymbolmap_path="$1" + local destination="${BUILT_PRODUCTS_DIR}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identity + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" + + if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + code_sign_cmd="$code_sign_cmd &" + fi + echo "$code_sign_cmd" + eval "$code_sign_cmd" + fi +} + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseAuth/FirebaseAuth.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseDatabase/FirebaseDatabase.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseStorage/FirebaseStorage.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework" + install_framework "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework" + install_framework "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework" + install_framework "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseAuth/FirebaseAuth.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseDatabase/FirebaseDatabase.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseStorage/FirebaseStorage.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework" + install_framework "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework" + install_framework "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework" + install_framework "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework" +fi +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-umbrella.h b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-umbrella.h new file mode 100644 index 0000000..af1ddf6 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_saraWhatsUpVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_saraWhatsUpVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.debug.xcconfig new file mode 100644 index 0000000..b58e768 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAuth" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseDatabase" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseStorage" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAuth/FirebaseAuth.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore/FirebaseCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseDatabase/FirebaseDatabase.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseStorage/FirebaseStorage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport/GoogleDataTransport.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities/GoogleUtilities.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library/leveldb.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb/nanopb.framework/Headers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources "${PODS_TARGET_SRCROOT}/Sources/FBLPromises/include" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -l"c++" -l"icucore" -l"z" -framework "CFNetwork" -framework "CoreTelephony" -framework "FBLPromises" -framework "FirebaseAuth" -framework "FirebaseCore" -framework "FirebaseCoreDiagnostics" -framework "FirebaseDatabase" -framework "FirebaseStorage" -framework "Foundation" -framework "GTMSessionFetcher" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "SafariServices" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "leveldb" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.modulemap b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.modulemap new file mode 100644 index 0000000..c8b176f --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.modulemap @@ -0,0 +1,6 @@ +framework module Pods_saraWhatsUp { + umbrella header "Pods-saraWhatsUp-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.release.xcconfig new file mode 100644 index 0000000..b58e768 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAuth" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseDatabase" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseStorage" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAuth/FirebaseAuth.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore/FirebaseCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics/FirebaseCoreDiagnostics.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseDatabase/FirebaseDatabase.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseStorage/FirebaseStorage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport/GoogleDataTransport.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities/GoogleUtilities.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library/leveldb.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb/nanopb.framework/Headers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources "${PODS_TARGET_SRCROOT}/Sources/FBLPromises/include" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -l"c++" -l"icucore" -l"z" -framework "CFNetwork" -framework "CoreTelephony" -framework "FBLPromises" -framework "FirebaseAuth" -framework "FirebaseCore" -framework "FirebaseCoreDiagnostics" -framework "FirebaseDatabase" -framework "FirebaseStorage" -framework "Foundation" -framework "GTMSessionFetcher" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "SafariServices" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "leveldb" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-Info.plist b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-Info.plist new file mode 100644 index 0000000..0a12077 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-dummy.m b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-dummy.m new file mode 100644 index 0000000..ab1f210 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_PromisesObjC : NSObject +@end +@implementation PodsDummy_PromisesObjC +@end diff --git a/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-umbrella.h b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-umbrella.h new file mode 100644 index 0000000..5b014a8 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC-umbrella.h @@ -0,0 +1,36 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FBLPromise+All.h" +#import "FBLPromise+Always.h" +#import "FBLPromise+Any.h" +#import "FBLPromise+Async.h" +#import "FBLPromise+Await.h" +#import "FBLPromise+Catch.h" +#import "FBLPromise+Delay.h" +#import "FBLPromise+Do.h" +#import "FBLPromise+Race.h" +#import "FBLPromise+Recover.h" +#import "FBLPromise+Reduce.h" +#import "FBLPromise+Retry.h" +#import "FBLPromise+Testing.h" +#import "FBLPromise+Then.h" +#import "FBLPromise+Timeout.h" +#import "FBLPromise+Validate.h" +#import "FBLPromise+Wrap.h" +#import "FBLPromise.h" +#import "FBLPromiseError.h" +#import "FBLPromises.h" + +FOUNDATION_EXPORT double FBLPromisesVersionNumber; +FOUNDATION_EXPORT const unsigned char FBLPromisesVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.debug.xcconfig new file mode 100644 index 0000000..1f5ad57 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}/Sources/FBLPromises/include" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PromisesObjC +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.modulemap b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.modulemap new file mode 100644 index 0000000..7d485cd --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.modulemap @@ -0,0 +1,6 @@ +framework module FBLPromises { + umbrella header "PromisesObjC-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.release.xcconfig new file mode 100644 index 0000000..1f5ad57 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/PromisesObjC/PromisesObjC.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}/Sources/FBLPromises/include" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PromisesObjC +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-Info.plist b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-Info.plist new file mode 100644 index 0000000..0f6eb4f --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.22.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-dummy.m b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-dummy.m new file mode 100644 index 0000000..dba1492 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_leveldb_library : NSObject +@end +@implementation PodsDummy_leveldb_library +@end diff --git a/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-prefix.pch b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-umbrella.h b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-umbrella.h new file mode 100644 index 0000000..6a45902 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library-umbrella.h @@ -0,0 +1,31 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "c.h" +#import "cache.h" +#import "comparator.h" +#import "db.h" +#import "dumpfile.h" +#import "env.h" +#import "export.h" +#import "filter_policy.h" +#import "iterator.h" +#import "options.h" +#import "slice.h" +#import "status.h" +#import "table.h" +#import "table_builder.h" +#import "write_batch.h" + +FOUNDATION_EXPORT double leveldbVersionNumber; +FOUNDATION_EXPORT const unsigned char leveldbVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.debug.xcconfig new file mode 100644 index 0000000..ea1c640 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 LEVELDB_IS_BIG_ENDIAN=0 LEVELDB_PLATFORM_POSIX HAVE_FULLFSYNC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/leveldb-library" "${PODS_ROOT}/leveldb-library/include" +OTHER_LDFLAGS = $(inherited) -l"c++" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/leveldb-library +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_HEADERMAP = No +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES +WARNING_CFLAGS = -Wno-shorten-64-to-32 -Wno-comma -Wno-unreachable-code -Wno-conditional-uninitialized -Wno-deprecated-declarations diff --git a/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.modulemap b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.modulemap new file mode 100644 index 0000000..fd77435 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.modulemap @@ -0,0 +1,6 @@ +framework module leveldb { + umbrella header "leveldb-library-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.release.xcconfig new file mode 100644 index 0000000..ea1c640 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/leveldb-library/leveldb-library.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 LEVELDB_IS_BIG_ENDIAN=0 LEVELDB_PLATFORM_POSIX HAVE_FULLFSYNC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/leveldb-library" "${PODS_ROOT}/leveldb-library/include" +OTHER_LDFLAGS = $(inherited) -l"c++" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/leveldb-library +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_HEADERMAP = No +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES +WARNING_CFLAGS = -Wno-shorten-64-to-32 -Wno-comma -Wno-unreachable-code -Wno-conditional-uninitialized -Wno-deprecated-declarations diff --git a/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-Info.plist b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-Info.plist new file mode 100644 index 0000000..658a7bf --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.30908.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-dummy.m b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-dummy.m new file mode 100644 index 0000000..b3fa595 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_nanopb : NSObject +@end +@implementation PodsDummy_nanopb +@end diff --git a/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-prefix.pch b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-umbrella.h b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-umbrella.h new file mode 100644 index 0000000..07e77b3 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb-umbrella.h @@ -0,0 +1,26 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "pb.h" +#import "pb_common.h" +#import "pb_decode.h" +#import "pb_encode.h" +#import "pb.h" +#import "pb_decode.h" +#import "pb_common.h" +#import "pb.h" +#import "pb_encode.h" +#import "pb_common.h" + +FOUNDATION_EXPORT double nanopbVersionNumber; +FOUNDATION_EXPORT const unsigned char nanopbVersionString[]; + diff --git a/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.debug.xcconfig b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.debug.xcconfig new file mode 100644 index 0000000..7156998 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.debug.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/nanopb +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/nanopb +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.modulemap b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.modulemap new file mode 100644 index 0000000..e8d4b53 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.modulemap @@ -0,0 +1,6 @@ +framework module nanopb { + umbrella header "nanopb-umbrella.h" + + export * + module * { export * } +} diff --git a/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.release.xcconfig b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.release.xcconfig new file mode 100644 index 0000000..7156998 --- /dev/null +++ b/saraWhatsUp/Pods/Target Support Files/nanopb/nanopb.release.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/nanopb +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/nanopb +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/saraWhatsUp/Pods/leveldb-library/LICENSE b/saraWhatsUp/Pods/leveldb-library/LICENSE new file mode 100644 index 0000000..8e80208 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/saraWhatsUp/Pods/leveldb-library/README.md b/saraWhatsUp/Pods/leveldb-library/README.md new file mode 100644 index 0000000..0b660ae --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/README.md @@ -0,0 +1,225 @@ +**LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.** + +[![Build Status](https://travis-ci.org/google/leveldb.svg?branch=master)](https://travis-ci.org/google/leveldb) +[![Build status](https://ci.appveyor.com/api/projects/status/g2j5j4rfkda6eyw5/branch/master?svg=true)](https://ci.appveyor.com/project/pwnall/leveldb) + +Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) + +# Features + + * Keys and values are arbitrary byte arrays. + * Data is stored sorted by key. + * Callers can provide a custom comparison function to override the sort order. + * The basic operations are `Put(key,value)`, `Get(key)`, `Delete(key)`. + * Multiple changes can be made in one atomic batch. + * Users can create a transient snapshot to get a consistent view of data. + * Forward and backward iteration is supported over the data. + * Data is automatically compressed using the [Snappy compression library](http://google.github.io/snappy/). + * External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions. + +# Documentation + + [LevelDB library documentation](https://github.com/google/leveldb/blob/master/doc/index.md) is online and bundled with the source code. + +# Limitations + + * This is not a SQL database. It does not have a relational data model, it does not support SQL queries, and it has no support for indexes. + * Only a single process (possibly multi-threaded) can access a particular database at a time. + * There is no client-server support builtin to the library. An application that needs such support will have to wrap their own server around the library. + +# Building + +This project supports [CMake](https://cmake.org/) out of the box. + +### Build for POSIX + +Quick start: + +```bash +mkdir -p build && cd build +cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build . +``` + +### Building for Windows + +First generate the Visual Studio 2017 project/solution files: + +```cmd +mkdir build +cd build +cmake -G "Visual Studio 15" .. +``` +The default default will build for x86. For 64-bit run: + +```cmd +cmake -G "Visual Studio 15 Win64" .. +``` + +To compile the Windows solution from the command-line: + +```cmd +devenv /build Debug leveldb.sln +``` + +or open leveldb.sln in Visual Studio and build from within. + +Please see the CMake documentation and `CMakeLists.txt` for more advanced usage. + +# Contributing to the leveldb Project + +The leveldb project welcomes contributions. leveldb's primary goal is to be +a reliable and fast key/value store. Changes that are in line with the +features/limitations outlined above, and meet the requirements below, +will be considered. + +Contribution requirements: + +1. **Tested platforms only**. We _generally_ will only accept changes for + platforms that are compiled and tested. This means POSIX (for Linux and + macOS) or Windows. Very small changes will sometimes be accepted, but + consider that more of an exception than the rule. + +2. **Stable API**. We strive very hard to maintain a stable API. Changes that + require changes for projects using leveldb _might_ be rejected without + sufficient benefit to the project. + +3. **Tests**: All changes must be accompanied by a new (or changed) test, or + a sufficient explanation as to why a new (or changed) test is not required. + +4. **Consistent Style**: This project conforms to the + [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). + To ensure your changes are properly formatted please run: + + ``` + clang-format -i --style=file + ``` + +## Submitting a Pull Request + +Before any pull request will be accepted the author must first sign a +Contributor License Agreement (CLA) at https://cla.developers.google.com/. + +In order to keep the commit timeline linear +[squash](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Squashing-Commits) +your changes down to a single commit and [rebase](https://git-scm.com/docs/git-rebase) +on google/leveldb/master. This keeps the commit timeline linear and more easily sync'ed +with the internal repository at Google. More information at GitHub's +[About Git rebase](https://help.github.com/articles/about-git-rebase/) page. + +# Performance + +Here is a performance report (with explanations) from the run of the +included db_bench program. The results are somewhat noisy, but should +be enough to get a ballpark performance estimate. + +## Setup + +We use a database with a million entries. Each entry has a 16 byte +key, and a 100 byte value. Values used by the benchmark compress to +about half their original size. + + LevelDB: version 1.1 + Date: Sun May 1 12:11:26 2011 + CPU: 4 x Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz + CPUCache: 4096 KB + Keys: 16 bytes each + Values: 100 bytes each (50 bytes after compression) + Entries: 1000000 + Raw Size: 110.6 MB (estimated) + File Size: 62.9 MB (estimated) + +## Write performance + +The "fill" benchmarks create a brand new database, in either +sequential, or random order. The "fillsync" benchmark flushes data +from the operating system to the disk after every operation; the other +write operations leave the data sitting in the operating system buffer +cache for a while. The "overwrite" benchmark does random writes that +update existing keys in the database. + + fillseq : 1.765 micros/op; 62.7 MB/s + fillsync : 268.409 micros/op; 0.4 MB/s (10000 ops) + fillrandom : 2.460 micros/op; 45.0 MB/s + overwrite : 2.380 micros/op; 46.5 MB/s + +Each "op" above corresponds to a write of a single key/value pair. +I.e., a random write benchmark goes at approximately 400,000 writes per second. + +Each "fillsync" operation costs much less (0.3 millisecond) +than a disk seek (typically 10 milliseconds). We suspect that this is +because the hard disk itself is buffering the update in its memory and +responding before the data has been written to the platter. This may +or may not be safe based on whether or not the hard disk has enough +power to save its memory in the event of a power failure. + +## Read performance + +We list the performance of reading sequentially in both the forward +and reverse direction, and also the performance of a random lookup. +Note that the database created by the benchmark is quite small. +Therefore the report characterizes the performance of leveldb when the +working set fits in memory. The cost of reading a piece of data that +is not present in the operating system buffer cache will be dominated +by the one or two disk seeks needed to fetch the data from disk. +Write performance will be mostly unaffected by whether or not the +working set fits in memory. + + readrandom : 16.677 micros/op; (approximately 60,000 reads per second) + readseq : 0.476 micros/op; 232.3 MB/s + readreverse : 0.724 micros/op; 152.9 MB/s + +LevelDB compacts its underlying storage data in the background to +improve read performance. The results listed above were done +immediately after a lot of random writes. The results after +compactions (which are usually triggered automatically) are better. + + readrandom : 11.602 micros/op; (approximately 85,000 reads per second) + readseq : 0.423 micros/op; 261.8 MB/s + readreverse : 0.663 micros/op; 166.9 MB/s + +Some of the high cost of reads comes from repeated decompression of blocks +read from disk. If we supply enough cache to the leveldb so it can hold the +uncompressed blocks in memory, the read performance improves again: + + readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction) + readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction) + +## Repository contents + +See [doc/index.md](doc/index.md) for more explanation. See +[doc/impl.md](doc/impl.md) for a brief overview of the implementation. + +The public interface is in include/*.h. Callers should not include or +rely on the details of any other header files in this package. Those +internal APIs may be changed without warning. + +Guide to header files: + +* **include/db.h**: Main interface to the DB: Start here + +* **include/options.h**: Control over the behavior of an entire database, +and also control over the behavior of individual reads and writes. + +* **include/comparator.h**: Abstraction for user-specified comparison function. +If you want just bytewise comparison of keys, you can use the default +comparator, but clients can write their own comparator implementations if they +want custom ordering (e.g. to handle different character encodings, etc.) + +* **include/iterator.h**: Interface for iterating over data. You can get +an iterator from a DB object. + +* **include/write_batch.h**: Interface for atomically applying multiple +updates to a database. + +* **include/slice.h**: A simple module for maintaining a pointer and a +length into some other byte array. + +* **include/status.h**: Status is returned from many of the public interfaces +and is used to report success and various kinds of errors. + +* **include/env.h**: +Abstraction of the OS environment. A posix implementation of this interface is +in util/env_posix.cc + +* **include/table.h, include/table_builder.h**: Lower-level modules that most +clients probably won't use directly diff --git a/saraWhatsUp/Pods/leveldb-library/db/builder.cc b/saraWhatsUp/Pods/leveldb-library/db/builder.cc new file mode 100644 index 0000000..9520ee4 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/builder.cc @@ -0,0 +1,79 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/builder.h" + +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/table_cache.h" +#include "db/version_edit.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" + +namespace leveldb { + +Status BuildTable(const std::string& dbname, Env* env, const Options& options, + TableCache* table_cache, Iterator* iter, FileMetaData* meta) { + Status s; + meta->file_size = 0; + iter->SeekToFirst(); + + std::string fname = TableFileName(dbname, meta->number); + if (iter->Valid()) { + WritableFile* file; + s = env->NewWritableFile(fname, &file); + if (!s.ok()) { + return s; + } + + TableBuilder* builder = new TableBuilder(options, file); + meta->smallest.DecodeFrom(iter->key()); + for (; iter->Valid(); iter->Next()) { + Slice key = iter->key(); + meta->largest.DecodeFrom(key); + builder->Add(key, iter->value()); + } + + // Finish and check for builder errors + s = builder->Finish(); + if (s.ok()) { + meta->file_size = builder->FileSize(); + assert(meta->file_size > 0); + } + delete builder; + + // Finish and check for file errors + if (s.ok()) { + s = file->Sync(); + } + if (s.ok()) { + s = file->Close(); + } + delete file; + file = nullptr; + + if (s.ok()) { + // Verify that the table is usable + Iterator* it = table_cache->NewIterator(ReadOptions(), meta->number, + meta->file_size); + s = it->status(); + delete it; + } + } + + // Check for input iterator errors + if (!iter->status().ok()) { + s = iter->status(); + } + + if (s.ok() && meta->file_size > 0) { + // Keep it + } else { + env->DeleteFile(fname); + } + return s; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/builder.h b/saraWhatsUp/Pods/leveldb-library/db/builder.h new file mode 100644 index 0000000..7bd0b80 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/builder.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_BUILDER_H_ +#define STORAGE_LEVELDB_DB_BUILDER_H_ + +#include "leveldb/status.h" + +namespace leveldb { + +struct Options; +struct FileMetaData; + +class Env; +class Iterator; +class TableCache; +class VersionEdit; + +// Build a Table file from the contents of *iter. The generated file +// will be named according to meta->number. On success, the rest of +// *meta will be filled with metadata about the generated table. +// If no data is present in *iter, meta->file_size will be set to +// zero, and no Table file will be produced. +Status BuildTable(const std::string& dbname, Env* env, const Options& options, + TableCache* table_cache, Iterator* iter, FileMetaData* meta); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_BUILDER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/c.cc b/saraWhatsUp/Pods/leveldb-library/db/c.cc new file mode 100644 index 0000000..e0f3367 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/c.cc @@ -0,0 +1,566 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/c.h" + +#include + +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" +#include "leveldb/write_batch.h" + +using leveldb::Cache; +using leveldb::Comparator; +using leveldb::CompressionType; +using leveldb::DB; +using leveldb::Env; +using leveldb::FileLock; +using leveldb::FilterPolicy; +using leveldb::Iterator; +using leveldb::kMajorVersion; +using leveldb::kMinorVersion; +using leveldb::Logger; +using leveldb::NewBloomFilterPolicy; +using leveldb::NewLRUCache; +using leveldb::Options; +using leveldb::RandomAccessFile; +using leveldb::Range; +using leveldb::ReadOptions; +using leveldb::SequentialFile; +using leveldb::Slice; +using leveldb::Snapshot; +using leveldb::Status; +using leveldb::WritableFile; +using leveldb::WriteBatch; +using leveldb::WriteOptions; + +extern "C" { + +struct leveldb_t { + DB* rep; +}; +struct leveldb_iterator_t { + Iterator* rep; +}; +struct leveldb_writebatch_t { + WriteBatch rep; +}; +struct leveldb_snapshot_t { + const Snapshot* rep; +}; +struct leveldb_readoptions_t { + ReadOptions rep; +}; +struct leveldb_writeoptions_t { + WriteOptions rep; +}; +struct leveldb_options_t { + Options rep; +}; +struct leveldb_cache_t { + Cache* rep; +}; +struct leveldb_seqfile_t { + SequentialFile* rep; +}; +struct leveldb_randomfile_t { + RandomAccessFile* rep; +}; +struct leveldb_writablefile_t { + WritableFile* rep; +}; +struct leveldb_logger_t { + Logger* rep; +}; +struct leveldb_filelock_t { + FileLock* rep; +}; + +struct leveldb_comparator_t : public Comparator { + virtual ~leveldb_comparator_t() { (*destructor_)(state_); } + + virtual int Compare(const Slice& a, const Slice& b) const { + return (*compare_)(state_, a.data(), a.size(), b.data(), b.size()); + } + + virtual const char* Name() const { return (*name_)(state_); } + + // No-ops since the C binding does not support key shortening methods. + virtual void FindShortestSeparator(std::string*, const Slice&) const {} + virtual void FindShortSuccessor(std::string* key) const {} + + void* state_; + void (*destructor_)(void*); + int (*compare_)(void*, const char* a, size_t alen, const char* b, + size_t blen); + const char* (*name_)(void*); +}; + +struct leveldb_filterpolicy_t : public FilterPolicy { + virtual ~leveldb_filterpolicy_t() { (*destructor_)(state_); } + + virtual const char* Name() const { return (*name_)(state_); } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + std::vector key_pointers(n); + std::vector key_sizes(n); + for (int i = 0; i < n; i++) { + key_pointers[i] = keys[i].data(); + key_sizes[i] = keys[i].size(); + } + size_t len; + char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len); + dst->append(filter, len); + free(filter); + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { + return (*key_match_)(state_, key.data(), key.size(), filter.data(), + filter.size()); + } + + void* state_; + void (*destructor_)(void*); + const char* (*name_)(void*); + char* (*create_)(void*, const char* const* key_array, + const size_t* key_length_array, int num_keys, + size_t* filter_length); + unsigned char (*key_match_)(void*, const char* key, size_t length, + const char* filter, size_t filter_length); +}; + +struct leveldb_env_t { + Env* rep; + bool is_default; +}; + +static bool SaveError(char** errptr, const Status& s) { + assert(errptr != nullptr); + if (s.ok()) { + return false; + } else if (*errptr == nullptr) { + *errptr = strdup(s.ToString().c_str()); + } else { + // TODO(sanjay): Merge with existing error? + free(*errptr); + *errptr = strdup(s.ToString().c_str()); + } + return true; +} + +static char* CopyString(const std::string& str) { + char* result = reinterpret_cast(malloc(sizeof(char) * str.size())); + memcpy(result, str.data(), sizeof(char) * str.size()); + return result; +} + +leveldb_t* leveldb_open(const leveldb_options_t* options, const char* name, + char** errptr) { + DB* db; + if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) { + return nullptr; + } + leveldb_t* result = new leveldb_t; + result->rep = db; + return result; +} + +void leveldb_close(leveldb_t* db) { + delete db->rep; + delete db; +} + +void leveldb_put(leveldb_t* db, const leveldb_writeoptions_t* options, + const char* key, size_t keylen, const char* val, size_t vallen, + char** errptr) { + SaveError(errptr, + db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen))); +} + +void leveldb_delete(leveldb_t* db, const leveldb_writeoptions_t* options, + const char* key, size_t keylen, char** errptr) { + SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen))); +} + +void leveldb_write(leveldb_t* db, const leveldb_writeoptions_t* options, + leveldb_writebatch_t* batch, char** errptr) { + SaveError(errptr, db->rep->Write(options->rep, &batch->rep)); +} + +char* leveldb_get(leveldb_t* db, const leveldb_readoptions_t* options, + const char* key, size_t keylen, size_t* vallen, + char** errptr) { + char* result = nullptr; + std::string tmp; + Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp); + if (s.ok()) { + *vallen = tmp.size(); + result = CopyString(tmp); + } else { + *vallen = 0; + if (!s.IsNotFound()) { + SaveError(errptr, s); + } + } + return result; +} + +leveldb_iterator_t* leveldb_create_iterator( + leveldb_t* db, const leveldb_readoptions_t* options) { + leveldb_iterator_t* result = new leveldb_iterator_t; + result->rep = db->rep->NewIterator(options->rep); + return result; +} + +const leveldb_snapshot_t* leveldb_create_snapshot(leveldb_t* db) { + leveldb_snapshot_t* result = new leveldb_snapshot_t; + result->rep = db->rep->GetSnapshot(); + return result; +} + +void leveldb_release_snapshot(leveldb_t* db, + const leveldb_snapshot_t* snapshot) { + db->rep->ReleaseSnapshot(snapshot->rep); + delete snapshot; +} + +char* leveldb_property_value(leveldb_t* db, const char* propname) { + std::string tmp; + if (db->rep->GetProperty(Slice(propname), &tmp)) { + // We use strdup() since we expect human readable output. + return strdup(tmp.c_str()); + } else { + return nullptr; + } +} + +void leveldb_approximate_sizes(leveldb_t* db, int num_ranges, + const char* const* range_start_key, + const size_t* range_start_key_len, + const char* const* range_limit_key, + const size_t* range_limit_key_len, + uint64_t* sizes) { + Range* ranges = new Range[num_ranges]; + for (int i = 0; i < num_ranges; i++) { + ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]); + ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]); + } + db->rep->GetApproximateSizes(ranges, num_ranges, sizes); + delete[] ranges; +} + +void leveldb_compact_range(leveldb_t* db, const char* start_key, + size_t start_key_len, const char* limit_key, + size_t limit_key_len) { + Slice a, b; + db->rep->CompactRange( + // Pass null Slice if corresponding "const char*" is null + (start_key ? (a = Slice(start_key, start_key_len), &a) : nullptr), + (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : nullptr)); +} + +void leveldb_destroy_db(const leveldb_options_t* options, const char* name, + char** errptr) { + SaveError(errptr, DestroyDB(name, options->rep)); +} + +void leveldb_repair_db(const leveldb_options_t* options, const char* name, + char** errptr) { + SaveError(errptr, RepairDB(name, options->rep)); +} + +void leveldb_iter_destroy(leveldb_iterator_t* iter) { + delete iter->rep; + delete iter; +} + +unsigned char leveldb_iter_valid(const leveldb_iterator_t* iter) { + return iter->rep->Valid(); +} + +void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) { + iter->rep->SeekToFirst(); +} + +void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) { + iter->rep->SeekToLast(); +} + +void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) { + iter->rep->Seek(Slice(k, klen)); +} + +void leveldb_iter_next(leveldb_iterator_t* iter) { iter->rep->Next(); } + +void leveldb_iter_prev(leveldb_iterator_t* iter) { iter->rep->Prev(); } + +const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) { + Slice s = iter->rep->key(); + *klen = s.size(); + return s.data(); +} + +const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) { + Slice s = iter->rep->value(); + *vlen = s.size(); + return s.data(); +} + +void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) { + SaveError(errptr, iter->rep->status()); +} + +leveldb_writebatch_t* leveldb_writebatch_create() { + return new leveldb_writebatch_t; +} + +void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { delete b; } + +void leveldb_writebatch_clear(leveldb_writebatch_t* b) { b->rep.Clear(); } + +void leveldb_writebatch_put(leveldb_writebatch_t* b, const char* key, + size_t klen, const char* val, size_t vlen) { + b->rep.Put(Slice(key, klen), Slice(val, vlen)); +} + +void leveldb_writebatch_delete(leveldb_writebatch_t* b, const char* key, + size_t klen) { + b->rep.Delete(Slice(key, klen)); +} + +void leveldb_writebatch_iterate(const leveldb_writebatch_t* b, void* state, + void (*put)(void*, const char* k, size_t klen, + const char* v, size_t vlen), + void (*deleted)(void*, const char* k, + size_t klen)) { + class H : public WriteBatch::Handler { + public: + void* state_; + void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen); + void (*deleted_)(void*, const char* k, size_t klen); + virtual void Put(const Slice& key, const Slice& value) { + (*put_)(state_, key.data(), key.size(), value.data(), value.size()); + } + virtual void Delete(const Slice& key) { + (*deleted_)(state_, key.data(), key.size()); + } + }; + H handler; + handler.state_ = state; + handler.put_ = put; + handler.deleted_ = deleted; + b->rep.Iterate(&handler); +} + +void leveldb_writebatch_append(leveldb_writebatch_t* destination, + const leveldb_writebatch_t* source) { + destination->rep.Append(source->rep); +} + +leveldb_options_t* leveldb_options_create() { return new leveldb_options_t; } + +void leveldb_options_destroy(leveldb_options_t* options) { delete options; } + +void leveldb_options_set_comparator(leveldb_options_t* opt, + leveldb_comparator_t* cmp) { + opt->rep.comparator = cmp; +} + +void leveldb_options_set_filter_policy(leveldb_options_t* opt, + leveldb_filterpolicy_t* policy) { + opt->rep.filter_policy = policy; +} + +void leveldb_options_set_create_if_missing(leveldb_options_t* opt, + unsigned char v) { + opt->rep.create_if_missing = v; +} + +void leveldb_options_set_error_if_exists(leveldb_options_t* opt, + unsigned char v) { + opt->rep.error_if_exists = v; +} + +void leveldb_options_set_paranoid_checks(leveldb_options_t* opt, + unsigned char v) { + opt->rep.paranoid_checks = v; +} + +void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) { + opt->rep.env = (env ? env->rep : nullptr); +} + +void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) { + opt->rep.info_log = (l ? l->rep : nullptr); +} + +void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) { + opt->rep.write_buffer_size = s; +} + +void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) { + opt->rep.max_open_files = n; +} + +void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) { + opt->rep.block_cache = c->rep; +} + +void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) { + opt->rep.block_size = s; +} + +void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) { + opt->rep.block_restart_interval = n; +} + +void leveldb_options_set_max_file_size(leveldb_options_t* opt, size_t s) { + opt->rep.max_file_size = s; +} + +void leveldb_options_set_compression(leveldb_options_t* opt, int t) { + opt->rep.compression = static_cast(t); +} + +leveldb_comparator_t* leveldb_comparator_create( + void* state, void (*destructor)(void*), + int (*compare)(void*, const char* a, size_t alen, const char* b, + size_t blen), + const char* (*name)(void*)) { + leveldb_comparator_t* result = new leveldb_comparator_t; + result->state_ = state; + result->destructor_ = destructor; + result->compare_ = compare; + result->name_ = name; + return result; +} + +void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { delete cmp; } + +leveldb_filterpolicy_t* leveldb_filterpolicy_create( + void* state, void (*destructor)(void*), + char* (*create_filter)(void*, const char* const* key_array, + const size_t* key_length_array, int num_keys, + size_t* filter_length), + unsigned char (*key_may_match)(void*, const char* key, size_t length, + const char* filter, size_t filter_length), + const char* (*name)(void*)) { + leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t; + result->state_ = state; + result->destructor_ = destructor; + result->create_ = create_filter; + result->key_match_ = key_may_match; + result->name_ = name; + return result; +} + +void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) { + delete filter; +} + +leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) { + // Make a leveldb_filterpolicy_t, but override all of its methods so + // they delegate to a NewBloomFilterPolicy() instead of user + // supplied C functions. + struct Wrapper : public leveldb_filterpolicy_t { + static void DoNothing(void*) {} + + ~Wrapper() { delete rep_; } + const char* Name() const { return rep_->Name(); } + void CreateFilter(const Slice* keys, int n, std::string* dst) const { + return rep_->CreateFilter(keys, n, dst); + } + bool KeyMayMatch(const Slice& key, const Slice& filter) const { + return rep_->KeyMayMatch(key, filter); + } + + const FilterPolicy* rep_; + }; + Wrapper* wrapper = new Wrapper; + wrapper->rep_ = NewBloomFilterPolicy(bits_per_key); + wrapper->state_ = nullptr; + wrapper->destructor_ = &Wrapper::DoNothing; + return wrapper; +} + +leveldb_readoptions_t* leveldb_readoptions_create() { + return new leveldb_readoptions_t; +} + +void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { delete opt; } + +void leveldb_readoptions_set_verify_checksums(leveldb_readoptions_t* opt, + unsigned char v) { + opt->rep.verify_checksums = v; +} + +void leveldb_readoptions_set_fill_cache(leveldb_readoptions_t* opt, + unsigned char v) { + opt->rep.fill_cache = v; +} + +void leveldb_readoptions_set_snapshot(leveldb_readoptions_t* opt, + const leveldb_snapshot_t* snap) { + opt->rep.snapshot = (snap ? snap->rep : nullptr); +} + +leveldb_writeoptions_t* leveldb_writeoptions_create() { + return new leveldb_writeoptions_t; +} + +void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { delete opt; } + +void leveldb_writeoptions_set_sync(leveldb_writeoptions_t* opt, + unsigned char v) { + opt->rep.sync = v; +} + +leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) { + leveldb_cache_t* c = new leveldb_cache_t; + c->rep = NewLRUCache(capacity); + return c; +} + +void leveldb_cache_destroy(leveldb_cache_t* cache) { + delete cache->rep; + delete cache; +} + +leveldb_env_t* leveldb_create_default_env() { + leveldb_env_t* result = new leveldb_env_t; + result->rep = Env::Default(); + result->is_default = true; + return result; +} + +void leveldb_env_destroy(leveldb_env_t* env) { + if (!env->is_default) delete env->rep; + delete env; +} + +char* leveldb_env_get_test_directory(leveldb_env_t* env) { + std::string result; + if (!env->rep->GetTestDirectory(&result).ok()) { + return nullptr; + } + + char* buffer = static_cast(malloc(result.size() + 1)); + memcpy(buffer, result.data(), result.size()); + buffer[result.size()] = '\0'; + return buffer; +} + +void leveldb_free(void* ptr) { free(ptr); } + +int leveldb_major_version() { return kMajorVersion; } + +int leveldb_minor_version() { return kMinorVersion; } + +} // end extern "C" diff --git a/saraWhatsUp/Pods/leveldb-library/db/db_impl.cc b/saraWhatsUp/Pods/leveldb-library/db/db_impl.cc new file mode 100644 index 0000000..761ebf6 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/db_impl.cc @@ -0,0 +1,1550 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_impl.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "db/builder.h" +#include "db/db_iter.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/status.h" +#include "leveldb/table.h" +#include "leveldb/table_builder.h" +#include "port/port.h" +#include "table/block.h" +#include "table/merger.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" +#include "util/logging.h" +#include "util/mutexlock.h" + +namespace leveldb { + +const int kNumNonTableCacheFiles = 10; + +// Information kept for every waiting writer +struct DBImpl::Writer { + explicit Writer(port::Mutex* mu) + : batch(nullptr), sync(false), done(false), cv(mu) {} + + Status status; + WriteBatch* batch; + bool sync; + bool done; + port::CondVar cv; +}; + +struct DBImpl::CompactionState { + // Files produced by compaction + struct Output { + uint64_t number; + uint64_t file_size; + InternalKey smallest, largest; + }; + + Output* current_output() { return &outputs[outputs.size() - 1]; } + + explicit CompactionState(Compaction* c) + : compaction(c), + smallest_snapshot(0), + outfile(nullptr), + builder(nullptr), + total_bytes(0) {} + + Compaction* const compaction; + + // Sequence numbers < smallest_snapshot are not significant since we + // will never have to service a snapshot below smallest_snapshot. + // Therefore if we have seen a sequence number S <= smallest_snapshot, + // we can drop all entries for the same key with sequence numbers < S. + SequenceNumber smallest_snapshot; + + std::vector outputs; + + // State kept for output being generated + WritableFile* outfile; + TableBuilder* builder; + + uint64_t total_bytes; +}; + +// Fix user-supplied options to be reasonable +template +static void ClipToRange(T* ptr, V minvalue, V maxvalue) { + if (static_cast(*ptr) > maxvalue) *ptr = maxvalue; + if (static_cast(*ptr) < minvalue) *ptr = minvalue; +} +Options SanitizeOptions(const std::string& dbname, + const InternalKeyComparator* icmp, + const InternalFilterPolicy* ipolicy, + const Options& src) { + Options result = src; + result.comparator = icmp; + result.filter_policy = (src.filter_policy != nullptr) ? ipolicy : nullptr; + ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000); + ClipToRange(&result.write_buffer_size, 64 << 10, 1 << 30); + ClipToRange(&result.max_file_size, 1 << 20, 1 << 30); + ClipToRange(&result.block_size, 1 << 10, 4 << 20); + if (result.info_log == nullptr) { + // Open a log file in the same directory as the db + src.env->CreateDir(dbname); // In case it does not exist + src.env->RenameFile(InfoLogFileName(dbname), OldInfoLogFileName(dbname)); + Status s = src.env->NewLogger(InfoLogFileName(dbname), &result.info_log); + if (!s.ok()) { + // No place suitable for logging + result.info_log = nullptr; + } + } + if (result.block_cache == nullptr) { + result.block_cache = NewLRUCache(8 << 20); + } + return result; +} + +static int TableCacheSize(const Options& sanitized_options) { + // Reserve ten files or so for other uses and give the rest to TableCache. + return sanitized_options.max_open_files - kNumNonTableCacheFiles; +} + +DBImpl::DBImpl(const Options& raw_options, const std::string& dbname) + : env_(raw_options.env), + internal_comparator_(raw_options.comparator), + internal_filter_policy_(raw_options.filter_policy), + options_(SanitizeOptions(dbname, &internal_comparator_, + &internal_filter_policy_, raw_options)), + owns_info_log_(options_.info_log != raw_options.info_log), + owns_cache_(options_.block_cache != raw_options.block_cache), + dbname_(dbname), + table_cache_(new TableCache(dbname_, options_, TableCacheSize(options_))), + db_lock_(nullptr), + shutting_down_(false), + background_work_finished_signal_(&mutex_), + mem_(nullptr), + imm_(nullptr), + has_imm_(false), + logfile_(nullptr), + logfile_number_(0), + log_(nullptr), + seed_(0), + tmp_batch_(new WriteBatch), + background_compaction_scheduled_(false), + manual_compaction_(nullptr), + versions_(new VersionSet(dbname_, &options_, table_cache_, + &internal_comparator_)) {} + +DBImpl::~DBImpl() { + // Wait for background work to finish. + mutex_.Lock(); + shutting_down_.store(true, std::memory_order_release); + while (background_compaction_scheduled_) { + background_work_finished_signal_.Wait(); + } + mutex_.Unlock(); + + if (db_lock_ != nullptr) { + env_->UnlockFile(db_lock_); + } + + delete versions_; + if (mem_ != nullptr) mem_->Unref(); + if (imm_ != nullptr) imm_->Unref(); + delete tmp_batch_; + delete log_; + delete logfile_; + delete table_cache_; + + if (owns_info_log_) { + delete options_.info_log; + } + if (owns_cache_) { + delete options_.block_cache; + } +} + +Status DBImpl::NewDB() { + VersionEdit new_db; + new_db.SetComparatorName(user_comparator()->Name()); + new_db.SetLogNumber(0); + new_db.SetNextFile(2); + new_db.SetLastSequence(0); + + const std::string manifest = DescriptorFileName(dbname_, 1); + WritableFile* file; + Status s = env_->NewWritableFile(manifest, &file); + if (!s.ok()) { + return s; + } + { + log::Writer log(file); + std::string record; + new_db.EncodeTo(&record); + s = log.AddRecord(record); + if (s.ok()) { + s = file->Close(); + } + } + delete file; + if (s.ok()) { + // Make "CURRENT" file that points to the new manifest file. + s = SetCurrentFile(env_, dbname_, 1); + } else { + env_->DeleteFile(manifest); + } + return s; +} + +void DBImpl::MaybeIgnoreError(Status* s) const { + if (s->ok() || options_.paranoid_checks) { + // No change needed + } else { + Log(options_.info_log, "Ignoring error %s", s->ToString().c_str()); + *s = Status::OK(); + } +} + +void DBImpl::DeleteObsoleteFiles() { + mutex_.AssertHeld(); + + if (!bg_error_.ok()) { + // After a background error, we don't know whether a new version may + // or may not have been committed, so we cannot safely garbage collect. + return; + } + + // Make a set of all of the live files + std::set live = pending_outputs_; + versions_->AddLiveFiles(&live); + + std::vector filenames; + env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + bool keep = true; + switch (type) { + case kLogFile: + keep = ((number >= versions_->LogNumber()) || + (number == versions_->PrevLogNumber())); + break; + case kDescriptorFile: + // Keep my manifest file, and any newer incarnations' + // (in case there is a race that allows other incarnations) + keep = (number >= versions_->ManifestFileNumber()); + break; + case kTableFile: + keep = (live.find(number) != live.end()); + break; + case kTempFile: + // Any temp files that are currently being written to must + // be recorded in pending_outputs_, which is inserted into "live" + keep = (live.find(number) != live.end()); + break; + case kCurrentFile: + case kDBLockFile: + case kInfoLogFile: + keep = true; + break; + } + + if (!keep) { + if (type == kTableFile) { + table_cache_->Evict(number); + } + Log(options_.info_log, "Delete type=%d #%lld\n", static_cast(type), + static_cast(number)); + env_->DeleteFile(dbname_ + "/" + filenames[i]); + } + } + } +} + +Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest) { + mutex_.AssertHeld(); + + // Ignore error from CreateDir since the creation of the DB is + // committed only when the descriptor is created, and this directory + // may already exist from a previous failed creation attempt. + env_->CreateDir(dbname_); + assert(db_lock_ == nullptr); + Status s = env_->LockFile(LockFileName(dbname_), &db_lock_); + if (!s.ok()) { + return s; + } + + if (!env_->FileExists(CurrentFileName(dbname_))) { + if (options_.create_if_missing) { + s = NewDB(); + if (!s.ok()) { + return s; + } + } else { + return Status::InvalidArgument( + dbname_, "does not exist (create_if_missing is false)"); + } + } else { + if (options_.error_if_exists) { + return Status::InvalidArgument(dbname_, + "exists (error_if_exists is true)"); + } + } + + s = versions_->Recover(save_manifest); + if (!s.ok()) { + return s; + } + SequenceNumber max_sequence(0); + + // Recover from all newer log files than the ones named in the + // descriptor (new log files may have been added by the previous + // incarnation without registering them in the descriptor). + // + // Note that PrevLogNumber() is no longer used, but we pay + // attention to it in case we are recovering a database + // produced by an older version of leveldb. + const uint64_t min_log = versions_->LogNumber(); + const uint64_t prev_log = versions_->PrevLogNumber(); + std::vector filenames; + s = env_->GetChildren(dbname_, &filenames); + if (!s.ok()) { + return s; + } + std::set expected; + versions_->AddLiveFiles(&expected); + uint64_t number; + FileType type; + std::vector logs; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + expected.erase(number); + if (type == kLogFile && ((number >= min_log) || (number == prev_log))) + logs.push_back(number); + } + } + if (!expected.empty()) { + char buf[50]; + snprintf(buf, sizeof(buf), "%d missing files; e.g.", + static_cast(expected.size())); + return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin()))); + } + + // Recover in the order in which the logs were generated + std::sort(logs.begin(), logs.end()); + for (size_t i = 0; i < logs.size(); i++) { + s = RecoverLogFile(logs[i], (i == logs.size() - 1), save_manifest, edit, + &max_sequence); + if (!s.ok()) { + return s; + } + + // The previous incarnation may not have written any MANIFEST + // records after allocating this log number. So we manually + // update the file number allocation counter in VersionSet. + versions_->MarkFileNumberUsed(logs[i]); + } + + if (versions_->LastSequence() < max_sequence) { + versions_->SetLastSequence(max_sequence); + } + + return Status::OK(); +} + +Status DBImpl::RecoverLogFile(uint64_t log_number, bool last_log, + bool* save_manifest, VersionEdit* edit, + SequenceNumber* max_sequence) { + struct LogReporter : public log::Reader::Reporter { + Env* env; + Logger* info_log; + const char* fname; + Status* status; // null if options_.paranoid_checks==false + virtual void Corruption(size_t bytes, const Status& s) { + Log(info_log, "%s%s: dropping %d bytes; %s", + (this->status == nullptr ? "(ignoring error) " : ""), fname, + static_cast(bytes), s.ToString().c_str()); + if (this->status != nullptr && this->status->ok()) *this->status = s; + } + }; + + mutex_.AssertHeld(); + + // Open the log file + std::string fname = LogFileName(dbname_, log_number); + SequentialFile* file; + Status status = env_->NewSequentialFile(fname, &file); + if (!status.ok()) { + MaybeIgnoreError(&status); + return status; + } + + // Create the log reader. + LogReporter reporter; + reporter.env = env_; + reporter.info_log = options_.info_log; + reporter.fname = fname.c_str(); + reporter.status = (options_.paranoid_checks ? &status : nullptr); + // We intentionally make log::Reader do checksumming even if + // paranoid_checks==false so that corruptions cause entire commits + // to be skipped instead of propagating bad information (like overly + // large sequence numbers). + log::Reader reader(file, &reporter, true /*checksum*/, 0 /*initial_offset*/); + Log(options_.info_log, "Recovering log #%llu", + (unsigned long long)log_number); + + // Read all the records and add to a memtable + std::string scratch; + Slice record; + WriteBatch batch; + int compactions = 0; + MemTable* mem = nullptr; + while (reader.ReadRecord(&record, &scratch) && status.ok()) { + if (record.size() < 12) { + reporter.Corruption(record.size(), + Status::Corruption("log record too small")); + continue; + } + WriteBatchInternal::SetContents(&batch, record); + + if (mem == nullptr) { + mem = new MemTable(internal_comparator_); + mem->Ref(); + } + status = WriteBatchInternal::InsertInto(&batch, mem); + MaybeIgnoreError(&status); + if (!status.ok()) { + break; + } + const SequenceNumber last_seq = WriteBatchInternal::Sequence(&batch) + + WriteBatchInternal::Count(&batch) - 1; + if (last_seq > *max_sequence) { + *max_sequence = last_seq; + } + + if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) { + compactions++; + *save_manifest = true; + status = WriteLevel0Table(mem, edit, nullptr); + mem->Unref(); + mem = nullptr; + if (!status.ok()) { + // Reflect errors immediately so that conditions like full + // file-systems cause the DB::Open() to fail. + break; + } + } + } + + delete file; + + // See if we should keep reusing the last log file. + if (status.ok() && options_.reuse_logs && last_log && compactions == 0) { + assert(logfile_ == nullptr); + assert(log_ == nullptr); + assert(mem_ == nullptr); + uint64_t lfile_size; + if (env_->GetFileSize(fname, &lfile_size).ok() && + env_->NewAppendableFile(fname, &logfile_).ok()) { + Log(options_.info_log, "Reusing old log %s \n", fname.c_str()); + log_ = new log::Writer(logfile_, lfile_size); + logfile_number_ = log_number; + if (mem != nullptr) { + mem_ = mem; + mem = nullptr; + } else { + // mem can be nullptr if lognum exists but was empty. + mem_ = new MemTable(internal_comparator_); + mem_->Ref(); + } + } + } + + if (mem != nullptr) { + // mem did not get reused; compact it. + if (status.ok()) { + *save_manifest = true; + status = WriteLevel0Table(mem, edit, nullptr); + } + mem->Unref(); + } + + return status; +} + +Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit, + Version* base) { + mutex_.AssertHeld(); + const uint64_t start_micros = env_->NowMicros(); + FileMetaData meta; + meta.number = versions_->NewFileNumber(); + pending_outputs_.insert(meta.number); + Iterator* iter = mem->NewIterator(); + Log(options_.info_log, "Level-0 table #%llu: started", + (unsigned long long)meta.number); + + Status s; + { + mutex_.Unlock(); + s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); + mutex_.Lock(); + } + + Log(options_.info_log, "Level-0 table #%llu: %lld bytes %s", + (unsigned long long)meta.number, (unsigned long long)meta.file_size, + s.ToString().c_str()); + delete iter; + pending_outputs_.erase(meta.number); + + // Note that if file_size is zero, the file has been deleted and + // should not be added to the manifest. + int level = 0; + if (s.ok() && meta.file_size > 0) { + const Slice min_user_key = meta.smallest.user_key(); + const Slice max_user_key = meta.largest.user_key(); + if (base != nullptr) { + level = base->PickLevelForMemTableOutput(min_user_key, max_user_key); + } + edit->AddFile(level, meta.number, meta.file_size, meta.smallest, + meta.largest); + } + + CompactionStats stats; + stats.micros = env_->NowMicros() - start_micros; + stats.bytes_written = meta.file_size; + stats_[level].Add(stats); + return s; +} + +void DBImpl::CompactMemTable() { + mutex_.AssertHeld(); + assert(imm_ != nullptr); + + // Save the contents of the memtable as a new Table + VersionEdit edit; + Version* base = versions_->current(); + base->Ref(); + Status s = WriteLevel0Table(imm_, &edit, base); + base->Unref(); + + if (s.ok() && shutting_down_.load(std::memory_order_acquire)) { + s = Status::IOError("Deleting DB during memtable compaction"); + } + + // Replace immutable memtable with the generated Table + if (s.ok()) { + edit.SetPrevLogNumber(0); + edit.SetLogNumber(logfile_number_); // Earlier logs no longer needed + s = versions_->LogAndApply(&edit, &mutex_); + } + + if (s.ok()) { + // Commit to the new state + imm_->Unref(); + imm_ = nullptr; + has_imm_.store(false, std::memory_order_release); + DeleteObsoleteFiles(); + } else { + RecordBackgroundError(s); + } +} + +void DBImpl::CompactRange(const Slice* begin, const Slice* end) { + int max_level_with_files = 1; + { + MutexLock l(&mutex_); + Version* base = versions_->current(); + for (int level = 1; level < config::kNumLevels; level++) { + if (base->OverlapInLevel(level, begin, end)) { + max_level_with_files = level; + } + } + } + TEST_CompactMemTable(); // TODO(sanjay): Skip if memtable does not overlap + for (int level = 0; level < max_level_with_files; level++) { + TEST_CompactRange(level, begin, end); + } +} + +void DBImpl::TEST_CompactRange(int level, const Slice* begin, + const Slice* end) { + assert(level >= 0); + assert(level + 1 < config::kNumLevels); + + InternalKey begin_storage, end_storage; + + ManualCompaction manual; + manual.level = level; + manual.done = false; + if (begin == nullptr) { + manual.begin = nullptr; + } else { + begin_storage = InternalKey(*begin, kMaxSequenceNumber, kValueTypeForSeek); + manual.begin = &begin_storage; + } + if (end == nullptr) { + manual.end = nullptr; + } else { + end_storage = InternalKey(*end, 0, static_cast(0)); + manual.end = &end_storage; + } + + MutexLock l(&mutex_); + while (!manual.done && !shutting_down_.load(std::memory_order_acquire) && + bg_error_.ok()) { + if (manual_compaction_ == nullptr) { // Idle + manual_compaction_ = &manual; + MaybeScheduleCompaction(); + } else { // Running either my compaction or another compaction. + background_work_finished_signal_.Wait(); + } + } + if (manual_compaction_ == &manual) { + // Cancel my manual compaction since we aborted early for some reason. + manual_compaction_ = nullptr; + } +} + +Status DBImpl::TEST_CompactMemTable() { + // nullptr batch means just wait for earlier writes to be done + Status s = Write(WriteOptions(), nullptr); + if (s.ok()) { + // Wait until the compaction completes + MutexLock l(&mutex_); + while (imm_ != nullptr && bg_error_.ok()) { + background_work_finished_signal_.Wait(); + } + if (imm_ != nullptr) { + s = bg_error_; + } + } + return s; +} + +void DBImpl::RecordBackgroundError(const Status& s) { + mutex_.AssertHeld(); + if (bg_error_.ok()) { + bg_error_ = s; + background_work_finished_signal_.SignalAll(); + } +} + +void DBImpl::MaybeScheduleCompaction() { + mutex_.AssertHeld(); + if (background_compaction_scheduled_) { + // Already scheduled + } else if (shutting_down_.load(std::memory_order_acquire)) { + // DB is being deleted; no more background compactions + } else if (!bg_error_.ok()) { + // Already got an error; no more changes + } else if (imm_ == nullptr && manual_compaction_ == nullptr && + !versions_->NeedsCompaction()) { + // No work to be done + } else { + background_compaction_scheduled_ = true; + env_->Schedule(&DBImpl::BGWork, this); + } +} + +void DBImpl::BGWork(void* db) { + reinterpret_cast(db)->BackgroundCall(); +} + +void DBImpl::BackgroundCall() { + MutexLock l(&mutex_); + assert(background_compaction_scheduled_); + if (shutting_down_.load(std::memory_order_acquire)) { + // No more background work when shutting down. + } else if (!bg_error_.ok()) { + // No more background work after a background error. + } else { + BackgroundCompaction(); + } + + background_compaction_scheduled_ = false; + + // Previous compaction may have produced too many files in a level, + // so reschedule another compaction if needed. + MaybeScheduleCompaction(); + background_work_finished_signal_.SignalAll(); +} + +void DBImpl::BackgroundCompaction() { + mutex_.AssertHeld(); + + if (imm_ != nullptr) { + CompactMemTable(); + return; + } + + Compaction* c; + bool is_manual = (manual_compaction_ != nullptr); + InternalKey manual_end; + if (is_manual) { + ManualCompaction* m = manual_compaction_; + c = versions_->CompactRange(m->level, m->begin, m->end); + m->done = (c == nullptr); + if (c != nullptr) { + manual_end = c->input(0, c->num_input_files(0) - 1)->largest; + } + Log(options_.info_log, + "Manual compaction at level-%d from %s .. %s; will stop at %s\n", + m->level, (m->begin ? m->begin->DebugString().c_str() : "(begin)"), + (m->end ? m->end->DebugString().c_str() : "(end)"), + (m->done ? "(end)" : manual_end.DebugString().c_str())); + } else { + c = versions_->PickCompaction(); + } + + Status status; + if (c == nullptr) { + // Nothing to do + } else if (!is_manual && c->IsTrivialMove()) { + // Move file to next level + assert(c->num_input_files(0) == 1); + FileMetaData* f = c->input(0, 0); + c->edit()->DeleteFile(c->level(), f->number); + c->edit()->AddFile(c->level() + 1, f->number, f->file_size, f->smallest, + f->largest); + status = versions_->LogAndApply(c->edit(), &mutex_); + if (!status.ok()) { + RecordBackgroundError(status); + } + VersionSet::LevelSummaryStorage tmp; + Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n", + static_cast(f->number), c->level() + 1, + static_cast(f->file_size), + status.ToString().c_str(), versions_->LevelSummary(&tmp)); + } else { + CompactionState* compact = new CompactionState(c); + status = DoCompactionWork(compact); + if (!status.ok()) { + RecordBackgroundError(status); + } + CleanupCompaction(compact); + c->ReleaseInputs(); + DeleteObsoleteFiles(); + } + delete c; + + if (status.ok()) { + // Done + } else if (shutting_down_.load(std::memory_order_acquire)) { + // Ignore compaction errors found during shutting down + } else { + Log(options_.info_log, "Compaction error: %s", status.ToString().c_str()); + } + + if (is_manual) { + ManualCompaction* m = manual_compaction_; + if (!status.ok()) { + m->done = true; + } + if (!m->done) { + // We only compacted part of the requested range. Update *m + // to the range that is left to be compacted. + m->tmp_storage = manual_end; + m->begin = &m->tmp_storage; + } + manual_compaction_ = nullptr; + } +} + +void DBImpl::CleanupCompaction(CompactionState* compact) { + mutex_.AssertHeld(); + if (compact->builder != nullptr) { + // May happen if we get a shutdown call in the middle of compaction + compact->builder->Abandon(); + delete compact->builder; + } else { + assert(compact->outfile == nullptr); + } + delete compact->outfile; + for (size_t i = 0; i < compact->outputs.size(); i++) { + const CompactionState::Output& out = compact->outputs[i]; + pending_outputs_.erase(out.number); + } + delete compact; +} + +Status DBImpl::OpenCompactionOutputFile(CompactionState* compact) { + assert(compact != nullptr); + assert(compact->builder == nullptr); + uint64_t file_number; + { + mutex_.Lock(); + file_number = versions_->NewFileNumber(); + pending_outputs_.insert(file_number); + CompactionState::Output out; + out.number = file_number; + out.smallest.Clear(); + out.largest.Clear(); + compact->outputs.push_back(out); + mutex_.Unlock(); + } + + // Make the output file + std::string fname = TableFileName(dbname_, file_number); + Status s = env_->NewWritableFile(fname, &compact->outfile); + if (s.ok()) { + compact->builder = new TableBuilder(options_, compact->outfile); + } + return s; +} + +Status DBImpl::FinishCompactionOutputFile(CompactionState* compact, + Iterator* input) { + assert(compact != nullptr); + assert(compact->outfile != nullptr); + assert(compact->builder != nullptr); + + const uint64_t output_number = compact->current_output()->number; + assert(output_number != 0); + + // Check for iterator errors + Status s = input->status(); + const uint64_t current_entries = compact->builder->NumEntries(); + if (s.ok()) { + s = compact->builder->Finish(); + } else { + compact->builder->Abandon(); + } + const uint64_t current_bytes = compact->builder->FileSize(); + compact->current_output()->file_size = current_bytes; + compact->total_bytes += current_bytes; + delete compact->builder; + compact->builder = nullptr; + + // Finish and check for file errors + if (s.ok()) { + s = compact->outfile->Sync(); + } + if (s.ok()) { + s = compact->outfile->Close(); + } + delete compact->outfile; + compact->outfile = nullptr; + + if (s.ok() && current_entries > 0) { + // Verify that the table is usable + Iterator* iter = + table_cache_->NewIterator(ReadOptions(), output_number, current_bytes); + s = iter->status(); + delete iter; + if (s.ok()) { + Log(options_.info_log, "Generated table #%llu@%d: %lld keys, %lld bytes", + (unsigned long long)output_number, compact->compaction->level(), + (unsigned long long)current_entries, + (unsigned long long)current_bytes); + } + } + return s; +} + +Status DBImpl::InstallCompactionResults(CompactionState* compact) { + mutex_.AssertHeld(); + Log(options_.info_log, "Compacted %d@%d + %d@%d files => %lld bytes", + compact->compaction->num_input_files(0), compact->compaction->level(), + compact->compaction->num_input_files(1), compact->compaction->level() + 1, + static_cast(compact->total_bytes)); + + // Add compaction outputs + compact->compaction->AddInputDeletions(compact->compaction->edit()); + const int level = compact->compaction->level(); + for (size_t i = 0; i < compact->outputs.size(); i++) { + const CompactionState::Output& out = compact->outputs[i]; + compact->compaction->edit()->AddFile(level + 1, out.number, out.file_size, + out.smallest, out.largest); + } + return versions_->LogAndApply(compact->compaction->edit(), &mutex_); +} + +Status DBImpl::DoCompactionWork(CompactionState* compact) { + const uint64_t start_micros = env_->NowMicros(); + int64_t imm_micros = 0; // Micros spent doing imm_ compactions + + Log(options_.info_log, "Compacting %d@%d + %d@%d files", + compact->compaction->num_input_files(0), compact->compaction->level(), + compact->compaction->num_input_files(1), + compact->compaction->level() + 1); + + assert(versions_->NumLevelFiles(compact->compaction->level()) > 0); + assert(compact->builder == nullptr); + assert(compact->outfile == nullptr); + if (snapshots_.empty()) { + compact->smallest_snapshot = versions_->LastSequence(); + } else { + compact->smallest_snapshot = snapshots_.oldest()->sequence_number(); + } + + // Release mutex while we're actually doing the compaction work + mutex_.Unlock(); + + Iterator* input = versions_->MakeInputIterator(compact->compaction); + input->SeekToFirst(); + Status status; + ParsedInternalKey ikey; + std::string current_user_key; + bool has_current_user_key = false; + SequenceNumber last_sequence_for_key = kMaxSequenceNumber; + for (; input->Valid() && !shutting_down_.load(std::memory_order_acquire);) { + // Prioritize immutable compaction work + if (has_imm_.load(std::memory_order_relaxed)) { + const uint64_t imm_start = env_->NowMicros(); + mutex_.Lock(); + if (imm_ != nullptr) { + CompactMemTable(); + // Wake up MakeRoomForWrite() if necessary. + background_work_finished_signal_.SignalAll(); + } + mutex_.Unlock(); + imm_micros += (env_->NowMicros() - imm_start); + } + + Slice key = input->key(); + if (compact->compaction->ShouldStopBefore(key) && + compact->builder != nullptr) { + status = FinishCompactionOutputFile(compact, input); + if (!status.ok()) { + break; + } + } + + // Handle key/value, add to state, etc. + bool drop = false; + if (!ParseInternalKey(key, &ikey)) { + // Do not hide error keys + current_user_key.clear(); + has_current_user_key = false; + last_sequence_for_key = kMaxSequenceNumber; + } else { + if (!has_current_user_key || + user_comparator()->Compare(ikey.user_key, Slice(current_user_key)) != + 0) { + // First occurrence of this user key + current_user_key.assign(ikey.user_key.data(), ikey.user_key.size()); + has_current_user_key = true; + last_sequence_for_key = kMaxSequenceNumber; + } + + if (last_sequence_for_key <= compact->smallest_snapshot) { + // Hidden by an newer entry for same user key + drop = true; // (A) + } else if (ikey.type == kTypeDeletion && + ikey.sequence <= compact->smallest_snapshot && + compact->compaction->IsBaseLevelForKey(ikey.user_key)) { + // For this user key: + // (1) there is no data in higher levels + // (2) data in lower levels will have larger sequence numbers + // (3) data in layers that are being compacted here and have + // smaller sequence numbers will be dropped in the next + // few iterations of this loop (by rule (A) above). + // Therefore this deletion marker is obsolete and can be dropped. + drop = true; + } + + last_sequence_for_key = ikey.sequence; + } +#if 0 + Log(options_.info_log, + " Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, " + "%d smallest_snapshot: %d", + ikey.user_key.ToString().c_str(), + (int)ikey.sequence, ikey.type, kTypeValue, drop, + compact->compaction->IsBaseLevelForKey(ikey.user_key), + (int)last_sequence_for_key, (int)compact->smallest_snapshot); +#endif + + if (!drop) { + // Open output file if necessary + if (compact->builder == nullptr) { + status = OpenCompactionOutputFile(compact); + if (!status.ok()) { + break; + } + } + if (compact->builder->NumEntries() == 0) { + compact->current_output()->smallest.DecodeFrom(key); + } + compact->current_output()->largest.DecodeFrom(key); + compact->builder->Add(key, input->value()); + + // Close output file if it is big enough + if (compact->builder->FileSize() >= + compact->compaction->MaxOutputFileSize()) { + status = FinishCompactionOutputFile(compact, input); + if (!status.ok()) { + break; + } + } + } + + input->Next(); + } + + if (status.ok() && shutting_down_.load(std::memory_order_acquire)) { + status = Status::IOError("Deleting DB during compaction"); + } + if (status.ok() && compact->builder != nullptr) { + status = FinishCompactionOutputFile(compact, input); + } + if (status.ok()) { + status = input->status(); + } + delete input; + input = nullptr; + + CompactionStats stats; + stats.micros = env_->NowMicros() - start_micros - imm_micros; + for (int which = 0; which < 2; which++) { + for (int i = 0; i < compact->compaction->num_input_files(which); i++) { + stats.bytes_read += compact->compaction->input(which, i)->file_size; + } + } + for (size_t i = 0; i < compact->outputs.size(); i++) { + stats.bytes_written += compact->outputs[i].file_size; + } + + mutex_.Lock(); + stats_[compact->compaction->level() + 1].Add(stats); + + if (status.ok()) { + status = InstallCompactionResults(compact); + } + if (!status.ok()) { + RecordBackgroundError(status); + } + VersionSet::LevelSummaryStorage tmp; + Log(options_.info_log, "compacted to: %s", versions_->LevelSummary(&tmp)); + return status; +} + +namespace { + +struct IterState { + port::Mutex* const mu; + Version* const version GUARDED_BY(mu); + MemTable* const mem GUARDED_BY(mu); + MemTable* const imm GUARDED_BY(mu); + + IterState(port::Mutex* mutex, MemTable* mem, MemTable* imm, Version* version) + : mu(mutex), version(version), mem(mem), imm(imm) {} +}; + +static void CleanupIteratorState(void* arg1, void* arg2) { + IterState* state = reinterpret_cast(arg1); + state->mu->Lock(); + state->mem->Unref(); + if (state->imm != nullptr) state->imm->Unref(); + state->version->Unref(); + state->mu->Unlock(); + delete state; +} + +} // anonymous namespace + +Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, + SequenceNumber* latest_snapshot, + uint32_t* seed) { + mutex_.Lock(); + *latest_snapshot = versions_->LastSequence(); + + // Collect together all needed child iterators + std::vector list; + list.push_back(mem_->NewIterator()); + mem_->Ref(); + if (imm_ != nullptr) { + list.push_back(imm_->NewIterator()); + imm_->Ref(); + } + versions_->current()->AddIterators(options, &list); + Iterator* internal_iter = + NewMergingIterator(&internal_comparator_, &list[0], list.size()); + versions_->current()->Ref(); + + IterState* cleanup = new IterState(&mutex_, mem_, imm_, versions_->current()); + internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, nullptr); + + *seed = ++seed_; + mutex_.Unlock(); + return internal_iter; +} + +Iterator* DBImpl::TEST_NewInternalIterator() { + SequenceNumber ignored; + uint32_t ignored_seed; + return NewInternalIterator(ReadOptions(), &ignored, &ignored_seed); +} + +int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { + MutexLock l(&mutex_); + return versions_->MaxNextLevelOverlappingBytes(); +} + +Status DBImpl::Get(const ReadOptions& options, const Slice& key, + std::string* value) { + Status s; + MutexLock l(&mutex_); + SequenceNumber snapshot; + if (options.snapshot != nullptr) { + snapshot = + static_cast(options.snapshot)->sequence_number(); + } else { + snapshot = versions_->LastSequence(); + } + + MemTable* mem = mem_; + MemTable* imm = imm_; + Version* current = versions_->current(); + mem->Ref(); + if (imm != nullptr) imm->Ref(); + current->Ref(); + + bool have_stat_update = false; + Version::GetStats stats; + + // Unlock while reading from files and memtables + { + mutex_.Unlock(); + // First look in the memtable, then in the immutable memtable (if any). + LookupKey lkey(key, snapshot); + if (mem->Get(lkey, value, &s)) { + // Done + } else if (imm != nullptr && imm->Get(lkey, value, &s)) { + // Done + } else { + s = current->Get(options, lkey, value, &stats); + have_stat_update = true; + } + mutex_.Lock(); + } + + if (have_stat_update && current->UpdateStats(stats)) { + MaybeScheduleCompaction(); + } + mem->Unref(); + if (imm != nullptr) imm->Unref(); + current->Unref(); + return s; +} + +Iterator* DBImpl::NewIterator(const ReadOptions& options) { + SequenceNumber latest_snapshot; + uint32_t seed; + Iterator* iter = NewInternalIterator(options, &latest_snapshot, &seed); + return NewDBIterator(this, user_comparator(), iter, + (options.snapshot != nullptr + ? static_cast(options.snapshot) + ->sequence_number() + : latest_snapshot), + seed); +} + +void DBImpl::RecordReadSample(Slice key) { + MutexLock l(&mutex_); + if (versions_->current()->RecordReadSample(key)) { + MaybeScheduleCompaction(); + } +} + +const Snapshot* DBImpl::GetSnapshot() { + MutexLock l(&mutex_); + return snapshots_.New(versions_->LastSequence()); +} + +void DBImpl::ReleaseSnapshot(const Snapshot* snapshot) { + MutexLock l(&mutex_); + snapshots_.Delete(static_cast(snapshot)); +} + +// Convenience methods +Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) { + return DB::Put(o, key, val); +} + +Status DBImpl::Delete(const WriteOptions& options, const Slice& key) { + return DB::Delete(options, key); +} + +Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) { + Writer w(&mutex_); + w.batch = updates; + w.sync = options.sync; + w.done = false; + + MutexLock l(&mutex_); + writers_.push_back(&w); + while (!w.done && &w != writers_.front()) { + w.cv.Wait(); + } + if (w.done) { + return w.status; + } + + // May temporarily unlock and wait. + Status status = MakeRoomForWrite(updates == nullptr); + uint64_t last_sequence = versions_->LastSequence(); + Writer* last_writer = &w; + if (status.ok() && updates != nullptr) { // nullptr batch is for compactions + WriteBatch* updates = BuildBatchGroup(&last_writer); + WriteBatchInternal::SetSequence(updates, last_sequence + 1); + last_sequence += WriteBatchInternal::Count(updates); + + // Add to log and apply to memtable. We can release the lock + // during this phase since &w is currently responsible for logging + // and protects against concurrent loggers and concurrent writes + // into mem_. + { + mutex_.Unlock(); + status = log_->AddRecord(WriteBatchInternal::Contents(updates)); + bool sync_error = false; + if (status.ok() && options.sync) { + status = logfile_->Sync(); + if (!status.ok()) { + sync_error = true; + } + } + if (status.ok()) { + status = WriteBatchInternal::InsertInto(updates, mem_); + } + mutex_.Lock(); + if (sync_error) { + // The state of the log file is indeterminate: the log record we + // just added may or may not show up when the DB is re-opened. + // So we force the DB into a mode where all future writes fail. + RecordBackgroundError(status); + } + } + if (updates == tmp_batch_) tmp_batch_->Clear(); + + versions_->SetLastSequence(last_sequence); + } + + while (true) { + Writer* ready = writers_.front(); + writers_.pop_front(); + if (ready != &w) { + ready->status = status; + ready->done = true; + ready->cv.Signal(); + } + if (ready == last_writer) break; + } + + // Notify new head of write queue + if (!writers_.empty()) { + writers_.front()->cv.Signal(); + } + + return status; +} + +// REQUIRES: Writer list must be non-empty +// REQUIRES: First writer must have a non-null batch +WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) { + mutex_.AssertHeld(); + assert(!writers_.empty()); + Writer* first = writers_.front(); + WriteBatch* result = first->batch; + assert(result != nullptr); + + size_t size = WriteBatchInternal::ByteSize(first->batch); + + // Allow the group to grow up to a maximum size, but if the + // original write is small, limit the growth so we do not slow + // down the small write too much. + size_t max_size = 1 << 20; + if (size <= (128 << 10)) { + max_size = size + (128 << 10); + } + + *last_writer = first; + std::deque::iterator iter = writers_.begin(); + ++iter; // Advance past "first" + for (; iter != writers_.end(); ++iter) { + Writer* w = *iter; + if (w->sync && !first->sync) { + // Do not include a sync write into a batch handled by a non-sync write. + break; + } + + if (w->batch != nullptr) { + size += WriteBatchInternal::ByteSize(w->batch); + if (size > max_size) { + // Do not make batch too big + break; + } + + // Append to *result + if (result == first->batch) { + // Switch to temporary batch instead of disturbing caller's batch + result = tmp_batch_; + assert(WriteBatchInternal::Count(result) == 0); + WriteBatchInternal::Append(result, first->batch); + } + WriteBatchInternal::Append(result, w->batch); + } + *last_writer = w; + } + return result; +} + +// REQUIRES: mutex_ is held +// REQUIRES: this thread is currently at the front of the writer queue +Status DBImpl::MakeRoomForWrite(bool force) { + mutex_.AssertHeld(); + assert(!writers_.empty()); + bool allow_delay = !force; + Status s; + while (true) { + if (!bg_error_.ok()) { + // Yield previous error + s = bg_error_; + break; + } else if (allow_delay && versions_->NumLevelFiles(0) >= + config::kL0_SlowdownWritesTrigger) { + // We are getting close to hitting a hard limit on the number of + // L0 files. Rather than delaying a single write by several + // seconds when we hit the hard limit, start delaying each + // individual write by 1ms to reduce latency variance. Also, + // this delay hands over some CPU to the compaction thread in + // case it is sharing the same core as the writer. + mutex_.Unlock(); + env_->SleepForMicroseconds(1000); + allow_delay = false; // Do not delay a single write more than once + mutex_.Lock(); + } else if (!force && + (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) { + // There is room in current memtable + break; + } else if (imm_ != nullptr) { + // We have filled up the current memtable, but the previous + // one is still being compacted, so we wait. + Log(options_.info_log, "Current memtable full; waiting...\n"); + background_work_finished_signal_.Wait(); + } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) { + // There are too many level-0 files. + Log(options_.info_log, "Too many L0 files; waiting...\n"); + background_work_finished_signal_.Wait(); + } else { + // Attempt to switch to a new memtable and trigger compaction of old + assert(versions_->PrevLogNumber() == 0); + uint64_t new_log_number = versions_->NewFileNumber(); + WritableFile* lfile = nullptr; + s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile); + if (!s.ok()) { + // Avoid chewing through file number space in a tight loop. + versions_->ReuseFileNumber(new_log_number); + break; + } + delete log_; + delete logfile_; + logfile_ = lfile; + logfile_number_ = new_log_number; + log_ = new log::Writer(lfile); + imm_ = mem_; + has_imm_.store(true, std::memory_order_release); + mem_ = new MemTable(internal_comparator_); + mem_->Ref(); + force = false; // Do not force another compaction if have room + MaybeScheduleCompaction(); + } + } + return s; +} + +bool DBImpl::GetProperty(const Slice& property, std::string* value) { + value->clear(); + + MutexLock l(&mutex_); + Slice in = property; + Slice prefix("leveldb."); + if (!in.starts_with(prefix)) return false; + in.remove_prefix(prefix.size()); + + if (in.starts_with("num-files-at-level")) { + in.remove_prefix(strlen("num-files-at-level")); + uint64_t level; + bool ok = ConsumeDecimalNumber(&in, &level) && in.empty(); + if (!ok || level >= config::kNumLevels) { + return false; + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "%d", + versions_->NumLevelFiles(static_cast(level))); + *value = buf; + return true; + } + } else if (in == "stats") { + char buf[200]; + snprintf(buf, sizeof(buf), + " Compactions\n" + "Level Files Size(MB) Time(sec) Read(MB) Write(MB)\n" + "--------------------------------------------------\n"); + value->append(buf); + for (int level = 0; level < config::kNumLevels; level++) { + int files = versions_->NumLevelFiles(level); + if (stats_[level].micros > 0 || files > 0) { + snprintf(buf, sizeof(buf), "%3d %8d %8.0f %9.0f %8.0f %9.0f\n", level, + files, versions_->NumLevelBytes(level) / 1048576.0, + stats_[level].micros / 1e6, + stats_[level].bytes_read / 1048576.0, + stats_[level].bytes_written / 1048576.0); + value->append(buf); + } + } + return true; + } else if (in == "sstables") { + *value = versions_->current()->DebugString(); + return true; + } else if (in == "approximate-memory-usage") { + size_t total_usage = options_.block_cache->TotalCharge(); + if (mem_) { + total_usage += mem_->ApproximateMemoryUsage(); + } + if (imm_) { + total_usage += imm_->ApproximateMemoryUsage(); + } + char buf[50]; + snprintf(buf, sizeof(buf), "%llu", + static_cast(total_usage)); + value->append(buf); + return true; + } + + return false; +} + +void DBImpl::GetApproximateSizes(const Range* range, int n, uint64_t* sizes) { + // TODO(opt): better implementation + Version* v; + { + MutexLock l(&mutex_); + versions_->current()->Ref(); + v = versions_->current(); + } + + for (int i = 0; i < n; i++) { + // Convert user_key into a corresponding internal key. + InternalKey k1(range[i].start, kMaxSequenceNumber, kValueTypeForSeek); + InternalKey k2(range[i].limit, kMaxSequenceNumber, kValueTypeForSeek); + uint64_t start = versions_->ApproximateOffsetOf(v, k1); + uint64_t limit = versions_->ApproximateOffsetOf(v, k2); + sizes[i] = (limit >= start ? limit - start : 0); + } + + { + MutexLock l(&mutex_); + v->Unref(); + } +} + +// Default implementations of convenience methods that subclasses of DB +// can call if they wish +Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) { + WriteBatch batch; + batch.Put(key, value); + return Write(opt, &batch); +} + +Status DB::Delete(const WriteOptions& opt, const Slice& key) { + WriteBatch batch; + batch.Delete(key); + return Write(opt, &batch); +} + +DB::~DB() {} + +Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr) { + *dbptr = nullptr; + + DBImpl* impl = new DBImpl(options, dbname); + impl->mutex_.Lock(); + VersionEdit edit; + // Recover handles create_if_missing, error_if_exists + bool save_manifest = false; + Status s = impl->Recover(&edit, &save_manifest); + if (s.ok() && impl->mem_ == nullptr) { + // Create new log and a corresponding memtable. + uint64_t new_log_number = impl->versions_->NewFileNumber(); + WritableFile* lfile; + s = options.env->NewWritableFile(LogFileName(dbname, new_log_number), + &lfile); + if (s.ok()) { + edit.SetLogNumber(new_log_number); + impl->logfile_ = lfile; + impl->logfile_number_ = new_log_number; + impl->log_ = new log::Writer(lfile); + impl->mem_ = new MemTable(impl->internal_comparator_); + impl->mem_->Ref(); + } + } + if (s.ok() && save_manifest) { + edit.SetPrevLogNumber(0); // No older logs needed after recovery. + edit.SetLogNumber(impl->logfile_number_); + s = impl->versions_->LogAndApply(&edit, &impl->mutex_); + } + if (s.ok()) { + impl->DeleteObsoleteFiles(); + impl->MaybeScheduleCompaction(); + } + impl->mutex_.Unlock(); + if (s.ok()) { + assert(impl->mem_ != nullptr); + *dbptr = impl; + } else { + delete impl; + } + return s; +} + +Snapshot::~Snapshot() {} + +Status DestroyDB(const std::string& dbname, const Options& options) { + Env* env = options.env; + std::vector filenames; + Status result = env->GetChildren(dbname, &filenames); + if (!result.ok()) { + // Ignore error in case directory does not exist + return Status::OK(); + } + + FileLock* lock; + const std::string lockname = LockFileName(dbname); + result = env->LockFile(lockname, &lock); + if (result.ok()) { + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && + type != kDBLockFile) { // Lock file will be deleted at end + Status del = env->DeleteFile(dbname + "/" + filenames[i]); + if (result.ok() && !del.ok()) { + result = del; + } + } + } + env->UnlockFile(lock); // Ignore error since state is already gone + env->DeleteFile(lockname); + env->DeleteDir(dbname); // Ignore error in case dir contains other files + } + return result; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/db_impl.h b/saraWhatsUp/Pods/leveldb-library/db/db_impl.h new file mode 100644 index 0000000..ae87d6e --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/db_impl.h @@ -0,0 +1,216 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DB_IMPL_H_ +#define STORAGE_LEVELDB_DB_DB_IMPL_H_ + +#include +#include +#include +#include + +#include "db/dbformat.h" +#include "db/log_writer.h" +#include "db/snapshot.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +class MemTable; +class TableCache; +class Version; +class VersionEdit; +class VersionSet; + +class DBImpl : public DB { + public: + DBImpl(const Options& options, const std::string& dbname); + + DBImpl(const DBImpl&) = delete; + DBImpl& operator=(const DBImpl&) = delete; + + virtual ~DBImpl(); + + // Implementations of the DB interface + virtual Status Put(const WriteOptions&, const Slice& key, const Slice& value); + virtual Status Delete(const WriteOptions&, const Slice& key); + virtual Status Write(const WriteOptions& options, WriteBatch* updates); + virtual Status Get(const ReadOptions& options, const Slice& key, + std::string* value); + virtual Iterator* NewIterator(const ReadOptions&); + virtual const Snapshot* GetSnapshot(); + virtual void ReleaseSnapshot(const Snapshot* snapshot); + virtual bool GetProperty(const Slice& property, std::string* value); + virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes); + virtual void CompactRange(const Slice* begin, const Slice* end); + + // Extra methods (for testing) that are not in the public DB interface + + // Compact any files in the named level that overlap [*begin,*end] + void TEST_CompactRange(int level, const Slice* begin, const Slice* end); + + // Force current memtable contents to be compacted. + Status TEST_CompactMemTable(); + + // Return an internal iterator over the current state of the database. + // The keys of this iterator are internal keys (see format.h). + // The returned iterator should be deleted when no longer needed. + Iterator* TEST_NewInternalIterator(); + + // Return the maximum overlapping data (in bytes) at next level for any + // file at a level >= 1. + int64_t TEST_MaxNextLevelOverlappingBytes(); + + // Record a sample of bytes read at the specified internal key. + // Samples are taken approximately once every config::kReadBytesPeriod + // bytes. + void RecordReadSample(Slice key); + + private: + friend class DB; + struct CompactionState; + struct Writer; + + // Information for a manual compaction + struct ManualCompaction { + int level; + bool done; + const InternalKey* begin; // null means beginning of key range + const InternalKey* end; // null means end of key range + InternalKey tmp_storage; // Used to keep track of compaction progress + }; + + // Per level compaction stats. stats_[level] stores the stats for + // compactions that produced data for the specified "level". + struct CompactionStats { + CompactionStats() : micros(0), bytes_read(0), bytes_written(0) {} + + void Add(const CompactionStats& c) { + this->micros += c.micros; + this->bytes_read += c.bytes_read; + this->bytes_written += c.bytes_written; + } + + int64_t micros; + int64_t bytes_read; + int64_t bytes_written; + }; + + Iterator* NewInternalIterator(const ReadOptions&, + SequenceNumber* latest_snapshot, + uint32_t* seed); + + Status NewDB(); + + // Recover the descriptor from persistent storage. May do a significant + // amount of work to recover recently logged updates. Any changes to + // be made to the descriptor are added to *edit. + Status Recover(VersionEdit* edit, bool* save_manifest) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void MaybeIgnoreError(Status* s) const; + + // Delete any unneeded files and stale in-memory entries. + void DeleteObsoleteFiles() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Compact the in-memory write buffer to disk. Switches to a new + // log-file/memtable and writes a new descriptor iff successful. + // Errors are recorded in bg_error_. + void CompactMemTable() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status RecoverLogFile(uint64_t log_number, bool last_log, bool* save_manifest, + VersionEdit* edit, SequenceNumber* max_sequence) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status MakeRoomForWrite(bool force /* compact even if there is room? */) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + WriteBatch* BuildBatchGroup(Writer** last_writer) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void RecordBackgroundError(const Status& s); + + void MaybeScheduleCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + static void BGWork(void* db); + void BackgroundCall(); + void BackgroundCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + void CleanupCompaction(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + Status DoCompactionWork(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status OpenCompactionOutputFile(CompactionState* compact); + Status FinishCompactionOutputFile(CompactionState* compact, Iterator* input); + Status InstallCompactionResults(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + const Comparator* user_comparator() const { + return internal_comparator_.user_comparator(); + } + + // Constant after construction + Env* const env_; + const InternalKeyComparator internal_comparator_; + const InternalFilterPolicy internal_filter_policy_; + const Options options_; // options_.comparator == &internal_comparator_ + const bool owns_info_log_; + const bool owns_cache_; + const std::string dbname_; + + // table_cache_ provides its own synchronization + TableCache* const table_cache_; + + // Lock over the persistent DB state. Non-null iff successfully acquired. + FileLock* db_lock_; + + // State below is protected by mutex_ + port::Mutex mutex_; + std::atomic shutting_down_; + port::CondVar background_work_finished_signal_ GUARDED_BY(mutex_); + MemTable* mem_; + MemTable* imm_ GUARDED_BY(mutex_); // Memtable being compacted + std::atomic has_imm_; // So bg thread can detect non-null imm_ + WritableFile* logfile_; + uint64_t logfile_number_ GUARDED_BY(mutex_); + log::Writer* log_; + uint32_t seed_ GUARDED_BY(mutex_); // For sampling. + + // Queue of writers. + std::deque writers_ GUARDED_BY(mutex_); + WriteBatch* tmp_batch_ GUARDED_BY(mutex_); + + SnapshotList snapshots_ GUARDED_BY(mutex_); + + // Set of table files to protect from deletion because they are + // part of ongoing compactions. + std::set pending_outputs_ GUARDED_BY(mutex_); + + // Has a background compaction been scheduled or is running? + bool background_compaction_scheduled_ GUARDED_BY(mutex_); + + ManualCompaction* manual_compaction_ GUARDED_BY(mutex_); + + VersionSet* const versions_; + + // Have we encountered a background error in paranoid mode? + Status bg_error_ GUARDED_BY(mutex_); + + CompactionStats stats_[config::kNumLevels] GUARDED_BY(mutex_); +}; + +// Sanitize db options. The caller should delete result.info_log if +// it is not equal to src.info_log. +Options SanitizeOptions(const std::string& db, + const InternalKeyComparator* icmp, + const InternalFilterPolicy* ipolicy, + const Options& src); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DB_IMPL_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/db_iter.cc b/saraWhatsUp/Pods/leveldb-library/db/db_iter.cc new file mode 100644 index 0000000..8ff288e --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/db_iter.cc @@ -0,0 +1,309 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_iter.h" + +#include "db/db_impl.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/random.h" + +namespace leveldb { + +#if 0 +static void DumpInternalIter(Iterator* iter) { + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey k; + if (!ParseInternalKey(iter->key(), &k)) { + fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str()); + } else { + fprintf(stderr, "@ '%s'\n", k.DebugString().c_str()); + } + } +} +#endif + +namespace { + +// Memtables and sstables that make the DB representation contain +// (userkey,seq,type) => uservalue entries. DBIter +// combines multiple entries for the same userkey found in the DB +// representation into a single entry while accounting for sequence +// numbers, deletion markers, overwrites, etc. +class DBIter : public Iterator { + public: + // Which direction is the iterator currently moving? + // (1) When moving forward, the internal iterator is positioned at + // the exact entry that yields this->key(), this->value() + // (2) When moving backwards, the internal iterator is positioned + // just before all entries whose user key == this->key(). + enum Direction { kForward, kReverse }; + + DBIter(DBImpl* db, const Comparator* cmp, Iterator* iter, SequenceNumber s, + uint32_t seed) + : db_(db), + user_comparator_(cmp), + iter_(iter), + sequence_(s), + direction_(kForward), + valid_(false), + rnd_(seed), + bytes_until_read_sampling_(RandomCompactionPeriod()) {} + + DBIter(const DBIter&) = delete; + DBIter& operator=(const DBIter&) = delete; + + virtual ~DBIter() { delete iter_; } + virtual bool Valid() const { return valid_; } + virtual Slice key() const { + assert(valid_); + return (direction_ == kForward) ? ExtractUserKey(iter_->key()) : saved_key_; + } + virtual Slice value() const { + assert(valid_); + return (direction_ == kForward) ? iter_->value() : saved_value_; + } + virtual Status status() const { + if (status_.ok()) { + return iter_->status(); + } else { + return status_; + } + } + + virtual void Next(); + virtual void Prev(); + virtual void Seek(const Slice& target); + virtual void SeekToFirst(); + virtual void SeekToLast(); + + private: + void FindNextUserEntry(bool skipping, std::string* skip); + void FindPrevUserEntry(); + bool ParseKey(ParsedInternalKey* key); + + inline void SaveKey(const Slice& k, std::string* dst) { + dst->assign(k.data(), k.size()); + } + + inline void ClearSavedValue() { + if (saved_value_.capacity() > 1048576) { + std::string empty; + swap(empty, saved_value_); + } else { + saved_value_.clear(); + } + } + + // Picks the number of bytes that can be read until a compaction is scheduled. + size_t RandomCompactionPeriod() { + return rnd_.Uniform(2 * config::kReadBytesPeriod); + } + + DBImpl* db_; + const Comparator* const user_comparator_; + Iterator* const iter_; + SequenceNumber const sequence_; + Status status_; + std::string saved_key_; // == current key when direction_==kReverse + std::string saved_value_; // == current raw value when direction_==kReverse + Direction direction_; + bool valid_; + Random rnd_; + size_t bytes_until_read_sampling_; +}; + +inline bool DBIter::ParseKey(ParsedInternalKey* ikey) { + Slice k = iter_->key(); + + size_t bytes_read = k.size() + iter_->value().size(); + while (bytes_until_read_sampling_ < bytes_read) { + bytes_until_read_sampling_ += RandomCompactionPeriod(); + db_->RecordReadSample(k); + } + assert(bytes_until_read_sampling_ >= bytes_read); + bytes_until_read_sampling_ -= bytes_read; + + if (!ParseInternalKey(k, ikey)) { + status_ = Status::Corruption("corrupted internal key in DBIter"); + return false; + } else { + return true; + } +} + +void DBIter::Next() { + assert(valid_); + + if (direction_ == kReverse) { // Switch directions? + direction_ = kForward; + // iter_ is pointing just before the entries for this->key(), + // so advance into the range of entries for this->key() and then + // use the normal skipping code below. + if (!iter_->Valid()) { + iter_->SeekToFirst(); + } else { + iter_->Next(); + } + if (!iter_->Valid()) { + valid_ = false; + saved_key_.clear(); + return; + } + // saved_key_ already contains the key to skip past. + } else { + // Store in saved_key_ the current key so we skip it below. + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + } + + FindNextUserEntry(true, &saved_key_); +} + +void DBIter::FindNextUserEntry(bool skipping, std::string* skip) { + // Loop until we hit an acceptable entry to yield + assert(iter_->Valid()); + assert(direction_ == kForward); + do { + ParsedInternalKey ikey; + if (ParseKey(&ikey) && ikey.sequence <= sequence_) { + switch (ikey.type) { + case kTypeDeletion: + // Arrange to skip all upcoming entries for this key since + // they are hidden by this deletion. + SaveKey(ikey.user_key, skip); + skipping = true; + break; + case kTypeValue: + if (skipping && + user_comparator_->Compare(ikey.user_key, *skip) <= 0) { + // Entry hidden + } else { + valid_ = true; + saved_key_.clear(); + return; + } + break; + } + } + iter_->Next(); + } while (iter_->Valid()); + saved_key_.clear(); + valid_ = false; +} + +void DBIter::Prev() { + assert(valid_); + + if (direction_ == kForward) { // Switch directions? + // iter_ is pointing at the current entry. Scan backwards until + // the key changes so we can use the normal reverse scanning code. + assert(iter_->Valid()); // Otherwise valid_ would have been false + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + while (true) { + iter_->Prev(); + if (!iter_->Valid()) { + valid_ = false; + saved_key_.clear(); + ClearSavedValue(); + return; + } + if (user_comparator_->Compare(ExtractUserKey(iter_->key()), saved_key_) < + 0) { + break; + } + } + direction_ = kReverse; + } + + FindPrevUserEntry(); +} + +void DBIter::FindPrevUserEntry() { + assert(direction_ == kReverse); + + ValueType value_type = kTypeDeletion; + if (iter_->Valid()) { + do { + ParsedInternalKey ikey; + if (ParseKey(&ikey) && ikey.sequence <= sequence_) { + if ((value_type != kTypeDeletion) && + user_comparator_->Compare(ikey.user_key, saved_key_) < 0) { + // We encountered a non-deleted value in entries for previous keys, + break; + } + value_type = ikey.type; + if (value_type == kTypeDeletion) { + saved_key_.clear(); + ClearSavedValue(); + } else { + Slice raw_value = iter_->value(); + if (saved_value_.capacity() > raw_value.size() + 1048576) { + std::string empty; + swap(empty, saved_value_); + } + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + saved_value_.assign(raw_value.data(), raw_value.size()); + } + } + iter_->Prev(); + } while (iter_->Valid()); + } + + if (value_type == kTypeDeletion) { + // End + valid_ = false; + saved_key_.clear(); + ClearSavedValue(); + direction_ = kForward; + } else { + valid_ = true; + } +} + +void DBIter::Seek(const Slice& target) { + direction_ = kForward; + ClearSavedValue(); + saved_key_.clear(); + AppendInternalKey(&saved_key_, + ParsedInternalKey(target, sequence_, kValueTypeForSeek)); + iter_->Seek(saved_key_); + if (iter_->Valid()) { + FindNextUserEntry(false, &saved_key_ /* temporary storage */); + } else { + valid_ = false; + } +} + +void DBIter::SeekToFirst() { + direction_ = kForward; + ClearSavedValue(); + iter_->SeekToFirst(); + if (iter_->Valid()) { + FindNextUserEntry(false, &saved_key_ /* temporary storage */); + } else { + valid_ = false; + } +} + +void DBIter::SeekToLast() { + direction_ = kReverse; + ClearSavedValue(); + iter_->SeekToLast(); + FindPrevUserEntry(); +} + +} // anonymous namespace + +Iterator* NewDBIterator(DBImpl* db, const Comparator* user_key_comparator, + Iterator* internal_iter, SequenceNumber sequence, + uint32_t seed) { + return new DBIter(db, user_key_comparator, internal_iter, sequence, seed); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/db_iter.h b/saraWhatsUp/Pods/leveldb-library/db/db_iter.h new file mode 100644 index 0000000..fd93e91 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/db_iter.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DB_ITER_H_ +#define STORAGE_LEVELDB_DB_DB_ITER_H_ + +#include + +#include "db/dbformat.h" +#include "leveldb/db.h" + +namespace leveldb { + +class DBImpl; + +// Return a new iterator that converts internal keys (yielded by +// "*internal_iter") that were live at the specified "sequence" number +// into appropriate user keys. +Iterator* NewDBIterator(DBImpl* db, const Comparator* user_key_comparator, + Iterator* internal_iter, SequenceNumber sequence, + uint32_t seed); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DB_ITER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/dbformat.cc b/saraWhatsUp/Pods/leveldb-library/db/dbformat.cc new file mode 100644 index 0000000..69e8dc6 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/dbformat.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/dbformat.h" + +#include + +#include "port/port.h" +#include "util/coding.h" + +namespace leveldb { + +static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) { + assert(seq <= kMaxSequenceNumber); + assert(t <= kValueTypeForSeek); + return (seq << 8) | t; +} + +void AppendInternalKey(std::string* result, const ParsedInternalKey& key) { + result->append(key.user_key.data(), key.user_key.size()); + PutFixed64(result, PackSequenceAndType(key.sequence, key.type)); +} + +std::string ParsedInternalKey::DebugString() const { + char buf[50]; + snprintf(buf, sizeof(buf), "' @ %llu : %d", (unsigned long long)sequence, + int(type)); + std::string result = "'"; + result += EscapeString(user_key.ToString()); + result += buf; + return result; +} + +std::string InternalKey::DebugString() const { + std::string result; + ParsedInternalKey parsed; + if (ParseInternalKey(rep_, &parsed)) { + result = parsed.DebugString(); + } else { + result = "(bad)"; + result.append(EscapeString(rep_)); + } + return result; +} + +const char* InternalKeyComparator::Name() const { + return "leveldb.InternalKeyComparator"; +} + +int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const { + // Order by: + // increasing user key (according to user-supplied comparator) + // decreasing sequence number + // decreasing type (though sequence# should be enough to disambiguate) + int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey)); + if (r == 0) { + const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8); + const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8); + if (anum > bnum) { + r = -1; + } else if (anum < bnum) { + r = +1; + } + } + return r; +} + +void InternalKeyComparator::FindShortestSeparator(std::string* start, + const Slice& limit) const { + // Attempt to shorten the user portion of the key + Slice user_start = ExtractUserKey(*start); + Slice user_limit = ExtractUserKey(limit); + std::string tmp(user_start.data(), user_start.size()); + user_comparator_->FindShortestSeparator(&tmp, user_limit); + if (tmp.size() < user_start.size() && + user_comparator_->Compare(user_start, tmp) < 0) { + // User key has become shorter physically, but larger logically. + // Tack on the earliest possible number to the shortened user key. + PutFixed64(&tmp, + PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek)); + assert(this->Compare(*start, tmp) < 0); + assert(this->Compare(tmp, limit) < 0); + start->swap(tmp); + } +} + +void InternalKeyComparator::FindShortSuccessor(std::string* key) const { + Slice user_key = ExtractUserKey(*key); + std::string tmp(user_key.data(), user_key.size()); + user_comparator_->FindShortSuccessor(&tmp); + if (tmp.size() < user_key.size() && + user_comparator_->Compare(user_key, tmp) < 0) { + // User key has become shorter physically, but larger logically. + // Tack on the earliest possible number to the shortened user key. + PutFixed64(&tmp, + PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek)); + assert(this->Compare(*key, tmp) < 0); + key->swap(tmp); + } +} + +const char* InternalFilterPolicy::Name() const { return user_policy_->Name(); } + +void InternalFilterPolicy::CreateFilter(const Slice* keys, int n, + std::string* dst) const { + // We rely on the fact that the code in table.cc does not mind us + // adjusting keys[]. + Slice* mkey = const_cast(keys); + for (int i = 0; i < n; i++) { + mkey[i] = ExtractUserKey(keys[i]); + // TODO(sanjay): Suppress dups? + } + user_policy_->CreateFilter(keys, n, dst); +} + +bool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const { + return user_policy_->KeyMayMatch(ExtractUserKey(key), f); +} + +LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) { + size_t usize = user_key.size(); + size_t needed = usize + 13; // A conservative estimate + char* dst; + if (needed <= sizeof(space_)) { + dst = space_; + } else { + dst = new char[needed]; + } + start_ = dst; + dst = EncodeVarint32(dst, usize + 8); + kstart_ = dst; + memcpy(dst, user_key.data(), usize); + dst += usize; + EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek)); + dst += 8; + end_ = dst; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/dbformat.h b/saraWhatsUp/Pods/leveldb-library/db/dbformat.h new file mode 100644 index 0000000..013028a --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/dbformat.h @@ -0,0 +1,218 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DBFORMAT_H_ +#define STORAGE_LEVELDB_DB_DBFORMAT_H_ + +#include + +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/filter_policy.h" +#include "leveldb/slice.h" +#include "leveldb/table_builder.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +// Grouping of constants. We may want to make some of these +// parameters set via options. +namespace config { +static const int kNumLevels = 7; + +// Level-0 compaction is started when we hit this many files. +static const int kL0_CompactionTrigger = 4; + +// Soft limit on number of level-0 files. We slow down writes at this point. +static const int kL0_SlowdownWritesTrigger = 8; + +// Maximum number of level-0 files. We stop writes at this point. +static const int kL0_StopWritesTrigger = 12; + +// Maximum level to which a new compacted memtable is pushed if it +// does not create overlap. We try to push to level 2 to avoid the +// relatively expensive level 0=>1 compactions and to avoid some +// expensive manifest file operations. We do not push all the way to +// the largest level since that can generate a lot of wasted disk +// space if the same key space is being repeatedly overwritten. +static const int kMaxMemCompactLevel = 2; + +// Approximate gap in bytes between samples of data read during iteration. +static const int kReadBytesPeriod = 1048576; + +} // namespace config + +class InternalKey; + +// Value types encoded as the last component of internal keys. +// DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk +// data structures. +enum ValueType { kTypeDeletion = 0x0, kTypeValue = 0x1 }; +// kValueTypeForSeek defines the ValueType that should be passed when +// constructing a ParsedInternalKey object for seeking to a particular +// sequence number (since we sort sequence numbers in decreasing order +// and the value type is embedded as the low 8 bits in the sequence +// number in internal keys, we need to use the highest-numbered +// ValueType, not the lowest). +static const ValueType kValueTypeForSeek = kTypeValue; + +typedef uint64_t SequenceNumber; + +// We leave eight bits empty at the bottom so a type and sequence# +// can be packed together into 64-bits. +static const SequenceNumber kMaxSequenceNumber = ((0x1ull << 56) - 1); + +struct ParsedInternalKey { + Slice user_key; + SequenceNumber sequence; + ValueType type; + + ParsedInternalKey() {} // Intentionally left uninitialized (for speed) + ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t) + : user_key(u), sequence(seq), type(t) {} + std::string DebugString() const; +}; + +// Return the length of the encoding of "key". +inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) { + return key.user_key.size() + 8; +} + +// Append the serialization of "key" to *result. +void AppendInternalKey(std::string* result, const ParsedInternalKey& key); + +// Attempt to parse an internal key from "internal_key". On success, +// stores the parsed data in "*result", and returns true. +// +// On error, returns false, leaves "*result" in an undefined state. +bool ParseInternalKey(const Slice& internal_key, ParsedInternalKey* result); + +// Returns the user key portion of an internal key. +inline Slice ExtractUserKey(const Slice& internal_key) { + assert(internal_key.size() >= 8); + return Slice(internal_key.data(), internal_key.size() - 8); +} + +// A comparator for internal keys that uses a specified comparator for +// the user key portion and breaks ties by decreasing sequence number. +class InternalKeyComparator : public Comparator { + private: + const Comparator* user_comparator_; + + public: + explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) {} + virtual const char* Name() const; + virtual int Compare(const Slice& a, const Slice& b) const; + virtual void FindShortestSeparator(std::string* start, + const Slice& limit) const; + virtual void FindShortSuccessor(std::string* key) const; + + const Comparator* user_comparator() const { return user_comparator_; } + + int Compare(const InternalKey& a, const InternalKey& b) const; +}; + +// Filter policy wrapper that converts from internal keys to user keys +class InternalFilterPolicy : public FilterPolicy { + private: + const FilterPolicy* const user_policy_; + + public: + explicit InternalFilterPolicy(const FilterPolicy* p) : user_policy_(p) {} + virtual const char* Name() const; + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const; + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const; +}; + +// Modules in this directory should keep internal keys wrapped inside +// the following class instead of plain strings so that we do not +// incorrectly use string comparisons instead of an InternalKeyComparator. +class InternalKey { + private: + std::string rep_; + + public: + InternalKey() {} // Leave rep_ as empty to indicate it is invalid + InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) { + AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t)); + } + + void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); } + Slice Encode() const { + assert(!rep_.empty()); + return rep_; + } + + Slice user_key() const { return ExtractUserKey(rep_); } + + void SetFrom(const ParsedInternalKey& p) { + rep_.clear(); + AppendInternalKey(&rep_, p); + } + + void Clear() { rep_.clear(); } + + std::string DebugString() const; +}; + +inline int InternalKeyComparator::Compare(const InternalKey& a, + const InternalKey& b) const { + return Compare(a.Encode(), b.Encode()); +} + +inline bool ParseInternalKey(const Slice& internal_key, + ParsedInternalKey* result) { + const size_t n = internal_key.size(); + if (n < 8) return false; + uint64_t num = DecodeFixed64(internal_key.data() + n - 8); + unsigned char c = num & 0xff; + result->sequence = num >> 8; + result->type = static_cast(c); + result->user_key = Slice(internal_key.data(), n - 8); + return (c <= static_cast(kTypeValue)); +} + +// A helper class useful for DBImpl::Get() +class LookupKey { + public: + // Initialize *this for looking up user_key at a snapshot with + // the specified sequence number. + LookupKey(const Slice& user_key, SequenceNumber sequence); + + LookupKey(const LookupKey&) = delete; + LookupKey& operator=(const LookupKey&) = delete; + + ~LookupKey(); + + // Return a key suitable for lookup in a MemTable. + Slice memtable_key() const { return Slice(start_, end_ - start_); } + + // Return an internal key (suitable for passing to an internal iterator) + Slice internal_key() const { return Slice(kstart_, end_ - kstart_); } + + // Return the user key + Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); } + + private: + // We construct a char array of the form: + // klength varint32 <-- start_ + // userkey char[klength] <-- kstart_ + // tag uint64 + // <-- end_ + // The array is a suitable MemTable key. + // The suffix starting with "userkey" can be used as an InternalKey. + const char* start_; + const char* kstart_; + const char* end_; + char space_[200]; // Avoid allocation for short keys +}; + +inline LookupKey::~LookupKey() { + if (start_ != space_) delete[] start_; +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DBFORMAT_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/dumpfile.cc b/saraWhatsUp/Pods/leveldb-library/db/dumpfile.cc new file mode 100644 index 0000000..9d22d58 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/dumpfile.cc @@ -0,0 +1,232 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/dumpfile.h" + +#include + +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/version_edit.h" +#include "db/write_batch_internal.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "util/logging.h" + +namespace leveldb { + +namespace { + +bool GuessType(const std::string& fname, FileType* type) { + size_t pos = fname.rfind('/'); + std::string basename; + if (pos == std::string::npos) { + basename = fname; + } else { + basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1); + } + uint64_t ignored; + return ParseFileName(basename, &ignored, type); +} + +// Notified when log reader encounters corruption. +class CorruptionReporter : public log::Reader::Reporter { + public: + virtual void Corruption(size_t bytes, const Status& status) { + std::string r = "corruption: "; + AppendNumberTo(&r, bytes); + r += " bytes; "; + r += status.ToString(); + r.push_back('\n'); + dst_->Append(r); + } + + WritableFile* dst_; +}; + +// Print contents of a log file. (*func)() is called on every record. +Status PrintLogContents(Env* env, const std::string& fname, + void (*func)(uint64_t, Slice, WritableFile*), + WritableFile* dst) { + SequentialFile* file; + Status s = env->NewSequentialFile(fname, &file); + if (!s.ok()) { + return s; + } + CorruptionReporter reporter; + reporter.dst_ = dst; + log::Reader reader(file, &reporter, true, 0); + Slice record; + std::string scratch; + while (reader.ReadRecord(&record, &scratch)) { + (*func)(reader.LastRecordOffset(), record, dst); + } + delete file; + return Status::OK(); +} + +// Called on every item found in a WriteBatch. +class WriteBatchItemPrinter : public WriteBatch::Handler { + public: + virtual void Put(const Slice& key, const Slice& value) { + std::string r = " put '"; + AppendEscapedStringTo(&r, key); + r += "' '"; + AppendEscapedStringTo(&r, value); + r += "'\n"; + dst_->Append(r); + } + virtual void Delete(const Slice& key) { + std::string r = " del '"; + AppendEscapedStringTo(&r, key); + r += "'\n"; + dst_->Append(r); + } + + WritableFile* dst_; +}; + +// Called on every log record (each one of which is a WriteBatch) +// found in a kLogFile. +static void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile* dst) { + std::string r = "--- offset "; + AppendNumberTo(&r, pos); + r += "; "; + if (record.size() < 12) { + r += "log record length "; + AppendNumberTo(&r, record.size()); + r += " is too small\n"; + dst->Append(r); + return; + } + WriteBatch batch; + WriteBatchInternal::SetContents(&batch, record); + r += "sequence "; + AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch)); + r.push_back('\n'); + dst->Append(r); + WriteBatchItemPrinter batch_item_printer; + batch_item_printer.dst_ = dst; + Status s = batch.Iterate(&batch_item_printer); + if (!s.ok()) { + dst->Append(" error: " + s.ToString() + "\n"); + } +} + +Status DumpLog(Env* env, const std::string& fname, WritableFile* dst) { + return PrintLogContents(env, fname, WriteBatchPrinter, dst); +} + +// Called on every log record (each one of which is a WriteBatch) +// found in a kDescriptorFile. +static void VersionEditPrinter(uint64_t pos, Slice record, WritableFile* dst) { + std::string r = "--- offset "; + AppendNumberTo(&r, pos); + r += "; "; + VersionEdit edit; + Status s = edit.DecodeFrom(record); + if (!s.ok()) { + r += s.ToString(); + r.push_back('\n'); + } else { + r += edit.DebugString(); + } + dst->Append(r); +} + +Status DumpDescriptor(Env* env, const std::string& fname, WritableFile* dst) { + return PrintLogContents(env, fname, VersionEditPrinter, dst); +} + +Status DumpTable(Env* env, const std::string& fname, WritableFile* dst) { + uint64_t file_size; + RandomAccessFile* file = nullptr; + Table* table = nullptr; + Status s = env->GetFileSize(fname, &file_size); + if (s.ok()) { + s = env->NewRandomAccessFile(fname, &file); + } + if (s.ok()) { + // We use the default comparator, which may or may not match the + // comparator used in this database. However this should not cause + // problems since we only use Table operations that do not require + // any comparisons. In particular, we do not call Seek or Prev. + s = Table::Open(Options(), file, file_size, &table); + } + if (!s.ok()) { + delete table; + delete file; + return s; + } + + ReadOptions ro; + ro.fill_cache = false; + Iterator* iter = table->NewIterator(ro); + std::string r; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + r.clear(); + ParsedInternalKey key; + if (!ParseInternalKey(iter->key(), &key)) { + r = "badkey '"; + AppendEscapedStringTo(&r, iter->key()); + r += "' => '"; + AppendEscapedStringTo(&r, iter->value()); + r += "'\n"; + dst->Append(r); + } else { + r = "'"; + AppendEscapedStringTo(&r, key.user_key); + r += "' @ "; + AppendNumberTo(&r, key.sequence); + r += " : "; + if (key.type == kTypeDeletion) { + r += "del"; + } else if (key.type == kTypeValue) { + r += "val"; + } else { + AppendNumberTo(&r, key.type); + } + r += " => '"; + AppendEscapedStringTo(&r, iter->value()); + r += "'\n"; + dst->Append(r); + } + } + s = iter->status(); + if (!s.ok()) { + dst->Append("iterator error: " + s.ToString() + "\n"); + } + + delete iter; + delete table; + delete file; + return Status::OK(); +} + +} // namespace + +Status DumpFile(Env* env, const std::string& fname, WritableFile* dst) { + FileType ftype; + if (!GuessType(fname, &ftype)) { + return Status::InvalidArgument(fname + ": unknown file type"); + } + switch (ftype) { + case kLogFile: + return DumpLog(env, fname, dst); + case kDescriptorFile: + return DumpDescriptor(env, fname, dst); + case kTableFile: + return DumpTable(env, fname, dst); + default: + break; + } + return Status::InvalidArgument(fname + ": not a dump-able file type"); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/filename.cc b/saraWhatsUp/Pods/leveldb-library/db/filename.cc new file mode 100644 index 0000000..85de45c --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/filename.cc @@ -0,0 +1,141 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/filename.h" + +#include +#include + +#include "db/dbformat.h" +#include "leveldb/env.h" +#include "util/logging.h" + +namespace leveldb { + +// A utility routine: write "data" to the named file and Sync() it. +Status WriteStringToFileSync(Env* env, const Slice& data, + const std::string& fname); + +static std::string MakeFileName(const std::string& dbname, uint64_t number, + const char* suffix) { + char buf[100]; + snprintf(buf, sizeof(buf), "/%06llu.%s", + static_cast(number), suffix); + return dbname + buf; +} + +std::string LogFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + return MakeFileName(dbname, number, "log"); +} + +std::string TableFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + return MakeFileName(dbname, number, "ldb"); +} + +std::string SSTTableFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + return MakeFileName(dbname, number, "sst"); +} + +std::string DescriptorFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + char buf[100]; + snprintf(buf, sizeof(buf), "/MANIFEST-%06llu", + static_cast(number)); + return dbname + buf; +} + +std::string CurrentFileName(const std::string& dbname) { + return dbname + "/CURRENT"; +} + +std::string LockFileName(const std::string& dbname) { return dbname + "/LOCK"; } + +std::string TempFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + return MakeFileName(dbname, number, "dbtmp"); +} + +std::string InfoLogFileName(const std::string& dbname) { + return dbname + "/LOG"; +} + +// Return the name of the old info log file for "dbname". +std::string OldInfoLogFileName(const std::string& dbname) { + return dbname + "/LOG.old"; +} + +// Owned filenames have the form: +// dbname/CURRENT +// dbname/LOCK +// dbname/LOG +// dbname/LOG.old +// dbname/MANIFEST-[0-9]+ +// dbname/[0-9]+.(log|sst|ldb) +bool ParseFileName(const std::string& filename, uint64_t* number, + FileType* type) { + Slice rest(filename); + if (rest == "CURRENT") { + *number = 0; + *type = kCurrentFile; + } else if (rest == "LOCK") { + *number = 0; + *type = kDBLockFile; + } else if (rest == "LOG" || rest == "LOG.old") { + *number = 0; + *type = kInfoLogFile; + } else if (rest.starts_with("MANIFEST-")) { + rest.remove_prefix(strlen("MANIFEST-")); + uint64_t num; + if (!ConsumeDecimalNumber(&rest, &num)) { + return false; + } + if (!rest.empty()) { + return false; + } + *type = kDescriptorFile; + *number = num; + } else { + // Avoid strtoull() to keep filename format independent of the + // current locale + uint64_t num; + if (!ConsumeDecimalNumber(&rest, &num)) { + return false; + } + Slice suffix = rest; + if (suffix == Slice(".log")) { + *type = kLogFile; + } else if (suffix == Slice(".sst") || suffix == Slice(".ldb")) { + *type = kTableFile; + } else if (suffix == Slice(".dbtmp")) { + *type = kTempFile; + } else { + return false; + } + *number = num; + } + return true; +} + +Status SetCurrentFile(Env* env, const std::string& dbname, + uint64_t descriptor_number) { + // Remove leading "dbname/" and add newline to manifest file name + std::string manifest = DescriptorFileName(dbname, descriptor_number); + Slice contents = manifest; + assert(contents.starts_with(dbname + "/")); + contents.remove_prefix(dbname.size() + 1); + std::string tmp = TempFileName(dbname, descriptor_number); + Status s = WriteStringToFileSync(env, contents.ToString() + "\n", tmp); + if (s.ok()) { + s = env->RenameFile(tmp, CurrentFileName(dbname)); + } + if (!s.ok()) { + env->DeleteFile(tmp); + } + return s; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/filename.h b/saraWhatsUp/Pods/leveldb-library/db/filename.h new file mode 100644 index 0000000..524e813 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/filename.h @@ -0,0 +1,84 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// File names used by DB code + +#ifndef STORAGE_LEVELDB_DB_FILENAME_H_ +#define STORAGE_LEVELDB_DB_FILENAME_H_ + +#include + +#include + +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "port/port.h" + +namespace leveldb { + +class Env; + +enum FileType { + kLogFile, + kDBLockFile, + kTableFile, + kDescriptorFile, + kCurrentFile, + kTempFile, + kInfoLogFile // Either the current one, or an old one +}; + +// Return the name of the log file with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +std::string LogFileName(const std::string& dbname, uint64_t number); + +// Return the name of the sstable with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +std::string TableFileName(const std::string& dbname, uint64_t number); + +// Return the legacy file name for an sstable with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +std::string SSTTableFileName(const std::string& dbname, uint64_t number); + +// Return the name of the descriptor file for the db named by +// "dbname" and the specified incarnation number. The result will be +// prefixed with "dbname". +std::string DescriptorFileName(const std::string& dbname, uint64_t number); + +// Return the name of the current file. This file contains the name +// of the current manifest file. The result will be prefixed with +// "dbname". +std::string CurrentFileName(const std::string& dbname); + +// Return the name of the lock file for the db named by +// "dbname". The result will be prefixed with "dbname". +std::string LockFileName(const std::string& dbname); + +// Return the name of a temporary file owned by the db named "dbname". +// The result will be prefixed with "dbname". +std::string TempFileName(const std::string& dbname, uint64_t number); + +// Return the name of the info log file for "dbname". +std::string InfoLogFileName(const std::string& dbname); + +// Return the name of the old info log file for "dbname". +std::string OldInfoLogFileName(const std::string& dbname); + +// If filename is a leveldb file, store the type of the file in *type. +// The number encoded in the filename is stored in *number. If the +// filename was successfully parsed, returns true. Else return false. +bool ParseFileName(const std::string& filename, uint64_t* number, + FileType* type); + +// Make the CURRENT file point to the descriptor file with the +// specified number. +Status SetCurrentFile(Env* env, const std::string& dbname, + uint64_t descriptor_number); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_FILENAME_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/log_format.h b/saraWhatsUp/Pods/leveldb-library/db/log_format.h new file mode 100644 index 0000000..356e69f --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/log_format.h @@ -0,0 +1,35 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Log format information shared by reader and writer. +// See ../doc/log_format.md for more detail. + +#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_ +#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_ + +namespace leveldb { +namespace log { + +enum RecordType { + // Zero is reserved for preallocated files + kZeroType = 0, + + kFullType = 1, + + // For fragments + kFirstType = 2, + kMiddleType = 3, + kLastType = 4 +}; +static const int kMaxRecordType = kLastType; + +static const int kBlockSize = 32768; + +// Header is checksum (4 bytes), length (2 bytes), type (1 byte). +static const int kHeaderSize = 4 + 2 + 1; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_FORMAT_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/log_reader.cc b/saraWhatsUp/Pods/leveldb-library/db/log_reader.cc new file mode 100644 index 0000000..f472723 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/log_reader.cc @@ -0,0 +1,274 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_reader.h" + +#include + +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +Reader::Reporter::~Reporter() {} + +Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum, + uint64_t initial_offset) + : file_(file), + reporter_(reporter), + checksum_(checksum), + backing_store_(new char[kBlockSize]), + buffer_(), + eof_(false), + last_record_offset_(0), + end_of_buffer_offset_(0), + initial_offset_(initial_offset), + resyncing_(initial_offset > 0) {} + +Reader::~Reader() { delete[] backing_store_; } + +bool Reader::SkipToInitialBlock() { + const size_t offset_in_block = initial_offset_ % kBlockSize; + uint64_t block_start_location = initial_offset_ - offset_in_block; + + // Don't search a block if we'd be in the trailer + if (offset_in_block > kBlockSize - 6) { + block_start_location += kBlockSize; + } + + end_of_buffer_offset_ = block_start_location; + + // Skip to start of first block that can contain the initial record + if (block_start_location > 0) { + Status skip_status = file_->Skip(block_start_location); + if (!skip_status.ok()) { + ReportDrop(block_start_location, skip_status); + return false; + } + } + + return true; +} + +bool Reader::ReadRecord(Slice* record, std::string* scratch) { + if (last_record_offset_ < initial_offset_) { + if (!SkipToInitialBlock()) { + return false; + } + } + + scratch->clear(); + record->clear(); + bool in_fragmented_record = false; + // Record offset of the logical record that we're reading + // 0 is a dummy value to make compilers happy + uint64_t prospective_record_offset = 0; + + Slice fragment; + while (true) { + const unsigned int record_type = ReadPhysicalRecord(&fragment); + + // ReadPhysicalRecord may have only had an empty trailer remaining in its + // internal buffer. Calculate the offset of the next physical record now + // that it has returned, properly accounting for its header size. + uint64_t physical_record_offset = + end_of_buffer_offset_ - buffer_.size() - kHeaderSize - fragment.size(); + + if (resyncing_) { + if (record_type == kMiddleType) { + continue; + } else if (record_type == kLastType) { + resyncing_ = false; + continue; + } else { + resyncing_ = false; + } + } + + switch (record_type) { + case kFullType: + if (in_fragmented_record) { + // Handle bug in earlier versions of log::Writer where + // it could emit an empty kFirstType record at the tail end + // of a block followed by a kFullType or kFirstType record + // at the beginning of the next block. + if (!scratch->empty()) { + ReportCorruption(scratch->size(), "partial record without end(1)"); + } + } + prospective_record_offset = physical_record_offset; + scratch->clear(); + *record = fragment; + last_record_offset_ = prospective_record_offset; + return true; + + case kFirstType: + if (in_fragmented_record) { + // Handle bug in earlier versions of log::Writer where + // it could emit an empty kFirstType record at the tail end + // of a block followed by a kFullType or kFirstType record + // at the beginning of the next block. + if (!scratch->empty()) { + ReportCorruption(scratch->size(), "partial record without end(2)"); + } + } + prospective_record_offset = physical_record_offset; + scratch->assign(fragment.data(), fragment.size()); + in_fragmented_record = true; + break; + + case kMiddleType: + if (!in_fragmented_record) { + ReportCorruption(fragment.size(), + "missing start of fragmented record(1)"); + } else { + scratch->append(fragment.data(), fragment.size()); + } + break; + + case kLastType: + if (!in_fragmented_record) { + ReportCorruption(fragment.size(), + "missing start of fragmented record(2)"); + } else { + scratch->append(fragment.data(), fragment.size()); + *record = Slice(*scratch); + last_record_offset_ = prospective_record_offset; + return true; + } + break; + + case kEof: + if (in_fragmented_record) { + // This can be caused by the writer dying immediately after + // writing a physical record but before completing the next; don't + // treat it as a corruption, just ignore the entire logical record. + scratch->clear(); + } + return false; + + case kBadRecord: + if (in_fragmented_record) { + ReportCorruption(scratch->size(), "error in middle of record"); + in_fragmented_record = false; + scratch->clear(); + } + break; + + default: { + char buf[40]; + snprintf(buf, sizeof(buf), "unknown record type %u", record_type); + ReportCorruption( + (fragment.size() + (in_fragmented_record ? scratch->size() : 0)), + buf); + in_fragmented_record = false; + scratch->clear(); + break; + } + } + } + return false; +} + +uint64_t Reader::LastRecordOffset() { return last_record_offset_; } + +void Reader::ReportCorruption(uint64_t bytes, const char* reason) { + ReportDrop(bytes, Status::Corruption(reason)); +} + +void Reader::ReportDrop(uint64_t bytes, const Status& reason) { + if (reporter_ != nullptr && + end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) { + reporter_->Corruption(static_cast(bytes), reason); + } +} + +unsigned int Reader::ReadPhysicalRecord(Slice* result) { + while (true) { + if (buffer_.size() < kHeaderSize) { + if (!eof_) { + // Last read was a full read, so this is a trailer to skip + buffer_.clear(); + Status status = file_->Read(kBlockSize, &buffer_, backing_store_); + end_of_buffer_offset_ += buffer_.size(); + if (!status.ok()) { + buffer_.clear(); + ReportDrop(kBlockSize, status); + eof_ = true; + return kEof; + } else if (buffer_.size() < kBlockSize) { + eof_ = true; + } + continue; + } else { + // Note that if buffer_ is non-empty, we have a truncated header at the + // end of the file, which can be caused by the writer crashing in the + // middle of writing the header. Instead of considering this an error, + // just report EOF. + buffer_.clear(); + return kEof; + } + } + + // Parse the header + const char* header = buffer_.data(); + const uint32_t a = static_cast(header[4]) & 0xff; + const uint32_t b = static_cast(header[5]) & 0xff; + const unsigned int type = header[6]; + const uint32_t length = a | (b << 8); + if (kHeaderSize + length > buffer_.size()) { + size_t drop_size = buffer_.size(); + buffer_.clear(); + if (!eof_) { + ReportCorruption(drop_size, "bad record length"); + return kBadRecord; + } + // If the end of the file has been reached without reading |length| bytes + // of payload, assume the writer died in the middle of writing the record. + // Don't report a corruption. + return kEof; + } + + if (type == kZeroType && length == 0) { + // Skip zero length record without reporting any drops since + // such records are produced by the mmap based writing code in + // env_posix.cc that preallocates file regions. + buffer_.clear(); + return kBadRecord; + } + + // Check crc + if (checksum_) { + uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header)); + uint32_t actual_crc = crc32c::Value(header + 6, 1 + length); + if (actual_crc != expected_crc) { + // Drop the rest of the buffer since "length" itself may have + // been corrupted and if we trust it, we could find some + // fragment of a real log record that just happens to look + // like a valid log record. + size_t drop_size = buffer_.size(); + buffer_.clear(); + ReportCorruption(drop_size, "checksum mismatch"); + return kBadRecord; + } + } + + buffer_.remove_prefix(kHeaderSize + length); + + // Skip physical record that started before initial_offset_ + if (end_of_buffer_offset_ - buffer_.size() - kHeaderSize - length < + initial_offset_) { + result->clear(); + return kBadRecord; + } + + *result = Slice(header + kHeaderSize, length); + return type; + } +} + +} // namespace log +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/log_reader.h b/saraWhatsUp/Pods/leveldb-library/db/log_reader.h new file mode 100644 index 0000000..001da89 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/log_reader.h @@ -0,0 +1,112 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_LOG_READER_H_ +#define STORAGE_LEVELDB_DB_LOG_READER_H_ + +#include + +#include "db/log_format.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class SequentialFile; + +namespace log { + +class Reader { + public: + // Interface for reporting errors. + class Reporter { + public: + virtual ~Reporter(); + + // Some corruption was detected. "size" is the approximate number + // of bytes dropped due to the corruption. + virtual void Corruption(size_t bytes, const Status& status) = 0; + }; + + // Create a reader that will return log records from "*file". + // "*file" must remain live while this Reader is in use. + // + // If "reporter" is non-null, it is notified whenever some data is + // dropped due to a detected corruption. "*reporter" must remain + // live while this Reader is in use. + // + // If "checksum" is true, verify checksums if available. + // + // The Reader will start reading at the first record located at physical + // position >= initial_offset within the file. + Reader(SequentialFile* file, Reporter* reporter, bool checksum, + uint64_t initial_offset); + + Reader(const Reader&) = delete; + Reader& operator=(const Reader&) = delete; + + ~Reader(); + + // Read the next record into *record. Returns true if read + // successfully, false if we hit end of the input. May use + // "*scratch" as temporary storage. The contents filled in *record + // will only be valid until the next mutating operation on this + // reader or the next mutation to *scratch. + bool ReadRecord(Slice* record, std::string* scratch); + + // Returns the physical offset of the last record returned by ReadRecord. + // + // Undefined before the first call to ReadRecord. + uint64_t LastRecordOffset(); + + private: + // Extend record types with the following special values + enum { + kEof = kMaxRecordType + 1, + // Returned whenever we find an invalid physical record. + // Currently there are three situations in which this happens: + // * The record has an invalid CRC (ReadPhysicalRecord reports a drop) + // * The record is a 0-length record (No drop is reported) + // * The record is below constructor's initial_offset (No drop is reported) + kBadRecord = kMaxRecordType + 2 + }; + + // Skips all blocks that are completely before "initial_offset_". + // + // Returns true on success. Handles reporting. + bool SkipToInitialBlock(); + + // Return type, or one of the preceding special values + unsigned int ReadPhysicalRecord(Slice* result); + + // Reports dropped bytes to the reporter. + // buffer_ must be updated to remove the dropped bytes prior to invocation. + void ReportCorruption(uint64_t bytes, const char* reason); + void ReportDrop(uint64_t bytes, const Status& reason); + + SequentialFile* const file_; + Reporter* const reporter_; + bool const checksum_; + char* const backing_store_; + Slice buffer_; + bool eof_; // Last Read() indicated EOF by returning < kBlockSize + + // Offset of the last record returned by ReadRecord. + uint64_t last_record_offset_; + // Offset of the first location past the end of buffer_. + uint64_t end_of_buffer_offset_; + + // Offset at which to start looking for the first record to return + uint64_t const initial_offset_; + + // True if we are resynchronizing after a seek (initial_offset_ > 0). In + // particular, a run of kMiddleType and kLastType records can be silently + // skipped in this mode + bool resyncing_; +}; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_READER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/log_writer.cc b/saraWhatsUp/Pods/leveldb-library/db/log_writer.cc new file mode 100644 index 0000000..5e83f6a --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/log_writer.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_writer.h" + +#include + +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +static void InitTypeCrc(uint32_t* type_crc) { + for (int i = 0; i <= kMaxRecordType; i++) { + char t = static_cast(i); + type_crc[i] = crc32c::Value(&t, 1); + } +} + +Writer::Writer(WritableFile* dest) : dest_(dest), block_offset_(0) { + InitTypeCrc(type_crc_); +} + +Writer::Writer(WritableFile* dest, uint64_t dest_length) + : dest_(dest), block_offset_(dest_length % kBlockSize) { + InitTypeCrc(type_crc_); +} + +Writer::~Writer() {} + +Status Writer::AddRecord(const Slice& slice) { + const char* ptr = slice.data(); + size_t left = slice.size(); + + // Fragment the record if necessary and emit it. Note that if slice + // is empty, we still want to iterate once to emit a single + // zero-length record + Status s; + bool begin = true; + do { + const int leftover = kBlockSize - block_offset_; + assert(leftover >= 0); + if (leftover < kHeaderSize) { + // Switch to a new block + if (leftover > 0) { + // Fill the trailer (literal below relies on kHeaderSize being 7) + static_assert(kHeaderSize == 7, ""); + dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover)); + } + block_offset_ = 0; + } + + // Invariant: we never leave < kHeaderSize bytes in a block. + assert(kBlockSize - block_offset_ - kHeaderSize >= 0); + + const size_t avail = kBlockSize - block_offset_ - kHeaderSize; + const size_t fragment_length = (left < avail) ? left : avail; + + RecordType type; + const bool end = (left == fragment_length); + if (begin && end) { + type = kFullType; + } else if (begin) { + type = kFirstType; + } else if (end) { + type = kLastType; + } else { + type = kMiddleType; + } + + s = EmitPhysicalRecord(type, ptr, fragment_length); + ptr += fragment_length; + left -= fragment_length; + begin = false; + } while (s.ok() && left > 0); + return s; +} + +Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, + size_t length) { + assert(length <= 0xffff); // Must fit in two bytes + assert(block_offset_ + kHeaderSize + length <= kBlockSize); + + // Format the header + char buf[kHeaderSize]; + buf[4] = static_cast(length & 0xff); + buf[5] = static_cast(length >> 8); + buf[6] = static_cast(t); + + // Compute the crc of the record type and the payload. + uint32_t crc = crc32c::Extend(type_crc_[t], ptr, length); + crc = crc32c::Mask(crc); // Adjust for storage + EncodeFixed32(buf, crc); + + // Write the header and the payload + Status s = dest_->Append(Slice(buf, kHeaderSize)); + if (s.ok()) { + s = dest_->Append(Slice(ptr, length)); + if (s.ok()) { + s = dest_->Flush(); + } + } + block_offset_ += kHeaderSize + length; + return s; +} + +} // namespace log +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/log_writer.h b/saraWhatsUp/Pods/leveldb-library/db/log_writer.h new file mode 100644 index 0000000..c0a2114 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/log_writer.h @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_LOG_WRITER_H_ +#define STORAGE_LEVELDB_DB_LOG_WRITER_H_ + +#include + +#include "db/log_format.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class WritableFile; + +namespace log { + +class Writer { + public: + // Create a writer that will append data to "*dest". + // "*dest" must be initially empty. + // "*dest" must remain live while this Writer is in use. + explicit Writer(WritableFile* dest); + + // Create a writer that will append data to "*dest". + // "*dest" must have initial length "dest_length". + // "*dest" must remain live while this Writer is in use. + Writer(WritableFile* dest, uint64_t dest_length); + + Writer(const Writer&) = delete; + Writer& operator=(const Writer&) = delete; + + ~Writer(); + + Status AddRecord(const Slice& slice); + + private: + Status EmitPhysicalRecord(RecordType type, const char* ptr, size_t length); + + WritableFile* dest_; + int block_offset_; // Current offset in block + + // crc32c values for all supported record types. These are + // pre-computed to reduce the overhead of computing the crc of the + // record type stored in the header. + uint32_t type_crc_[kMaxRecordType + 1]; +}; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_WRITER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/memtable.cc b/saraWhatsUp/Pods/leveldb-library/db/memtable.cc new file mode 100644 index 0000000..c91405c --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/memtable.cc @@ -0,0 +1,136 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/memtable.h" +#include "db/dbformat.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "util/coding.h" + +namespace leveldb { + +static Slice GetLengthPrefixedSlice(const char* data) { + uint32_t len; + const char* p = data; + p = GetVarint32Ptr(p, p + 5, &len); // +5: we assume "p" is not corrupted + return Slice(p, len); +} + +MemTable::MemTable(const InternalKeyComparator& comparator) + : comparator_(comparator), refs_(0), table_(comparator_, &arena_) {} + +MemTable::~MemTable() { assert(refs_ == 0); } + +size_t MemTable::ApproximateMemoryUsage() { return arena_.MemoryUsage(); } + +int MemTable::KeyComparator::operator()(const char* aptr, + const char* bptr) const { + // Internal keys are encoded as length-prefixed strings. + Slice a = GetLengthPrefixedSlice(aptr); + Slice b = GetLengthPrefixedSlice(bptr); + return comparator.Compare(a, b); +} + +// Encode a suitable internal key target for "target" and return it. +// Uses *scratch as scratch space, and the returned pointer will point +// into this scratch space. +static const char* EncodeKey(std::string* scratch, const Slice& target) { + scratch->clear(); + PutVarint32(scratch, target.size()); + scratch->append(target.data(), target.size()); + return scratch->data(); +} + +class MemTableIterator : public Iterator { + public: + explicit MemTableIterator(MemTable::Table* table) : iter_(table) {} + + virtual bool Valid() const { return iter_.Valid(); } + virtual void Seek(const Slice& k) { iter_.Seek(EncodeKey(&tmp_, k)); } + virtual void SeekToFirst() { iter_.SeekToFirst(); } + virtual void SeekToLast() { iter_.SeekToLast(); } + virtual void Next() { iter_.Next(); } + virtual void Prev() { iter_.Prev(); } + virtual Slice key() const { return GetLengthPrefixedSlice(iter_.key()); } + virtual Slice value() const { + Slice key_slice = GetLengthPrefixedSlice(iter_.key()); + return GetLengthPrefixedSlice(key_slice.data() + key_slice.size()); + } + + virtual Status status() const { return Status::OK(); } + + private: + MemTable::Table::Iterator iter_; + std::string tmp_; // For passing to EncodeKey + + // No copying allowed + MemTableIterator(const MemTableIterator&); + void operator=(const MemTableIterator&); +}; + +Iterator* MemTable::NewIterator() { return new MemTableIterator(&table_); } + +void MemTable::Add(SequenceNumber s, ValueType type, const Slice& key, + const Slice& value) { + // Format of an entry is concatenation of: + // key_size : varint32 of internal_key.size() + // key bytes : char[internal_key.size()] + // value_size : varint32 of value.size() + // value bytes : char[value.size()] + size_t key_size = key.size(); + size_t val_size = value.size(); + size_t internal_key_size = key_size + 8; + const size_t encoded_len = VarintLength(internal_key_size) + + internal_key_size + VarintLength(val_size) + + val_size; + char* buf = arena_.Allocate(encoded_len); + char* p = EncodeVarint32(buf, internal_key_size); + memcpy(p, key.data(), key_size); + p += key_size; + EncodeFixed64(p, (s << 8) | type); + p += 8; + p = EncodeVarint32(p, val_size); + memcpy(p, value.data(), val_size); + assert(p + val_size == buf + encoded_len); + table_.Insert(buf); +} + +bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { + Slice memkey = key.memtable_key(); + Table::Iterator iter(&table_); + iter.Seek(memkey.data()); + if (iter.Valid()) { + // entry format is: + // klength varint32 + // userkey char[klength] + // tag uint64 + // vlength varint32 + // value char[vlength] + // Check that it belongs to same user key. We do not check the + // sequence number since the Seek() call above should have skipped + // all entries with overly large sequence numbers. + const char* entry = iter.key(); + uint32_t key_length; + const char* key_ptr = GetVarint32Ptr(entry, entry + 5, &key_length); + if (comparator_.comparator.user_comparator()->Compare( + Slice(key_ptr, key_length - 8), key.user_key()) == 0) { + // Correct user key + const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8); + switch (static_cast(tag & 0xff)) { + case kTypeValue: { + Slice v = GetLengthPrefixedSlice(key_ptr + key_length); + value->assign(v.data(), v.size()); + return true; + } + case kTypeDeletion: + *s = Status::NotFound(Slice()); + return true; + } + } + } + return false; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/memtable.h b/saraWhatsUp/Pods/leveldb-library/db/memtable.h new file mode 100644 index 0000000..9d986b1 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/memtable.h @@ -0,0 +1,87 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_MEMTABLE_H_ +#define STORAGE_LEVELDB_DB_MEMTABLE_H_ + +#include + +#include "db/dbformat.h" +#include "db/skiplist.h" +#include "leveldb/db.h" +#include "util/arena.h" + +namespace leveldb { + +class InternalKeyComparator; +class MemTableIterator; + +class MemTable { + public: + // MemTables are reference counted. The initial reference count + // is zero and the caller must call Ref() at least once. + explicit MemTable(const InternalKeyComparator& comparator); + + MemTable(const MemTable&) = delete; + MemTable& operator=(const MemTable&) = delete; + + // Increase reference count. + void Ref() { ++refs_; } + + // Drop reference count. Delete if no more references exist. + void Unref() { + --refs_; + assert(refs_ >= 0); + if (refs_ <= 0) { + delete this; + } + } + + // Returns an estimate of the number of bytes of data in use by this + // data structure. It is safe to call when MemTable is being modified. + size_t ApproximateMemoryUsage(); + + // Return an iterator that yields the contents of the memtable. + // + // The caller must ensure that the underlying MemTable remains live + // while the returned iterator is live. The keys returned by this + // iterator are internal keys encoded by AppendInternalKey in the + // db/format.{h,cc} module. + Iterator* NewIterator(); + + // Add an entry into memtable that maps key to value at the + // specified sequence number and with the specified type. + // Typically value will be empty if type==kTypeDeletion. + void Add(SequenceNumber seq, ValueType type, const Slice& key, + const Slice& value); + + // If memtable contains a value for key, store it in *value and return true. + // If memtable contains a deletion for key, store a NotFound() error + // in *status and return true. + // Else, return false. + bool Get(const LookupKey& key, std::string* value, Status* s); + + private: + friend class MemTableIterator; + friend class MemTableBackwardIterator; + + struct KeyComparator { + const InternalKeyComparator comparator; + explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) {} + int operator()(const char* a, const char* b) const; + }; + + typedef SkipList Table; + + ~MemTable(); // Private since only Unref() should be used to delete it + + KeyComparator comparator_; + int refs_; + Arena arena_; + Table table_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_MEMTABLE_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/repair.cc b/saraWhatsUp/Pods/leveldb-library/db/repair.cc new file mode 100644 index 0000000..3c676ca --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/repair.cc @@ -0,0 +1,450 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// We recover the contents of the descriptor from the other files we find. +// (1) Any log files are first converted to tables +// (2) We scan every table to compute +// (a) smallest/largest for the table +// (b) largest sequence number in the table +// (3) We generate descriptor contents: +// - log number is set to zero +// - next-file-number is set to 1 + largest file number we found +// - last-sequence-number is set to largest sequence# found across +// all tables (see 2c) +// - compaction pointers are cleared +// - every table file is added at level 0 +// +// Possible optimization 1: +// (a) Compute total size and use to pick appropriate max-level M +// (b) Sort tables by largest sequence# in the table +// (c) For each table: if it overlaps earlier table, place in level-0, +// else place in level-M. +// Possible optimization 2: +// Store per-table metadata (smallest, largest, largest-seq#, ...) +// in the table's meta section to speed up ScanTable. + +#include "db/builder.h" +#include "db/db_impl.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "db/version_edit.h" +#include "db/write_batch_internal.h" +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/env.h" + +namespace leveldb { + +namespace { + +class Repairer { + public: + Repairer(const std::string& dbname, const Options& options) + : dbname_(dbname), + env_(options.env), + icmp_(options.comparator), + ipolicy_(options.filter_policy), + options_(SanitizeOptions(dbname, &icmp_, &ipolicy_, options)), + owns_info_log_(options_.info_log != options.info_log), + owns_cache_(options_.block_cache != options.block_cache), + next_file_number_(1) { + // TableCache can be small since we expect each table to be opened once. + table_cache_ = new TableCache(dbname_, options_, 10); + } + + ~Repairer() { + delete table_cache_; + if (owns_info_log_) { + delete options_.info_log; + } + if (owns_cache_) { + delete options_.block_cache; + } + } + + Status Run() { + Status status = FindFiles(); + if (status.ok()) { + ConvertLogFilesToTables(); + ExtractMetaData(); + status = WriteDescriptor(); + } + if (status.ok()) { + unsigned long long bytes = 0; + for (size_t i = 0; i < tables_.size(); i++) { + bytes += tables_[i].meta.file_size; + } + Log(options_.info_log, + "**** Repaired leveldb %s; " + "recovered %d files; %llu bytes. " + "Some data may have been lost. " + "****", + dbname_.c_str(), static_cast(tables_.size()), bytes); + } + return status; + } + + private: + struct TableInfo { + FileMetaData meta; + SequenceNumber max_sequence; + }; + + Status FindFiles() { + std::vector filenames; + Status status = env_->GetChildren(dbname_, &filenames); + if (!status.ok()) { + return status; + } + if (filenames.empty()) { + return Status::IOError(dbname_, "repair found no files"); + } + + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + if (type == kDescriptorFile) { + manifests_.push_back(filenames[i]); + } else { + if (number + 1 > next_file_number_) { + next_file_number_ = number + 1; + } + if (type == kLogFile) { + logs_.push_back(number); + } else if (type == kTableFile) { + table_numbers_.push_back(number); + } else { + // Ignore other files + } + } + } + } + return status; + } + + void ConvertLogFilesToTables() { + for (size_t i = 0; i < logs_.size(); i++) { + std::string logname = LogFileName(dbname_, logs_[i]); + Status status = ConvertLogToTable(logs_[i]); + if (!status.ok()) { + Log(options_.info_log, "Log #%llu: ignoring conversion error: %s", + (unsigned long long)logs_[i], status.ToString().c_str()); + } + ArchiveFile(logname); + } + } + + Status ConvertLogToTable(uint64_t log) { + struct LogReporter : public log::Reader::Reporter { + Env* env; + Logger* info_log; + uint64_t lognum; + virtual void Corruption(size_t bytes, const Status& s) { + // We print error messages for corruption, but continue repairing. + Log(info_log, "Log #%llu: dropping %d bytes; %s", + (unsigned long long)lognum, static_cast(bytes), + s.ToString().c_str()); + } + }; + + // Open the log file + std::string logname = LogFileName(dbname_, log); + SequentialFile* lfile; + Status status = env_->NewSequentialFile(logname, &lfile); + if (!status.ok()) { + return status; + } + + // Create the log reader. + LogReporter reporter; + reporter.env = env_; + reporter.info_log = options_.info_log; + reporter.lognum = log; + // We intentionally make log::Reader do checksumming so that + // corruptions cause entire commits to be skipped instead of + // propagating bad information (like overly large sequence + // numbers). + log::Reader reader(lfile, &reporter, false /*do not checksum*/, + 0 /*initial_offset*/); + + // Read all the records and add to a memtable + std::string scratch; + Slice record; + WriteBatch batch; + MemTable* mem = new MemTable(icmp_); + mem->Ref(); + int counter = 0; + while (reader.ReadRecord(&record, &scratch)) { + if (record.size() < 12) { + reporter.Corruption(record.size(), + Status::Corruption("log record too small")); + continue; + } + WriteBatchInternal::SetContents(&batch, record); + status = WriteBatchInternal::InsertInto(&batch, mem); + if (status.ok()) { + counter += WriteBatchInternal::Count(&batch); + } else { + Log(options_.info_log, "Log #%llu: ignoring %s", + (unsigned long long)log, status.ToString().c_str()); + status = Status::OK(); // Keep going with rest of file + } + } + delete lfile; + + // Do not record a version edit for this conversion to a Table + // since ExtractMetaData() will also generate edits. + FileMetaData meta; + meta.number = next_file_number_++; + Iterator* iter = mem->NewIterator(); + status = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); + delete iter; + mem->Unref(); + mem = nullptr; + if (status.ok()) { + if (meta.file_size > 0) { + table_numbers_.push_back(meta.number); + } + } + Log(options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s", + (unsigned long long)log, counter, (unsigned long long)meta.number, + status.ToString().c_str()); + return status; + } + + void ExtractMetaData() { + for (size_t i = 0; i < table_numbers_.size(); i++) { + ScanTable(table_numbers_[i]); + } + } + + Iterator* NewTableIterator(const FileMetaData& meta) { + // Same as compaction iterators: if paranoid_checks are on, turn + // on checksum verification. + ReadOptions r; + r.verify_checksums = options_.paranoid_checks; + return table_cache_->NewIterator(r, meta.number, meta.file_size); + } + + void ScanTable(uint64_t number) { + TableInfo t; + t.meta.number = number; + std::string fname = TableFileName(dbname_, number); + Status status = env_->GetFileSize(fname, &t.meta.file_size); + if (!status.ok()) { + // Try alternate file name. + fname = SSTTableFileName(dbname_, number); + Status s2 = env_->GetFileSize(fname, &t.meta.file_size); + if (s2.ok()) { + status = Status::OK(); + } + } + if (!status.ok()) { + ArchiveFile(TableFileName(dbname_, number)); + ArchiveFile(SSTTableFileName(dbname_, number)); + Log(options_.info_log, "Table #%llu: dropped: %s", + (unsigned long long)t.meta.number, status.ToString().c_str()); + return; + } + + // Extract metadata by scanning through table. + int counter = 0; + Iterator* iter = NewTableIterator(t.meta); + bool empty = true; + ParsedInternalKey parsed; + t.max_sequence = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + Slice key = iter->key(); + if (!ParseInternalKey(key, &parsed)) { + Log(options_.info_log, "Table #%llu: unparsable key %s", + (unsigned long long)t.meta.number, EscapeString(key).c_str()); + continue; + } + + counter++; + if (empty) { + empty = false; + t.meta.smallest.DecodeFrom(key); + } + t.meta.largest.DecodeFrom(key); + if (parsed.sequence > t.max_sequence) { + t.max_sequence = parsed.sequence; + } + } + if (!iter->status().ok()) { + status = iter->status(); + } + delete iter; + Log(options_.info_log, "Table #%llu: %d entries %s", + (unsigned long long)t.meta.number, counter, status.ToString().c_str()); + + if (status.ok()) { + tables_.push_back(t); + } else { + RepairTable(fname, t); // RepairTable archives input file. + } + } + + void RepairTable(const std::string& src, TableInfo t) { + // We will copy src contents to a new table and then rename the + // new table over the source. + + // Create builder. + std::string copy = TableFileName(dbname_, next_file_number_++); + WritableFile* file; + Status s = env_->NewWritableFile(copy, &file); + if (!s.ok()) { + return; + } + TableBuilder* builder = new TableBuilder(options_, file); + + // Copy data. + Iterator* iter = NewTableIterator(t.meta); + int counter = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + builder->Add(iter->key(), iter->value()); + counter++; + } + delete iter; + + ArchiveFile(src); + if (counter == 0) { + builder->Abandon(); // Nothing to save + } else { + s = builder->Finish(); + if (s.ok()) { + t.meta.file_size = builder->FileSize(); + } + } + delete builder; + builder = nullptr; + + if (s.ok()) { + s = file->Close(); + } + delete file; + file = nullptr; + + if (counter > 0 && s.ok()) { + std::string orig = TableFileName(dbname_, t.meta.number); + s = env_->RenameFile(copy, orig); + if (s.ok()) { + Log(options_.info_log, "Table #%llu: %d entries repaired", + (unsigned long long)t.meta.number, counter); + tables_.push_back(t); + } + } + if (!s.ok()) { + env_->DeleteFile(copy); + } + } + + Status WriteDescriptor() { + std::string tmp = TempFileName(dbname_, 1); + WritableFile* file; + Status status = env_->NewWritableFile(tmp, &file); + if (!status.ok()) { + return status; + } + + SequenceNumber max_sequence = 0; + for (size_t i = 0; i < tables_.size(); i++) { + if (max_sequence < tables_[i].max_sequence) { + max_sequence = tables_[i].max_sequence; + } + } + + edit_.SetComparatorName(icmp_.user_comparator()->Name()); + edit_.SetLogNumber(0); + edit_.SetNextFile(next_file_number_); + edit_.SetLastSequence(max_sequence); + + for (size_t i = 0; i < tables_.size(); i++) { + // TODO(opt): separate out into multiple levels + const TableInfo& t = tables_[i]; + edit_.AddFile(0, t.meta.number, t.meta.file_size, t.meta.smallest, + t.meta.largest); + } + + // fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str()); + { + log::Writer log(file); + std::string record; + edit_.EncodeTo(&record); + status = log.AddRecord(record); + } + if (status.ok()) { + status = file->Close(); + } + delete file; + file = nullptr; + + if (!status.ok()) { + env_->DeleteFile(tmp); + } else { + // Discard older manifests + for (size_t i = 0; i < manifests_.size(); i++) { + ArchiveFile(dbname_ + "/" + manifests_[i]); + } + + // Install new manifest + status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1)); + if (status.ok()) { + status = SetCurrentFile(env_, dbname_, 1); + } else { + env_->DeleteFile(tmp); + } + } + return status; + } + + void ArchiveFile(const std::string& fname) { + // Move into another directory. E.g., for + // dir/foo + // rename to + // dir/lost/foo + const char* slash = strrchr(fname.c_str(), '/'); + std::string new_dir; + if (slash != nullptr) { + new_dir.assign(fname.data(), slash - fname.data()); + } + new_dir.append("/lost"); + env_->CreateDir(new_dir); // Ignore error + std::string new_file = new_dir; + new_file.append("/"); + new_file.append((slash == nullptr) ? fname.c_str() : slash + 1); + Status s = env_->RenameFile(fname, new_file); + Log(options_.info_log, "Archiving %s: %s\n", fname.c_str(), + s.ToString().c_str()); + } + + const std::string dbname_; + Env* const env_; + InternalKeyComparator const icmp_; + InternalFilterPolicy const ipolicy_; + const Options options_; + bool owns_info_log_; + bool owns_cache_; + TableCache* table_cache_; + VersionEdit edit_; + + std::vector manifests_; + std::vector table_numbers_; + std::vector logs_; + std::vector tables_; + uint64_t next_file_number_; +}; +} // namespace + +Status RepairDB(const std::string& dbname, const Options& options) { + Repairer repairer(dbname, options); + return repairer.Run(); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/skiplist.h b/saraWhatsUp/Pods/leveldb-library/db/skiplist.h new file mode 100644 index 0000000..a59b45b --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/skiplist.h @@ -0,0 +1,382 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_ +#define STORAGE_LEVELDB_DB_SKIPLIST_H_ + +// Thread safety +// ------------- +// +// Writes require external synchronization, most likely a mutex. +// Reads require a guarantee that the SkipList will not be destroyed +// while the read is in progress. Apart from that, reads progress +// without any internal locking or synchronization. +// +// Invariants: +// +// (1) Allocated nodes are never deleted until the SkipList is +// destroyed. This is trivially guaranteed by the code since we +// never delete any skip list nodes. +// +// (2) The contents of a Node except for the next/prev pointers are +// immutable after the Node has been linked into the SkipList. +// Only Insert() modifies the list, and it is careful to initialize +// a node and use release-stores to publish the nodes in one or +// more lists. +// +// ... prev vs. next pointer ordering ... + +#include +#include +#include + +#include "util/arena.h" +#include "util/random.h" + +namespace leveldb { + +class Arena; + +template +class SkipList { + private: + struct Node; + + public: + // Create a new SkipList object that will use "cmp" for comparing keys, + // and will allocate memory using "*arena". Objects allocated in the arena + // must remain allocated for the lifetime of the skiplist object. + explicit SkipList(Comparator cmp, Arena* arena); + + SkipList(const SkipList&) = delete; + SkipList& operator=(const SkipList&) = delete; + + // Insert key into the list. + // REQUIRES: nothing that compares equal to key is currently in the list. + void Insert(const Key& key); + + // Returns true iff an entry that compares equal to key is in the list. + bool Contains(const Key& key) const; + + // Iteration over the contents of a skip list + class Iterator { + public: + // Initialize an iterator over the specified list. + // The returned iterator is not valid. + explicit Iterator(const SkipList* list); + + // Returns true iff the iterator is positioned at a valid node. + bool Valid() const; + + // Returns the key at the current position. + // REQUIRES: Valid() + const Key& key() const; + + // Advances to the next position. + // REQUIRES: Valid() + void Next(); + + // Advances to the previous position. + // REQUIRES: Valid() + void Prev(); + + // Advance to the first entry with a key >= target + void Seek(const Key& target); + + // Position at the first entry in list. + // Final state of iterator is Valid() iff list is not empty. + void SeekToFirst(); + + // Position at the last entry in list. + // Final state of iterator is Valid() iff list is not empty. + void SeekToLast(); + + private: + const SkipList* list_; + Node* node_; + // Intentionally copyable + }; + + private: + enum { kMaxHeight = 12 }; + + inline int GetMaxHeight() const { + return max_height_.load(std::memory_order_relaxed); + } + + Node* NewNode(const Key& key, int height); + int RandomHeight(); + bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); } + + // Return true if key is greater than the data stored in "n" + bool KeyIsAfterNode(const Key& key, Node* n) const; + + // Return the earliest node that comes at or after key. + // Return nullptr if there is no such node. + // + // If prev is non-null, fills prev[level] with pointer to previous + // node at "level" for every level in [0..max_height_-1]. + Node* FindGreaterOrEqual(const Key& key, Node** prev) const; + + // Return the latest node with a key < key. + // Return head_ if there is no such node. + Node* FindLessThan(const Key& key) const; + + // Return the last node in the list. + // Return head_ if list is empty. + Node* FindLast() const; + + // Immutable after construction + Comparator const compare_; + Arena* const arena_; // Arena used for allocations of nodes + + Node* const head_; + + // Modified only by Insert(). Read racily by readers, but stale + // values are ok. + std::atomic max_height_; // Height of the entire list + + // Read/written only by Insert(). + Random rnd_; +}; + +// Implementation details follow +template +struct SkipList::Node { + explicit Node(const Key& k) : key(k) {} + + Key const key; + + // Accessors/mutators for links. Wrapped in methods so we can + // add the appropriate barriers as necessary. + Node* Next(int n) { + assert(n >= 0); + // Use an 'acquire load' so that we observe a fully initialized + // version of the returned Node. + return next_[n].load(std::memory_order_acquire); + } + void SetNext(int n, Node* x) { + assert(n >= 0); + // Use a 'release store' so that anybody who reads through this + // pointer observes a fully initialized version of the inserted node. + next_[n].store(x, std::memory_order_release); + } + + // No-barrier variants that can be safely used in a few locations. + Node* NoBarrier_Next(int n) { + assert(n >= 0); + return next_[n].load(std::memory_order_relaxed); + } + void NoBarrier_SetNext(int n, Node* x) { + assert(n >= 0); + next_[n].store(x, std::memory_order_relaxed); + } + + private: + // Array of length equal to the node height. next_[0] is lowest level link. + std::atomic next_[1]; +}; + +template +typename SkipList::Node* SkipList::NewNode( + const Key& key, int height) { + char* const node_memory = arena_->AllocateAligned( + sizeof(Node) + sizeof(std::atomic) * (height - 1)); + return new (node_memory) Node(key); +} + +template +inline SkipList::Iterator::Iterator(const SkipList* list) { + list_ = list; + node_ = nullptr; +} + +template +inline bool SkipList::Iterator::Valid() const { + return node_ != nullptr; +} + +template +inline const Key& SkipList::Iterator::key() const { + assert(Valid()); + return node_->key; +} + +template +inline void SkipList::Iterator::Next() { + assert(Valid()); + node_ = node_->Next(0); +} + +template +inline void SkipList::Iterator::Prev() { + // Instead of using explicit "prev" links, we just search for the + // last node that falls before key. + assert(Valid()); + node_ = list_->FindLessThan(node_->key); + if (node_ == list_->head_) { + node_ = nullptr; + } +} + +template +inline void SkipList::Iterator::Seek(const Key& target) { + node_ = list_->FindGreaterOrEqual(target, nullptr); +} + +template +inline void SkipList::Iterator::SeekToFirst() { + node_ = list_->head_->Next(0); +} + +template +inline void SkipList::Iterator::SeekToLast() { + node_ = list_->FindLast(); + if (node_ == list_->head_) { + node_ = nullptr; + } +} + +template +int SkipList::RandomHeight() { + // Increase height with probability 1 in kBranching + static const unsigned int kBranching = 4; + int height = 1; + while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) { + height++; + } + assert(height > 0); + assert(height <= kMaxHeight); + return height; +} + +template +bool SkipList::KeyIsAfterNode(const Key& key, Node* n) const { + // null n is considered infinite + return (n != nullptr) && (compare_(n->key, key) < 0); +} + +template +typename SkipList::Node* +SkipList::FindGreaterOrEqual(const Key& key, + Node** prev) const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + Node* next = x->Next(level); + if (KeyIsAfterNode(key, next)) { + // Keep searching in this list + x = next; + } else { + if (prev != nullptr) prev[level] = x; + if (level == 0) { + return next; + } else { + // Switch to next list + level--; + } + } + } +} + +template +typename SkipList::Node* +SkipList::FindLessThan(const Key& key) const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + assert(x == head_ || compare_(x->key, key) < 0); + Node* next = x->Next(level); + if (next == nullptr || compare_(next->key, key) >= 0) { + if (level == 0) { + return x; + } else { + // Switch to next list + level--; + } + } else { + x = next; + } + } +} + +template +typename SkipList::Node* SkipList::FindLast() + const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + Node* next = x->Next(level); + if (next == nullptr) { + if (level == 0) { + return x; + } else { + // Switch to next list + level--; + } + } else { + x = next; + } + } +} + +template +SkipList::SkipList(Comparator cmp, Arena* arena) + : compare_(cmp), + arena_(arena), + head_(NewNode(0 /* any key will do */, kMaxHeight)), + max_height_(1), + rnd_(0xdeadbeef) { + for (int i = 0; i < kMaxHeight; i++) { + head_->SetNext(i, nullptr); + } +} + +template +void SkipList::Insert(const Key& key) { + // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual() + // here since Insert() is externally synchronized. + Node* prev[kMaxHeight]; + Node* x = FindGreaterOrEqual(key, prev); + + // Our data structure does not allow duplicate insertion + assert(x == nullptr || !Equal(key, x->key)); + + int height = RandomHeight(); + if (height > GetMaxHeight()) { + for (int i = GetMaxHeight(); i < height; i++) { + prev[i] = head_; + } + // It is ok to mutate max_height_ without any synchronization + // with concurrent readers. A concurrent reader that observes + // the new value of max_height_ will see either the old value of + // new level pointers from head_ (nullptr), or a new value set in + // the loop below. In the former case the reader will + // immediately drop to the next level since nullptr sorts after all + // keys. In the latter case the reader will use the new node. + max_height_.store(height, std::memory_order_relaxed); + } + + x = NewNode(key, height); + for (int i = 0; i < height; i++) { + // NoBarrier_SetNext() suffices since we will add a barrier when + // we publish a pointer to "x" in prev[i]. + x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i)); + prev[i]->SetNext(i, x); + } +} + +template +bool SkipList::Contains(const Key& key) const { + Node* x = FindGreaterOrEqual(key, nullptr); + if (x != nullptr && Equal(key, x->key)) { + return true; + } else { + return false; + } +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_SKIPLIST_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/snapshot.h b/saraWhatsUp/Pods/leveldb-library/db/snapshot.h new file mode 100644 index 0000000..9f1d664 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/snapshot.h @@ -0,0 +1,95 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_ +#define STORAGE_LEVELDB_DB_SNAPSHOT_H_ + +#include "db/dbformat.h" +#include "leveldb/db.h" + +namespace leveldb { + +class SnapshotList; + +// Snapshots are kept in a doubly-linked list in the DB. +// Each SnapshotImpl corresponds to a particular sequence number. +class SnapshotImpl : public Snapshot { + public: + SnapshotImpl(SequenceNumber sequence_number) + : sequence_number_(sequence_number) {} + + SequenceNumber sequence_number() const { return sequence_number_; } + + private: + friend class SnapshotList; + + // SnapshotImpl is kept in a doubly-linked circular list. The SnapshotList + // implementation operates on the next/previous fields direcly. + SnapshotImpl* prev_; + SnapshotImpl* next_; + + const SequenceNumber sequence_number_; + +#if !defined(NDEBUG) + SnapshotList* list_ = nullptr; +#endif // !defined(NDEBUG) +}; + +class SnapshotList { + public: + SnapshotList() : head_(0) { + head_.prev_ = &head_; + head_.next_ = &head_; + } + + bool empty() const { return head_.next_ == &head_; } + SnapshotImpl* oldest() const { + assert(!empty()); + return head_.next_; + } + SnapshotImpl* newest() const { + assert(!empty()); + return head_.prev_; + } + + // Creates a SnapshotImpl and appends it to the end of the list. + SnapshotImpl* New(SequenceNumber sequence_number) { + assert(empty() || newest()->sequence_number_ <= sequence_number); + + SnapshotImpl* snapshot = new SnapshotImpl(sequence_number); + +#if !defined(NDEBUG) + snapshot->list_ = this; +#endif // !defined(NDEBUG) + snapshot->next_ = &head_; + snapshot->prev_ = head_.prev_; + snapshot->prev_->next_ = snapshot; + snapshot->next_->prev_ = snapshot; + return snapshot; + } + + // Removes a SnapshotImpl from this list. + // + // The snapshot must have been created by calling New() on this list. + // + // The snapshot pointer should not be const, because its memory is + // deallocated. However, that would force us to change DB::ReleaseSnapshot(), + // which is in the API, and currently takes a const Snapshot. + void Delete(const SnapshotImpl* snapshot) { +#if !defined(NDEBUG) + assert(snapshot->list_ == this); +#endif // !defined(NDEBUG) + snapshot->prev_->next_ = snapshot->next_; + snapshot->next_->prev_ = snapshot->prev_; + delete snapshot; + } + + private: + // Dummy head of doubly-linked list of snapshots + SnapshotImpl head_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_SNAPSHOT_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/table_cache.cc b/saraWhatsUp/Pods/leveldb-library/db/table_cache.cc new file mode 100644 index 0000000..73f05fd --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/table_cache.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/table_cache.h" + +#include "db/filename.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "util/coding.h" + +namespace leveldb { + +struct TableAndFile { + RandomAccessFile* file; + Table* table; +}; + +static void DeleteEntry(const Slice& key, void* value) { + TableAndFile* tf = reinterpret_cast(value); + delete tf->table; + delete tf->file; + delete tf; +} + +static void UnrefEntry(void* arg1, void* arg2) { + Cache* cache = reinterpret_cast(arg1); + Cache::Handle* h = reinterpret_cast(arg2); + cache->Release(h); +} + +TableCache::TableCache(const std::string& dbname, const Options& options, + int entries) + : env_(options.env), + dbname_(dbname), + options_(options), + cache_(NewLRUCache(entries)) {} + +TableCache::~TableCache() { delete cache_; } + +Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, + Cache::Handle** handle) { + Status s; + char buf[sizeof(file_number)]; + EncodeFixed64(buf, file_number); + Slice key(buf, sizeof(buf)); + *handle = cache_->Lookup(key); + if (*handle == nullptr) { + std::string fname = TableFileName(dbname_, file_number); + RandomAccessFile* file = nullptr; + Table* table = nullptr; + s = env_->NewRandomAccessFile(fname, &file); + if (!s.ok()) { + std::string old_fname = SSTTableFileName(dbname_, file_number); + if (env_->NewRandomAccessFile(old_fname, &file).ok()) { + s = Status::OK(); + } + } + if (s.ok()) { + s = Table::Open(options_, file, file_size, &table); + } + + if (!s.ok()) { + assert(table == nullptr); + delete file; + // We do not cache error results so that if the error is transient, + // or somebody repairs the file, we recover automatically. + } else { + TableAndFile* tf = new TableAndFile; + tf->file = file; + tf->table = table; + *handle = cache_->Insert(key, tf, 1, &DeleteEntry); + } + } + return s; +} + +Iterator* TableCache::NewIterator(const ReadOptions& options, + uint64_t file_number, uint64_t file_size, + Table** tableptr) { + if (tableptr != nullptr) { + *tableptr = nullptr; + } + + Cache::Handle* handle = nullptr; + Status s = FindTable(file_number, file_size, &handle); + if (!s.ok()) { + return NewErrorIterator(s); + } + + Table* table = reinterpret_cast(cache_->Value(handle))->table; + Iterator* result = table->NewIterator(options); + result->RegisterCleanup(&UnrefEntry, cache_, handle); + if (tableptr != nullptr) { + *tableptr = table; + } + return result; +} + +Status TableCache::Get(const ReadOptions& options, uint64_t file_number, + uint64_t file_size, const Slice& k, void* arg, + void (*handle_result)(void*, const Slice&, + const Slice&)) { + Cache::Handle* handle = nullptr; + Status s = FindTable(file_number, file_size, &handle); + if (s.ok()) { + Table* t = reinterpret_cast(cache_->Value(handle))->table; + s = t->InternalGet(options, k, arg, handle_result); + cache_->Release(handle); + } + return s; +} + +void TableCache::Evict(uint64_t file_number) { + char buf[sizeof(file_number)]; + EncodeFixed64(buf, file_number); + cache_->Erase(Slice(buf, sizeof(buf))); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/table_cache.h b/saraWhatsUp/Pods/leveldb-library/db/table_cache.h new file mode 100644 index 0000000..93069c8 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/table_cache.h @@ -0,0 +1,58 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Thread-safe (provides internal synchronization) + +#ifndef STORAGE_LEVELDB_DB_TABLE_CACHE_H_ +#define STORAGE_LEVELDB_DB_TABLE_CACHE_H_ + +#include + +#include + +#include "db/dbformat.h" +#include "leveldb/cache.h" +#include "leveldb/table.h" +#include "port/port.h" + +namespace leveldb { + +class Env; + +class TableCache { + public: + TableCache(const std::string& dbname, const Options& options, int entries); + ~TableCache(); + + // Return an iterator for the specified file number (the corresponding + // file length must be exactly "file_size" bytes). If "tableptr" is + // non-null, also sets "*tableptr" to point to the Table object + // underlying the returned iterator, or to nullptr if no Table object + // underlies the returned iterator. The returned "*tableptr" object is owned + // by the cache and should not be deleted, and is valid for as long as the + // returned iterator is live. + Iterator* NewIterator(const ReadOptions& options, uint64_t file_number, + uint64_t file_size, Table** tableptr = nullptr); + + // If a seek to internal key "k" in specified file finds an entry, + // call (*handle_result)(arg, found_key, found_value). + Status Get(const ReadOptions& options, uint64_t file_number, + uint64_t file_size, const Slice& k, void* arg, + void (*handle_result)(void*, const Slice&, const Slice&)); + + // Evict any entry for the specified file number + void Evict(uint64_t file_number); + + private: + Status FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle**); + + Env* const env_; + const std::string dbname_; + const Options& options_; + Cache* cache_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_TABLE_CACHE_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/version_edit.cc b/saraWhatsUp/Pods/leveldb-library/db/version_edit.cc new file mode 100644 index 0000000..44a4d02 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/version_edit.cc @@ -0,0 +1,260 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_edit.h" + +#include "db/version_set.h" +#include "util/coding.h" + +namespace leveldb { + +// Tag numbers for serialized VersionEdit. These numbers are written to +// disk and should not be changed. +enum Tag { + kComparator = 1, + kLogNumber = 2, + kNextFileNumber = 3, + kLastSequence = 4, + kCompactPointer = 5, + kDeletedFile = 6, + kNewFile = 7, + // 8 was used for large value refs + kPrevLogNumber = 9 +}; + +void VersionEdit::Clear() { + comparator_.clear(); + log_number_ = 0; + prev_log_number_ = 0; + last_sequence_ = 0; + next_file_number_ = 0; + has_comparator_ = false; + has_log_number_ = false; + has_prev_log_number_ = false; + has_next_file_number_ = false; + has_last_sequence_ = false; + deleted_files_.clear(); + new_files_.clear(); +} + +void VersionEdit::EncodeTo(std::string* dst) const { + if (has_comparator_) { + PutVarint32(dst, kComparator); + PutLengthPrefixedSlice(dst, comparator_); + } + if (has_log_number_) { + PutVarint32(dst, kLogNumber); + PutVarint64(dst, log_number_); + } + if (has_prev_log_number_) { + PutVarint32(dst, kPrevLogNumber); + PutVarint64(dst, prev_log_number_); + } + if (has_next_file_number_) { + PutVarint32(dst, kNextFileNumber); + PutVarint64(dst, next_file_number_); + } + if (has_last_sequence_) { + PutVarint32(dst, kLastSequence); + PutVarint64(dst, last_sequence_); + } + + for (size_t i = 0; i < compact_pointers_.size(); i++) { + PutVarint32(dst, kCompactPointer); + PutVarint32(dst, compact_pointers_[i].first); // level + PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode()); + } + + for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); + iter != deleted_files_.end(); ++iter) { + PutVarint32(dst, kDeletedFile); + PutVarint32(dst, iter->first); // level + PutVarint64(dst, iter->second); // file number + } + + for (size_t i = 0; i < new_files_.size(); i++) { + const FileMetaData& f = new_files_[i].second; + PutVarint32(dst, kNewFile); + PutVarint32(dst, new_files_[i].first); // level + PutVarint64(dst, f.number); + PutVarint64(dst, f.file_size); + PutLengthPrefixedSlice(dst, f.smallest.Encode()); + PutLengthPrefixedSlice(dst, f.largest.Encode()); + } +} + +static bool GetInternalKey(Slice* input, InternalKey* dst) { + Slice str; + if (GetLengthPrefixedSlice(input, &str)) { + dst->DecodeFrom(str); + return true; + } else { + return false; + } +} + +static bool GetLevel(Slice* input, int* level) { + uint32_t v; + if (GetVarint32(input, &v) && v < config::kNumLevels) { + *level = v; + return true; + } else { + return false; + } +} + +Status VersionEdit::DecodeFrom(const Slice& src) { + Clear(); + Slice input = src; + const char* msg = nullptr; + uint32_t tag; + + // Temporary storage for parsing + int level; + uint64_t number; + FileMetaData f; + Slice str; + InternalKey key; + + while (msg == nullptr && GetVarint32(&input, &tag)) { + switch (tag) { + case kComparator: + if (GetLengthPrefixedSlice(&input, &str)) { + comparator_ = str.ToString(); + has_comparator_ = true; + } else { + msg = "comparator name"; + } + break; + + case kLogNumber: + if (GetVarint64(&input, &log_number_)) { + has_log_number_ = true; + } else { + msg = "log number"; + } + break; + + case kPrevLogNumber: + if (GetVarint64(&input, &prev_log_number_)) { + has_prev_log_number_ = true; + } else { + msg = "previous log number"; + } + break; + + case kNextFileNumber: + if (GetVarint64(&input, &next_file_number_)) { + has_next_file_number_ = true; + } else { + msg = "next file number"; + } + break; + + case kLastSequence: + if (GetVarint64(&input, &last_sequence_)) { + has_last_sequence_ = true; + } else { + msg = "last sequence number"; + } + break; + + case kCompactPointer: + if (GetLevel(&input, &level) && GetInternalKey(&input, &key)) { + compact_pointers_.push_back(std::make_pair(level, key)); + } else { + msg = "compaction pointer"; + } + break; + + case kDeletedFile: + if (GetLevel(&input, &level) && GetVarint64(&input, &number)) { + deleted_files_.insert(std::make_pair(level, number)); + } else { + msg = "deleted file"; + } + break; + + case kNewFile: + if (GetLevel(&input, &level) && GetVarint64(&input, &f.number) && + GetVarint64(&input, &f.file_size) && + GetInternalKey(&input, &f.smallest) && + GetInternalKey(&input, &f.largest)) { + new_files_.push_back(std::make_pair(level, f)); + } else { + msg = "new-file entry"; + } + break; + + default: + msg = "unknown tag"; + break; + } + } + + if (msg == nullptr && !input.empty()) { + msg = "invalid tag"; + } + + Status result; + if (msg != nullptr) { + result = Status::Corruption("VersionEdit", msg); + } + return result; +} + +std::string VersionEdit::DebugString() const { + std::string r; + r.append("VersionEdit {"); + if (has_comparator_) { + r.append("\n Comparator: "); + r.append(comparator_); + } + if (has_log_number_) { + r.append("\n LogNumber: "); + AppendNumberTo(&r, log_number_); + } + if (has_prev_log_number_) { + r.append("\n PrevLogNumber: "); + AppendNumberTo(&r, prev_log_number_); + } + if (has_next_file_number_) { + r.append("\n NextFile: "); + AppendNumberTo(&r, next_file_number_); + } + if (has_last_sequence_) { + r.append("\n LastSeq: "); + AppendNumberTo(&r, last_sequence_); + } + for (size_t i = 0; i < compact_pointers_.size(); i++) { + r.append("\n CompactPointer: "); + AppendNumberTo(&r, compact_pointers_[i].first); + r.append(" "); + r.append(compact_pointers_[i].second.DebugString()); + } + for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); + iter != deleted_files_.end(); ++iter) { + r.append("\n DeleteFile: "); + AppendNumberTo(&r, iter->first); + r.append(" "); + AppendNumberTo(&r, iter->second); + } + for (size_t i = 0; i < new_files_.size(); i++) { + const FileMetaData& f = new_files_[i].second; + r.append("\n AddFile: "); + AppendNumberTo(&r, new_files_[i].first); + r.append(" "); + AppendNumberTo(&r, f.number); + r.append(" "); + AppendNumberTo(&r, f.file_size); + r.append(" "); + r.append(f.smallest.DebugString()); + r.append(" .. "); + r.append(f.largest.DebugString()); + } + r.append("\n}\n"); + return r; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/version_edit.h b/saraWhatsUp/Pods/leveldb-library/db/version_edit.h new file mode 100644 index 0000000..2dadda7 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/version_edit.h @@ -0,0 +1,106 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_VERSION_EDIT_H_ +#define STORAGE_LEVELDB_DB_VERSION_EDIT_H_ + +#include +#include +#include + +#include "db/dbformat.h" + +namespace leveldb { + +class VersionSet; + +struct FileMetaData { + FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) {} + + int refs; + int allowed_seeks; // Seeks allowed until compaction + uint64_t number; + uint64_t file_size; // File size in bytes + InternalKey smallest; // Smallest internal key served by table + InternalKey largest; // Largest internal key served by table +}; + +class VersionEdit { + public: + VersionEdit() { Clear(); } + ~VersionEdit() {} + + void Clear(); + + void SetComparatorName(const Slice& name) { + has_comparator_ = true; + comparator_ = name.ToString(); + } + void SetLogNumber(uint64_t num) { + has_log_number_ = true; + log_number_ = num; + } + void SetPrevLogNumber(uint64_t num) { + has_prev_log_number_ = true; + prev_log_number_ = num; + } + void SetNextFile(uint64_t num) { + has_next_file_number_ = true; + next_file_number_ = num; + } + void SetLastSequence(SequenceNumber seq) { + has_last_sequence_ = true; + last_sequence_ = seq; + } + void SetCompactPointer(int level, const InternalKey& key) { + compact_pointers_.push_back(std::make_pair(level, key)); + } + + // Add the specified file at the specified number. + // REQUIRES: This version has not been saved (see VersionSet::SaveTo) + // REQUIRES: "smallest" and "largest" are smallest and largest keys in file + void AddFile(int level, uint64_t file, uint64_t file_size, + const InternalKey& smallest, const InternalKey& largest) { + FileMetaData f; + f.number = file; + f.file_size = file_size; + f.smallest = smallest; + f.largest = largest; + new_files_.push_back(std::make_pair(level, f)); + } + + // Delete the specified "file" from the specified "level". + void DeleteFile(int level, uint64_t file) { + deleted_files_.insert(std::make_pair(level, file)); + } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(const Slice& src); + + std::string DebugString() const; + + private: + friend class VersionSet; + + typedef std::set > DeletedFileSet; + + std::string comparator_; + uint64_t log_number_; + uint64_t prev_log_number_; + uint64_t next_file_number_; + SequenceNumber last_sequence_; + bool has_comparator_; + bool has_log_number_; + bool has_prev_log_number_; + bool has_next_file_number_; + bool has_last_sequence_; + + std::vector > compact_pointers_; + DeletedFileSet deleted_files_; + std::vector > new_files_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_VERSION_EDIT_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/version_set.cc b/saraWhatsUp/Pods/leveldb-library/db/version_set.cc new file mode 100644 index 0000000..96a92cc --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/version_set.cc @@ -0,0 +1,1585 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_set.h" + +#include + +#include + +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "leveldb/env.h" +#include "leveldb/table_builder.h" +#include "table/merger.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +static size_t TargetFileSize(const Options* options) { + return options->max_file_size; +} + +// Maximum bytes of overlaps in grandparent (i.e., level+2) before we +// stop building a single file in a level->level+1 compaction. +static int64_t MaxGrandParentOverlapBytes(const Options* options) { + return 10 * TargetFileSize(options); +} + +// Maximum number of bytes in all compacted files. We avoid expanding +// the lower level file set of a compaction if it would make the +// total compaction cover more than this many bytes. +static int64_t ExpandedCompactionByteSizeLimit(const Options* options) { + return 25 * TargetFileSize(options); +} + +static double MaxBytesForLevel(const Options* options, int level) { + // Note: the result for level zero is not really used since we set + // the level-0 compaction threshold based on number of files. + + // Result for both level-0 and level-1 + double result = 10. * 1048576.0; + while (level > 1) { + result *= 10; + level--; + } + return result; +} + +static uint64_t MaxFileSizeForLevel(const Options* options, int level) { + // We could vary per level to reduce number of files? + return TargetFileSize(options); +} + +static int64_t TotalFileSize(const std::vector& files) { + int64_t sum = 0; + for (size_t i = 0; i < files.size(); i++) { + sum += files[i]->file_size; + } + return sum; +} + +Version::~Version() { + assert(refs_ == 0); + + // Remove from linked list + prev_->next_ = next_; + next_->prev_ = prev_; + + // Drop references to files + for (int level = 0; level < config::kNumLevels; level++) { + for (size_t i = 0; i < files_[level].size(); i++) { + FileMetaData* f = files_[level][i]; + assert(f->refs > 0); + f->refs--; + if (f->refs <= 0) { + delete f; + } + } + } +} + +int FindFile(const InternalKeyComparator& icmp, + const std::vector& files, const Slice& key) { + uint32_t left = 0; + uint32_t right = files.size(); + while (left < right) { + uint32_t mid = (left + right) / 2; + const FileMetaData* f = files[mid]; + if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) { + // Key at "mid.largest" is < "target". Therefore all + // files at or before "mid" are uninteresting. + left = mid + 1; + } else { + // Key at "mid.largest" is >= "target". Therefore all files + // after "mid" are uninteresting. + right = mid; + } + } + return right; +} + +static bool AfterFile(const Comparator* ucmp, const Slice* user_key, + const FileMetaData* f) { + // null user_key occurs before all keys and is therefore never after *f + return (user_key != nullptr && + ucmp->Compare(*user_key, f->largest.user_key()) > 0); +} + +static bool BeforeFile(const Comparator* ucmp, const Slice* user_key, + const FileMetaData* f) { + // null user_key occurs after all keys and is therefore never before *f + return (user_key != nullptr && + ucmp->Compare(*user_key, f->smallest.user_key()) < 0); +} + +bool SomeFileOverlapsRange(const InternalKeyComparator& icmp, + bool disjoint_sorted_files, + const std::vector& files, + const Slice* smallest_user_key, + const Slice* largest_user_key) { + const Comparator* ucmp = icmp.user_comparator(); + if (!disjoint_sorted_files) { + // Need to check against all files + for (size_t i = 0; i < files.size(); i++) { + const FileMetaData* f = files[i]; + if (AfterFile(ucmp, smallest_user_key, f) || + BeforeFile(ucmp, largest_user_key, f)) { + // No overlap + } else { + return true; // Overlap + } + } + return false; + } + + // Binary search over file list + uint32_t index = 0; + if (smallest_user_key != nullptr) { + // Find the earliest possible internal key for smallest_user_key + InternalKey small_key(*smallest_user_key, kMaxSequenceNumber, + kValueTypeForSeek); + index = FindFile(icmp, files, small_key.Encode()); + } + + if (index >= files.size()) { + // beginning of range is after all files, so no overlap. + return false; + } + + return !BeforeFile(ucmp, largest_user_key, files[index]); +} + +// An internal iterator. For a given version/level pair, yields +// information about the files in the level. For a given entry, key() +// is the largest key that occurs in the file, and value() is an +// 16-byte value containing the file number and file size, both +// encoded using EncodeFixed64. +class Version::LevelFileNumIterator : public Iterator { + public: + LevelFileNumIterator(const InternalKeyComparator& icmp, + const std::vector* flist) + : icmp_(icmp), flist_(flist), index_(flist->size()) { // Marks as invalid + } + virtual bool Valid() const { return index_ < flist_->size(); } + virtual void Seek(const Slice& target) { + index_ = FindFile(icmp_, *flist_, target); + } + virtual void SeekToFirst() { index_ = 0; } + virtual void SeekToLast() { + index_ = flist_->empty() ? 0 : flist_->size() - 1; + } + virtual void Next() { + assert(Valid()); + index_++; + } + virtual void Prev() { + assert(Valid()); + if (index_ == 0) { + index_ = flist_->size(); // Marks as invalid + } else { + index_--; + } + } + Slice key() const { + assert(Valid()); + return (*flist_)[index_]->largest.Encode(); + } + Slice value() const { + assert(Valid()); + EncodeFixed64(value_buf_, (*flist_)[index_]->number); + EncodeFixed64(value_buf_ + 8, (*flist_)[index_]->file_size); + return Slice(value_buf_, sizeof(value_buf_)); + } + virtual Status status() const { return Status::OK(); } + + private: + const InternalKeyComparator icmp_; + const std::vector* const flist_; + uint32_t index_; + + // Backing store for value(). Holds the file number and size. + mutable char value_buf_[16]; +}; + +static Iterator* GetFileIterator(void* arg, const ReadOptions& options, + const Slice& file_value) { + TableCache* cache = reinterpret_cast(arg); + if (file_value.size() != 16) { + return NewErrorIterator( + Status::Corruption("FileReader invoked with unexpected value")); + } else { + return cache->NewIterator(options, DecodeFixed64(file_value.data()), + DecodeFixed64(file_value.data() + 8)); + } +} + +Iterator* Version::NewConcatenatingIterator(const ReadOptions& options, + int level) const { + return NewTwoLevelIterator( + new LevelFileNumIterator(vset_->icmp_, &files_[level]), &GetFileIterator, + vset_->table_cache_, options); +} + +void Version::AddIterators(const ReadOptions& options, + std::vector* iters) { + // Merge all level zero files together since they may overlap + for (size_t i = 0; i < files_[0].size(); i++) { + iters->push_back(vset_->table_cache_->NewIterator( + options, files_[0][i]->number, files_[0][i]->file_size)); + } + + // For levels > 0, we can use a concatenating iterator that sequentially + // walks through the non-overlapping files in the level, opening them + // lazily. + for (int level = 1; level < config::kNumLevels; level++) { + if (!files_[level].empty()) { + iters->push_back(NewConcatenatingIterator(options, level)); + } + } +} + +// Callback from TableCache::Get() +namespace { +enum SaverState { + kNotFound, + kFound, + kDeleted, + kCorrupt, +}; +struct Saver { + SaverState state; + const Comparator* ucmp; + Slice user_key; + std::string* value; +}; +} // namespace +static void SaveValue(void* arg, const Slice& ikey, const Slice& v) { + Saver* s = reinterpret_cast(arg); + ParsedInternalKey parsed_key; + if (!ParseInternalKey(ikey, &parsed_key)) { + s->state = kCorrupt; + } else { + if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) { + s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted; + if (s->state == kFound) { + s->value->assign(v.data(), v.size()); + } + } + } +} + +static bool NewestFirst(FileMetaData* a, FileMetaData* b) { + return a->number > b->number; +} + +void Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg, + bool (*func)(void*, int, FileMetaData*)) { + // TODO(sanjay): Change Version::Get() to use this function. + const Comparator* ucmp = vset_->icmp_.user_comparator(); + + // Search level-0 in order from newest to oldest. + std::vector tmp; + tmp.reserve(files_[0].size()); + for (uint32_t i = 0; i < files_[0].size(); i++) { + FileMetaData* f = files_[0][i]; + if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && + ucmp->Compare(user_key, f->largest.user_key()) <= 0) { + tmp.push_back(f); + } + } + if (!tmp.empty()) { + std::sort(tmp.begin(), tmp.end(), NewestFirst); + for (uint32_t i = 0; i < tmp.size(); i++) { + if (!(*func)(arg, 0, tmp[i])) { + return; + } + } + } + + // Search other levels. + for (int level = 1; level < config::kNumLevels; level++) { + size_t num_files = files_[level].size(); + if (num_files == 0) continue; + + // Binary search to find earliest index whose largest key >= internal_key. + uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key); + if (index < num_files) { + FileMetaData* f = files_[level][index]; + if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) { + // All of "f" is past any data for user_key + } else { + if (!(*func)(arg, level, f)) { + return; + } + } + } + } +} + +Status Version::Get(const ReadOptions& options, const LookupKey& k, + std::string* value, GetStats* stats) { + Slice ikey = k.internal_key(); + Slice user_key = k.user_key(); + const Comparator* ucmp = vset_->icmp_.user_comparator(); + Status s; + + stats->seek_file = nullptr; + stats->seek_file_level = -1; + FileMetaData* last_file_read = nullptr; + int last_file_read_level = -1; + + // We can search level-by-level since entries never hop across + // levels. Therefore we are guaranteed that if we find data + // in a smaller level, later levels are irrelevant. + std::vector tmp; + FileMetaData* tmp2; + for (int level = 0; level < config::kNumLevels; level++) { + size_t num_files = files_[level].size(); + if (num_files == 0) continue; + + // Get the list of files to search in this level + FileMetaData* const* files = &files_[level][0]; + if (level == 0) { + // Level-0 files may overlap each other. Find all files that + // overlap user_key and process them in order from newest to oldest. + tmp.reserve(num_files); + for (uint32_t i = 0; i < num_files; i++) { + FileMetaData* f = files[i]; + if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && + ucmp->Compare(user_key, f->largest.user_key()) <= 0) { + tmp.push_back(f); + } + } + if (tmp.empty()) continue; + + std::sort(tmp.begin(), tmp.end(), NewestFirst); + files = &tmp[0]; + num_files = tmp.size(); + } else { + // Binary search to find earliest index whose largest key >= ikey. + uint32_t index = FindFile(vset_->icmp_, files_[level], ikey); + if (index >= num_files) { + files = nullptr; + num_files = 0; + } else { + tmp2 = files[index]; + if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) { + // All of "tmp2" is past any data for user_key + files = nullptr; + num_files = 0; + } else { + files = &tmp2; + num_files = 1; + } + } + } + + for (uint32_t i = 0; i < num_files; ++i) { + if (last_file_read != nullptr && stats->seek_file == nullptr) { + // We have had more than one seek for this read. Charge the 1st file. + stats->seek_file = last_file_read; + stats->seek_file_level = last_file_read_level; + } + + FileMetaData* f = files[i]; + last_file_read = f; + last_file_read_level = level; + + Saver saver; + saver.state = kNotFound; + saver.ucmp = ucmp; + saver.user_key = user_key; + saver.value = value; + s = vset_->table_cache_->Get(options, f->number, f->file_size, ikey, + &saver, SaveValue); + if (!s.ok()) { + return s; + } + switch (saver.state) { + case kNotFound: + break; // Keep searching in other files + case kFound: + return s; + case kDeleted: + s = Status::NotFound(Slice()); // Use empty error message for speed + return s; + case kCorrupt: + s = Status::Corruption("corrupted key for ", user_key); + return s; + } + } + } + + return Status::NotFound(Slice()); // Use an empty error message for speed +} + +bool Version::UpdateStats(const GetStats& stats) { + FileMetaData* f = stats.seek_file; + if (f != nullptr) { + f->allowed_seeks--; + if (f->allowed_seeks <= 0 && file_to_compact_ == nullptr) { + file_to_compact_ = f; + file_to_compact_level_ = stats.seek_file_level; + return true; + } + } + return false; +} + +bool Version::RecordReadSample(Slice internal_key) { + ParsedInternalKey ikey; + if (!ParseInternalKey(internal_key, &ikey)) { + return false; + } + + struct State { + GetStats stats; // Holds first matching file + int matches; + + static bool Match(void* arg, int level, FileMetaData* f) { + State* state = reinterpret_cast(arg); + state->matches++; + if (state->matches == 1) { + // Remember first match. + state->stats.seek_file = f; + state->stats.seek_file_level = level; + } + // We can stop iterating once we have a second match. + return state->matches < 2; + } + }; + + State state; + state.matches = 0; + ForEachOverlapping(ikey.user_key, internal_key, &state, &State::Match); + + // Must have at least two matches since we want to merge across + // files. But what if we have a single file that contains many + // overwrites and deletions? Should we have another mechanism for + // finding such files? + if (state.matches >= 2) { + // 1MB cost is about 1 seek (see comment in Builder::Apply). + return UpdateStats(state.stats); + } + return false; +} + +void Version::Ref() { ++refs_; } + +void Version::Unref() { + assert(this != &vset_->dummy_versions_); + assert(refs_ >= 1); + --refs_; + if (refs_ == 0) { + delete this; + } +} + +bool Version::OverlapInLevel(int level, const Slice* smallest_user_key, + const Slice* largest_user_key) { + return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level], + smallest_user_key, largest_user_key); +} + +int Version::PickLevelForMemTableOutput(const Slice& smallest_user_key, + const Slice& largest_user_key) { + int level = 0; + if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) { + // Push to next level if there is no overlap in next level, + // and the #bytes overlapping in the level after that are limited. + InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek); + InternalKey limit(largest_user_key, 0, static_cast(0)); + std::vector overlaps; + while (level < config::kMaxMemCompactLevel) { + if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) { + break; + } + if (level + 2 < config::kNumLevels) { + // Check that file does not overlap too many grandparent bytes. + GetOverlappingInputs(level + 2, &start, &limit, &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > MaxGrandParentOverlapBytes(vset_->options_)) { + break; + } + } + level++; + } + } + return level; +} + +// Store in "*inputs" all files in "level" that overlap [begin,end] +void Version::GetOverlappingInputs(int level, const InternalKey* begin, + const InternalKey* end, + std::vector* inputs) { + assert(level >= 0); + assert(level < config::kNumLevels); + inputs->clear(); + Slice user_begin, user_end; + if (begin != nullptr) { + user_begin = begin->user_key(); + } + if (end != nullptr) { + user_end = end->user_key(); + } + const Comparator* user_cmp = vset_->icmp_.user_comparator(); + for (size_t i = 0; i < files_[level].size();) { + FileMetaData* f = files_[level][i++]; + const Slice file_start = f->smallest.user_key(); + const Slice file_limit = f->largest.user_key(); + if (begin != nullptr && user_cmp->Compare(file_limit, user_begin) < 0) { + // "f" is completely before specified range; skip it + } else if (end != nullptr && user_cmp->Compare(file_start, user_end) > 0) { + // "f" is completely after specified range; skip it + } else { + inputs->push_back(f); + if (level == 0) { + // Level-0 files may overlap each other. So check if the newly + // added file has expanded the range. If so, restart search. + if (begin != nullptr && user_cmp->Compare(file_start, user_begin) < 0) { + user_begin = file_start; + inputs->clear(); + i = 0; + } else if (end != nullptr && + user_cmp->Compare(file_limit, user_end) > 0) { + user_end = file_limit; + inputs->clear(); + i = 0; + } + } + } + } +} + +std::string Version::DebugString() const { + std::string r; + for (int level = 0; level < config::kNumLevels; level++) { + // E.g., + // --- level 1 --- + // 17:123['a' .. 'd'] + // 20:43['e' .. 'g'] + r.append("--- level "); + AppendNumberTo(&r, level); + r.append(" ---\n"); + const std::vector& files = files_[level]; + for (size_t i = 0; i < files.size(); i++) { + r.push_back(' '); + AppendNumberTo(&r, files[i]->number); + r.push_back(':'); + AppendNumberTo(&r, files[i]->file_size); + r.append("["); + r.append(files[i]->smallest.DebugString()); + r.append(" .. "); + r.append(files[i]->largest.DebugString()); + r.append("]\n"); + } + } + return r; +} + +// A helper class so we can efficiently apply a whole sequence +// of edits to a particular state without creating intermediate +// Versions that contain full copies of the intermediate state. +class VersionSet::Builder { + private: + // Helper to sort by v->files_[file_number].smallest + struct BySmallestKey { + const InternalKeyComparator* internal_comparator; + + bool operator()(FileMetaData* f1, FileMetaData* f2) const { + int r = internal_comparator->Compare(f1->smallest, f2->smallest); + if (r != 0) { + return (r < 0); + } else { + // Break ties by file number + return (f1->number < f2->number); + } + } + }; + + typedef std::set FileSet; + struct LevelState { + std::set deleted_files; + FileSet* added_files; + }; + + VersionSet* vset_; + Version* base_; + LevelState levels_[config::kNumLevels]; + + public: + // Initialize a builder with the files from *base and other info from *vset + Builder(VersionSet* vset, Version* base) : vset_(vset), base_(base) { + base_->Ref(); + BySmallestKey cmp; + cmp.internal_comparator = &vset_->icmp_; + for (int level = 0; level < config::kNumLevels; level++) { + levels_[level].added_files = new FileSet(cmp); + } + } + + ~Builder() { + for (int level = 0; level < config::kNumLevels; level++) { + const FileSet* added = levels_[level].added_files; + std::vector to_unref; + to_unref.reserve(added->size()); + for (FileSet::const_iterator it = added->begin(); it != added->end(); + ++it) { + to_unref.push_back(*it); + } + delete added; + for (uint32_t i = 0; i < to_unref.size(); i++) { + FileMetaData* f = to_unref[i]; + f->refs--; + if (f->refs <= 0) { + delete f; + } + } + } + base_->Unref(); + } + + // Apply all of the edits in *edit to the current state. + void Apply(VersionEdit* edit) { + // Update compaction pointers + for (size_t i = 0; i < edit->compact_pointers_.size(); i++) { + const int level = edit->compact_pointers_[i].first; + vset_->compact_pointer_[level] = + edit->compact_pointers_[i].second.Encode().ToString(); + } + + // Delete files + const VersionEdit::DeletedFileSet& del = edit->deleted_files_; + for (VersionEdit::DeletedFileSet::const_iterator iter = del.begin(); + iter != del.end(); ++iter) { + const int level = iter->first; + const uint64_t number = iter->second; + levels_[level].deleted_files.insert(number); + } + + // Add new files + for (size_t i = 0; i < edit->new_files_.size(); i++) { + const int level = edit->new_files_[i].first; + FileMetaData* f = new FileMetaData(edit->new_files_[i].second); + f->refs = 1; + + // We arrange to automatically compact this file after + // a certain number of seeks. Let's assume: + // (1) One seek costs 10ms + // (2) Writing or reading 1MB costs 10ms (100MB/s) + // (3) A compaction of 1MB does 25MB of IO: + // 1MB read from this level + // 10-12MB read from next level (boundaries may be misaligned) + // 10-12MB written to next level + // This implies that 25 seeks cost the same as the compaction + // of 1MB of data. I.e., one seek costs approximately the + // same as the compaction of 40KB of data. We are a little + // conservative and allow approximately one seek for every 16KB + // of data before triggering a compaction. + f->allowed_seeks = static_cast((f->file_size / 16384U)); + if (f->allowed_seeks < 100) f->allowed_seeks = 100; + + levels_[level].deleted_files.erase(f->number); + levels_[level].added_files->insert(f); + } + } + + // Save the current state in *v. + void SaveTo(Version* v) { + BySmallestKey cmp; + cmp.internal_comparator = &vset_->icmp_; + for (int level = 0; level < config::kNumLevels; level++) { + // Merge the set of added files with the set of pre-existing files. + // Drop any deleted files. Store the result in *v. + const std::vector& base_files = base_->files_[level]; + std::vector::const_iterator base_iter = base_files.begin(); + std::vector::const_iterator base_end = base_files.end(); + const FileSet* added = levels_[level].added_files; + v->files_[level].reserve(base_files.size() + added->size()); + for (FileSet::const_iterator added_iter = added->begin(); + added_iter != added->end(); ++added_iter) { + // Add all smaller files listed in base_ + for (std::vector::const_iterator bpos = + std::upper_bound(base_iter, base_end, *added_iter, cmp); + base_iter != bpos; ++base_iter) { + MaybeAddFile(v, level, *base_iter); + } + + MaybeAddFile(v, level, *added_iter); + } + + // Add remaining base files + for (; base_iter != base_end; ++base_iter) { + MaybeAddFile(v, level, *base_iter); + } + +#ifndef NDEBUG + // Make sure there is no overlap in levels > 0 + if (level > 0) { + for (uint32_t i = 1; i < v->files_[level].size(); i++) { + const InternalKey& prev_end = v->files_[level][i - 1]->largest; + const InternalKey& this_begin = v->files_[level][i]->smallest; + if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) { + fprintf(stderr, "overlapping ranges in same level %s vs. %s\n", + prev_end.DebugString().c_str(), + this_begin.DebugString().c_str()); + abort(); + } + } + } +#endif + } + } + + void MaybeAddFile(Version* v, int level, FileMetaData* f) { + if (levels_[level].deleted_files.count(f->number) > 0) { + // File is deleted: do nothing + } else { + std::vector* files = &v->files_[level]; + if (level > 0 && !files->empty()) { + // Must not overlap + assert(vset_->icmp_.Compare((*files)[files->size() - 1]->largest, + f->smallest) < 0); + } + f->refs++; + files->push_back(f); + } + } +}; + +VersionSet::VersionSet(const std::string& dbname, const Options* options, + TableCache* table_cache, + const InternalKeyComparator* cmp) + : env_(options->env), + dbname_(dbname), + options_(options), + table_cache_(table_cache), + icmp_(*cmp), + next_file_number_(2), + manifest_file_number_(0), // Filled by Recover() + last_sequence_(0), + log_number_(0), + prev_log_number_(0), + descriptor_file_(nullptr), + descriptor_log_(nullptr), + dummy_versions_(this), + current_(nullptr) { + AppendVersion(new Version(this)); +} + +VersionSet::~VersionSet() { + current_->Unref(); + assert(dummy_versions_.next_ == &dummy_versions_); // List must be empty + delete descriptor_log_; + delete descriptor_file_; +} + +void VersionSet::AppendVersion(Version* v) { + // Make "v" current + assert(v->refs_ == 0); + assert(v != current_); + if (current_ != nullptr) { + current_->Unref(); + } + current_ = v; + v->Ref(); + + // Append to linked list + v->prev_ = dummy_versions_.prev_; + v->next_ = &dummy_versions_; + v->prev_->next_ = v; + v->next_->prev_ = v; +} + +Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) { + if (edit->has_log_number_) { + assert(edit->log_number_ >= log_number_); + assert(edit->log_number_ < next_file_number_); + } else { + edit->SetLogNumber(log_number_); + } + + if (!edit->has_prev_log_number_) { + edit->SetPrevLogNumber(prev_log_number_); + } + + edit->SetNextFile(next_file_number_); + edit->SetLastSequence(last_sequence_); + + Version* v = new Version(this); + { + Builder builder(this, current_); + builder.Apply(edit); + builder.SaveTo(v); + } + Finalize(v); + + // Initialize new descriptor log file if necessary by creating + // a temporary file that contains a snapshot of the current version. + std::string new_manifest_file; + Status s; + if (descriptor_log_ == nullptr) { + // No reason to unlock *mu here since we only hit this path in the + // first call to LogAndApply (when opening the database). + assert(descriptor_file_ == nullptr); + new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_); + edit->SetNextFile(next_file_number_); + s = env_->NewWritableFile(new_manifest_file, &descriptor_file_); + if (s.ok()) { + descriptor_log_ = new log::Writer(descriptor_file_); + s = WriteSnapshot(descriptor_log_); + } + } + + // Unlock during expensive MANIFEST log write + { + mu->Unlock(); + + // Write new record to MANIFEST log + if (s.ok()) { + std::string record; + edit->EncodeTo(&record); + s = descriptor_log_->AddRecord(record); + if (s.ok()) { + s = descriptor_file_->Sync(); + } + if (!s.ok()) { + Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str()); + } + } + + // If we just created a new descriptor file, install it by writing a + // new CURRENT file that points to it. + if (s.ok() && !new_manifest_file.empty()) { + s = SetCurrentFile(env_, dbname_, manifest_file_number_); + } + + mu->Lock(); + } + + // Install the new version + if (s.ok()) { + AppendVersion(v); + log_number_ = edit->log_number_; + prev_log_number_ = edit->prev_log_number_; + } else { + delete v; + if (!new_manifest_file.empty()) { + delete descriptor_log_; + delete descriptor_file_; + descriptor_log_ = nullptr; + descriptor_file_ = nullptr; + env_->DeleteFile(new_manifest_file); + } + } + + return s; +} + +Status VersionSet::Recover(bool* save_manifest) { + struct LogReporter : public log::Reader::Reporter { + Status* status; + virtual void Corruption(size_t bytes, const Status& s) { + if (this->status->ok()) *this->status = s; + } + }; + + // Read "CURRENT" file, which contains a pointer to the current manifest file + std::string current; + Status s = ReadFileToString(env_, CurrentFileName(dbname_), ¤t); + if (!s.ok()) { + return s; + } + if (current.empty() || current[current.size() - 1] != '\n') { + return Status::Corruption("CURRENT file does not end with newline"); + } + current.resize(current.size() - 1); + + std::string dscname = dbname_ + "/" + current; + SequentialFile* file; + s = env_->NewSequentialFile(dscname, &file); + if (!s.ok()) { + if (s.IsNotFound()) { + return Status::Corruption("CURRENT points to a non-existent file", + s.ToString()); + } + return s; + } + + bool have_log_number = false; + bool have_prev_log_number = false; + bool have_next_file = false; + bool have_last_sequence = false; + uint64_t next_file = 0; + uint64_t last_sequence = 0; + uint64_t log_number = 0; + uint64_t prev_log_number = 0; + Builder builder(this, current_); + + { + LogReporter reporter; + reporter.status = &s; + log::Reader reader(file, &reporter, true /*checksum*/, + 0 /*initial_offset*/); + Slice record; + std::string scratch; + while (reader.ReadRecord(&record, &scratch) && s.ok()) { + VersionEdit edit; + s = edit.DecodeFrom(record); + if (s.ok()) { + if (edit.has_comparator_ && + edit.comparator_ != icmp_.user_comparator()->Name()) { + s = Status::InvalidArgument( + edit.comparator_ + " does not match existing comparator ", + icmp_.user_comparator()->Name()); + } + } + + if (s.ok()) { + builder.Apply(&edit); + } + + if (edit.has_log_number_) { + log_number = edit.log_number_; + have_log_number = true; + } + + if (edit.has_prev_log_number_) { + prev_log_number = edit.prev_log_number_; + have_prev_log_number = true; + } + + if (edit.has_next_file_number_) { + next_file = edit.next_file_number_; + have_next_file = true; + } + + if (edit.has_last_sequence_) { + last_sequence = edit.last_sequence_; + have_last_sequence = true; + } + } + } + delete file; + file = nullptr; + + if (s.ok()) { + if (!have_next_file) { + s = Status::Corruption("no meta-nextfile entry in descriptor"); + } else if (!have_log_number) { + s = Status::Corruption("no meta-lognumber entry in descriptor"); + } else if (!have_last_sequence) { + s = Status::Corruption("no last-sequence-number entry in descriptor"); + } + + if (!have_prev_log_number) { + prev_log_number = 0; + } + + MarkFileNumberUsed(prev_log_number); + MarkFileNumberUsed(log_number); + } + + if (s.ok()) { + Version* v = new Version(this); + builder.SaveTo(v); + // Install recovered version + Finalize(v); + AppendVersion(v); + manifest_file_number_ = next_file; + next_file_number_ = next_file + 1; + last_sequence_ = last_sequence; + log_number_ = log_number; + prev_log_number_ = prev_log_number; + + // See if we can reuse the existing MANIFEST file. + if (ReuseManifest(dscname, current)) { + // No need to save new manifest + } else { + *save_manifest = true; + } + } + + return s; +} + +bool VersionSet::ReuseManifest(const std::string& dscname, + const std::string& dscbase) { + if (!options_->reuse_logs) { + return false; + } + FileType manifest_type; + uint64_t manifest_number; + uint64_t manifest_size; + if (!ParseFileName(dscbase, &manifest_number, &manifest_type) || + manifest_type != kDescriptorFile || + !env_->GetFileSize(dscname, &manifest_size).ok() || + // Make new compacted MANIFEST if old one is too big + manifest_size >= TargetFileSize(options_)) { + return false; + } + + assert(descriptor_file_ == nullptr); + assert(descriptor_log_ == nullptr); + Status r = env_->NewAppendableFile(dscname, &descriptor_file_); + if (!r.ok()) { + Log(options_->info_log, "Reuse MANIFEST: %s\n", r.ToString().c_str()); + assert(descriptor_file_ == nullptr); + return false; + } + + Log(options_->info_log, "Reusing MANIFEST %s\n", dscname.c_str()); + descriptor_log_ = new log::Writer(descriptor_file_, manifest_size); + manifest_file_number_ = manifest_number; + return true; +} + +void VersionSet::MarkFileNumberUsed(uint64_t number) { + if (next_file_number_ <= number) { + next_file_number_ = number + 1; + } +} + +void VersionSet::Finalize(Version* v) { + // Precomputed best level for next compaction + int best_level = -1; + double best_score = -1; + + for (int level = 0; level < config::kNumLevels - 1; level++) { + double score; + if (level == 0) { + // We treat level-0 specially by bounding the number of files + // instead of number of bytes for two reasons: + // + // (1) With larger write-buffer sizes, it is nice not to do too + // many level-0 compactions. + // + // (2) The files in level-0 are merged on every read and + // therefore we wish to avoid too many files when the individual + // file size is small (perhaps because of a small write-buffer + // setting, or very high compression ratios, or lots of + // overwrites/deletions). + score = v->files_[level].size() / + static_cast(config::kL0_CompactionTrigger); + } else { + // Compute the ratio of current size to size limit. + const uint64_t level_bytes = TotalFileSize(v->files_[level]); + score = + static_cast(level_bytes) / MaxBytesForLevel(options_, level); + } + + if (score > best_score) { + best_level = level; + best_score = score; + } + } + + v->compaction_level_ = best_level; + v->compaction_score_ = best_score; +} + +Status VersionSet::WriteSnapshot(log::Writer* log) { + // TODO: Break up into multiple records to reduce memory usage on recovery? + + // Save metadata + VersionEdit edit; + edit.SetComparatorName(icmp_.user_comparator()->Name()); + + // Save compaction pointers + for (int level = 0; level < config::kNumLevels; level++) { + if (!compact_pointer_[level].empty()) { + InternalKey key; + key.DecodeFrom(compact_pointer_[level]); + edit.SetCompactPointer(level, key); + } + } + + // Save files + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = current_->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + const FileMetaData* f = files[i]; + edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest); + } + } + + std::string record; + edit.EncodeTo(&record); + return log->AddRecord(record); +} + +int VersionSet::NumLevelFiles(int level) const { + assert(level >= 0); + assert(level < config::kNumLevels); + return current_->files_[level].size(); +} + +const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const { + // Update code if kNumLevels changes + static_assert(config::kNumLevels == 7, ""); + snprintf(scratch->buffer, sizeof(scratch->buffer), + "files[ %d %d %d %d %d %d %d ]", int(current_->files_[0].size()), + int(current_->files_[1].size()), int(current_->files_[2].size()), + int(current_->files_[3].size()), int(current_->files_[4].size()), + int(current_->files_[5].size()), int(current_->files_[6].size())); + return scratch->buffer; +} + +uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) { + uint64_t result = 0; + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = v->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + if (icmp_.Compare(files[i]->largest, ikey) <= 0) { + // Entire file is before "ikey", so just add the file size + result += files[i]->file_size; + } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) { + // Entire file is after "ikey", so ignore + if (level > 0) { + // Files other than level 0 are sorted by meta->smallest, so + // no further files in this level will contain data for + // "ikey". + break; + } + } else { + // "ikey" falls in the range for this table. Add the + // approximate offset of "ikey" within the table. + Table* tableptr; + Iterator* iter = table_cache_->NewIterator( + ReadOptions(), files[i]->number, files[i]->file_size, &tableptr); + if (tableptr != nullptr) { + result += tableptr->ApproximateOffsetOf(ikey.Encode()); + } + delete iter; + } + } + } + return result; +} + +void VersionSet::AddLiveFiles(std::set* live) { + for (Version* v = dummy_versions_.next_; v != &dummy_versions_; + v = v->next_) { + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = v->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + live->insert(files[i]->number); + } + } + } +} + +int64_t VersionSet::NumLevelBytes(int level) const { + assert(level >= 0); + assert(level < config::kNumLevels); + return TotalFileSize(current_->files_[level]); +} + +int64_t VersionSet::MaxNextLevelOverlappingBytes() { + int64_t result = 0; + std::vector overlaps; + for (int level = 1; level < config::kNumLevels - 1; level++) { + for (size_t i = 0; i < current_->files_[level].size(); i++) { + const FileMetaData* f = current_->files_[level][i]; + current_->GetOverlappingInputs(level + 1, &f->smallest, &f->largest, + &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > result) { + result = sum; + } + } + } + return result; +} + +// Stores the minimal range that covers all entries in inputs in +// *smallest, *largest. +// REQUIRES: inputs is not empty +void VersionSet::GetRange(const std::vector& inputs, + InternalKey* smallest, InternalKey* largest) { + assert(!inputs.empty()); + smallest->Clear(); + largest->Clear(); + for (size_t i = 0; i < inputs.size(); i++) { + FileMetaData* f = inputs[i]; + if (i == 0) { + *smallest = f->smallest; + *largest = f->largest; + } else { + if (icmp_.Compare(f->smallest, *smallest) < 0) { + *smallest = f->smallest; + } + if (icmp_.Compare(f->largest, *largest) > 0) { + *largest = f->largest; + } + } + } +} + +// Stores the minimal range that covers all entries in inputs1 and inputs2 +// in *smallest, *largest. +// REQUIRES: inputs is not empty +void VersionSet::GetRange2(const std::vector& inputs1, + const std::vector& inputs2, + InternalKey* smallest, InternalKey* largest) { + std::vector all = inputs1; + all.insert(all.end(), inputs2.begin(), inputs2.end()); + GetRange(all, smallest, largest); +} + +Iterator* VersionSet::MakeInputIterator(Compaction* c) { + ReadOptions options; + options.verify_checksums = options_->paranoid_checks; + options.fill_cache = false; + + // Level-0 files have to be merged together. For other levels, + // we will make a concatenating iterator per level. + // TODO(opt): use concatenating iterator for level-0 if there is no overlap + const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2); + Iterator** list = new Iterator*[space]; + int num = 0; + for (int which = 0; which < 2; which++) { + if (!c->inputs_[which].empty()) { + if (c->level() + which == 0) { + const std::vector& files = c->inputs_[which]; + for (size_t i = 0; i < files.size(); i++) { + list[num++] = table_cache_->NewIterator(options, files[i]->number, + files[i]->file_size); + } + } else { + // Create concatenating iterator for the files from this level + list[num++] = NewTwoLevelIterator( + new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]), + &GetFileIterator, table_cache_, options); + } + } + } + assert(num <= space); + Iterator* result = NewMergingIterator(&icmp_, list, num); + delete[] list; + return result; +} + +Compaction* VersionSet::PickCompaction() { + Compaction* c; + int level; + + // We prefer compactions triggered by too much data in a level over + // the compactions triggered by seeks. + const bool size_compaction = (current_->compaction_score_ >= 1); + const bool seek_compaction = (current_->file_to_compact_ != nullptr); + if (size_compaction) { + level = current_->compaction_level_; + assert(level >= 0); + assert(level + 1 < config::kNumLevels); + c = new Compaction(options_, level); + + // Pick the first file that comes after compact_pointer_[level] + for (size_t i = 0; i < current_->files_[level].size(); i++) { + FileMetaData* f = current_->files_[level][i]; + if (compact_pointer_[level].empty() || + icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { + c->inputs_[0].push_back(f); + break; + } + } + if (c->inputs_[0].empty()) { + // Wrap-around to the beginning of the key space + c->inputs_[0].push_back(current_->files_[level][0]); + } + } else if (seek_compaction) { + level = current_->file_to_compact_level_; + c = new Compaction(options_, level); + c->inputs_[0].push_back(current_->file_to_compact_); + } else { + return nullptr; + } + + c->input_version_ = current_; + c->input_version_->Ref(); + + // Files in level 0 may overlap each other, so pick up all overlapping ones + if (level == 0) { + InternalKey smallest, largest; + GetRange(c->inputs_[0], &smallest, &largest); + // Note that the next call will discard the file we placed in + // c->inputs_[0] earlier and replace it with an overlapping set + // which will include the picked file. + current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]); + assert(!c->inputs_[0].empty()); + } + + SetupOtherInputs(c); + + return c; +} + +// Finds the largest key in a vector of files. Returns true if files it not +// empty. +bool FindLargestKey(const InternalKeyComparator& icmp, + const std::vector& files, + InternalKey* largest_key) { + if (files.empty()) { + return false; + } + *largest_key = files[0]->largest; + for (size_t i = 1; i < files.size(); ++i) { + FileMetaData* f = files[i]; + if (icmp.Compare(f->largest, *largest_key) > 0) { + *largest_key = f->largest; + } + } + return true; +} + +// Finds minimum file b2=(l2, u2) in level file for which l2 > u1 and +// user_key(l2) = user_key(u1) +FileMetaData* FindSmallestBoundaryFile( + const InternalKeyComparator& icmp, + const std::vector& level_files, + const InternalKey& largest_key) { + const Comparator* user_cmp = icmp.user_comparator(); + FileMetaData* smallest_boundary_file = nullptr; + for (size_t i = 0; i < level_files.size(); ++i) { + FileMetaData* f = level_files[i]; + if (icmp.Compare(f->smallest, largest_key) > 0 && + user_cmp->Compare(f->smallest.user_key(), largest_key.user_key()) == + 0) { + if (smallest_boundary_file == nullptr || + icmp.Compare(f->smallest, smallest_boundary_file->smallest) < 0) { + smallest_boundary_file = f; + } + } + } + return smallest_boundary_file; +} + +// Extracts the largest file b1 from |compaction_files| and then searches for a +// b2 in |level_files| for which user_key(u1) = user_key(l2). If it finds such a +// file b2 (known as a boundary file) it adds it to |compaction_files| and then +// searches again using this new upper bound. +// +// If there are two blocks, b1=(l1, u1) and b2=(l2, u2) and +// user_key(u1) = user_key(l2), and if we compact b1 but not b2 then a +// subsequent get operation will yield an incorrect result because it will +// return the record from b2 in level i rather than from b1 because it searches +// level by level for records matching the supplied user key. +// +// parameters: +// in level_files: List of files to search for boundary files. +// in/out compaction_files: List of files to extend by adding boundary files. +void AddBoundaryInputs(const InternalKeyComparator& icmp, + const std::vector& level_files, + std::vector* compaction_files) { + InternalKey largest_key; + + // Quick return if compaction_files is empty. + if (!FindLargestKey(icmp, *compaction_files, &largest_key)) { + return; + } + + bool continue_searching = true; + while (continue_searching) { + FileMetaData* smallest_boundary_file = + FindSmallestBoundaryFile(icmp, level_files, largest_key); + + // If a boundary file was found advance largest_key, otherwise we're done. + if (smallest_boundary_file != NULL) { + compaction_files->push_back(smallest_boundary_file); + largest_key = smallest_boundary_file->largest; + } else { + continue_searching = false; + } + } +} + +void VersionSet::SetupOtherInputs(Compaction* c) { + const int level = c->level(); + InternalKey smallest, largest; + + AddBoundaryInputs(icmp_, current_->files_[level], &c->inputs_[0]); + GetRange(c->inputs_[0], &smallest, &largest); + + current_->GetOverlappingInputs(level + 1, &smallest, &largest, + &c->inputs_[1]); + + // Get entire range covered by compaction + InternalKey all_start, all_limit; + GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); + + // See if we can grow the number of inputs in "level" without + // changing the number of "level+1" files we pick up. + if (!c->inputs_[1].empty()) { + std::vector expanded0; + current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0); + AddBoundaryInputs(icmp_, current_->files_[level], &expanded0); + const int64_t inputs0_size = TotalFileSize(c->inputs_[0]); + const int64_t inputs1_size = TotalFileSize(c->inputs_[1]); + const int64_t expanded0_size = TotalFileSize(expanded0); + if (expanded0.size() > c->inputs_[0].size() && + inputs1_size + expanded0_size < + ExpandedCompactionByteSizeLimit(options_)) { + InternalKey new_start, new_limit; + GetRange(expanded0, &new_start, &new_limit); + std::vector expanded1; + current_->GetOverlappingInputs(level + 1, &new_start, &new_limit, + &expanded1); + if (expanded1.size() == c->inputs_[1].size()) { + Log(options_->info_log, + "Expanding@%d %d+%d (%ld+%ld bytes) to %d+%d (%ld+%ld bytes)\n", + level, int(c->inputs_[0].size()), int(c->inputs_[1].size()), + long(inputs0_size), long(inputs1_size), int(expanded0.size()), + int(expanded1.size()), long(expanded0_size), long(inputs1_size)); + smallest = new_start; + largest = new_limit; + c->inputs_[0] = expanded0; + c->inputs_[1] = expanded1; + GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); + } + } + } + + // Compute the set of grandparent files that overlap this compaction + // (parent == level+1; grandparent == level+2) + if (level + 2 < config::kNumLevels) { + current_->GetOverlappingInputs(level + 2, &all_start, &all_limit, + &c->grandparents_); + } + + // Update the place where we will do the next compaction for this level. + // We update this immediately instead of waiting for the VersionEdit + // to be applied so that if the compaction fails, we will try a different + // key range next time. + compact_pointer_[level] = largest.Encode().ToString(); + c->edit_.SetCompactPointer(level, largest); +} + +Compaction* VersionSet::CompactRange(int level, const InternalKey* begin, + const InternalKey* end) { + std::vector inputs; + current_->GetOverlappingInputs(level, begin, end, &inputs); + if (inputs.empty()) { + return nullptr; + } + + // Avoid compacting too much in one shot in case the range is large. + // But we cannot do this for level-0 since level-0 files can overlap + // and we must not pick one file and drop another older file if the + // two files overlap. + if (level > 0) { + const uint64_t limit = MaxFileSizeForLevel(options_, level); + uint64_t total = 0; + for (size_t i = 0; i < inputs.size(); i++) { + uint64_t s = inputs[i]->file_size; + total += s; + if (total >= limit) { + inputs.resize(i + 1); + break; + } + } + } + + Compaction* c = new Compaction(options_, level); + c->input_version_ = current_; + c->input_version_->Ref(); + c->inputs_[0] = inputs; + SetupOtherInputs(c); + return c; +} + +Compaction::Compaction(const Options* options, int level) + : level_(level), + max_output_file_size_(MaxFileSizeForLevel(options, level)), + input_version_(nullptr), + grandparent_index_(0), + seen_key_(false), + overlapped_bytes_(0) { + for (int i = 0; i < config::kNumLevels; i++) { + level_ptrs_[i] = 0; + } +} + +Compaction::~Compaction() { + if (input_version_ != nullptr) { + input_version_->Unref(); + } +} + +bool Compaction::IsTrivialMove() const { + const VersionSet* vset = input_version_->vset_; + // Avoid a move if there is lots of overlapping grandparent data. + // Otherwise, the move could create a parent file that will require + // a very expensive merge later on. + return (num_input_files(0) == 1 && num_input_files(1) == 0 && + TotalFileSize(grandparents_) <= + MaxGrandParentOverlapBytes(vset->options_)); +} + +void Compaction::AddInputDeletions(VersionEdit* edit) { + for (int which = 0; which < 2; which++) { + for (size_t i = 0; i < inputs_[which].size(); i++) { + edit->DeleteFile(level_ + which, inputs_[which][i]->number); + } + } +} + +bool Compaction::IsBaseLevelForKey(const Slice& user_key) { + // Maybe use binary search to find right entry instead of linear search? + const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator(); + for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) { + const std::vector& files = input_version_->files_[lvl]; + for (; level_ptrs_[lvl] < files.size();) { + FileMetaData* f = files[level_ptrs_[lvl]]; + if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) { + // We've advanced far enough + if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) { + // Key falls in this file's range, so definitely not base level + return false; + } + break; + } + level_ptrs_[lvl]++; + } + } + return true; +} + +bool Compaction::ShouldStopBefore(const Slice& internal_key) { + const VersionSet* vset = input_version_->vset_; + // Scan to find earliest grandparent file that contains key. + const InternalKeyComparator* icmp = &vset->icmp_; + while (grandparent_index_ < grandparents_.size() && + icmp->Compare(internal_key, + grandparents_[grandparent_index_]->largest.Encode()) > + 0) { + if (seen_key_) { + overlapped_bytes_ += grandparents_[grandparent_index_]->file_size; + } + grandparent_index_++; + } + seen_key_ = true; + + if (overlapped_bytes_ > MaxGrandParentOverlapBytes(vset->options_)) { + // Too much overlap for current output; start new output + overlapped_bytes_ = 0; + return true; + } else { + return false; + } +} + +void Compaction::ReleaseInputs() { + if (input_version_ != nullptr) { + input_version_->Unref(); + input_version_ = nullptr; + } +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/version_set.h b/saraWhatsUp/Pods/leveldb-library/db/version_set.h new file mode 100644 index 0000000..69f3d70 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/version_set.h @@ -0,0 +1,393 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// The representation of a DBImpl consists of a set of Versions. The +// newest version is called "current". Older versions may be kept +// around to provide a consistent view to live iterators. +// +// Each Version keeps track of a set of Table files per level. The +// entire set of versions is maintained in a VersionSet. +// +// Version,VersionSet are thread-compatible, but require external +// synchronization on all accesses. + +#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_ +#define STORAGE_LEVELDB_DB_VERSION_SET_H_ + +#include +#include +#include + +#include "db/dbformat.h" +#include "db/version_edit.h" +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +namespace log { +class Writer; +} + +class Compaction; +class Iterator; +class MemTable; +class TableBuilder; +class TableCache; +class Version; +class VersionSet; +class WritableFile; + +// Return the smallest index i such that files[i]->largest >= key. +// Return files.size() if there is no such file. +// REQUIRES: "files" contains a sorted list of non-overlapping files. +int FindFile(const InternalKeyComparator& icmp, + const std::vector& files, const Slice& key); + +// Returns true iff some file in "files" overlaps the user key range +// [*smallest,*largest]. +// smallest==nullptr represents a key smaller than all keys in the DB. +// largest==nullptr represents a key largest than all keys in the DB. +// REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges +// in sorted order. +bool SomeFileOverlapsRange(const InternalKeyComparator& icmp, + bool disjoint_sorted_files, + const std::vector& files, + const Slice* smallest_user_key, + const Slice* largest_user_key); + +class Version { + public: + // Lookup the value for key. If found, store it in *val and + // return OK. Else return a non-OK status. Fills *stats. + // REQUIRES: lock is not held + struct GetStats { + FileMetaData* seek_file; + int seek_file_level; + }; + + // Append to *iters a sequence of iterators that will + // yield the contents of this Version when merged together. + // REQUIRES: This version has been saved (see VersionSet::SaveTo) + void AddIterators(const ReadOptions&, std::vector* iters); + + Status Get(const ReadOptions&, const LookupKey& key, std::string* val, + GetStats* stats); + + // Adds "stats" into the current state. Returns true if a new + // compaction may need to be triggered, false otherwise. + // REQUIRES: lock is held + bool UpdateStats(const GetStats& stats); + + // Record a sample of bytes read at the specified internal key. + // Samples are taken approximately once every config::kReadBytesPeriod + // bytes. Returns true if a new compaction may need to be triggered. + // REQUIRES: lock is held + bool RecordReadSample(Slice key); + + // Reference count management (so Versions do not disappear out from + // under live iterators) + void Ref(); + void Unref(); + + void GetOverlappingInputs( + int level, + const InternalKey* begin, // nullptr means before all keys + const InternalKey* end, // nullptr means after all keys + std::vector* inputs); + + // Returns true iff some file in the specified level overlaps + // some part of [*smallest_user_key,*largest_user_key]. + // smallest_user_key==nullptr represents a key smaller than all the DB's keys. + // largest_user_key==nullptr represents a key largest than all the DB's keys. + bool OverlapInLevel(int level, const Slice* smallest_user_key, + const Slice* largest_user_key); + + // Return the level at which we should place a new memtable compaction + // result that covers the range [smallest_user_key,largest_user_key]. + int PickLevelForMemTableOutput(const Slice& smallest_user_key, + const Slice& largest_user_key); + + int NumFiles(int level) const { return files_[level].size(); } + + // Return a human readable string that describes this version's contents. + std::string DebugString() const; + + private: + friend class Compaction; + friend class VersionSet; + + class LevelFileNumIterator; + + explicit Version(VersionSet* vset) + : vset_(vset), + next_(this), + prev_(this), + refs_(0), + file_to_compact_(nullptr), + file_to_compact_level_(-1), + compaction_score_(-1), + compaction_level_(-1) {} + + Version(const Version&) = delete; + Version& operator=(const Version&) = delete; + + ~Version(); + + Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const; + + // Call func(arg, level, f) for every file that overlaps user_key in + // order from newest to oldest. If an invocation of func returns + // false, makes no more calls. + // + // REQUIRES: user portion of internal_key == user_key. + void ForEachOverlapping(Slice user_key, Slice internal_key, void* arg, + bool (*func)(void*, int, FileMetaData*)); + + VersionSet* vset_; // VersionSet to which this Version belongs + Version* next_; // Next version in linked list + Version* prev_; // Previous version in linked list + int refs_; // Number of live refs to this version + + // List of files per level + std::vector files_[config::kNumLevels]; + + // Next file to compact based on seek stats. + FileMetaData* file_to_compact_; + int file_to_compact_level_; + + // Level that should be compacted next and its compaction score. + // Score < 1 means compaction is not strictly needed. These fields + // are initialized by Finalize(). + double compaction_score_; + int compaction_level_; +}; + +class VersionSet { + public: + VersionSet(const std::string& dbname, const Options* options, + TableCache* table_cache, const InternalKeyComparator*); + VersionSet(const VersionSet&) = delete; + VersionSet& operator=(const VersionSet&) = delete; + + ~VersionSet(); + + // Apply *edit to the current version to form a new descriptor that + // is both saved to persistent state and installed as the new + // current version. Will release *mu while actually writing to the file. + // REQUIRES: *mu is held on entry. + // REQUIRES: no other thread concurrently calls LogAndApply() + Status LogAndApply(VersionEdit* edit, port::Mutex* mu) + EXCLUSIVE_LOCKS_REQUIRED(mu); + + // Recover the last saved descriptor from persistent storage. + Status Recover(bool* save_manifest); + + // Return the current version. + Version* current() const { return current_; } + + // Return the current manifest file number + uint64_t ManifestFileNumber() const { return manifest_file_number_; } + + // Allocate and return a new file number + uint64_t NewFileNumber() { return next_file_number_++; } + + // Arrange to reuse "file_number" unless a newer file number has + // already been allocated. + // REQUIRES: "file_number" was returned by a call to NewFileNumber(). + void ReuseFileNumber(uint64_t file_number) { + if (next_file_number_ == file_number + 1) { + next_file_number_ = file_number; + } + } + + // Return the number of Table files at the specified level. + int NumLevelFiles(int level) const; + + // Return the combined file size of all files at the specified level. + int64_t NumLevelBytes(int level) const; + + // Return the last sequence number. + uint64_t LastSequence() const { return last_sequence_; } + + // Set the last sequence number to s. + void SetLastSequence(uint64_t s) { + assert(s >= last_sequence_); + last_sequence_ = s; + } + + // Mark the specified file number as used. + void MarkFileNumberUsed(uint64_t number); + + // Return the current log file number. + uint64_t LogNumber() const { return log_number_; } + + // Return the log file number for the log file that is currently + // being compacted, or zero if there is no such log file. + uint64_t PrevLogNumber() const { return prev_log_number_; } + + // Pick level and inputs for a new compaction. + // Returns nullptr if there is no compaction to be done. + // Otherwise returns a pointer to a heap-allocated object that + // describes the compaction. Caller should delete the result. + Compaction* PickCompaction(); + + // Return a compaction object for compacting the range [begin,end] in + // the specified level. Returns nullptr if there is nothing in that + // level that overlaps the specified range. Caller should delete + // the result. + Compaction* CompactRange(int level, const InternalKey* begin, + const InternalKey* end); + + // Return the maximum overlapping data (in bytes) at next level for any + // file at a level >= 1. + int64_t MaxNextLevelOverlappingBytes(); + + // Create an iterator that reads over the compaction inputs for "*c". + // The caller should delete the iterator when no longer needed. + Iterator* MakeInputIterator(Compaction* c); + + // Returns true iff some level needs a compaction. + bool NeedsCompaction() const { + Version* v = current_; + return (v->compaction_score_ >= 1) || (v->file_to_compact_ != nullptr); + } + + // Add all files listed in any live version to *live. + // May also mutate some internal state. + void AddLiveFiles(std::set* live); + + // Return the approximate offset in the database of the data for + // "key" as of version "v". + uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key); + + // Return a human-readable short (single-line) summary of the number + // of files per level. Uses *scratch as backing store. + struct LevelSummaryStorage { + char buffer[100]; + }; + const char* LevelSummary(LevelSummaryStorage* scratch) const; + + private: + class Builder; + + friend class Compaction; + friend class Version; + + bool ReuseManifest(const std::string& dscname, const std::string& dscbase); + + void Finalize(Version* v); + + void GetRange(const std::vector& inputs, InternalKey* smallest, + InternalKey* largest); + + void GetRange2(const std::vector& inputs1, + const std::vector& inputs2, + InternalKey* smallest, InternalKey* largest); + + void SetupOtherInputs(Compaction* c); + + // Save current contents to *log + Status WriteSnapshot(log::Writer* log); + + void AppendVersion(Version* v); + + Env* const env_; + const std::string dbname_; + const Options* const options_; + TableCache* const table_cache_; + const InternalKeyComparator icmp_; + uint64_t next_file_number_; + uint64_t manifest_file_number_; + uint64_t last_sequence_; + uint64_t log_number_; + uint64_t prev_log_number_; // 0 or backing store for memtable being compacted + + // Opened lazily + WritableFile* descriptor_file_; + log::Writer* descriptor_log_; + Version dummy_versions_; // Head of circular doubly-linked list of versions. + Version* current_; // == dummy_versions_.prev_ + + // Per-level key at which the next compaction at that level should start. + // Either an empty string, or a valid InternalKey. + std::string compact_pointer_[config::kNumLevels]; +}; + +// A Compaction encapsulates information about a compaction. +class Compaction { + public: + ~Compaction(); + + // Return the level that is being compacted. Inputs from "level" + // and "level+1" will be merged to produce a set of "level+1" files. + int level() const { return level_; } + + // Return the object that holds the edits to the descriptor done + // by this compaction. + VersionEdit* edit() { return &edit_; } + + // "which" must be either 0 or 1 + int num_input_files(int which) const { return inputs_[which].size(); } + + // Return the ith input file at "level()+which" ("which" must be 0 or 1). + FileMetaData* input(int which, int i) const { return inputs_[which][i]; } + + // Maximum size of files to build during this compaction. + uint64_t MaxOutputFileSize() const { return max_output_file_size_; } + + // Is this a trivial compaction that can be implemented by just + // moving a single input file to the next level (no merging or splitting) + bool IsTrivialMove() const; + + // Add all inputs to this compaction as delete operations to *edit. + void AddInputDeletions(VersionEdit* edit); + + // Returns true if the information we have available guarantees that + // the compaction is producing data in "level+1" for which no data exists + // in levels greater than "level+1". + bool IsBaseLevelForKey(const Slice& user_key); + + // Returns true iff we should stop building the current output + // before processing "internal_key". + bool ShouldStopBefore(const Slice& internal_key); + + // Release the input version for the compaction, once the compaction + // is successful. + void ReleaseInputs(); + + private: + friend class Version; + friend class VersionSet; + + Compaction(const Options* options, int level); + + int level_; + uint64_t max_output_file_size_; + Version* input_version_; + VersionEdit edit_; + + // Each compaction reads inputs from "level_" and "level_+1" + std::vector inputs_[2]; // The two sets of inputs + + // State used to check for number of overlapping grandparent files + // (parent == level_ + 1, grandparent == level_ + 2) + std::vector grandparents_; + size_t grandparent_index_; // Index in grandparent_starts_ + bool seen_key_; // Some output key has been seen + int64_t overlapped_bytes_; // Bytes of overlap between current output + // and grandparent files + + // State for implementing IsBaseLevelForKey + + // level_ptrs_ holds indices into input_version_->levels_: our state + // is that we are positioned at one of the file ranges for each + // higher level than the ones involved in this compaction (i.e. for + // all L >= level_ + 2). + size_t level_ptrs_[config::kNumLevels]; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_VERSION_SET_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/db/write_batch.cc b/saraWhatsUp/Pods/leveldb-library/db/write_batch.cc new file mode 100644 index 0000000..2dec642 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/write_batch.cc @@ -0,0 +1,150 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// WriteBatch::rep_ := +// sequence: fixed64 +// count: fixed32 +// data: record[count] +// record := +// kTypeValue varstring varstring | +// kTypeDeletion varstring +// varstring := +// len: varint32 +// data: uint8[len] + +#include "leveldb/write_batch.h" + +#include "db/dbformat.h" +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "util/coding.h" + +namespace leveldb { + +// WriteBatch header has an 8-byte sequence number followed by a 4-byte count. +static const size_t kHeader = 12; + +WriteBatch::WriteBatch() { Clear(); } + +WriteBatch::~WriteBatch() {} + +WriteBatch::Handler::~Handler() {} + +void WriteBatch::Clear() { + rep_.clear(); + rep_.resize(kHeader); +} + +size_t WriteBatch::ApproximateSize() const { return rep_.size(); } + +Status WriteBatch::Iterate(Handler* handler) const { + Slice input(rep_); + if (input.size() < kHeader) { + return Status::Corruption("malformed WriteBatch (too small)"); + } + + input.remove_prefix(kHeader); + Slice key, value; + int found = 0; + while (!input.empty()) { + found++; + char tag = input[0]; + input.remove_prefix(1); + switch (tag) { + case kTypeValue: + if (GetLengthPrefixedSlice(&input, &key) && + GetLengthPrefixedSlice(&input, &value)) { + handler->Put(key, value); + } else { + return Status::Corruption("bad WriteBatch Put"); + } + break; + case kTypeDeletion: + if (GetLengthPrefixedSlice(&input, &key)) { + handler->Delete(key); + } else { + return Status::Corruption("bad WriteBatch Delete"); + } + break; + default: + return Status::Corruption("unknown WriteBatch tag"); + } + } + if (found != WriteBatchInternal::Count(this)) { + return Status::Corruption("WriteBatch has wrong count"); + } else { + return Status::OK(); + } +} + +int WriteBatchInternal::Count(const WriteBatch* b) { + return DecodeFixed32(b->rep_.data() + 8); +} + +void WriteBatchInternal::SetCount(WriteBatch* b, int n) { + EncodeFixed32(&b->rep_[8], n); +} + +SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) { + return SequenceNumber(DecodeFixed64(b->rep_.data())); +} + +void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) { + EncodeFixed64(&b->rep_[0], seq); +} + +void WriteBatch::Put(const Slice& key, const Slice& value) { + WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); + rep_.push_back(static_cast(kTypeValue)); + PutLengthPrefixedSlice(&rep_, key); + PutLengthPrefixedSlice(&rep_, value); +} + +void WriteBatch::Delete(const Slice& key) { + WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); + rep_.push_back(static_cast(kTypeDeletion)); + PutLengthPrefixedSlice(&rep_, key); +} + +void WriteBatch::Append(const WriteBatch& source) { + WriteBatchInternal::Append(this, &source); +} + +namespace { +class MemTableInserter : public WriteBatch::Handler { + public: + SequenceNumber sequence_; + MemTable* mem_; + + virtual void Put(const Slice& key, const Slice& value) { + mem_->Add(sequence_, kTypeValue, key, value); + sequence_++; + } + virtual void Delete(const Slice& key) { + mem_->Add(sequence_, kTypeDeletion, key, Slice()); + sequence_++; + } +}; +} // namespace + +Status WriteBatchInternal::InsertInto(const WriteBatch* b, MemTable* memtable) { + MemTableInserter inserter; + inserter.sequence_ = WriteBatchInternal::Sequence(b); + inserter.mem_ = memtable; + return b->Iterate(&inserter); +} + +void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) { + assert(contents.size() >= kHeader); + b->rep_.assign(contents.data(), contents.size()); +} + +void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) { + SetCount(dst, Count(dst) + Count(src)); + assert(src->rep_.size() >= kHeader); + dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/db/write_batch_internal.h b/saraWhatsUp/Pods/leveldb-library/db/write_batch_internal.h new file mode 100644 index 0000000..fce86e3 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/db/write_batch_internal.h @@ -0,0 +1,45 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ +#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ + +#include "db/dbformat.h" +#include "leveldb/write_batch.h" + +namespace leveldb { + +class MemTable; + +// WriteBatchInternal provides static methods for manipulating a +// WriteBatch that we don't want in the public WriteBatch interface. +class WriteBatchInternal { + public: + // Return the number of entries in the batch. + static int Count(const WriteBatch* batch); + + // Set the count for the number of entries in the batch. + static void SetCount(WriteBatch* batch, int n); + + // Return the sequence number for the start of this batch. + static SequenceNumber Sequence(const WriteBatch* batch); + + // Store the specified number as the sequence number for the start of + // this batch. + static void SetSequence(WriteBatch* batch, SequenceNumber seq); + + static Slice Contents(const WriteBatch* batch) { return Slice(batch->rep_); } + + static size_t ByteSize(const WriteBatch* batch) { return batch->rep_.size(); } + + static void SetContents(WriteBatch* batch, const Slice& contents); + + static Status InsertInto(const WriteBatch* batch, MemTable* memtable); + + static void Append(WriteBatch* dst, const WriteBatch* src); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/c.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/c.h new file mode 100644 index 0000000..8e0d592 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/c.h @@ -0,0 +1,270 @@ +/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. See the AUTHORS file for names of contributors. + + C bindings for leveldb. May be useful as a stable ABI that can be + used by programs that keep leveldb in a shared library, or for + a JNI api. + + Does not support: + . getters for the option types + . custom comparators that implement key shortening + . custom iter, db, env, cache implementations using just the C bindings + + Some conventions: + + (1) We expose just opaque struct pointers and functions to clients. + This allows us to change internal representations without having to + recompile clients. + + (2) For simplicity, there is no equivalent to the Slice type. Instead, + the caller has to pass the pointer and length as separate + arguments. + + (3) Errors are represented by a null-terminated c string. NULL + means no error. All operations that can raise an error are passed + a "char** errptr" as the last argument. One of the following must + be true on entry: + *errptr == NULL + *errptr points to a malloc()ed null-terminated error message + (On Windows, *errptr must have been malloc()-ed by this library.) + On success, a leveldb routine leaves *errptr unchanged. + On failure, leveldb frees the old value of *errptr and + set *errptr to a malloc()ed error message. + + (4) Bools have the type unsigned char (0 == false; rest == true) + + (5) All of the pointer arguments must be non-NULL. +*/ + +#ifndef STORAGE_LEVELDB_INCLUDE_C_H_ +#define STORAGE_LEVELDB_INCLUDE_C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "leveldb/export.h" + +/* Exported types */ + +typedef struct leveldb_t leveldb_t; +typedef struct leveldb_cache_t leveldb_cache_t; +typedef struct leveldb_comparator_t leveldb_comparator_t; +typedef struct leveldb_env_t leveldb_env_t; +typedef struct leveldb_filelock_t leveldb_filelock_t; +typedef struct leveldb_filterpolicy_t leveldb_filterpolicy_t; +typedef struct leveldb_iterator_t leveldb_iterator_t; +typedef struct leveldb_logger_t leveldb_logger_t; +typedef struct leveldb_options_t leveldb_options_t; +typedef struct leveldb_randomfile_t leveldb_randomfile_t; +typedef struct leveldb_readoptions_t leveldb_readoptions_t; +typedef struct leveldb_seqfile_t leveldb_seqfile_t; +typedef struct leveldb_snapshot_t leveldb_snapshot_t; +typedef struct leveldb_writablefile_t leveldb_writablefile_t; +typedef struct leveldb_writebatch_t leveldb_writebatch_t; +typedef struct leveldb_writeoptions_t leveldb_writeoptions_t; + +/* DB operations */ + +LEVELDB_EXPORT leveldb_t* leveldb_open(const leveldb_options_t* options, + const char* name, char** errptr); + +LEVELDB_EXPORT void leveldb_close(leveldb_t* db); + +LEVELDB_EXPORT void leveldb_put(leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, const char* val, + size_t vallen, char** errptr); + +LEVELDB_EXPORT void leveldb_delete(leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + char** errptr); + +LEVELDB_EXPORT void leveldb_write(leveldb_t* db, + const leveldb_writeoptions_t* options, + leveldb_writebatch_t* batch, char** errptr); + +/* Returns NULL if not found. A malloc()ed array otherwise. + Stores the length of the array in *vallen. */ +LEVELDB_EXPORT char* leveldb_get(leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, size_t keylen, size_t* vallen, + char** errptr); + +LEVELDB_EXPORT leveldb_iterator_t* leveldb_create_iterator( + leveldb_t* db, const leveldb_readoptions_t* options); + +LEVELDB_EXPORT const leveldb_snapshot_t* leveldb_create_snapshot(leveldb_t* db); + +LEVELDB_EXPORT void leveldb_release_snapshot( + leveldb_t* db, const leveldb_snapshot_t* snapshot); + +/* Returns NULL if property name is unknown. + Else returns a pointer to a malloc()-ed null-terminated value. */ +LEVELDB_EXPORT char* leveldb_property_value(leveldb_t* db, + const char* propname); + +LEVELDB_EXPORT void leveldb_approximate_sizes( + leveldb_t* db, int num_ranges, const char* const* range_start_key, + const size_t* range_start_key_len, const char* const* range_limit_key, + const size_t* range_limit_key_len, uint64_t* sizes); + +LEVELDB_EXPORT void leveldb_compact_range(leveldb_t* db, const char* start_key, + size_t start_key_len, + const char* limit_key, + size_t limit_key_len); + +/* Management operations */ + +LEVELDB_EXPORT void leveldb_destroy_db(const leveldb_options_t* options, + const char* name, char** errptr); + +LEVELDB_EXPORT void leveldb_repair_db(const leveldb_options_t* options, + const char* name, char** errptr); + +/* Iterator */ + +LEVELDB_EXPORT void leveldb_iter_destroy(leveldb_iterator_t*); +LEVELDB_EXPORT unsigned char leveldb_iter_valid(const leveldb_iterator_t*); +LEVELDB_EXPORT void leveldb_iter_seek_to_first(leveldb_iterator_t*); +LEVELDB_EXPORT void leveldb_iter_seek_to_last(leveldb_iterator_t*); +LEVELDB_EXPORT void leveldb_iter_seek(leveldb_iterator_t*, const char* k, + size_t klen); +LEVELDB_EXPORT void leveldb_iter_next(leveldb_iterator_t*); +LEVELDB_EXPORT void leveldb_iter_prev(leveldb_iterator_t*); +LEVELDB_EXPORT const char* leveldb_iter_key(const leveldb_iterator_t*, + size_t* klen); +LEVELDB_EXPORT const char* leveldb_iter_value(const leveldb_iterator_t*, + size_t* vlen); +LEVELDB_EXPORT void leveldb_iter_get_error(const leveldb_iterator_t*, + char** errptr); + +/* Write batch */ + +LEVELDB_EXPORT leveldb_writebatch_t* leveldb_writebatch_create(); +LEVELDB_EXPORT void leveldb_writebatch_destroy(leveldb_writebatch_t*); +LEVELDB_EXPORT void leveldb_writebatch_clear(leveldb_writebatch_t*); +LEVELDB_EXPORT void leveldb_writebatch_put(leveldb_writebatch_t*, + const char* key, size_t klen, + const char* val, size_t vlen); +LEVELDB_EXPORT void leveldb_writebatch_delete(leveldb_writebatch_t*, + const char* key, size_t klen); +LEVELDB_EXPORT void leveldb_writebatch_iterate( + const leveldb_writebatch_t*, void* state, + void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), + void (*deleted)(void*, const char* k, size_t klen)); +LEVELDB_EXPORT void leveldb_writebatch_append( + leveldb_writebatch_t* destination, const leveldb_writebatch_t* source); + +/* Options */ + +LEVELDB_EXPORT leveldb_options_t* leveldb_options_create(); +LEVELDB_EXPORT void leveldb_options_destroy(leveldb_options_t*); +LEVELDB_EXPORT void leveldb_options_set_comparator(leveldb_options_t*, + leveldb_comparator_t*); +LEVELDB_EXPORT void leveldb_options_set_filter_policy(leveldb_options_t*, + leveldb_filterpolicy_t*); +LEVELDB_EXPORT void leveldb_options_set_create_if_missing(leveldb_options_t*, + unsigned char); +LEVELDB_EXPORT void leveldb_options_set_error_if_exists(leveldb_options_t*, + unsigned char); +LEVELDB_EXPORT void leveldb_options_set_paranoid_checks(leveldb_options_t*, + unsigned char); +LEVELDB_EXPORT void leveldb_options_set_env(leveldb_options_t*, leveldb_env_t*); +LEVELDB_EXPORT void leveldb_options_set_info_log(leveldb_options_t*, + leveldb_logger_t*); +LEVELDB_EXPORT void leveldb_options_set_write_buffer_size(leveldb_options_t*, + size_t); +LEVELDB_EXPORT void leveldb_options_set_max_open_files(leveldb_options_t*, int); +LEVELDB_EXPORT void leveldb_options_set_cache(leveldb_options_t*, + leveldb_cache_t*); +LEVELDB_EXPORT void leveldb_options_set_block_size(leveldb_options_t*, size_t); +LEVELDB_EXPORT void leveldb_options_set_block_restart_interval( + leveldb_options_t*, int); +LEVELDB_EXPORT void leveldb_options_set_max_file_size(leveldb_options_t*, + size_t); + +enum { leveldb_no_compression = 0, leveldb_snappy_compression = 1 }; +LEVELDB_EXPORT void leveldb_options_set_compression(leveldb_options_t*, int); + +/* Comparator */ + +LEVELDB_EXPORT leveldb_comparator_t* leveldb_comparator_create( + void* state, void (*destructor)(void*), + int (*compare)(void*, const char* a, size_t alen, const char* b, + size_t blen), + const char* (*name)(void*)); +LEVELDB_EXPORT void leveldb_comparator_destroy(leveldb_comparator_t*); + +/* Filter policy */ + +LEVELDB_EXPORT leveldb_filterpolicy_t* leveldb_filterpolicy_create( + void* state, void (*destructor)(void*), + char* (*create_filter)(void*, const char* const* key_array, + const size_t* key_length_array, int num_keys, + size_t* filter_length), + unsigned char (*key_may_match)(void*, const char* key, size_t length, + const char* filter, size_t filter_length), + const char* (*name)(void*)); +LEVELDB_EXPORT void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t*); + +LEVELDB_EXPORT leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom( + int bits_per_key); + +/* Read options */ + +LEVELDB_EXPORT leveldb_readoptions_t* leveldb_readoptions_create(); +LEVELDB_EXPORT void leveldb_readoptions_destroy(leveldb_readoptions_t*); +LEVELDB_EXPORT void leveldb_readoptions_set_verify_checksums( + leveldb_readoptions_t*, unsigned char); +LEVELDB_EXPORT void leveldb_readoptions_set_fill_cache(leveldb_readoptions_t*, + unsigned char); +LEVELDB_EXPORT void leveldb_readoptions_set_snapshot(leveldb_readoptions_t*, + const leveldb_snapshot_t*); + +/* Write options */ + +LEVELDB_EXPORT leveldb_writeoptions_t* leveldb_writeoptions_create(); +LEVELDB_EXPORT void leveldb_writeoptions_destroy(leveldb_writeoptions_t*); +LEVELDB_EXPORT void leveldb_writeoptions_set_sync(leveldb_writeoptions_t*, + unsigned char); + +/* Cache */ + +LEVELDB_EXPORT leveldb_cache_t* leveldb_cache_create_lru(size_t capacity); +LEVELDB_EXPORT void leveldb_cache_destroy(leveldb_cache_t* cache); + +/* Env */ + +LEVELDB_EXPORT leveldb_env_t* leveldb_create_default_env(); +LEVELDB_EXPORT void leveldb_env_destroy(leveldb_env_t*); + +/* If not NULL, the returned buffer must be released using leveldb_free(). */ +LEVELDB_EXPORT char* leveldb_env_get_test_directory(leveldb_env_t*); + +/* Utility */ + +/* Calls free(ptr). + REQUIRES: ptr was malloc()-ed and returned by one of the routines + in this file. Note that in certain cases (typically on Windows), you + may need to call this routine instead of free(ptr) to dispose of + malloc()-ed memory returned by this library. */ +LEVELDB_EXPORT void leveldb_free(void* ptr); + +/* Return the major version number for this release. */ +LEVELDB_EXPORT int leveldb_major_version(); + +/* Return the minor version number for this release. */ +LEVELDB_EXPORT int leveldb_minor_version(); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* STORAGE_LEVELDB_INCLUDE_C_H_ */ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/cache.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/cache.h new file mode 100644 index 0000000..7d1a221 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/cache.h @@ -0,0 +1,111 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A Cache is an interface that maps keys to values. It has internal +// synchronization and may be safely accessed concurrently from +// multiple threads. It may automatically evict entries to make room +// for new entries. Values have a specified charge against the cache +// capacity. For example, a cache where the values are variable +// length strings, may use the length of the string as the charge for +// the string. +// +// A builtin cache implementation with a least-recently-used eviction +// policy is provided. Clients may use their own implementations if +// they want something more sophisticated (like scan-resistance, a +// custom eviction policy, variable cache sizing, etc.) + +#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_ +#define STORAGE_LEVELDB_INCLUDE_CACHE_H_ + +#include + +#include "leveldb/export.h" +#include "leveldb/slice.h" + +namespace leveldb { + +class LEVELDB_EXPORT Cache; + +// Create a new cache with a fixed size capacity. This implementation +// of Cache uses a least-recently-used eviction policy. +LEVELDB_EXPORT Cache* NewLRUCache(size_t capacity); + +class LEVELDB_EXPORT Cache { + public: + Cache() = default; + + Cache(const Cache&) = delete; + Cache& operator=(const Cache&) = delete; + + // Destroys all existing entries by calling the "deleter" + // function that was passed to the constructor. + virtual ~Cache(); + + // Opaque handle to an entry stored in the cache. + struct Handle {}; + + // Insert a mapping from key->value into the cache and assign it + // the specified charge against the total cache capacity. + // + // Returns a handle that corresponds to the mapping. The caller + // must call this->Release(handle) when the returned mapping is no + // longer needed. + // + // When the inserted entry is no longer needed, the key and + // value will be passed to "deleter". + virtual Handle* Insert(const Slice& key, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) = 0; + + // If the cache has no mapping for "key", returns nullptr. + // + // Else return a handle that corresponds to the mapping. The caller + // must call this->Release(handle) when the returned mapping is no + // longer needed. + virtual Handle* Lookup(const Slice& key) = 0; + + // Release a mapping returned by a previous Lookup(). + // REQUIRES: handle must not have been released yet. + // REQUIRES: handle must have been returned by a method on *this. + virtual void Release(Handle* handle) = 0; + + // Return the value encapsulated in a handle returned by a + // successful Lookup(). + // REQUIRES: handle must not have been released yet. + // REQUIRES: handle must have been returned by a method on *this. + virtual void* Value(Handle* handle) = 0; + + // If the cache contains entry for key, erase it. Note that the + // underlying entry will be kept around until all existing handles + // to it have been released. + virtual void Erase(const Slice& key) = 0; + + // Return a new numeric id. May be used by multiple clients who are + // sharing the same cache to partition the key space. Typically the + // client will allocate a new id at startup and prepend the id to + // its cache keys. + virtual uint64_t NewId() = 0; + + // Remove all cache entries that are not actively in use. Memory-constrained + // applications may wish to call this method to reduce memory usage. + // Default implementation of Prune() does nothing. Subclasses are strongly + // encouraged to override the default implementation. A future release of + // leveldb may change Prune() to a pure abstract method. + virtual void Prune() {} + + // Return an estimate of the combined charges of all elements stored in the + // cache. + virtual size_t TotalCharge() const = 0; + + private: + void LRU_Remove(Handle* e); + void LRU_Append(Handle* e); + void Unref(Handle* e); + + struct Rep; + Rep* rep_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_CACHE_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/comparator.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/comparator.h new file mode 100644 index 0000000..a85b51e --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/comparator.h @@ -0,0 +1,64 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ +#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ + +#include + +#include "leveldb/export.h" + +namespace leveldb { + +class Slice; + +// A Comparator object provides a total order across slices that are +// used as keys in an sstable or a database. A Comparator implementation +// must be thread-safe since leveldb may invoke its methods concurrently +// from multiple threads. +class LEVELDB_EXPORT Comparator { + public: + virtual ~Comparator(); + + // Three-way comparison. Returns value: + // < 0 iff "a" < "b", + // == 0 iff "a" == "b", + // > 0 iff "a" > "b" + virtual int Compare(const Slice& a, const Slice& b) const = 0; + + // The name of the comparator. Used to check for comparator + // mismatches (i.e., a DB created with one comparator is + // accessed using a different comparator. + // + // The client of this package should switch to a new name whenever + // the comparator implementation changes in a way that will cause + // the relative ordering of any two keys to change. + // + // Names starting with "leveldb." are reserved and should not be used + // by any clients of this package. + virtual const char* Name() const = 0; + + // Advanced functions: these are used to reduce the space requirements + // for internal data structures like index blocks. + + // If *start < limit, changes *start to a short string in [start,limit). + // Simple comparator implementations may return with *start unchanged, + // i.e., an implementation of this method that does nothing is correct. + virtual void FindShortestSeparator(std::string* start, + const Slice& limit) const = 0; + + // Changes *key to a short string >= *key. + // Simple comparator implementations may return with *key unchanged, + // i.e., an implementation of this method that does nothing is correct. + virtual void FindShortSuccessor(std::string* key) const = 0; +}; + +// Return a builtin comparator that uses lexicographic byte-wise +// ordering. The result remains the property of this module and +// must not be deleted. +LEVELDB_EXPORT const Comparator* BytewiseComparator(); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/db.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/db.h new file mode 100644 index 0000000..ea3d9e5 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/db.h @@ -0,0 +1,167 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_ +#define STORAGE_LEVELDB_INCLUDE_DB_H_ + +#include +#include + +#include "leveldb/export.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" + +namespace leveldb { + +// Update CMakeLists.txt if you change these +static const int kMajorVersion = 1; +static const int kMinorVersion = 22; + +struct Options; +struct ReadOptions; +struct WriteOptions; +class WriteBatch; + +// Abstract handle to particular state of a DB. +// A Snapshot is an immutable object and can therefore be safely +// accessed from multiple threads without any external synchronization. +class LEVELDB_EXPORT Snapshot { + protected: + virtual ~Snapshot(); +}; + +// A range of keys +struct LEVELDB_EXPORT Range { + Range() {} + Range(const Slice& s, const Slice& l) : start(s), limit(l) {} + + Slice start; // Included in the range + Slice limit; // Not included in the range +}; + +// A DB is a persistent ordered map from keys to values. +// A DB is safe for concurrent access from multiple threads without +// any external synchronization. +class LEVELDB_EXPORT DB { + public: + // Open the database with the specified "name". + // Stores a pointer to a heap-allocated database in *dbptr and returns + // OK on success. + // Stores nullptr in *dbptr and returns a non-OK status on error. + // Caller should delete *dbptr when it is no longer needed. + static Status Open(const Options& options, const std::string& name, + DB** dbptr); + + DB() = default; + + DB(const DB&) = delete; + DB& operator=(const DB&) = delete; + + virtual ~DB(); + + // Set the database entry for "key" to "value". Returns OK on success, + // and a non-OK status on error. + // Note: consider setting options.sync = true. + virtual Status Put(const WriteOptions& options, const Slice& key, + const Slice& value) = 0; + + // Remove the database entry (if any) for "key". Returns OK on + // success, and a non-OK status on error. It is not an error if "key" + // did not exist in the database. + // Note: consider setting options.sync = true. + virtual Status Delete(const WriteOptions& options, const Slice& key) = 0; + + // Apply the specified updates to the database. + // Returns OK on success, non-OK on failure. + // Note: consider setting options.sync = true. + virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0; + + // If the database contains an entry for "key" store the + // corresponding value in *value and return OK. + // + // If there is no entry for "key" leave *value unchanged and return + // a status for which Status::IsNotFound() returns true. + // + // May return some other Status on an error. + virtual Status Get(const ReadOptions& options, const Slice& key, + std::string* value) = 0; + + // Return a heap-allocated iterator over the contents of the database. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + // + // Caller should delete the iterator when it is no longer needed. + // The returned iterator should be deleted before this db is deleted. + virtual Iterator* NewIterator(const ReadOptions& options) = 0; + + // Return a handle to the current DB state. Iterators created with + // this handle will all observe a stable snapshot of the current DB + // state. The caller must call ReleaseSnapshot(result) when the + // snapshot is no longer needed. + virtual const Snapshot* GetSnapshot() = 0; + + // Release a previously acquired snapshot. The caller must not + // use "snapshot" after this call. + virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0; + + // DB implementations can export properties about their state + // via this method. If "property" is a valid property understood by this + // DB implementation, fills "*value" with its current value and returns + // true. Otherwise returns false. + // + // + // Valid property names include: + // + // "leveldb.num-files-at-level" - return the number of files at level , + // where is an ASCII representation of a level number (e.g. "0"). + // "leveldb.stats" - returns a multi-line string that describes statistics + // about the internal operation of the DB. + // "leveldb.sstables" - returns a multi-line string that describes all + // of the sstables that make up the db contents. + // "leveldb.approximate-memory-usage" - returns the approximate number of + // bytes of memory in use by the DB. + virtual bool GetProperty(const Slice& property, std::string* value) = 0; + + // For each i in [0,n-1], store in "sizes[i]", the approximate + // file system space used by keys in "[range[i].start .. range[i].limit)". + // + // Note that the returned sizes measure file system space usage, so + // if the user data compresses by a factor of ten, the returned + // sizes will be one-tenth the size of the corresponding user data size. + // + // The results may not include the sizes of recently written data. + virtual void GetApproximateSizes(const Range* range, int n, + uint64_t* sizes) = 0; + + // Compact the underlying storage for the key range [*begin,*end]. + // In particular, deleted and overwritten versions are discarded, + // and the data is rearranged to reduce the cost of operations + // needed to access the data. This operation should typically only + // be invoked by users who understand the underlying implementation. + // + // begin==nullptr is treated as a key before all keys in the database. + // end==nullptr is treated as a key after all keys in the database. + // Therefore the following call will compact the entire database: + // db->CompactRange(nullptr, nullptr); + virtual void CompactRange(const Slice* begin, const Slice* end) = 0; +}; + +// Destroy the contents of the specified database. +// Be very careful using this method. +// +// Note: For backwards compatibility, if DestroyDB is unable to list the +// database files, Status::OK() will still be returned masking this failure. +LEVELDB_EXPORT Status DestroyDB(const std::string& name, + const Options& options); + +// If a DB cannot be opened, you may attempt to call this method to +// resurrect as much of the contents of the database as possible. +// Some data may be lost, so be careful when calling this function +// on a database that contains important information. +LEVELDB_EXPORT Status RepairDB(const std::string& dbname, + const Options& options); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_DB_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/dumpfile.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/dumpfile.h new file mode 100644 index 0000000..a58bc6b --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/dumpfile.h @@ -0,0 +1,28 @@ +// Copyright (c) 2014 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ +#define STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ + +#include + +#include "leveldb/env.h" +#include "leveldb/export.h" +#include "leveldb/status.h" + +namespace leveldb { + +// Dump the contents of the file named by fname in text format to +// *dst. Makes a sequence of dst->Append() calls; each call is passed +// the newline-terminated text corresponding to a single item found +// in the file. +// +// Returns a non-OK result if fname does not name a leveldb storage +// file, or if the file cannot be read. +LEVELDB_EXPORT Status DumpFile(Env* env, const std::string& fname, + WritableFile* dst); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/env.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/env.h new file mode 100644 index 0000000..112fe96 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/env.h @@ -0,0 +1,387 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// An Env is an interface used by the leveldb implementation to access +// operating system functionality like the filesystem etc. Callers +// may wish to provide a custom Env object when opening a database to +// get fine gain control; e.g., to rate limit file system operations. +// +// All Env implementations are safe for concurrent access from +// multiple threads without any external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_ +#define STORAGE_LEVELDB_INCLUDE_ENV_H_ + +#include +#include + +#include +#include + +#include "leveldb/export.h" +#include "leveldb/status.h" + +#if defined(_WIN32) +// The leveldb::Env class below contains a DeleteFile method. +// At the same time, , a fairly popular header +// file for Windows applications, defines a DeleteFile macro. +// +// Without any intervention on our part, the result of this +// unfortunate coincidence is that the name of the +// leveldb::Env::DeleteFile method seen by the compiler depends on +// whether was included before or after the LevelDB +// headers. +// +// To avoid headaches, we undefined DeleteFile (if defined) and +// redefine it at the bottom of this file. This way +// can be included before this file (or not at all) and the +// exported method will always be leveldb::Env::DeleteFile. +#if defined(DeleteFile) +#undef DeleteFile +#define LEVELDB_DELETEFILE_UNDEFINED +#endif // defined(DeleteFile) +#endif // defined(_WIN32) + +namespace leveldb { + +class FileLock; +class Logger; +class RandomAccessFile; +class SequentialFile; +class Slice; +class WritableFile; + +class LEVELDB_EXPORT Env { + public: + Env() = default; + + Env(const Env&) = delete; + Env& operator=(const Env&) = delete; + + virtual ~Env(); + + // Return a default environment suitable for the current operating + // system. Sophisticated users may wish to provide their own Env + // implementation instead of relying on this default environment. + // + // The result of Default() belongs to leveldb and must never be deleted. + static Env* Default(); + + // Create an object that sequentially reads the file with the specified name. + // On success, stores a pointer to the new file in *result and returns OK. + // On failure stores nullptr in *result and returns non-OK. If the file does + // not exist, returns a non-OK status. Implementations should return a + // NotFound status when the file does not exist. + // + // The returned file will only be accessed by one thread at a time. + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) = 0; + + // Create an object supporting random-access reads from the file with the + // specified name. On success, stores a pointer to the new file in + // *result and returns OK. On failure stores nullptr in *result and + // returns non-OK. If the file does not exist, returns a non-OK + // status. Implementations should return a NotFound status when the file does + // not exist. + // + // The returned file may be concurrently accessed by multiple threads. + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) = 0; + + // Create an object that writes to a new file with the specified + // name. Deletes any existing file with the same name and creates a + // new file. On success, stores a pointer to the new file in + // *result and returns OK. On failure stores nullptr in *result and + // returns non-OK. + // + // The returned file will only be accessed by one thread at a time. + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) = 0; + + // Create an object that either appends to an existing file, or + // writes to a new file (if the file does not exist to begin with). + // On success, stores a pointer to the new file in *result and + // returns OK. On failure stores nullptr in *result and returns + // non-OK. + // + // The returned file will only be accessed by one thread at a time. + // + // May return an IsNotSupportedError error if this Env does + // not allow appending to an existing file. Users of Env (including + // the leveldb implementation) must be prepared to deal with + // an Env that does not support appending. + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result); + + // Returns true iff the named file exists. + virtual bool FileExists(const std::string& fname) = 0; + + // Store in *result the names of the children of the specified directory. + // The names are relative to "dir". + // Original contents of *results are dropped. + virtual Status GetChildren(const std::string& dir, + std::vector* result) = 0; + + // Delete the named file. + virtual Status DeleteFile(const std::string& fname) = 0; + + // Create the specified directory. + virtual Status CreateDir(const std::string& dirname) = 0; + + // Delete the specified directory. + virtual Status DeleteDir(const std::string& dirname) = 0; + + // Store the size of fname in *file_size. + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0; + + // Rename file src to target. + virtual Status RenameFile(const std::string& src, + const std::string& target) = 0; + + // Lock the specified file. Used to prevent concurrent access to + // the same db by multiple processes. On failure, stores nullptr in + // *lock and returns non-OK. + // + // On success, stores a pointer to the object that represents the + // acquired lock in *lock and returns OK. The caller should call + // UnlockFile(*lock) to release the lock. If the process exits, + // the lock will be automatically released. + // + // If somebody else already holds the lock, finishes immediately + // with a failure. I.e., this call does not wait for existing locks + // to go away. + // + // May create the named file if it does not already exist. + virtual Status LockFile(const std::string& fname, FileLock** lock) = 0; + + // Release the lock acquired by a previous successful call to LockFile. + // REQUIRES: lock was returned by a successful LockFile() call + // REQUIRES: lock has not already been unlocked. + virtual Status UnlockFile(FileLock* lock) = 0; + + // Arrange to run "(*function)(arg)" once in a background thread. + // + // "function" may run in an unspecified thread. Multiple functions + // added to the same Env may run concurrently in different threads. + // I.e., the caller may not assume that background work items are + // serialized. + virtual void Schedule(void (*function)(void* arg), void* arg) = 0; + + // Start a new thread, invoking "function(arg)" within the new thread. + // When "function(arg)" returns, the thread will be destroyed. + virtual void StartThread(void (*function)(void* arg), void* arg) = 0; + + // *path is set to a temporary directory that can be used for testing. It may + // or may not have just been created. The directory may or may not differ + // between runs of the same process, but subsequent calls will return the + // same directory. + virtual Status GetTestDirectory(std::string* path) = 0; + + // Create and return a log file for storing informational messages. + virtual Status NewLogger(const std::string& fname, Logger** result) = 0; + + // Returns the number of micro-seconds since some fixed point in time. Only + // useful for computing deltas of time. + virtual uint64_t NowMicros() = 0; + + // Sleep/delay the thread for the prescribed number of micro-seconds. + virtual void SleepForMicroseconds(int micros) = 0; +}; + +// A file abstraction for reading sequentially through a file +class LEVELDB_EXPORT SequentialFile { + public: + SequentialFile() = default; + + SequentialFile(const SequentialFile&) = delete; + SequentialFile& operator=(const SequentialFile&) = delete; + + virtual ~SequentialFile(); + + // Read up to "n" bytes from the file. "scratch[0..n-1]" may be + // written by this routine. Sets "*result" to the data that was + // read (including if fewer than "n" bytes were successfully read). + // May set "*result" to point at data in "scratch[0..n-1]", so + // "scratch[0..n-1]" must be live when "*result" is used. + // If an error was encountered, returns a non-OK status. + // + // REQUIRES: External synchronization + virtual Status Read(size_t n, Slice* result, char* scratch) = 0; + + // Skip "n" bytes from the file. This is guaranteed to be no + // slower that reading the same data, but may be faster. + // + // If end of file is reached, skipping will stop at the end of the + // file, and Skip will return OK. + // + // REQUIRES: External synchronization + virtual Status Skip(uint64_t n) = 0; +}; + +// A file abstraction for randomly reading the contents of a file. +class LEVELDB_EXPORT RandomAccessFile { + public: + RandomAccessFile() = default; + + RandomAccessFile(const RandomAccessFile&) = delete; + RandomAccessFile& operator=(const RandomAccessFile&) = delete; + + virtual ~RandomAccessFile(); + + // Read up to "n" bytes from the file starting at "offset". + // "scratch[0..n-1]" may be written by this routine. Sets "*result" + // to the data that was read (including if fewer than "n" bytes were + // successfully read). May set "*result" to point at data in + // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when + // "*result" is used. If an error was encountered, returns a non-OK + // status. + // + // Safe for concurrent use by multiple threads. + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const = 0; +}; + +// A file abstraction for sequential writing. The implementation +// must provide buffering since callers may append small fragments +// at a time to the file. +class LEVELDB_EXPORT WritableFile { + public: + WritableFile() = default; + + WritableFile(const WritableFile&) = delete; + WritableFile& operator=(const WritableFile&) = delete; + + virtual ~WritableFile(); + + virtual Status Append(const Slice& data) = 0; + virtual Status Close() = 0; + virtual Status Flush() = 0; + virtual Status Sync() = 0; +}; + +// An interface for writing log messages. +class LEVELDB_EXPORT Logger { + public: + Logger() = default; + + Logger(const Logger&) = delete; + Logger& operator=(const Logger&) = delete; + + virtual ~Logger(); + + // Write an entry to the log file with the specified format. + virtual void Logv(const char* format, va_list ap) = 0; +}; + +// Identifies a locked file. +class LEVELDB_EXPORT FileLock { + public: + FileLock() = default; + + FileLock(const FileLock&) = delete; + FileLock& operator=(const FileLock&) = delete; + + virtual ~FileLock(); +}; + +// Log the specified data to *info_log if info_log is non-null. +void Log(Logger* info_log, const char* format, ...) +#if defined(__GNUC__) || defined(__clang__) + __attribute__((__format__(__printf__, 2, 3))) +#endif + ; + +// A utility routine: write "data" to the named file. +LEVELDB_EXPORT Status WriteStringToFile(Env* env, const Slice& data, + const std::string& fname); + +// A utility routine: read contents of named file into *data +LEVELDB_EXPORT Status ReadFileToString(Env* env, const std::string& fname, + std::string* data); + +// An implementation of Env that forwards all calls to another Env. +// May be useful to clients who wish to override just part of the +// functionality of another Env. +class LEVELDB_EXPORT EnvWrapper : public Env { + public: + // Initialize an EnvWrapper that delegates all calls to *t. + explicit EnvWrapper(Env* t) : target_(t) {} + virtual ~EnvWrapper(); + + // Return the target to which this Env forwards all calls. + Env* target() const { return target_; } + + // The following text is boilerplate that forwards all methods to target(). + Status NewSequentialFile(const std::string& f, SequentialFile** r) override { + return target_->NewSequentialFile(f, r); + } + Status NewRandomAccessFile(const std::string& f, + RandomAccessFile** r) override { + return target_->NewRandomAccessFile(f, r); + } + Status NewWritableFile(const std::string& f, WritableFile** r) override { + return target_->NewWritableFile(f, r); + } + Status NewAppendableFile(const std::string& f, WritableFile** r) override { + return target_->NewAppendableFile(f, r); + } + bool FileExists(const std::string& f) override { + return target_->FileExists(f); + } + Status GetChildren(const std::string& dir, + std::vector* r) override { + return target_->GetChildren(dir, r); + } + Status DeleteFile(const std::string& f) override { + return target_->DeleteFile(f); + } + Status CreateDir(const std::string& d) override { + return target_->CreateDir(d); + } + Status DeleteDir(const std::string& d) override { + return target_->DeleteDir(d); + } + Status GetFileSize(const std::string& f, uint64_t* s) override { + return target_->GetFileSize(f, s); + } + Status RenameFile(const std::string& s, const std::string& t) override { + return target_->RenameFile(s, t); + } + Status LockFile(const std::string& f, FileLock** l) override { + return target_->LockFile(f, l); + } + Status UnlockFile(FileLock* l) override { return target_->UnlockFile(l); } + void Schedule(void (*f)(void*), void* a) override { + return target_->Schedule(f, a); + } + void StartThread(void (*f)(void*), void* a) override { + return target_->StartThread(f, a); + } + Status GetTestDirectory(std::string* path) override { + return target_->GetTestDirectory(path); + } + Status NewLogger(const std::string& fname, Logger** result) override { + return target_->NewLogger(fname, result); + } + uint64_t NowMicros() override { return target_->NowMicros(); } + void SleepForMicroseconds(int micros) override { + target_->SleepForMicroseconds(micros); + } + + private: + Env* target_; +}; + +} // namespace leveldb + +// Redefine DeleteFile if necessary. +#if defined(_WIN32) && defined(LEVELDB_DELETEFILE_UNDEFINED) +#if defined(UNICODE) +#define DeleteFile DeleteFileW +#else +#define DeleteFile DeleteFileA +#endif // defined(UNICODE) +#endif // defined(_WIN32) && defined(LEVELDB_DELETEFILE_UNDEFINED) + +#endif // STORAGE_LEVELDB_INCLUDE_ENV_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/export.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/export.h new file mode 100644 index 0000000..6ba9b18 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/export.h @@ -0,0 +1,33 @@ +// Copyright (c) 2017 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_EXPORT_H_ +#define STORAGE_LEVELDB_INCLUDE_EXPORT_H_ + +#if !defined(LEVELDB_EXPORT) + +#if defined(LEVELDB_SHARED_LIBRARY) +#if defined(_WIN32) + +#if defined(LEVELDB_COMPILE_LIBRARY) +#define LEVELDB_EXPORT __declspec(dllexport) +#else +#define LEVELDB_EXPORT __declspec(dllimport) +#endif // defined(LEVELDB_COMPILE_LIBRARY) + +#else // defined(_WIN32) +#if defined(LEVELDB_COMPILE_LIBRARY) +#define LEVELDB_EXPORT __attribute__((visibility("default"))) +#else +#define LEVELDB_EXPORT +#endif +#endif // defined(_WIN32) + +#else // defined(LEVELDB_SHARED_LIBRARY) +#define LEVELDB_EXPORT +#endif + +#endif // !defined(LEVELDB_EXPORT) + +#endif // STORAGE_LEVELDB_INCLUDE_EXPORT_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/filter_policy.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/filter_policy.h new file mode 100644 index 0000000..49c8eda --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/filter_policy.h @@ -0,0 +1,72 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A database can be configured with a custom FilterPolicy object. +// This object is responsible for creating a small filter from a set +// of keys. These filters are stored in leveldb and are consulted +// automatically by leveldb to decide whether or not to read some +// information from disk. In many cases, a filter can cut down the +// number of disk seeks form a handful to a single disk seek per +// DB::Get() call. +// +// Most people will want to use the builtin bloom filter support (see +// NewBloomFilterPolicy() below). + +#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ +#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ + +#include + +#include "leveldb/export.h" + +namespace leveldb { + +class Slice; + +class LEVELDB_EXPORT FilterPolicy { + public: + virtual ~FilterPolicy(); + + // Return the name of this policy. Note that if the filter encoding + // changes in an incompatible way, the name returned by this method + // must be changed. Otherwise, old incompatible filters may be + // passed to methods of this type. + virtual const char* Name() const = 0; + + // keys[0,n-1] contains a list of keys (potentially with duplicates) + // that are ordered according to the user supplied comparator. + // Append a filter that summarizes keys[0,n-1] to *dst. + // + // Warning: do not change the initial contents of *dst. Instead, + // append the newly constructed filter to *dst. + virtual void CreateFilter(const Slice* keys, int n, + std::string* dst) const = 0; + + // "filter" contains the data appended by a preceding call to + // CreateFilter() on this class. This method must return true if + // the key was in the list of keys passed to CreateFilter(). + // This method may return true or false if the key was not on the + // list, but it should aim to return false with a high probability. + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0; +}; + +// Return a new filter policy that uses a bloom filter with approximately +// the specified number of bits per key. A good value for bits_per_key +// is 10, which yields a filter with ~ 1% false positive rate. +// +// Callers must delete the result after any database that is using the +// result has been closed. +// +// Note: if you are using a custom comparator that ignores some parts +// of the keys being compared, you must not use NewBloomFilterPolicy() +// and must provide your own FilterPolicy that also ignores the +// corresponding parts of the keys. For example, if the comparator +// ignores trailing spaces, it would be incorrect to use a +// FilterPolicy (like NewBloomFilterPolicy) that does not ignore +// trailing spaces in keys. +LEVELDB_EXPORT const FilterPolicy* NewBloomFilterPolicy(int bits_per_key); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/iterator.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/iterator.h new file mode 100644 index 0000000..bb9a5df --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/iterator.h @@ -0,0 +1,112 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// An iterator yields a sequence of key/value pairs from a source. +// The following class defines the interface. Multiple implementations +// are provided by this library. In particular, iterators are provided +// to access the contents of a Table or a DB. +// +// Multiple threads can invoke const methods on an Iterator without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Iterator must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ +#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ + +#include "leveldb/export.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class LEVELDB_EXPORT Iterator { + public: + Iterator(); + + Iterator(const Iterator&) = delete; + Iterator& operator=(const Iterator&) = delete; + + virtual ~Iterator(); + + // An iterator is either positioned at a key/value pair, or + // not valid. This method returns true iff the iterator is valid. + virtual bool Valid() const = 0; + + // Position at the first key in the source. The iterator is Valid() + // after this call iff the source is not empty. + virtual void SeekToFirst() = 0; + + // Position at the last key in the source. The iterator is + // Valid() after this call iff the source is not empty. + virtual void SeekToLast() = 0; + + // Position at the first key in the source that is at or past target. + // The iterator is Valid() after this call iff the source contains + // an entry that comes at or past target. + virtual void Seek(const Slice& target) = 0; + + // Moves to the next entry in the source. After this call, Valid() is + // true iff the iterator was not positioned at the last entry in the source. + // REQUIRES: Valid() + virtual void Next() = 0; + + // Moves to the previous entry in the source. After this call, Valid() is + // true iff the iterator was not positioned at the first entry in source. + // REQUIRES: Valid() + virtual void Prev() = 0; + + // Return the key for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // REQUIRES: Valid() + virtual Slice key() const = 0; + + // Return the value for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // REQUIRES: Valid() + virtual Slice value() const = 0; + + // If an error has occurred, return it. Else return an ok status. + virtual Status status() const = 0; + + // Clients are allowed to register function/arg1/arg2 triples that + // will be invoked when this iterator is destroyed. + // + // Note that unlike all of the preceding methods, this method is + // not abstract and therefore clients should not override it. + using CleanupFunction = void (*)(void* arg1, void* arg2); + void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2); + + private: + // Cleanup functions are stored in a single-linked list. + // The list's head node is inlined in the iterator. + struct CleanupNode { + // True if the node is not used. Only head nodes might be unused. + bool IsEmpty() const { return function == nullptr; } + // Invokes the cleanup function. + void Run() { + assert(function != nullptr); + (*function)(arg1, arg2); + } + + // The head node is used if the function pointer is not null. + CleanupFunction function; + void* arg1; + void* arg2; + CleanupNode* next; + }; + CleanupNode cleanup_head_; +}; + +// Return an empty iterator (yields nothing). +LEVELDB_EXPORT Iterator* NewEmptyIterator(); + +// Return an empty iterator with the specified status. +LEVELDB_EXPORT Iterator* NewErrorIterator(const Status& status); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/options.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/options.h new file mode 100644 index 0000000..b748772 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/options.h @@ -0,0 +1,187 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ +#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ + +#include + +#include "leveldb/export.h" + +namespace leveldb { + +class Cache; +class Comparator; +class Env; +class FilterPolicy; +class Logger; +class Snapshot; + +// DB contents are stored in a set of blocks, each of which holds a +// sequence of key,value pairs. Each block may be compressed before +// being stored in a file. The following enum describes which +// compression method (if any) is used to compress a block. +enum CompressionType { + // NOTE: do not change the values of existing entries, as these are + // part of the persistent format on disk. + kNoCompression = 0x0, + kSnappyCompression = 0x1 +}; + +// Options to control the behavior of a database (passed to DB::Open) +struct LEVELDB_EXPORT Options { + // Create an Options object with default values for all fields. + Options(); + + // ------------------- + // Parameters that affect behavior + + // Comparator used to define the order of keys in the table. + // Default: a comparator that uses lexicographic byte-wise ordering + // + // REQUIRES: The client must ensure that the comparator supplied + // here has the same name and orders keys *exactly* the same as the + // comparator provided to previous open calls on the same DB. + const Comparator* comparator; + + // If true, the database will be created if it is missing. + bool create_if_missing = false; + + // If true, an error is raised if the database already exists. + bool error_if_exists = false; + + // If true, the implementation will do aggressive checking of the + // data it is processing and will stop early if it detects any + // errors. This may have unforeseen ramifications: for example, a + // corruption of one DB entry may cause a large number of entries to + // become unreadable or for the entire DB to become unopenable. + bool paranoid_checks = false; + + // Use the specified object to interact with the environment, + // e.g. to read/write files, schedule background work, etc. + // Default: Env::Default() + Env* env; + + // Any internal progress/error information generated by the db will + // be written to info_log if it is non-null, or to a file stored + // in the same directory as the DB contents if info_log is null. + Logger* info_log = nullptr; + + // ------------------- + // Parameters that affect performance + + // Amount of data to build up in memory (backed by an unsorted log + // on disk) before converting to a sorted on-disk file. + // + // Larger values increase performance, especially during bulk loads. + // Up to two write buffers may be held in memory at the same time, + // so you may wish to adjust this parameter to control memory usage. + // Also, a larger write buffer will result in a longer recovery time + // the next time the database is opened. + size_t write_buffer_size = 4 * 1024 * 1024; + + // Number of open files that can be used by the DB. You may need to + // increase this if your database has a large working set (budget + // one open file per 2MB of working set). + int max_open_files = 1000; + + // Control over blocks (user data is stored in a set of blocks, and + // a block is the unit of reading from disk). + + // If non-null, use the specified cache for blocks. + // If null, leveldb will automatically create and use an 8MB internal cache. + Cache* block_cache = nullptr; + + // Approximate size of user data packed per block. Note that the + // block size specified here corresponds to uncompressed data. The + // actual size of the unit read from disk may be smaller if + // compression is enabled. This parameter can be changed dynamically. + size_t block_size = 4 * 1024; + + // Number of keys between restart points for delta encoding of keys. + // This parameter can be changed dynamically. Most clients should + // leave this parameter alone. + int block_restart_interval = 16; + + // Leveldb will write up to this amount of bytes to a file before + // switching to a new one. + // Most clients should leave this parameter alone. However if your + // filesystem is more efficient with larger files, you could + // consider increasing the value. The downside will be longer + // compactions and hence longer latency/performance hiccups. + // Another reason to increase this parameter might be when you are + // initially populating a large database. + size_t max_file_size = 2 * 1024 * 1024; + + // Compress blocks using the specified compression algorithm. This + // parameter can be changed dynamically. + // + // Default: kSnappyCompression, which gives lightweight but fast + // compression. + // + // Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz: + // ~200-500MB/s compression + // ~400-800MB/s decompression + // Note that these speeds are significantly faster than most + // persistent storage speeds, and therefore it is typically never + // worth switching to kNoCompression. Even if the input data is + // incompressible, the kSnappyCompression implementation will + // efficiently detect that and will switch to uncompressed mode. + CompressionType compression = kSnappyCompression; + + // EXPERIMENTAL: If true, append to existing MANIFEST and log files + // when a database is opened. This can significantly speed up open. + // + // Default: currently false, but may become true later. + bool reuse_logs = false; + + // If non-null, use the specified filter policy to reduce disk reads. + // Many applications will benefit from passing the result of + // NewBloomFilterPolicy() here. + const FilterPolicy* filter_policy = nullptr; +}; + +// Options that control read operations +struct LEVELDB_EXPORT ReadOptions { + ReadOptions() = default; + + // If true, all data read from underlying storage will be + // verified against corresponding checksums. + bool verify_checksums = false; + + // Should the data read for this iteration be cached in memory? + // Callers may wish to set this field to false for bulk scans. + bool fill_cache = true; + + // If "snapshot" is non-null, read as of the supplied snapshot + // (which must belong to the DB that is being read and which must + // not have been released). If "snapshot" is null, use an implicit + // snapshot of the state at the beginning of this read operation. + const Snapshot* snapshot = nullptr; +}; + +// Options that control write operations +struct LEVELDB_EXPORT WriteOptions { + WriteOptions() = default; + + // If true, the write will be flushed from the operating system + // buffer cache (by calling WritableFile::Sync()) before the write + // is considered complete. If this flag is true, writes will be + // slower. + // + // If this flag is false, and the machine crashes, some recent + // writes may be lost. Note that if it is just the process that + // crashes (i.e., the machine does not reboot), no writes will be + // lost even if sync==false. + // + // In other words, a DB write with sync==false has similar + // crash semantics as the "write()" system call. A DB write + // with sync==true has similar crash semantics to a "write()" + // system call followed by "fsync()". + bool sync = false; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/slice.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/slice.h new file mode 100644 index 0000000..2df417d --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/slice.h @@ -0,0 +1,115 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Slice is a simple structure containing a pointer into some external +// storage and a size. The user of a Slice must ensure that the slice +// is not used after the corresponding external storage has been +// deallocated. +// +// Multiple threads can invoke const methods on a Slice without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Slice must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_H_ +#define STORAGE_LEVELDB_INCLUDE_SLICE_H_ + +#include +#include +#include + +#include + +#include "leveldb/export.h" + +namespace leveldb { + +class LEVELDB_EXPORT Slice { + public: + // Create an empty slice. + Slice() : data_(""), size_(0) {} + + // Create a slice that refers to d[0,n-1]. + Slice(const char* d, size_t n) : data_(d), size_(n) {} + + // Create a slice that refers to the contents of "s" + Slice(const std::string& s) : data_(s.data()), size_(s.size()) {} + + // Create a slice that refers to s[0,strlen(s)-1] + Slice(const char* s) : data_(s), size_(strlen(s)) {} + + // Intentionally copyable. + Slice(const Slice&) = default; + Slice& operator=(const Slice&) = default; + + // Return a pointer to the beginning of the referenced data + const char* data() const { return data_; } + + // Return the length (in bytes) of the referenced data + size_t size() const { return size_; } + + // Return true iff the length of the referenced data is zero + bool empty() const { return size_ == 0; } + + // Return the ith byte in the referenced data. + // REQUIRES: n < size() + char operator[](size_t n) const { + assert(n < size()); + return data_[n]; + } + + // Change this slice to refer to an empty array + void clear() { + data_ = ""; + size_ = 0; + } + + // Drop the first "n" bytes from this slice. + void remove_prefix(size_t n) { + assert(n <= size()); + data_ += n; + size_ -= n; + } + + // Return a string that contains the copy of the referenced data. + std::string ToString() const { return std::string(data_, size_); } + + // Three-way comparison. Returns value: + // < 0 iff "*this" < "b", + // == 0 iff "*this" == "b", + // > 0 iff "*this" > "b" + int compare(const Slice& b) const; + + // Return true iff "x" is a prefix of "*this" + bool starts_with(const Slice& x) const { + return ((size_ >= x.size_) && (memcmp(data_, x.data_, x.size_) == 0)); + } + + private: + const char* data_; + size_t size_; +}; + +inline bool operator==(const Slice& x, const Slice& y) { + return ((x.size() == y.size()) && + (memcmp(x.data(), y.data(), x.size()) == 0)); +} + +inline bool operator!=(const Slice& x, const Slice& y) { return !(x == y); } + +inline int Slice::compare(const Slice& b) const { + const size_t min_len = (size_ < b.size_) ? size_ : b.size_; + int r = memcmp(data_, b.data_, min_len); + if (r == 0) { + if (size_ < b.size_) + r = -1; + else if (size_ > b.size_) + r = +1; + } + return r; +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_SLICE_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/status.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/status.h new file mode 100644 index 0000000..e327314 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/status.h @@ -0,0 +1,122 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A Status encapsulates the result of an operation. It may indicate success, +// or it may indicate an error with an associated error message. +// +// Multiple threads can invoke const methods on a Status without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Status must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_ +#define STORAGE_LEVELDB_INCLUDE_STATUS_H_ + +#include +#include + +#include "leveldb/export.h" +#include "leveldb/slice.h" + +namespace leveldb { + +class LEVELDB_EXPORT Status { + public: + // Create a success status. + Status() noexcept : state_(nullptr) {} + ~Status() { delete[] state_; } + + Status(const Status& rhs); + Status& operator=(const Status& rhs); + + Status(Status&& rhs) noexcept : state_(rhs.state_) { rhs.state_ = nullptr; } + Status& operator=(Status&& rhs) noexcept; + + // Return a success status. + static Status OK() { return Status(); } + + // Return error status of an appropriate type. + static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kNotFound, msg, msg2); + } + static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kCorruption, msg, msg2); + } + static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kNotSupported, msg, msg2); + } + static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kInvalidArgument, msg, msg2); + } + static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kIOError, msg, msg2); + } + + // Returns true iff the status indicates success. + bool ok() const { return (state_ == nullptr); } + + // Returns true iff the status indicates a NotFound error. + bool IsNotFound() const { return code() == kNotFound; } + + // Returns true iff the status indicates a Corruption error. + bool IsCorruption() const { return code() == kCorruption; } + + // Returns true iff the status indicates an IOError. + bool IsIOError() const { return code() == kIOError; } + + // Returns true iff the status indicates a NotSupportedError. + bool IsNotSupportedError() const { return code() == kNotSupported; } + + // Returns true iff the status indicates an InvalidArgument. + bool IsInvalidArgument() const { return code() == kInvalidArgument; } + + // Return a string representation of this status suitable for printing. + // Returns the string "OK" for success. + std::string ToString() const; + + private: + enum Code { + kOk = 0, + kNotFound = 1, + kCorruption = 2, + kNotSupported = 3, + kInvalidArgument = 4, + kIOError = 5 + }; + + Code code() const { + return (state_ == nullptr) ? kOk : static_cast(state_[4]); + } + + Status(Code code, const Slice& msg, const Slice& msg2); + static const char* CopyState(const char* s); + + // OK status has a null state_. Otherwise, state_ is a new[] array + // of the following form: + // state_[0..3] == length of message + // state_[4] == code + // state_[5..] == message + const char* state_; +}; + +inline Status::Status(const Status& rhs) { + state_ = (rhs.state_ == nullptr) ? nullptr : CopyState(rhs.state_); +} +inline Status& Status::operator=(const Status& rhs) { + // The following condition catches both aliasing (when this == &rhs), + // and the common case where both rhs and *this are ok. + if (state_ != rhs.state_) { + delete[] state_; + state_ = (rhs.state_ == nullptr) ? nullptr : CopyState(rhs.state_); + } + return *this; +} +inline Status& Status::operator=(Status&& rhs) noexcept { + std::swap(state_, rhs.state_); + return *this; +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_STATUS_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/table.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/table.h new file mode 100644 index 0000000..25c6013 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/table.h @@ -0,0 +1,84 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_H_ +#define STORAGE_LEVELDB_INCLUDE_TABLE_H_ + +#include + +#include "leveldb/export.h" +#include "leveldb/iterator.h" + +namespace leveldb { + +class Block; +class BlockHandle; +class Footer; +struct Options; +class RandomAccessFile; +struct ReadOptions; +class TableCache; + +// A Table is a sorted map from strings to strings. Tables are +// immutable and persistent. A Table may be safely accessed from +// multiple threads without external synchronization. +class LEVELDB_EXPORT Table { + public: + // Attempt to open the table that is stored in bytes [0..file_size) + // of "file", and read the metadata entries necessary to allow + // retrieving data from the table. + // + // If successful, returns ok and sets "*table" to the newly opened + // table. The client should delete "*table" when no longer needed. + // If there was an error while initializing the table, sets "*table" + // to nullptr and returns a non-ok status. Does not take ownership of + // "*source", but the client must ensure that "source" remains live + // for the duration of the returned table's lifetime. + // + // *file must remain live while this Table is in use. + static Status Open(const Options& options, RandomAccessFile* file, + uint64_t file_size, Table** table); + + Table(const Table&) = delete; + Table& operator=(const Table&) = delete; + + ~Table(); + + // Returns a new iterator over the table contents. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + Iterator* NewIterator(const ReadOptions&) const; + + // Given a key, return an approximate byte offset in the file where + // the data for that key begins (or would begin if the key were + // present in the file). The returned value is in terms of file + // bytes, and so includes effects like compression of the underlying data. + // E.g., the approximate offset of the last key in the table will + // be close to the file length. + uint64_t ApproximateOffsetOf(const Slice& key) const; + + private: + friend class TableCache; + struct Rep; + + static Iterator* BlockReader(void*, const ReadOptions&, const Slice&); + + explicit Table(Rep* rep) : rep_(rep) {} + + // Calls (*handle_result)(arg, ...) with the entry found after a call + // to Seek(key). May not make such a call if filter policy says + // that key is not present. + Status InternalGet(const ReadOptions&, const Slice& key, void* arg, + void (*handle_result)(void* arg, const Slice& k, + const Slice& v)); + + void ReadMeta(const Footer& footer); + void ReadFilter(const Slice& filter_handle_value); + + Rep* const rep_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_TABLE_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/table_builder.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/table_builder.h new file mode 100644 index 0000000..7d8896b --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/table_builder.h @@ -0,0 +1,93 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// TableBuilder provides the interface used to build a Table +// (an immutable and sorted map from keys to values). +// +// Multiple threads can invoke const methods on a TableBuilder without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same TableBuilder must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ +#define STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ + +#include + +#include "leveldb/export.h" +#include "leveldb/options.h" +#include "leveldb/status.h" + +namespace leveldb { + +class BlockBuilder; +class BlockHandle; +class WritableFile; + +class LEVELDB_EXPORT TableBuilder { + public: + // Create a builder that will store the contents of the table it is + // building in *file. Does not close the file. It is up to the + // caller to close the file after calling Finish(). + TableBuilder(const Options& options, WritableFile* file); + + TableBuilder(const TableBuilder&) = delete; + TableBuilder& operator=(const TableBuilder&) = delete; + + // REQUIRES: Either Finish() or Abandon() has been called. + ~TableBuilder(); + + // Change the options used by this builder. Note: only some of the + // option fields can be changed after construction. If a field is + // not allowed to change dynamically and its value in the structure + // passed to the constructor is different from its value in the + // structure passed to this method, this method will return an error + // without changing any fields. + Status ChangeOptions(const Options& options); + + // Add key,value to the table being constructed. + // REQUIRES: key is after any previously added key according to comparator. + // REQUIRES: Finish(), Abandon() have not been called + void Add(const Slice& key, const Slice& value); + + // Advanced operation: flush any buffered key/value pairs to file. + // Can be used to ensure that two adjacent entries never live in + // the same data block. Most clients should not need to use this method. + // REQUIRES: Finish(), Abandon() have not been called + void Flush(); + + // Return non-ok iff some error has been detected. + Status status() const; + + // Finish building the table. Stops using the file passed to the + // constructor after this function returns. + // REQUIRES: Finish(), Abandon() have not been called + Status Finish(); + + // Indicate that the contents of this builder should be abandoned. Stops + // using the file passed to the constructor after this function returns. + // If the caller is not going to call Finish(), it must call Abandon() + // before destroying this builder. + // REQUIRES: Finish(), Abandon() have not been called + void Abandon(); + + // Number of calls to Add() so far. + uint64_t NumEntries() const; + + // Size of the file generated so far. If invoked after a successful + // Finish() call, returns the size of the final generated file. + uint64_t FileSize() const; + + private: + bool ok() const { return status().ok(); } + void WriteBlock(BlockBuilder* block, BlockHandle* handle); + void WriteRawBlock(const Slice& data, CompressionType, BlockHandle* handle); + + struct Rep; + Rep* rep_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/include/leveldb/write_batch.h b/saraWhatsUp/Pods/leveldb-library/include/leveldb/write_batch.h new file mode 100644 index 0000000..94d4115 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/include/leveldb/write_batch.h @@ -0,0 +1,83 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// WriteBatch holds a collection of updates to apply atomically to a DB. +// +// The updates are applied in the order in which they are added +// to the WriteBatch. For example, the value of "key" will be "v3" +// after the following batch is written: +// +// batch.Put("key", "v1"); +// batch.Delete("key"); +// batch.Put("key", "v2"); +// batch.Put("key", "v3"); +// +// Multiple threads can invoke const methods on a WriteBatch without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same WriteBatch must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ +#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ + +#include + +#include "leveldb/export.h" +#include "leveldb/status.h" + +namespace leveldb { + +class Slice; + +class LEVELDB_EXPORT WriteBatch { + public: + class LEVELDB_EXPORT Handler { + public: + virtual ~Handler(); + virtual void Put(const Slice& key, const Slice& value) = 0; + virtual void Delete(const Slice& key) = 0; + }; + + WriteBatch(); + + // Intentionally copyable. + WriteBatch(const WriteBatch&) = default; + WriteBatch& operator=(const WriteBatch&) = default; + + ~WriteBatch(); + + // Store the mapping "key->value" in the database. + void Put(const Slice& key, const Slice& value); + + // If the database contains a mapping for "key", erase it. Else do nothing. + void Delete(const Slice& key); + + // Clear all updates buffered in this batch. + void Clear(); + + // The size of the database changes caused by this batch. + // + // This number is tied to implementation details, and may change across + // releases. It is intended for LevelDB usage metrics. + size_t ApproximateSize() const; + + // Copies the operations in "source" to this batch. + // + // This runs in O(source size) time. However, the constant factor is better + // than calling Iterate() over the source batch with a Handler that replicates + // the operations into this batch. + void Append(const WriteBatch& source); + + // Support for iterating over the contents of a batch. + Status Iterate(Handler* handler) const; + + private: + friend class WriteBatchInternal; + + std::string rep_; // See comment in write_batch.cc for the format of rep_ +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/port/port.h b/saraWhatsUp/Pods/leveldb-library/port/port.h new file mode 100644 index 0000000..4b247f7 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/port/port.h @@ -0,0 +1,19 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_PORT_H_ +#define STORAGE_LEVELDB_PORT_PORT_H_ + +#include + +// Include the appropriate platform specific file below. If you are +// porting to a new platform, see "port_example.h" for documentation +// of what the new port_.h file must provide. +#if defined(LEVELDB_PLATFORM_POSIX) || defined(LEVELDB_PLATFORM_WINDOWS) +#include "port/port_stdcxx.h" +#elif defined(LEVELDB_PLATFORM_CHROMIUM) +#include "port/port_chromium.h" +#endif + +#endif // STORAGE_LEVELDB_PORT_PORT_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/port/port_example.h b/saraWhatsUp/Pods/leveldb-library/port/port_example.h new file mode 100644 index 0000000..1a8fca2 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/port/port_example.h @@ -0,0 +1,104 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// This file contains the specification, but not the implementations, +// of the types/operations/etc. that should be defined by a platform +// specific port_.h file. Use this file as a reference for +// how to port this package to a new platform. + +#ifndef STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ +#define STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ + +#include "port/thread_annotations.h" + +namespace leveldb { +namespace port { + +// TODO(jorlow): Many of these belong more in the environment class rather than +// here. We should try moving them and see if it affects perf. + +// The following boolean constant must be true on a little-endian machine +// and false otherwise. +static const bool kLittleEndian = true /* or some other expression */; + +// ------------------ Threading ------------------- + +// A Mutex represents an exclusive lock. +class LOCKABLE Mutex { + public: + Mutex(); + ~Mutex(); + + // Lock the mutex. Waits until other lockers have exited. + // Will deadlock if the mutex is already locked by this thread. + void Lock() EXCLUSIVE_LOCK_FUNCTION(); + + // Unlock the mutex. + // REQUIRES: This mutex was locked by this thread. + void Unlock() UNLOCK_FUNCTION(); + + // Optionally crash if this thread does not hold this mutex. + // The implementation must be fast, especially if NDEBUG is + // defined. The implementation is allowed to skip all checks. + void AssertHeld() ASSERT_EXCLUSIVE_LOCK(); +}; + +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + + // Atomically release *mu and block on this condition variable until + // either a call to SignalAll(), or a call to Signal() that picks + // this thread to wakeup. + // REQUIRES: this thread holds *mu + void Wait(); + + // If there are some threads waiting, wake up at least one of them. + void Signal(); + + // Wake up all waiting threads. + void SignallAll(); +}; + +// ------------------ Compression ------------------- + +// Store the snappy compression of "input[0,input_length-1]" in *output. +// Returns false if snappy is not supported by this port. +bool Snappy_Compress(const char* input, size_t input_length, + std::string* output); + +// If input[0,input_length-1] looks like a valid snappy compressed +// buffer, store the size of the uncompressed data in *result and +// return true. Else return false. +bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result); + +// Attempt to snappy uncompress input[0,input_length-1] into *output. +// Returns true if successful, false if the input is invalid lightweight +// compressed data. +// +// REQUIRES: at least the first "n" bytes of output[] must be writable +// where "n" is the result of a successful call to +// Snappy_GetUncompressedLength. +bool Snappy_Uncompress(const char* input_data, size_t input_length, + char* output); + +// ------------------ Miscellaneous ------------------- + +// If heap profiling is not supported, returns false. +// Else repeatedly calls (*func)(arg, data, n) and then returns true. +// The concatenation of all "data[0,n-1]" fragments is the heap profile. +bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg); + +// Extend the CRC to include the first n bytes of buf. +// +// Returns zero if the CRC cannot be extended using acceleration, else returns +// the newly extended CRC value (which may also be zero). +uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/port/port_stdcxx.h b/saraWhatsUp/Pods/leveldb-library/port/port_stdcxx.h new file mode 100644 index 0000000..e9cb0e5 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/port/port_stdcxx.h @@ -0,0 +1,153 @@ +// Copyright (c) 2018 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_PORT_STDCXX_H_ +#define STORAGE_LEVELDB_PORT_PORT_STDCXX_H_ + +// port/port_config.h availability is automatically detected via __has_include +// in newer compilers. If LEVELDB_HAS_PORT_CONFIG_H is defined, it overrides the +// configuration detection. +#if defined(LEVELDB_HAS_PORT_CONFIG_H) + +#if LEVELDB_HAS_PORT_CONFIG_H +#include "port/port_config.h" +#endif // LEVELDB_HAS_PORT_CONFIG_H + +#elif defined(__has_include) + +#if __has_include("port/port_config.h") +#include "port/port_config.h" +#endif // __has_include("port/port_config.h") + +#endif // defined(LEVELDB_HAS_PORT_CONFIG_H) + +#if HAVE_CRC32C +#include +#endif // HAVE_CRC32C +#if HAVE_SNAPPY +#include +#endif // HAVE_SNAPPY + +#include +#include // NOLINT +#include +#include +#include // NOLINT +#include + +#include "port/thread_annotations.h" + +namespace leveldb { +namespace port { + +static const bool kLittleEndian = !LEVELDB_IS_BIG_ENDIAN; + +class CondVar; + +// Thinly wraps std::mutex. +class LOCKABLE Mutex { + public: + Mutex() = default; + ~Mutex() = default; + + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; + + void Lock() EXCLUSIVE_LOCK_FUNCTION() { mu_.lock(); } + void Unlock() UNLOCK_FUNCTION() { mu_.unlock(); } + void AssertHeld() ASSERT_EXCLUSIVE_LOCK() {} + + private: + friend class CondVar; + std::mutex mu_; +}; + +// Thinly wraps std::condition_variable. +class CondVar { + public: + explicit CondVar(Mutex* mu) : mu_(mu) { assert(mu != nullptr); } + ~CondVar() = default; + + CondVar(const CondVar&) = delete; + CondVar& operator=(const CondVar&) = delete; + + void Wait() { + std::unique_lock lock(mu_->mu_, std::adopt_lock); + cv_.wait(lock); + lock.release(); + } + void Signal() { cv_.notify_one(); } + void SignalAll() { cv_.notify_all(); } + + private: + std::condition_variable cv_; + Mutex* const mu_; +}; + +inline bool Snappy_Compress(const char* input, size_t length, + std::string* output) { +#if HAVE_SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#else + // Silence compiler warnings about unused arguments. + (void)input; + (void)length; + (void)output; +#endif // HAVE_SNAPPY + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#if HAVE_SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + // Silence compiler warnings about unused arguments. + (void)input; + (void)length; + (void)result; + return false; +#endif // HAVE_SNAPPY +} + +inline bool Snappy_Uncompress(const char* input, size_t length, char* output) { +#if HAVE_SNAPPY + return snappy::RawUncompress(input, length, output); +#else + // Silence compiler warnings about unused arguments. + (void)input; + (void)length; + (void)output; + return false; +#endif // HAVE_SNAPPY +} + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + // Silence compiler warnings about unused arguments. + (void)func; + (void)arg; + return false; +} + +inline uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size) { +#if HAVE_CRC32C + return ::crc32c::Extend(crc, reinterpret_cast(buf), size); +#else + // Silence compiler warnings about unused arguments. + (void)crc; + (void)buf; + (void)size; + return 0; +#endif // HAVE_CRC32C +} + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_STDCXX_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/port/thread_annotations.h b/saraWhatsUp/Pods/leveldb-library/port/thread_annotations.h new file mode 100644 index 0000000..1547df9 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/port/thread_annotations.h @@ -0,0 +1,108 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ +#define STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ + +// Use Clang's thread safety analysis annotations when available. In other +// environments, the macros receive empty definitions. +// Usage documentation: https://clang.llvm.org/docs/ThreadSafetyAnalysis.html + +#if !defined(THREAD_ANNOTATION_ATTRIBUTE__) + +#if defined(__clang__) + +#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +#endif // !defined(THREAD_ANNOTATION_ATTRIBUTE__) + +#ifndef GUARDED_BY +#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) +#endif + +#ifndef PT_GUARDED_BY +#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) +#endif + +#ifndef ACQUIRED_AFTER +#define ACQUIRED_AFTER(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) +#endif + +#ifndef ACQUIRED_BEFORE +#define ACQUIRED_BEFORE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) +#endif + +#ifndef EXCLUSIVE_LOCKS_REQUIRED +#define EXCLUSIVE_LOCKS_REQUIRED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) +#endif + +#ifndef SHARED_LOCKS_REQUIRED +#define SHARED_LOCKS_REQUIRED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) +#endif + +#ifndef LOCKS_EXCLUDED +#define LOCKS_EXCLUDED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) +#endif + +#ifndef LOCK_RETURNED +#define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) +#endif + +#ifndef LOCKABLE +#define LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(lockable) +#endif + +#ifndef SCOPED_LOCKABLE +#define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) +#endif + +#ifndef EXCLUSIVE_LOCK_FUNCTION +#define EXCLUSIVE_LOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) +#endif + +#ifndef SHARED_LOCK_FUNCTION +#define SHARED_LOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) +#endif + +#ifndef EXCLUSIVE_TRYLOCK_FUNCTION +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) +#endif + +#ifndef SHARED_TRYLOCK_FUNCTION +#define SHARED_TRYLOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) +#endif + +#ifndef UNLOCK_FUNCTION +#define UNLOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) +#endif + +#ifndef NO_THREAD_SAFETY_ANALYSIS +#define NO_THREAD_SAFETY_ANALYSIS \ + THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) +#endif + +#ifndef ASSERT_EXCLUSIVE_LOCK +#define ASSERT_EXCLUSIVE_LOCK(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__)) +#endif + +#ifndef ASSERT_SHARED_LOCK +#define ASSERT_SHARED_LOCK(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__)) +#endif + +#endif // STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/table/block.cc b/saraWhatsUp/Pods/leveldb-library/table/block.cc new file mode 100644 index 0000000..ad0ee98 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/block.cc @@ -0,0 +1,266 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Decodes the blocks generated by block_builder.cc. + +#include "table/block.h" + +#include +#include + +#include "leveldb/comparator.h" +#include "table/format.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +inline uint32_t Block::NumRestarts() const { + assert(size_ >= sizeof(uint32_t)); + return DecodeFixed32(data_ + size_ - sizeof(uint32_t)); +} + +Block::Block(const BlockContents& contents) + : data_(contents.data.data()), + size_(contents.data.size()), + owned_(contents.heap_allocated) { + if (size_ < sizeof(uint32_t)) { + size_ = 0; // Error marker + } else { + size_t max_restarts_allowed = (size_ - sizeof(uint32_t)) / sizeof(uint32_t); + if (NumRestarts() > max_restarts_allowed) { + // The size is too small for NumRestarts() + size_ = 0; + } else { + restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); + } + } +} + +Block::~Block() { + if (owned_) { + delete[] data_; + } +} + +// Helper routine: decode the next block entry starting at "p", +// storing the number of shared key bytes, non_shared key bytes, +// and the length of the value in "*shared", "*non_shared", and +// "*value_length", respectively. Will not dereference past "limit". +// +// If any errors are detected, returns nullptr. Otherwise, returns a +// pointer to the key delta (just past the three decoded values). +static inline const char* DecodeEntry(const char* p, const char* limit, + uint32_t* shared, uint32_t* non_shared, + uint32_t* value_length) { + if (limit - p < 3) return nullptr; + *shared = reinterpret_cast(p)[0]; + *non_shared = reinterpret_cast(p)[1]; + *value_length = reinterpret_cast(p)[2]; + if ((*shared | *non_shared | *value_length) < 128) { + // Fast path: all three values are encoded in one byte each + p += 3; + } else { + if ((p = GetVarint32Ptr(p, limit, shared)) == nullptr) return nullptr; + if ((p = GetVarint32Ptr(p, limit, non_shared)) == nullptr) return nullptr; + if ((p = GetVarint32Ptr(p, limit, value_length)) == nullptr) return nullptr; + } + + if (static_cast(limit - p) < (*non_shared + *value_length)) { + return nullptr; + } + return p; +} + +class Block::Iter : public Iterator { + private: + const Comparator* const comparator_; + const char* const data_; // underlying block contents + uint32_t const restarts_; // Offset of restart array (list of fixed32) + uint32_t const num_restarts_; // Number of uint32_t entries in restart array + + // current_ is offset in data_ of current entry. >= restarts_ if !Valid + uint32_t current_; + uint32_t restart_index_; // Index of restart block in which current_ falls + std::string key_; + Slice value_; + Status status_; + + inline int Compare(const Slice& a, const Slice& b) const { + return comparator_->Compare(a, b); + } + + // Return the offset in data_ just past the end of the current entry. + inline uint32_t NextEntryOffset() const { + return (value_.data() + value_.size()) - data_; + } + + uint32_t GetRestartPoint(uint32_t index) { + assert(index < num_restarts_); + return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t)); + } + + void SeekToRestartPoint(uint32_t index) { + key_.clear(); + restart_index_ = index; + // current_ will be fixed by ParseNextKey(); + + // ParseNextKey() starts at the end of value_, so set value_ accordingly + uint32_t offset = GetRestartPoint(index); + value_ = Slice(data_ + offset, 0); + } + + public: + Iter(const Comparator* comparator, const char* data, uint32_t restarts, + uint32_t num_restarts) + : comparator_(comparator), + data_(data), + restarts_(restarts), + num_restarts_(num_restarts), + current_(restarts_), + restart_index_(num_restarts_) { + assert(num_restarts_ > 0); + } + + virtual bool Valid() const { return current_ < restarts_; } + virtual Status status() const { return status_; } + virtual Slice key() const { + assert(Valid()); + return key_; + } + virtual Slice value() const { + assert(Valid()); + return value_; + } + + virtual void Next() { + assert(Valid()); + ParseNextKey(); + } + + virtual void Prev() { + assert(Valid()); + + // Scan backwards to a restart point before current_ + const uint32_t original = current_; + while (GetRestartPoint(restart_index_) >= original) { + if (restart_index_ == 0) { + // No more entries + current_ = restarts_; + restart_index_ = num_restarts_; + return; + } + restart_index_--; + } + + SeekToRestartPoint(restart_index_); + do { + // Loop until end of current entry hits the start of original entry + } while (ParseNextKey() && NextEntryOffset() < original); + } + + virtual void Seek(const Slice& target) { + // Binary search in restart array to find the last restart point + // with a key < target + uint32_t left = 0; + uint32_t right = num_restarts_ - 1; + while (left < right) { + uint32_t mid = (left + right + 1) / 2; + uint32_t region_offset = GetRestartPoint(mid); + uint32_t shared, non_shared, value_length; + const char* key_ptr = + DecodeEntry(data_ + region_offset, data_ + restarts_, &shared, + &non_shared, &value_length); + if (key_ptr == nullptr || (shared != 0)) { + CorruptionError(); + return; + } + Slice mid_key(key_ptr, non_shared); + if (Compare(mid_key, target) < 0) { + // Key at "mid" is smaller than "target". Therefore all + // blocks before "mid" are uninteresting. + left = mid; + } else { + // Key at "mid" is >= "target". Therefore all blocks at or + // after "mid" are uninteresting. + right = mid - 1; + } + } + + // Linear search (within restart block) for first key >= target + SeekToRestartPoint(left); + while (true) { + if (!ParseNextKey()) { + return; + } + if (Compare(key_, target) >= 0) { + return; + } + } + } + + virtual void SeekToFirst() { + SeekToRestartPoint(0); + ParseNextKey(); + } + + virtual void SeekToLast() { + SeekToRestartPoint(num_restarts_ - 1); + while (ParseNextKey() && NextEntryOffset() < restarts_) { + // Keep skipping + } + } + + private: + void CorruptionError() { + current_ = restarts_; + restart_index_ = num_restarts_; + status_ = Status::Corruption("bad entry in block"); + key_.clear(); + value_.clear(); + } + + bool ParseNextKey() { + current_ = NextEntryOffset(); + const char* p = data_ + current_; + const char* limit = data_ + restarts_; // Restarts come right after data + if (p >= limit) { + // No more entries to return. Mark as invalid. + current_ = restarts_; + restart_index_ = num_restarts_; + return false; + } + + // Decode next entry + uint32_t shared, non_shared, value_length; + p = DecodeEntry(p, limit, &shared, &non_shared, &value_length); + if (p == nullptr || key_.size() < shared) { + CorruptionError(); + return false; + } else { + key_.resize(shared); + key_.append(p, non_shared); + value_ = Slice(p + non_shared, value_length); + while (restart_index_ + 1 < num_restarts_ && + GetRestartPoint(restart_index_ + 1) < current_) { + ++restart_index_; + } + return true; + } + } +}; + +Iterator* Block::NewIterator(const Comparator* comparator) { + if (size_ < sizeof(uint32_t)) { + return NewErrorIterator(Status::Corruption("bad block contents")); + } + const uint32_t num_restarts = NumRestarts(); + if (num_restarts == 0) { + return NewEmptyIterator(); + } else { + return new Iter(comparator, data_, restart_offset_, num_restarts); + } +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/table/block.h b/saraWhatsUp/Pods/leveldb-library/table/block.h new file mode 100644 index 0000000..c8f1f7b --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/block.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_BLOCK_H_ +#define STORAGE_LEVELDB_TABLE_BLOCK_H_ + +#include +#include + +#include "leveldb/iterator.h" + +namespace leveldb { + +struct BlockContents; +class Comparator; + +class Block { + public: + // Initialize the block with the specified contents. + explicit Block(const BlockContents& contents); + + Block(const Block&) = delete; + Block& operator=(const Block&) = delete; + + ~Block(); + + size_t size() const { return size_; } + Iterator* NewIterator(const Comparator* comparator); + + private: + class Iter; + + uint32_t NumRestarts() const; + + const char* data_; + size_t size_; + uint32_t restart_offset_; // Offset in data_ of restart array + bool owned_; // Block owns data_[] +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_BLOCK_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/table/block_builder.cc b/saraWhatsUp/Pods/leveldb-library/table/block_builder.cc new file mode 100644 index 0000000..f7cb1b0 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/block_builder.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// BlockBuilder generates blocks where keys are prefix-compressed: +// +// When we store a key, we drop the prefix shared with the previous +// string. This helps reduce the space requirement significantly. +// Furthermore, once every K keys, we do not apply the prefix +// compression and store the entire key. We call this a "restart +// point". The tail end of the block stores the offsets of all of the +// restart points, and can be used to do a binary search when looking +// for a particular key. Values are stored as-is (without compression) +// immediately following the corresponding key. +// +// An entry for a particular key-value pair has the form: +// shared_bytes: varint32 +// unshared_bytes: varint32 +// value_length: varint32 +// key_delta: char[unshared_bytes] +// value: char[value_length] +// shared_bytes == 0 for restart points. +// +// The trailer of the block has the form: +// restarts: uint32[num_restarts] +// num_restarts: uint32 +// restarts[i] contains the offset within the block of the ith restart point. + +#include "table/block_builder.h" + +#include + +#include + +#include "leveldb/comparator.h" +#include "leveldb/table_builder.h" +#include "util/coding.h" + +namespace leveldb { + +BlockBuilder::BlockBuilder(const Options* options) + : options_(options), restarts_(), counter_(0), finished_(false) { + assert(options->block_restart_interval >= 1); + restarts_.push_back(0); // First restart point is at offset 0 +} + +void BlockBuilder::Reset() { + buffer_.clear(); + restarts_.clear(); + restarts_.push_back(0); // First restart point is at offset 0 + counter_ = 0; + finished_ = false; + last_key_.clear(); +} + +size_t BlockBuilder::CurrentSizeEstimate() const { + return (buffer_.size() + // Raw data buffer + restarts_.size() * sizeof(uint32_t) + // Restart array + sizeof(uint32_t)); // Restart array length +} + +Slice BlockBuilder::Finish() { + // Append restart array + for (size_t i = 0; i < restarts_.size(); i++) { + PutFixed32(&buffer_, restarts_[i]); + } + PutFixed32(&buffer_, restarts_.size()); + finished_ = true; + return Slice(buffer_); +} + +void BlockBuilder::Add(const Slice& key, const Slice& value) { + Slice last_key_piece(last_key_); + assert(!finished_); + assert(counter_ <= options_->block_restart_interval); + assert(buffer_.empty() // No values yet? + || options_->comparator->Compare(key, last_key_piece) > 0); + size_t shared = 0; + if (counter_ < options_->block_restart_interval) { + // See how much sharing to do with previous string + const size_t min_length = std::min(last_key_piece.size(), key.size()); + while ((shared < min_length) && (last_key_piece[shared] == key[shared])) { + shared++; + } + } else { + // Restart compression + restarts_.push_back(buffer_.size()); + counter_ = 0; + } + const size_t non_shared = key.size() - shared; + + // Add "" to buffer_ + PutVarint32(&buffer_, shared); + PutVarint32(&buffer_, non_shared); + PutVarint32(&buffer_, value.size()); + + // Add string delta to buffer_ followed by value + buffer_.append(key.data() + shared, non_shared); + buffer_.append(value.data(), value.size()); + + // Update state + last_key_.resize(shared); + last_key_.append(key.data() + shared, non_shared); + assert(Slice(last_key_) == key); + counter_++; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/table/block_builder.h b/saraWhatsUp/Pods/leveldb-library/table/block_builder.h new file mode 100644 index 0000000..f91f5e6 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/block_builder.h @@ -0,0 +1,55 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ +#define STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ + +#include + +#include + +#include "leveldb/slice.h" + +namespace leveldb { + +struct Options; + +class BlockBuilder { + public: + explicit BlockBuilder(const Options* options); + + BlockBuilder(const BlockBuilder&) = delete; + BlockBuilder& operator=(const BlockBuilder&) = delete; + + // Reset the contents as if the BlockBuilder was just constructed. + void Reset(); + + // REQUIRES: Finish() has not been called since the last call to Reset(). + // REQUIRES: key is larger than any previously added key + void Add(const Slice& key, const Slice& value); + + // Finish building the block and return a slice that refers to the + // block contents. The returned slice will remain valid for the + // lifetime of this builder or until Reset() is called. + Slice Finish(); + + // Returns an estimate of the current (uncompressed) size of the block + // we are building. + size_t CurrentSizeEstimate() const; + + // Return true iff no entries have been added since the last Reset() + bool empty() const { return buffer_.empty(); } + + private: + const Options* options_; + std::string buffer_; // Destination buffer + std::vector restarts_; // Restart points + int counter_; // Number of entries emitted since restart + bool finished_; // Has Finish() been called? + std::string last_key_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/table/filter_block.cc b/saraWhatsUp/Pods/leveldb-library/table/filter_block.cc new file mode 100644 index 0000000..09ec009 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/filter_block.cc @@ -0,0 +1,106 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/filter_block.h" + +#include "leveldb/filter_policy.h" +#include "util/coding.h" + +namespace leveldb { + +// See doc/table_format.md for an explanation of the filter block format. + +// Generate new filter every 2KB of data +static const size_t kFilterBaseLg = 11; +static const size_t kFilterBase = 1 << kFilterBaseLg; + +FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy) + : policy_(policy) {} + +void FilterBlockBuilder::StartBlock(uint64_t block_offset) { + uint64_t filter_index = (block_offset / kFilterBase); + assert(filter_index >= filter_offsets_.size()); + while (filter_index > filter_offsets_.size()) { + GenerateFilter(); + } +} + +void FilterBlockBuilder::AddKey(const Slice& key) { + Slice k = key; + start_.push_back(keys_.size()); + keys_.append(k.data(), k.size()); +} + +Slice FilterBlockBuilder::Finish() { + if (!start_.empty()) { + GenerateFilter(); + } + + // Append array of per-filter offsets + const uint32_t array_offset = result_.size(); + for (size_t i = 0; i < filter_offsets_.size(); i++) { + PutFixed32(&result_, filter_offsets_[i]); + } + + PutFixed32(&result_, array_offset); + result_.push_back(kFilterBaseLg); // Save encoding parameter in result + return Slice(result_); +} + +void FilterBlockBuilder::GenerateFilter() { + const size_t num_keys = start_.size(); + if (num_keys == 0) { + // Fast path if there are no keys for this filter + filter_offsets_.push_back(result_.size()); + return; + } + + // Make list of keys from flattened key structure + start_.push_back(keys_.size()); // Simplify length computation + tmp_keys_.resize(num_keys); + for (size_t i = 0; i < num_keys; i++) { + const char* base = keys_.data() + start_[i]; + size_t length = start_[i + 1] - start_[i]; + tmp_keys_[i] = Slice(base, length); + } + + // Generate filter for current set of keys and append to result_. + filter_offsets_.push_back(result_.size()); + policy_->CreateFilter(&tmp_keys_[0], static_cast(num_keys), &result_); + + tmp_keys_.clear(); + keys_.clear(); + start_.clear(); +} + +FilterBlockReader::FilterBlockReader(const FilterPolicy* policy, + const Slice& contents) + : policy_(policy), data_(nullptr), offset_(nullptr), num_(0), base_lg_(0) { + size_t n = contents.size(); + if (n < 5) return; // 1 byte for base_lg_ and 4 for start of offset array + base_lg_ = contents[n - 1]; + uint32_t last_word = DecodeFixed32(contents.data() + n - 5); + if (last_word > n - 5) return; + data_ = contents.data(); + offset_ = data_ + last_word; + num_ = (n - 5 - last_word) / 4; +} + +bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) { + uint64_t index = block_offset >> base_lg_; + if (index < num_) { + uint32_t start = DecodeFixed32(offset_ + index * 4); + uint32_t limit = DecodeFixed32(offset_ + index * 4 + 4); + if (start <= limit && limit <= static_cast(offset_ - data_)) { + Slice filter = Slice(data_ + start, limit - start); + return policy_->KeyMayMatch(key, filter); + } else if (start == limit) { + // Empty filters do not match any keys + return false; + } + } + return true; // Errors are treated as potential matches +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/table/filter_block.h b/saraWhatsUp/Pods/leveldb-library/table/filter_block.h new file mode 100644 index 0000000..73b5399 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/filter_block.h @@ -0,0 +1,69 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A filter block is stored near the end of a Table file. It contains +// filters (e.g., bloom filters) for all data blocks in the table combined +// into a single filter block. + +#ifndef STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ +#define STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ + +#include +#include + +#include +#include + +#include "leveldb/slice.h" +#include "util/hash.h" + +namespace leveldb { + +class FilterPolicy; + +// A FilterBlockBuilder is used to construct all of the filters for a +// particular Table. It generates a single string which is stored as +// a special block in the Table. +// +// The sequence of calls to FilterBlockBuilder must match the regexp: +// (StartBlock AddKey*)* Finish +class FilterBlockBuilder { + public: + explicit FilterBlockBuilder(const FilterPolicy*); + + FilterBlockBuilder(const FilterBlockBuilder&) = delete; + FilterBlockBuilder& operator=(const FilterBlockBuilder&) = delete; + + void StartBlock(uint64_t block_offset); + void AddKey(const Slice& key); + Slice Finish(); + + private: + void GenerateFilter(); + + const FilterPolicy* policy_; + std::string keys_; // Flattened key contents + std::vector start_; // Starting index in keys_ of each key + std::string result_; // Filter data computed so far + std::vector tmp_keys_; // policy_->CreateFilter() argument + std::vector filter_offsets_; +}; + +class FilterBlockReader { + public: + // REQUIRES: "contents" and *policy must stay live while *this is live. + FilterBlockReader(const FilterPolicy* policy, const Slice& contents); + bool KeyMayMatch(uint64_t block_offset, const Slice& key); + + private: + const FilterPolicy* policy_; + const char* data_; // Pointer to filter data (at block-start) + const char* offset_; // Pointer to beginning of offset array (at block-end) + size_t num_; // Number of entries in offset array + size_t base_lg_; // Encoding parameter (see kFilterBaseLg in .cc file) +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/table/format.cc b/saraWhatsUp/Pods/leveldb-library/table/format.cc new file mode 100644 index 0000000..e183977 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/format.cc @@ -0,0 +1,141 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/format.h" + +#include "leveldb/env.h" +#include "port/port.h" +#include "table/block.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { + +void BlockHandle::EncodeTo(std::string* dst) const { + // Sanity check that all fields have been set + assert(offset_ != ~static_cast(0)); + assert(size_ != ~static_cast(0)); + PutVarint64(dst, offset_); + PutVarint64(dst, size_); +} + +Status BlockHandle::DecodeFrom(Slice* input) { + if (GetVarint64(input, &offset_) && GetVarint64(input, &size_)) { + return Status::OK(); + } else { + return Status::Corruption("bad block handle"); + } +} + +void Footer::EncodeTo(std::string* dst) const { + const size_t original_size = dst->size(); + metaindex_handle_.EncodeTo(dst); + index_handle_.EncodeTo(dst); + dst->resize(2 * BlockHandle::kMaxEncodedLength); // Padding + PutFixed32(dst, static_cast(kTableMagicNumber & 0xffffffffu)); + PutFixed32(dst, static_cast(kTableMagicNumber >> 32)); + assert(dst->size() == original_size + kEncodedLength); + (void)original_size; // Disable unused variable warning. +} + +Status Footer::DecodeFrom(Slice* input) { + const char* magic_ptr = input->data() + kEncodedLength - 8; + const uint32_t magic_lo = DecodeFixed32(magic_ptr); + const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4); + const uint64_t magic = ((static_cast(magic_hi) << 32) | + (static_cast(magic_lo))); + if (magic != kTableMagicNumber) { + return Status::Corruption("not an sstable (bad magic number)"); + } + + Status result = metaindex_handle_.DecodeFrom(input); + if (result.ok()) { + result = index_handle_.DecodeFrom(input); + } + if (result.ok()) { + // We skip over any leftover data (just padding for now) in "input" + const char* end = magic_ptr + 8; + *input = Slice(end, input->data() + input->size() - end); + } + return result; +} + +Status ReadBlock(RandomAccessFile* file, const ReadOptions& options, + const BlockHandle& handle, BlockContents* result) { + result->data = Slice(); + result->cachable = false; + result->heap_allocated = false; + + // Read the block contents as well as the type/crc footer. + // See table_builder.cc for the code that built this structure. + size_t n = static_cast(handle.size()); + char* buf = new char[n + kBlockTrailerSize]; + Slice contents; + Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf); + if (!s.ok()) { + delete[] buf; + return s; + } + if (contents.size() != n + kBlockTrailerSize) { + delete[] buf; + return Status::Corruption("truncated block read"); + } + + // Check the crc of the type and the block contents + const char* data = contents.data(); // Pointer to where Read put the data + if (options.verify_checksums) { + const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1)); + const uint32_t actual = crc32c::Value(data, n + 1); + if (actual != crc) { + delete[] buf; + s = Status::Corruption("block checksum mismatch"); + return s; + } + } + + switch (data[n]) { + case kNoCompression: + if (data != buf) { + // File implementation gave us pointer to some other data. + // Use it directly under the assumption that it will be live + // while the file is open. + delete[] buf; + result->data = Slice(data, n); + result->heap_allocated = false; + result->cachable = false; // Do not double-cache + } else { + result->data = Slice(buf, n); + result->heap_allocated = true; + result->cachable = true; + } + + // Ok + break; + case kSnappyCompression: { + size_t ulength = 0; + if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { + delete[] buf; + return Status::Corruption("corrupted compressed block contents"); + } + char* ubuf = new char[ulength]; + if (!port::Snappy_Uncompress(data, n, ubuf)) { + delete[] buf; + delete[] ubuf; + return Status::Corruption("corrupted compressed block contents"); + } + delete[] buf; + result->data = Slice(ubuf, ulength); + result->heap_allocated = true; + result->cachable = true; + break; + } + default: + delete[] buf; + return Status::Corruption("bad block type"); + } + + return Status::OK(); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/table/format.h b/saraWhatsUp/Pods/leveldb-library/table/format.h new file mode 100644 index 0000000..2ad145c --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/format.h @@ -0,0 +1,100 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_FORMAT_H_ +#define STORAGE_LEVELDB_TABLE_FORMAT_H_ + +#include + +#include + +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "leveldb/table_builder.h" + +namespace leveldb { + +class Block; +class RandomAccessFile; +struct ReadOptions; + +// BlockHandle is a pointer to the extent of a file that stores a data +// block or a meta block. +class BlockHandle { + public: + // Maximum encoding length of a BlockHandle + enum { kMaxEncodedLength = 10 + 10 }; + + BlockHandle(); + + // The offset of the block in the file. + uint64_t offset() const { return offset_; } + void set_offset(uint64_t offset) { offset_ = offset; } + + // The size of the stored block + uint64_t size() const { return size_; } + void set_size(uint64_t size) { size_ = size; } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(Slice* input); + + private: + uint64_t offset_; + uint64_t size_; +}; + +// Footer encapsulates the fixed information stored at the tail +// end of every table file. +class Footer { + public: + // Encoded length of a Footer. Note that the serialization of a + // Footer will always occupy exactly this many bytes. It consists + // of two block handles and a magic number. + enum { kEncodedLength = 2 * BlockHandle::kMaxEncodedLength + 8 }; + + Footer() {} + + // The block handle for the metaindex block of the table + const BlockHandle& metaindex_handle() const { return metaindex_handle_; } + void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; } + + // The block handle for the index block of the table + const BlockHandle& index_handle() const { return index_handle_; } + void set_index_handle(const BlockHandle& h) { index_handle_ = h; } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(Slice* input); + + private: + BlockHandle metaindex_handle_; + BlockHandle index_handle_; +}; + +// kTableMagicNumber was picked by running +// echo http://code.google.com/p/leveldb/ | sha1sum +// and taking the leading 64 bits. +static const uint64_t kTableMagicNumber = 0xdb4775248b80fb57ull; + +// 1-byte type + 32-bit crc +static const size_t kBlockTrailerSize = 5; + +struct BlockContents { + Slice data; // Actual contents of data + bool cachable; // True iff data can be cached + bool heap_allocated; // True iff caller should delete[] data.data() +}; + +// Read the block identified by "handle" from "file". On failure +// return non-OK. On success fill *result and return OK. +Status ReadBlock(RandomAccessFile* file, const ReadOptions& options, + const BlockHandle& handle, BlockContents* result); + +// Implementation details follow. Clients should ignore, + +inline BlockHandle::BlockHandle() + : offset_(~static_cast(0)), size_(~static_cast(0)) {} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_FORMAT_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/table/iterator.cc b/saraWhatsUp/Pods/leveldb-library/table/iterator.cc new file mode 100644 index 0000000..dfef083 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/iterator.cc @@ -0,0 +1,76 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/iterator.h" + +namespace leveldb { + +Iterator::Iterator() { + cleanup_head_.function = nullptr; + cleanup_head_.next = nullptr; +} + +Iterator::~Iterator() { + if (!cleanup_head_.IsEmpty()) { + cleanup_head_.Run(); + for (CleanupNode* node = cleanup_head_.next; node != nullptr;) { + node->Run(); + CleanupNode* next_node = node->next; + delete node; + node = next_node; + } + } +} + +void Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) { + assert(func != nullptr); + CleanupNode* node; + if (cleanup_head_.IsEmpty()) { + node = &cleanup_head_; + } else { + node = new CleanupNode(); + node->next = cleanup_head_.next; + cleanup_head_.next = node; + } + node->function = func; + node->arg1 = arg1; + node->arg2 = arg2; +} + +namespace { + +class EmptyIterator : public Iterator { + public: + EmptyIterator(const Status& s) : status_(s) {} + ~EmptyIterator() override = default; + + bool Valid() const override { return false; } + void Seek(const Slice& target) override {} + void SeekToFirst() override {} + void SeekToLast() override {} + void Next() override { assert(false); } + void Prev() override { assert(false); } + Slice key() const override { + assert(false); + return Slice(); + } + Slice value() const override { + assert(false); + return Slice(); + } + Status status() const override { return status_; } + + private: + Status status_; +}; + +} // anonymous namespace + +Iterator* NewEmptyIterator() { return new EmptyIterator(Status::OK()); } + +Iterator* NewErrorIterator(const Status& status) { + return new EmptyIterator(status); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/table/iterator_wrapper.h b/saraWhatsUp/Pods/leveldb-library/table/iterator_wrapper.h new file mode 100644 index 0000000..c230572 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/iterator_wrapper.h @@ -0,0 +1,92 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ +#define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ + +#include "leveldb/iterator.h" +#include "leveldb/slice.h" + +namespace leveldb { + +// A internal wrapper class with an interface similar to Iterator that +// caches the valid() and key() results for an underlying iterator. +// This can help avoid virtual function calls and also gives better +// cache locality. +class IteratorWrapper { + public: + IteratorWrapper() : iter_(nullptr), valid_(false) {} + explicit IteratorWrapper(Iterator* iter) : iter_(nullptr) { Set(iter); } + ~IteratorWrapper() { delete iter_; } + Iterator* iter() const { return iter_; } + + // Takes ownership of "iter" and will delete it when destroyed, or + // when Set() is invoked again. + void Set(Iterator* iter) { + delete iter_; + iter_ = iter; + if (iter_ == nullptr) { + valid_ = false; + } else { + Update(); + } + } + + // Iterator interface methods + bool Valid() const { return valid_; } + Slice key() const { + assert(Valid()); + return key_; + } + Slice value() const { + assert(Valid()); + return iter_->value(); + } + // Methods below require iter() != nullptr + Status status() const { + assert(iter_); + return iter_->status(); + } + void Next() { + assert(iter_); + iter_->Next(); + Update(); + } + void Prev() { + assert(iter_); + iter_->Prev(); + Update(); + } + void Seek(const Slice& k) { + assert(iter_); + iter_->Seek(k); + Update(); + } + void SeekToFirst() { + assert(iter_); + iter_->SeekToFirst(); + Update(); + } + void SeekToLast() { + assert(iter_); + iter_->SeekToLast(); + Update(); + } + + private: + void Update() { + valid_ = iter_->Valid(); + if (valid_) { + key_ = iter_->key(); + } + } + + Iterator* iter_; + bool valid_; + Slice key_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/table/merger.cc b/saraWhatsUp/Pods/leveldb-library/table/merger.cc new file mode 100644 index 0000000..1bbc6cf --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/merger.cc @@ -0,0 +1,191 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/merger.h" + +#include "leveldb/comparator.h" +#include "leveldb/iterator.h" +#include "table/iterator_wrapper.h" + +namespace leveldb { + +namespace { +class MergingIterator : public Iterator { + public: + MergingIterator(const Comparator* comparator, Iterator** children, int n) + : comparator_(comparator), + children_(new IteratorWrapper[n]), + n_(n), + current_(nullptr), + direction_(kForward) { + for (int i = 0; i < n; i++) { + children_[i].Set(children[i]); + } + } + + virtual ~MergingIterator() { delete[] children_; } + + virtual bool Valid() const { return (current_ != nullptr); } + + virtual void SeekToFirst() { + for (int i = 0; i < n_; i++) { + children_[i].SeekToFirst(); + } + FindSmallest(); + direction_ = kForward; + } + + virtual void SeekToLast() { + for (int i = 0; i < n_; i++) { + children_[i].SeekToLast(); + } + FindLargest(); + direction_ = kReverse; + } + + virtual void Seek(const Slice& target) { + for (int i = 0; i < n_; i++) { + children_[i].Seek(target); + } + FindSmallest(); + direction_ = kForward; + } + + virtual void Next() { + assert(Valid()); + + // Ensure that all children are positioned after key(). + // If we are moving in the forward direction, it is already + // true for all of the non-current_ children since current_ is + // the smallest child and key() == current_->key(). Otherwise, + // we explicitly position the non-current_ children. + if (direction_ != kForward) { + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child != current_) { + child->Seek(key()); + if (child->Valid() && + comparator_->Compare(key(), child->key()) == 0) { + child->Next(); + } + } + } + direction_ = kForward; + } + + current_->Next(); + FindSmallest(); + } + + virtual void Prev() { + assert(Valid()); + + // Ensure that all children are positioned before key(). + // If we are moving in the reverse direction, it is already + // true for all of the non-current_ children since current_ is + // the largest child and key() == current_->key(). Otherwise, + // we explicitly position the non-current_ children. + if (direction_ != kReverse) { + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child != current_) { + child->Seek(key()); + if (child->Valid()) { + // Child is at first entry >= key(). Step back one to be < key() + child->Prev(); + } else { + // Child has no entries >= key(). Position at last entry. + child->SeekToLast(); + } + } + } + direction_ = kReverse; + } + + current_->Prev(); + FindLargest(); + } + + virtual Slice key() const { + assert(Valid()); + return current_->key(); + } + + virtual Slice value() const { + assert(Valid()); + return current_->value(); + } + + virtual Status status() const { + Status status; + for (int i = 0; i < n_; i++) { + status = children_[i].status(); + if (!status.ok()) { + break; + } + } + return status; + } + + private: + // Which direction is the iterator moving? + enum Direction { kForward, kReverse }; + + void FindSmallest(); + void FindLargest(); + + // We might want to use a heap in case there are lots of children. + // For now we use a simple array since we expect a very small number + // of children in leveldb. + const Comparator* comparator_; + IteratorWrapper* children_; + int n_; + IteratorWrapper* current_; + Direction direction_; +}; + +void MergingIterator::FindSmallest() { + IteratorWrapper* smallest = nullptr; + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child->Valid()) { + if (smallest == nullptr) { + smallest = child; + } else if (comparator_->Compare(child->key(), smallest->key()) < 0) { + smallest = child; + } + } + } + current_ = smallest; +} + +void MergingIterator::FindLargest() { + IteratorWrapper* largest = nullptr; + for (int i = n_ - 1; i >= 0; i--) { + IteratorWrapper* child = &children_[i]; + if (child->Valid()) { + if (largest == nullptr) { + largest = child; + } else if (comparator_->Compare(child->key(), largest->key()) > 0) { + largest = child; + } + } + } + current_ = largest; +} +} // namespace + +Iterator* NewMergingIterator(const Comparator* comparator, Iterator** children, + int n) { + assert(n >= 0); + if (n == 0) { + return NewEmptyIterator(); + } else if (n == 1) { + return children[0]; + } else { + return new MergingIterator(comparator, children, n); + } +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/table/merger.h b/saraWhatsUp/Pods/leveldb-library/table/merger.h new file mode 100644 index 0000000..41cedc5 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/merger.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_MERGER_H_ +#define STORAGE_LEVELDB_TABLE_MERGER_H_ + +namespace leveldb { + +class Comparator; +class Iterator; + +// Return an iterator that provided the union of the data in +// children[0,n-1]. Takes ownership of the child iterators and +// will delete them when the result iterator is deleted. +// +// The result does no duplicate suppression. I.e., if a particular +// key is present in K child iterators, it will be yielded K times. +// +// REQUIRES: n >= 0 +Iterator* NewMergingIterator(const Comparator* comparator, Iterator** children, + int n); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_MERGER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/table/table.cc b/saraWhatsUp/Pods/leveldb-library/table/table.cc new file mode 100644 index 0000000..b07bc88 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/table.cc @@ -0,0 +1,273 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table.h" + +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/options.h" +#include "table/block.h" +#include "table/filter_block.h" +#include "table/format.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" + +namespace leveldb { + +struct Table::Rep { + ~Rep() { + delete filter; + delete[] filter_data; + delete index_block; + } + + Options options; + Status status; + RandomAccessFile* file; + uint64_t cache_id; + FilterBlockReader* filter; + const char* filter_data; + + BlockHandle metaindex_handle; // Handle to metaindex_block: saved from footer + Block* index_block; +}; + +Status Table::Open(const Options& options, RandomAccessFile* file, + uint64_t size, Table** table) { + *table = nullptr; + if (size < Footer::kEncodedLength) { + return Status::Corruption("file is too short to be an sstable"); + } + + char footer_space[Footer::kEncodedLength]; + Slice footer_input; + Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength, + &footer_input, footer_space); + if (!s.ok()) return s; + + Footer footer; + s = footer.DecodeFrom(&footer_input); + if (!s.ok()) return s; + + // Read the index block + BlockContents index_block_contents; + if (s.ok()) { + ReadOptions opt; + if (options.paranoid_checks) { + opt.verify_checksums = true; + } + s = ReadBlock(file, opt, footer.index_handle(), &index_block_contents); + } + + if (s.ok()) { + // We've successfully read the footer and the index block: we're + // ready to serve requests. + Block* index_block = new Block(index_block_contents); + Rep* rep = new Table::Rep; + rep->options = options; + rep->file = file; + rep->metaindex_handle = footer.metaindex_handle(); + rep->index_block = index_block; + rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0); + rep->filter_data = nullptr; + rep->filter = nullptr; + *table = new Table(rep); + (*table)->ReadMeta(footer); + } + + return s; +} + +void Table::ReadMeta(const Footer& footer) { + if (rep_->options.filter_policy == nullptr) { + return; // Do not need any metadata + } + + // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates + // it is an empty block. + ReadOptions opt; + if (rep_->options.paranoid_checks) { + opt.verify_checksums = true; + } + BlockContents contents; + if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) { + // Do not propagate errors since meta info is not needed for operation + return; + } + Block* meta = new Block(contents); + + Iterator* iter = meta->NewIterator(BytewiseComparator()); + std::string key = "filter."; + key.append(rep_->options.filter_policy->Name()); + iter->Seek(key); + if (iter->Valid() && iter->key() == Slice(key)) { + ReadFilter(iter->value()); + } + delete iter; + delete meta; +} + +void Table::ReadFilter(const Slice& filter_handle_value) { + Slice v = filter_handle_value; + BlockHandle filter_handle; + if (!filter_handle.DecodeFrom(&v).ok()) { + return; + } + + // We might want to unify with ReadBlock() if we start + // requiring checksum verification in Table::Open. + ReadOptions opt; + if (rep_->options.paranoid_checks) { + opt.verify_checksums = true; + } + BlockContents block; + if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) { + return; + } + if (block.heap_allocated) { + rep_->filter_data = block.data.data(); // Will need to delete later + } + rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data); +} + +Table::~Table() { delete rep_; } + +static void DeleteBlock(void* arg, void* ignored) { + delete reinterpret_cast(arg); +} + +static void DeleteCachedBlock(const Slice& key, void* value) { + Block* block = reinterpret_cast(value); + delete block; +} + +static void ReleaseBlock(void* arg, void* h) { + Cache* cache = reinterpret_cast(arg); + Cache::Handle* handle = reinterpret_cast(h); + cache->Release(handle); +} + +// Convert an index iterator value (i.e., an encoded BlockHandle) +// into an iterator over the contents of the corresponding block. +Iterator* Table::BlockReader(void* arg, const ReadOptions& options, + const Slice& index_value) { + Table* table = reinterpret_cast(arg); + Cache* block_cache = table->rep_->options.block_cache; + Block* block = nullptr; + Cache::Handle* cache_handle = nullptr; + + BlockHandle handle; + Slice input = index_value; + Status s = handle.DecodeFrom(&input); + // We intentionally allow extra stuff in index_value so that we + // can add more features in the future. + + if (s.ok()) { + BlockContents contents; + if (block_cache != nullptr) { + char cache_key_buffer[16]; + EncodeFixed64(cache_key_buffer, table->rep_->cache_id); + EncodeFixed64(cache_key_buffer + 8, handle.offset()); + Slice key(cache_key_buffer, sizeof(cache_key_buffer)); + cache_handle = block_cache->Lookup(key); + if (cache_handle != nullptr) { + block = reinterpret_cast(block_cache->Value(cache_handle)); + } else { + s = ReadBlock(table->rep_->file, options, handle, &contents); + if (s.ok()) { + block = new Block(contents); + if (contents.cachable && options.fill_cache) { + cache_handle = block_cache->Insert(key, block, block->size(), + &DeleteCachedBlock); + } + } + } + } else { + s = ReadBlock(table->rep_->file, options, handle, &contents); + if (s.ok()) { + block = new Block(contents); + } + } + } + + Iterator* iter; + if (block != nullptr) { + iter = block->NewIterator(table->rep_->options.comparator); + if (cache_handle == nullptr) { + iter->RegisterCleanup(&DeleteBlock, block, nullptr); + } else { + iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle); + } + } else { + iter = NewErrorIterator(s); + } + return iter; +} + +Iterator* Table::NewIterator(const ReadOptions& options) const { + return NewTwoLevelIterator( + rep_->index_block->NewIterator(rep_->options.comparator), + &Table::BlockReader, const_cast(this), options); +} + +Status Table::InternalGet(const ReadOptions& options, const Slice& k, void* arg, + void (*handle_result)(void*, const Slice&, + const Slice&)) { + Status s; + Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator); + iiter->Seek(k); + if (iiter->Valid()) { + Slice handle_value = iiter->value(); + FilterBlockReader* filter = rep_->filter; + BlockHandle handle; + if (filter != nullptr && handle.DecodeFrom(&handle_value).ok() && + !filter->KeyMayMatch(handle.offset(), k)) { + // Not found + } else { + Iterator* block_iter = BlockReader(this, options, iiter->value()); + block_iter->Seek(k); + if (block_iter->Valid()) { + (*handle_result)(arg, block_iter->key(), block_iter->value()); + } + s = block_iter->status(); + delete block_iter; + } + } + if (s.ok()) { + s = iiter->status(); + } + delete iiter; + return s; +} + +uint64_t Table::ApproximateOffsetOf(const Slice& key) const { + Iterator* index_iter = + rep_->index_block->NewIterator(rep_->options.comparator); + index_iter->Seek(key); + uint64_t result; + if (index_iter->Valid()) { + BlockHandle handle; + Slice input = index_iter->value(); + Status s = handle.DecodeFrom(&input); + if (s.ok()) { + result = handle.offset(); + } else { + // Strange: we can't decode the block handle in the index block. + // We'll just return the offset of the metaindex block, which is + // close to the whole file size for this case. + result = rep_->metaindex_handle.offset(); + } + } else { + // key is past the last key in the file. Approximate the offset + // by returning the offset of the metaindex block (which is + // right near the end of the file). + result = rep_->metaindex_handle.offset(); + } + delete index_iter; + return result; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/table/table_builder.cc b/saraWhatsUp/Pods/leveldb-library/table/table_builder.cc new file mode 100644 index 0000000..278febf --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/table_builder.cc @@ -0,0 +1,265 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table_builder.h" + +#include + +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/options.h" +#include "table/block_builder.h" +#include "table/filter_block.h" +#include "table/format.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { + +struct TableBuilder::Rep { + Rep(const Options& opt, WritableFile* f) + : options(opt), + index_block_options(opt), + file(f), + offset(0), + data_block(&options), + index_block(&index_block_options), + num_entries(0), + closed(false), + filter_block(opt.filter_policy == nullptr + ? nullptr + : new FilterBlockBuilder(opt.filter_policy)), + pending_index_entry(false) { + index_block_options.block_restart_interval = 1; + } + + Options options; + Options index_block_options; + WritableFile* file; + uint64_t offset; + Status status; + BlockBuilder data_block; + BlockBuilder index_block; + std::string last_key; + int64_t num_entries; + bool closed; // Either Finish() or Abandon() has been called. + FilterBlockBuilder* filter_block; + + // We do not emit the index entry for a block until we have seen the + // first key for the next data block. This allows us to use shorter + // keys in the index block. For example, consider a block boundary + // between the keys "the quick brown fox" and "the who". We can use + // "the r" as the key for the index block entry since it is >= all + // entries in the first block and < all entries in subsequent + // blocks. + // + // Invariant: r->pending_index_entry is true only if data_block is empty. + bool pending_index_entry; + BlockHandle pending_handle; // Handle to add to index block + + std::string compressed_output; +}; + +TableBuilder::TableBuilder(const Options& options, WritableFile* file) + : rep_(new Rep(options, file)) { + if (rep_->filter_block != nullptr) { + rep_->filter_block->StartBlock(0); + } +} + +TableBuilder::~TableBuilder() { + assert(rep_->closed); // Catch errors where caller forgot to call Finish() + delete rep_->filter_block; + delete rep_; +} + +Status TableBuilder::ChangeOptions(const Options& options) { + // Note: if more fields are added to Options, update + // this function to catch changes that should not be allowed to + // change in the middle of building a Table. + if (options.comparator != rep_->options.comparator) { + return Status::InvalidArgument("changing comparator while building table"); + } + + // Note that any live BlockBuilders point to rep_->options and therefore + // will automatically pick up the updated options. + rep_->options = options; + rep_->index_block_options = options; + rep_->index_block_options.block_restart_interval = 1; + return Status::OK(); +} + +void TableBuilder::Add(const Slice& key, const Slice& value) { + Rep* r = rep_; + assert(!r->closed); + if (!ok()) return; + if (r->num_entries > 0) { + assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0); + } + + if (r->pending_index_entry) { + assert(r->data_block.empty()); + r->options.comparator->FindShortestSeparator(&r->last_key, key); + std::string handle_encoding; + r->pending_handle.EncodeTo(&handle_encoding); + r->index_block.Add(r->last_key, Slice(handle_encoding)); + r->pending_index_entry = false; + } + + if (r->filter_block != nullptr) { + r->filter_block->AddKey(key); + } + + r->last_key.assign(key.data(), key.size()); + r->num_entries++; + r->data_block.Add(key, value); + + const size_t estimated_block_size = r->data_block.CurrentSizeEstimate(); + if (estimated_block_size >= r->options.block_size) { + Flush(); + } +} + +void TableBuilder::Flush() { + Rep* r = rep_; + assert(!r->closed); + if (!ok()) return; + if (r->data_block.empty()) return; + assert(!r->pending_index_entry); + WriteBlock(&r->data_block, &r->pending_handle); + if (ok()) { + r->pending_index_entry = true; + r->status = r->file->Flush(); + } + if (r->filter_block != nullptr) { + r->filter_block->StartBlock(r->offset); + } +} + +void TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) { + // File format contains a sequence of blocks where each block has: + // block_data: uint8[n] + // type: uint8 + // crc: uint32 + assert(ok()); + Rep* r = rep_; + Slice raw = block->Finish(); + + Slice block_contents; + CompressionType type = r->options.compression; + // TODO(postrelease): Support more compression options: zlib? + switch (type) { + case kNoCompression: + block_contents = raw; + break; + + case kSnappyCompression: { + std::string* compressed = &r->compressed_output; + if (port::Snappy_Compress(raw.data(), raw.size(), compressed) && + compressed->size() < raw.size() - (raw.size() / 8u)) { + block_contents = *compressed; + } else { + // Snappy not supported, or compressed less than 12.5%, so just + // store uncompressed form + block_contents = raw; + type = kNoCompression; + } + break; + } + } + WriteRawBlock(block_contents, type, handle); + r->compressed_output.clear(); + block->Reset(); +} + +void TableBuilder::WriteRawBlock(const Slice& block_contents, + CompressionType type, BlockHandle* handle) { + Rep* r = rep_; + handle->set_offset(r->offset); + handle->set_size(block_contents.size()); + r->status = r->file->Append(block_contents); + if (r->status.ok()) { + char trailer[kBlockTrailerSize]; + trailer[0] = type; + uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size()); + crc = crc32c::Extend(crc, trailer, 1); // Extend crc to cover block type + EncodeFixed32(trailer + 1, crc32c::Mask(crc)); + r->status = r->file->Append(Slice(trailer, kBlockTrailerSize)); + if (r->status.ok()) { + r->offset += block_contents.size() + kBlockTrailerSize; + } + } +} + +Status TableBuilder::status() const { return rep_->status; } + +Status TableBuilder::Finish() { + Rep* r = rep_; + Flush(); + assert(!r->closed); + r->closed = true; + + BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle; + + // Write filter block + if (ok() && r->filter_block != nullptr) { + WriteRawBlock(r->filter_block->Finish(), kNoCompression, + &filter_block_handle); + } + + // Write metaindex block + if (ok()) { + BlockBuilder meta_index_block(&r->options); + if (r->filter_block != nullptr) { + // Add mapping from "filter.Name" to location of filter data + std::string key = "filter."; + key.append(r->options.filter_policy->Name()); + std::string handle_encoding; + filter_block_handle.EncodeTo(&handle_encoding); + meta_index_block.Add(key, handle_encoding); + } + + // TODO(postrelease): Add stats and other meta blocks + WriteBlock(&meta_index_block, &metaindex_block_handle); + } + + // Write index block + if (ok()) { + if (r->pending_index_entry) { + r->options.comparator->FindShortSuccessor(&r->last_key); + std::string handle_encoding; + r->pending_handle.EncodeTo(&handle_encoding); + r->index_block.Add(r->last_key, Slice(handle_encoding)); + r->pending_index_entry = false; + } + WriteBlock(&r->index_block, &index_block_handle); + } + + // Write footer + if (ok()) { + Footer footer; + footer.set_metaindex_handle(metaindex_block_handle); + footer.set_index_handle(index_block_handle); + std::string footer_encoding; + footer.EncodeTo(&footer_encoding); + r->status = r->file->Append(footer_encoding); + if (r->status.ok()) { + r->offset += footer_encoding.size(); + } + } + return r->status; +} + +void TableBuilder::Abandon() { + Rep* r = rep_; + assert(!r->closed); + r->closed = true; +} + +uint64_t TableBuilder::NumEntries() const { return rep_->num_entries; } + +uint64_t TableBuilder::FileSize() const { return rep_->offset; } + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/table/two_level_iterator.cc b/saraWhatsUp/Pods/leveldb-library/table/two_level_iterator.cc new file mode 100644 index 0000000..5340a4d --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/two_level_iterator.cc @@ -0,0 +1,171 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/two_level_iterator.h" + +#include "leveldb/table.h" +#include "table/block.h" +#include "table/format.h" +#include "table/iterator_wrapper.h" + +namespace leveldb { + +namespace { + +typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&); + +class TwoLevelIterator : public Iterator { + public: + TwoLevelIterator(Iterator* index_iter, BlockFunction block_function, + void* arg, const ReadOptions& options); + + virtual ~TwoLevelIterator(); + + virtual void Seek(const Slice& target); + virtual void SeekToFirst(); + virtual void SeekToLast(); + virtual void Next(); + virtual void Prev(); + + virtual bool Valid() const { return data_iter_.Valid(); } + virtual Slice key() const { + assert(Valid()); + return data_iter_.key(); + } + virtual Slice value() const { + assert(Valid()); + return data_iter_.value(); + } + virtual Status status() const { + // It'd be nice if status() returned a const Status& instead of a Status + if (!index_iter_.status().ok()) { + return index_iter_.status(); + } else if (data_iter_.iter() != nullptr && !data_iter_.status().ok()) { + return data_iter_.status(); + } else { + return status_; + } + } + + private: + void SaveError(const Status& s) { + if (status_.ok() && !s.ok()) status_ = s; + } + void SkipEmptyDataBlocksForward(); + void SkipEmptyDataBlocksBackward(); + void SetDataIterator(Iterator* data_iter); + void InitDataBlock(); + + BlockFunction block_function_; + void* arg_; + const ReadOptions options_; + Status status_; + IteratorWrapper index_iter_; + IteratorWrapper data_iter_; // May be nullptr + // If data_iter_ is non-null, then "data_block_handle_" holds the + // "index_value" passed to block_function_ to create the data_iter_. + std::string data_block_handle_; +}; + +TwoLevelIterator::TwoLevelIterator(Iterator* index_iter, + BlockFunction block_function, void* arg, + const ReadOptions& options) + : block_function_(block_function), + arg_(arg), + options_(options), + index_iter_(index_iter), + data_iter_(nullptr) {} + +TwoLevelIterator::~TwoLevelIterator() {} + +void TwoLevelIterator::Seek(const Slice& target) { + index_iter_.Seek(target); + InitDataBlock(); + if (data_iter_.iter() != nullptr) data_iter_.Seek(target); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::SeekToFirst() { + index_iter_.SeekToFirst(); + InitDataBlock(); + if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst(); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::SeekToLast() { + index_iter_.SeekToLast(); + InitDataBlock(); + if (data_iter_.iter() != nullptr) data_iter_.SeekToLast(); + SkipEmptyDataBlocksBackward(); +} + +void TwoLevelIterator::Next() { + assert(Valid()); + data_iter_.Next(); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::Prev() { + assert(Valid()); + data_iter_.Prev(); + SkipEmptyDataBlocksBackward(); +} + +void TwoLevelIterator::SkipEmptyDataBlocksForward() { + while (data_iter_.iter() == nullptr || !data_iter_.Valid()) { + // Move to next block + if (!index_iter_.Valid()) { + SetDataIterator(nullptr); + return; + } + index_iter_.Next(); + InitDataBlock(); + if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst(); + } +} + +void TwoLevelIterator::SkipEmptyDataBlocksBackward() { + while (data_iter_.iter() == nullptr || !data_iter_.Valid()) { + // Move to next block + if (!index_iter_.Valid()) { + SetDataIterator(nullptr); + return; + } + index_iter_.Prev(); + InitDataBlock(); + if (data_iter_.iter() != nullptr) data_iter_.SeekToLast(); + } +} + +void TwoLevelIterator::SetDataIterator(Iterator* data_iter) { + if (data_iter_.iter() != nullptr) SaveError(data_iter_.status()); + data_iter_.Set(data_iter); +} + +void TwoLevelIterator::InitDataBlock() { + if (!index_iter_.Valid()) { + SetDataIterator(nullptr); + } else { + Slice handle = index_iter_.value(); + if (data_iter_.iter() != nullptr && + handle.compare(data_block_handle_) == 0) { + // data_iter_ is already constructed with this iterator, so + // no need to change anything + } else { + Iterator* iter = (*block_function_)(arg_, options_, handle); + data_block_handle_.assign(handle.data(), handle.size()); + SetDataIterator(iter); + } + } +} + +} // namespace + +Iterator* NewTwoLevelIterator(Iterator* index_iter, + BlockFunction block_function, void* arg, + const ReadOptions& options) { + return new TwoLevelIterator(index_iter, block_function, arg, options); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/table/two_level_iterator.h b/saraWhatsUp/Pods/leveldb-library/table/two_level_iterator.h new file mode 100644 index 0000000..81ffe80 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/table/two_level_iterator.h @@ -0,0 +1,31 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ +#define STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ + +#include "leveldb/iterator.h" + +namespace leveldb { + +struct ReadOptions; + +// Return a new two level iterator. A two-level iterator contains an +// index iterator whose values point to a sequence of blocks where +// each block is itself a sequence of key,value pairs. The returned +// two-level iterator yields the concatenation of all key/value pairs +// in the sequence of blocks. Takes ownership of "index_iter" and +// will delete it when no longer needed. +// +// Uses a supplied function to convert an index_iter value into +// an iterator over the contents of the corresponding block. +Iterator* NewTwoLevelIterator( + Iterator* index_iter, + Iterator* (*block_function)(void* arg, const ReadOptions& options, + const Slice& index_value), + void* arg, const ReadOptions& options); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/arena.cc b/saraWhatsUp/Pods/leveldb-library/util/arena.cc new file mode 100644 index 0000000..46e3b2e --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/arena.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/arena.h" + +namespace leveldb { + +static const int kBlockSize = 4096; + +Arena::Arena() + : alloc_ptr_(nullptr), alloc_bytes_remaining_(0), memory_usage_(0) {} + +Arena::~Arena() { + for (size_t i = 0; i < blocks_.size(); i++) { + delete[] blocks_[i]; + } +} + +char* Arena::AllocateFallback(size_t bytes) { + if (bytes > kBlockSize / 4) { + // Object is more than a quarter of our block size. Allocate it separately + // to avoid wasting too much space in leftover bytes. + char* result = AllocateNewBlock(bytes); + return result; + } + + // We waste the remaining space in the current block. + alloc_ptr_ = AllocateNewBlock(kBlockSize); + alloc_bytes_remaining_ = kBlockSize; + + char* result = alloc_ptr_; + alloc_ptr_ += bytes; + alloc_bytes_remaining_ -= bytes; + return result; +} + +char* Arena::AllocateAligned(size_t bytes) { + const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8; + static_assert((align & (align - 1)) == 0, + "Pointer size should be a power of 2"); + size_t current_mod = reinterpret_cast(alloc_ptr_) & (align - 1); + size_t slop = (current_mod == 0 ? 0 : align - current_mod); + size_t needed = bytes + slop; + char* result; + if (needed <= alloc_bytes_remaining_) { + result = alloc_ptr_ + slop; + alloc_ptr_ += needed; + alloc_bytes_remaining_ -= needed; + } else { + // AllocateFallback always returned aligned memory + result = AllocateFallback(bytes); + } + assert((reinterpret_cast(result) & (align - 1)) == 0); + return result; +} + +char* Arena::AllocateNewBlock(size_t block_bytes) { + char* result = new char[block_bytes]; + blocks_.push_back(result); + memory_usage_.fetch_add(block_bytes + sizeof(char*), + std::memory_order_relaxed); + return result; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/arena.h b/saraWhatsUp/Pods/leveldb-library/util/arena.h new file mode 100644 index 0000000..68fc55d --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/arena.h @@ -0,0 +1,71 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_ARENA_H_ +#define STORAGE_LEVELDB_UTIL_ARENA_H_ + +#include +#include +#include +#include +#include + +namespace leveldb { + +class Arena { + public: + Arena(); + + Arena(const Arena&) = delete; + Arena& operator=(const Arena&) = delete; + + ~Arena(); + + // Return a pointer to a newly allocated memory block of "bytes" bytes. + char* Allocate(size_t bytes); + + // Allocate memory with the normal alignment guarantees provided by malloc. + char* AllocateAligned(size_t bytes); + + // Returns an estimate of the total memory usage of data allocated + // by the arena. + size_t MemoryUsage() const { + return memory_usage_.load(std::memory_order_relaxed); + } + + private: + char* AllocateFallback(size_t bytes); + char* AllocateNewBlock(size_t block_bytes); + + // Allocation state + char* alloc_ptr_; + size_t alloc_bytes_remaining_; + + // Array of new[] allocated memory blocks + std::vector blocks_; + + // Total memory usage of the arena. + // + // TODO(costan): This member is accessed via atomics, but the others are + // accessed without any locking. Is this OK? + std::atomic memory_usage_; +}; + +inline char* Arena::Allocate(size_t bytes) { + // The semantics of what to return are a bit messy if we allow + // 0-byte allocations, so we disallow them here (we don't need + // them for our internal use). + assert(bytes > 0); + if (bytes <= alloc_bytes_remaining_) { + char* result = alloc_ptr_; + alloc_ptr_ += bytes; + alloc_bytes_remaining_ -= bytes; + return result; + } + return AllocateFallback(bytes); +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_ARENA_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/bloom.cc b/saraWhatsUp/Pods/leveldb-library/util/bloom.cc new file mode 100644 index 0000000..7f97464 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/bloom.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +#include "leveldb/slice.h" +#include "util/hash.h" + +namespace leveldb { + +namespace { +static uint32_t BloomHash(const Slice& key) { + return Hash(key.data(), key.size(), 0xbc9f1d34); +} + +class BloomFilterPolicy : public FilterPolicy { + public: + explicit BloomFilterPolicy(int bits_per_key) : bits_per_key_(bits_per_key) { + // We intentionally round down to reduce probing cost a little bit + k_ = static_cast(bits_per_key * 0.69); // 0.69 =~ ln(2) + if (k_ < 1) k_ = 1; + if (k_ > 30) k_ = 30; + } + + virtual const char* Name() const { return "leveldb.BuiltinBloomFilter2"; } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + // Compute bloom filter size (in both bits and bytes) + size_t bits = n * bits_per_key_; + + // For small n, we can see a very high false positive rate. Fix it + // by enforcing a minimum bloom filter length. + if (bits < 64) bits = 64; + + size_t bytes = (bits + 7) / 8; + bits = bytes * 8; + + const size_t init_size = dst->size(); + dst->resize(init_size + bytes, 0); + dst->push_back(static_cast(k_)); // Remember # of probes in filter + char* array = &(*dst)[init_size]; + for (int i = 0; i < n; i++) { + // Use double-hashing to generate a sequence of hash values. + // See analysis in [Kirsch,Mitzenmacher 2006]. + uint32_t h = BloomHash(keys[i]); + const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits + for (size_t j = 0; j < k_; j++) { + const uint32_t bitpos = h % bits; + array[bitpos / 8] |= (1 << (bitpos % 8)); + h += delta; + } + } + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const { + const size_t len = bloom_filter.size(); + if (len < 2) return false; + + const char* array = bloom_filter.data(); + const size_t bits = (len - 1) * 8; + + // Use the encoded k so that we can read filters generated by + // bloom filters created using different parameters. + const size_t k = array[len - 1]; + if (k > 30) { + // Reserved for potentially new encodings for short bloom filters. + // Consider it a match. + return true; + } + + uint32_t h = BloomHash(key); + const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits + for (size_t j = 0; j < k; j++) { + const uint32_t bitpos = h % bits; + if ((array[bitpos / 8] & (1 << (bitpos % 8))) == 0) return false; + h += delta; + } + return true; + } + + private: + size_t bits_per_key_; + size_t k_; +}; +} // namespace + +const FilterPolicy* NewBloomFilterPolicy(int bits_per_key) { + return new BloomFilterPolicy(bits_per_key); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/cache.cc b/saraWhatsUp/Pods/leveldb-library/util/cache.cc new file mode 100644 index 0000000..0f801cc --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/cache.cc @@ -0,0 +1,400 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include + +#include "leveldb/cache.h" +#include "port/port.h" +#include "port/thread_annotations.h" +#include "util/hash.h" +#include "util/mutexlock.h" + +namespace leveldb { + +Cache::~Cache() {} + +namespace { + +// LRU cache implementation +// +// Cache entries have an "in_cache" boolean indicating whether the cache has a +// reference on the entry. The only ways that this can become false without the +// entry being passed to its "deleter" are via Erase(), via Insert() when +// an element with a duplicate key is inserted, or on destruction of the cache. +// +// The cache keeps two linked lists of items in the cache. All items in the +// cache are in one list or the other, and never both. Items still referenced +// by clients but erased from the cache are in neither list. The lists are: +// - in-use: contains the items currently referenced by clients, in no +// particular order. (This list is used for invariant checking. If we +// removed the check, elements that would otherwise be on this list could be +// left as disconnected singleton lists.) +// - LRU: contains the items not currently referenced by clients, in LRU order +// Elements are moved between these lists by the Ref() and Unref() methods, +// when they detect an element in the cache acquiring or losing its only +// external reference. + +// An entry is a variable length heap-allocated structure. Entries +// are kept in a circular doubly linked list ordered by access time. +struct LRUHandle { + void* value; + void (*deleter)(const Slice&, void* value); + LRUHandle* next_hash; + LRUHandle* next; + LRUHandle* prev; + size_t charge; // TODO(opt): Only allow uint32_t? + size_t key_length; + bool in_cache; // Whether entry is in the cache. + uint32_t refs; // References, including cache reference, if present. + uint32_t hash; // Hash of key(); used for fast sharding and comparisons + char key_data[1]; // Beginning of key + + Slice key() const { + // next_ is only equal to this if the LRU handle is the list head of an + // empty list. List heads never have meaningful keys. + assert(next != this); + + return Slice(key_data, key_length); + } +}; + +// We provide our own simple hash table since it removes a whole bunch +// of porting hacks and is also faster than some of the built-in hash +// table implementations in some of the compiler/runtime combinations +// we have tested. E.g., readrandom speeds up by ~5% over the g++ +// 4.4.3's builtin hashtable. +class HandleTable { + public: + HandleTable() : length_(0), elems_(0), list_(nullptr) { Resize(); } + ~HandleTable() { delete[] list_; } + + LRUHandle* Lookup(const Slice& key, uint32_t hash) { + return *FindPointer(key, hash); + } + + LRUHandle* Insert(LRUHandle* h) { + LRUHandle** ptr = FindPointer(h->key(), h->hash); + LRUHandle* old = *ptr; + h->next_hash = (old == nullptr ? nullptr : old->next_hash); + *ptr = h; + if (old == nullptr) { + ++elems_; + if (elems_ > length_) { + // Since each cache entry is fairly large, we aim for a small + // average linked list length (<= 1). + Resize(); + } + } + return old; + } + + LRUHandle* Remove(const Slice& key, uint32_t hash) { + LRUHandle** ptr = FindPointer(key, hash); + LRUHandle* result = *ptr; + if (result != nullptr) { + *ptr = result->next_hash; + --elems_; + } + return result; + } + + private: + // The table consists of an array of buckets where each bucket is + // a linked list of cache entries that hash into the bucket. + uint32_t length_; + uint32_t elems_; + LRUHandle** list_; + + // Return a pointer to slot that points to a cache entry that + // matches key/hash. If there is no such cache entry, return a + // pointer to the trailing slot in the corresponding linked list. + LRUHandle** FindPointer(const Slice& key, uint32_t hash) { + LRUHandle** ptr = &list_[hash & (length_ - 1)]; + while (*ptr != nullptr && ((*ptr)->hash != hash || key != (*ptr)->key())) { + ptr = &(*ptr)->next_hash; + } + return ptr; + } + + void Resize() { + uint32_t new_length = 4; + while (new_length < elems_) { + new_length *= 2; + } + LRUHandle** new_list = new LRUHandle*[new_length]; + memset(new_list, 0, sizeof(new_list[0]) * new_length); + uint32_t count = 0; + for (uint32_t i = 0; i < length_; i++) { + LRUHandle* h = list_[i]; + while (h != nullptr) { + LRUHandle* next = h->next_hash; + uint32_t hash = h->hash; + LRUHandle** ptr = &new_list[hash & (new_length - 1)]; + h->next_hash = *ptr; + *ptr = h; + h = next; + count++; + } + } + assert(elems_ == count); + delete[] list_; + list_ = new_list; + length_ = new_length; + } +}; + +// A single shard of sharded cache. +class LRUCache { + public: + LRUCache(); + ~LRUCache(); + + // Separate from constructor so caller can easily make an array of LRUCache + void SetCapacity(size_t capacity) { capacity_ = capacity; } + + // Like Cache methods, but with an extra "hash" parameter. + Cache::Handle* Insert(const Slice& key, uint32_t hash, void* value, + size_t charge, + void (*deleter)(const Slice& key, void* value)); + Cache::Handle* Lookup(const Slice& key, uint32_t hash); + void Release(Cache::Handle* handle); + void Erase(const Slice& key, uint32_t hash); + void Prune(); + size_t TotalCharge() const { + MutexLock l(&mutex_); + return usage_; + } + + private: + void LRU_Remove(LRUHandle* e); + void LRU_Append(LRUHandle* list, LRUHandle* e); + void Ref(LRUHandle* e); + void Unref(LRUHandle* e); + bool FinishErase(LRUHandle* e) EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Initialized before use. + size_t capacity_; + + // mutex_ protects the following state. + mutable port::Mutex mutex_; + size_t usage_ GUARDED_BY(mutex_); + + // Dummy head of LRU list. + // lru.prev is newest entry, lru.next is oldest entry. + // Entries have refs==1 and in_cache==true. + LRUHandle lru_ GUARDED_BY(mutex_); + + // Dummy head of in-use list. + // Entries are in use by clients, and have refs >= 2 and in_cache==true. + LRUHandle in_use_ GUARDED_BY(mutex_); + + HandleTable table_ GUARDED_BY(mutex_); +}; + +LRUCache::LRUCache() : capacity_(0), usage_(0) { + // Make empty circular linked lists. + lru_.next = &lru_; + lru_.prev = &lru_; + in_use_.next = &in_use_; + in_use_.prev = &in_use_; +} + +LRUCache::~LRUCache() { + assert(in_use_.next == &in_use_); // Error if caller has an unreleased handle + for (LRUHandle* e = lru_.next; e != &lru_;) { + LRUHandle* next = e->next; + assert(e->in_cache); + e->in_cache = false; + assert(e->refs == 1); // Invariant of lru_ list. + Unref(e); + e = next; + } +} + +void LRUCache::Ref(LRUHandle* e) { + if (e->refs == 1 && e->in_cache) { // If on lru_ list, move to in_use_ list. + LRU_Remove(e); + LRU_Append(&in_use_, e); + } + e->refs++; +} + +void LRUCache::Unref(LRUHandle* e) { + assert(e->refs > 0); + e->refs--; + if (e->refs == 0) { // Deallocate. + assert(!e->in_cache); + (*e->deleter)(e->key(), e->value); + free(e); + } else if (e->in_cache && e->refs == 1) { + // No longer in use; move to lru_ list. + LRU_Remove(e); + LRU_Append(&lru_, e); + } +} + +void LRUCache::LRU_Remove(LRUHandle* e) { + e->next->prev = e->prev; + e->prev->next = e->next; +} + +void LRUCache::LRU_Append(LRUHandle* list, LRUHandle* e) { + // Make "e" newest entry by inserting just before *list + e->next = list; + e->prev = list->prev; + e->prev->next = e; + e->next->prev = e; +} + +Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) { + MutexLock l(&mutex_); + LRUHandle* e = table_.Lookup(key, hash); + if (e != nullptr) { + Ref(e); + } + return reinterpret_cast(e); +} + +void LRUCache::Release(Cache::Handle* handle) { + MutexLock l(&mutex_); + Unref(reinterpret_cast(handle)); +} + +Cache::Handle* LRUCache::Insert(const Slice& key, uint32_t hash, void* value, + size_t charge, + void (*deleter)(const Slice& key, + void* value)) { + MutexLock l(&mutex_); + + LRUHandle* e = + reinterpret_cast(malloc(sizeof(LRUHandle) - 1 + key.size())); + e->value = value; + e->deleter = deleter; + e->charge = charge; + e->key_length = key.size(); + e->hash = hash; + e->in_cache = false; + e->refs = 1; // for the returned handle. + memcpy(e->key_data, key.data(), key.size()); + + if (capacity_ > 0) { + e->refs++; // for the cache's reference. + e->in_cache = true; + LRU_Append(&in_use_, e); + usage_ += charge; + FinishErase(table_.Insert(e)); + } else { // don't cache. (capacity_==0 is supported and turns off caching.) + // next is read by key() in an assert, so it must be initialized + e->next = nullptr; + } + while (usage_ > capacity_ && lru_.next != &lru_) { + LRUHandle* old = lru_.next; + assert(old->refs == 1); + bool erased = FinishErase(table_.Remove(old->key(), old->hash)); + if (!erased) { // to avoid unused variable when compiled NDEBUG + assert(erased); + } + } + + return reinterpret_cast(e); +} + +// If e != nullptr, finish removing *e from the cache; it has already been +// removed from the hash table. Return whether e != nullptr. +bool LRUCache::FinishErase(LRUHandle* e) { + if (e != nullptr) { + assert(e->in_cache); + LRU_Remove(e); + e->in_cache = false; + usage_ -= e->charge; + Unref(e); + } + return e != nullptr; +} + +void LRUCache::Erase(const Slice& key, uint32_t hash) { + MutexLock l(&mutex_); + FinishErase(table_.Remove(key, hash)); +} + +void LRUCache::Prune() { + MutexLock l(&mutex_); + while (lru_.next != &lru_) { + LRUHandle* e = lru_.next; + assert(e->refs == 1); + bool erased = FinishErase(table_.Remove(e->key(), e->hash)); + if (!erased) { // to avoid unused variable when compiled NDEBUG + assert(erased); + } + } +} + +static const int kNumShardBits = 4; +static const int kNumShards = 1 << kNumShardBits; + +class ShardedLRUCache : public Cache { + private: + LRUCache shard_[kNumShards]; + port::Mutex id_mutex_; + uint64_t last_id_; + + static inline uint32_t HashSlice(const Slice& s) { + return Hash(s.data(), s.size(), 0); + } + + static uint32_t Shard(uint32_t hash) { return hash >> (32 - kNumShardBits); } + + public: + explicit ShardedLRUCache(size_t capacity) : last_id_(0) { + const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards; + for (int s = 0; s < kNumShards; s++) { + shard_[s].SetCapacity(per_shard); + } + } + virtual ~ShardedLRUCache() {} + virtual Handle* Insert(const Slice& key, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) { + const uint32_t hash = HashSlice(key); + return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter); + } + virtual Handle* Lookup(const Slice& key) { + const uint32_t hash = HashSlice(key); + return shard_[Shard(hash)].Lookup(key, hash); + } + virtual void Release(Handle* handle) { + LRUHandle* h = reinterpret_cast(handle); + shard_[Shard(h->hash)].Release(handle); + } + virtual void Erase(const Slice& key) { + const uint32_t hash = HashSlice(key); + shard_[Shard(hash)].Erase(key, hash); + } + virtual void* Value(Handle* handle) { + return reinterpret_cast(handle)->value; + } + virtual uint64_t NewId() { + MutexLock l(&id_mutex_); + return ++(last_id_); + } + virtual void Prune() { + for (int s = 0; s < kNumShards; s++) { + shard_[s].Prune(); + } + } + virtual size_t TotalCharge() const { + size_t total = 0; + for (int s = 0; s < kNumShards; s++) { + total += shard_[s].TotalCharge(); + } + return total; + } +}; + +} // end anonymous namespace + +Cache* NewLRUCache(size_t capacity) { return new ShardedLRUCache(capacity); } + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/coding.cc b/saraWhatsUp/Pods/leveldb-library/util/coding.cc new file mode 100644 index 0000000..e2089df --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/coding.cc @@ -0,0 +1,192 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/coding.h" + +namespace leveldb { + +void EncodeFixed32(char* dst, uint32_t value) { + if (port::kLittleEndian) { + memcpy(dst, &value, sizeof(value)); + } else { + dst[0] = value & 0xff; + dst[1] = (value >> 8) & 0xff; + dst[2] = (value >> 16) & 0xff; + dst[3] = (value >> 24) & 0xff; + } +} + +void EncodeFixed64(char* dst, uint64_t value) { + if (port::kLittleEndian) { + memcpy(dst, &value, sizeof(value)); + } else { + dst[0] = value & 0xff; + dst[1] = (value >> 8) & 0xff; + dst[2] = (value >> 16) & 0xff; + dst[3] = (value >> 24) & 0xff; + dst[4] = (value >> 32) & 0xff; + dst[5] = (value >> 40) & 0xff; + dst[6] = (value >> 48) & 0xff; + dst[7] = (value >> 56) & 0xff; + } +} + +void PutFixed32(std::string* dst, uint32_t value) { + char buf[sizeof(value)]; + EncodeFixed32(buf, value); + dst->append(buf, sizeof(buf)); +} + +void PutFixed64(std::string* dst, uint64_t value) { + char buf[sizeof(value)]; + EncodeFixed64(buf, value); + dst->append(buf, sizeof(buf)); +} + +char* EncodeVarint32(char* dst, uint32_t v) { + // Operate on characters as unsigneds + unsigned char* ptr = reinterpret_cast(dst); + static const int B = 128; + if (v < (1 << 7)) { + *(ptr++) = v; + } else if (v < (1 << 14)) { + *(ptr++) = v | B; + *(ptr++) = v >> 7; + } else if (v < (1 << 21)) { + *(ptr++) = v | B; + *(ptr++) = (v >> 7) | B; + *(ptr++) = v >> 14; + } else if (v < (1 << 28)) { + *(ptr++) = v | B; + *(ptr++) = (v >> 7) | B; + *(ptr++) = (v >> 14) | B; + *(ptr++) = v >> 21; + } else { + *(ptr++) = v | B; + *(ptr++) = (v >> 7) | B; + *(ptr++) = (v >> 14) | B; + *(ptr++) = (v >> 21) | B; + *(ptr++) = v >> 28; + } + return reinterpret_cast(ptr); +} + +void PutVarint32(std::string* dst, uint32_t v) { + char buf[5]; + char* ptr = EncodeVarint32(buf, v); + dst->append(buf, ptr - buf); +} + +char* EncodeVarint64(char* dst, uint64_t v) { + static const int B = 128; + unsigned char* ptr = reinterpret_cast(dst); + while (v >= B) { + *(ptr++) = v | B; + v >>= 7; + } + *(ptr++) = static_cast(v); + return reinterpret_cast(ptr); +} + +void PutVarint64(std::string* dst, uint64_t v) { + char buf[10]; + char* ptr = EncodeVarint64(buf, v); + dst->append(buf, ptr - buf); +} + +void PutLengthPrefixedSlice(std::string* dst, const Slice& value) { + PutVarint32(dst, value.size()); + dst->append(value.data(), value.size()); +} + +int VarintLength(uint64_t v) { + int len = 1; + while (v >= 128) { + v >>= 7; + len++; + } + return len; +} + +const char* GetVarint32PtrFallback(const char* p, const char* limit, + uint32_t* value) { + uint32_t result = 0; + for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) { + uint32_t byte = *(reinterpret_cast(p)); + p++; + if (byte & 128) { + // More bytes are present + result |= ((byte & 127) << shift); + } else { + result |= (byte << shift); + *value = result; + return reinterpret_cast(p); + } + } + return nullptr; +} + +bool GetVarint32(Slice* input, uint32_t* value) { + const char* p = input->data(); + const char* limit = p + input->size(); + const char* q = GetVarint32Ptr(p, limit, value); + if (q == nullptr) { + return false; + } else { + *input = Slice(q, limit - q); + return true; + } +} + +const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* value) { + uint64_t result = 0; + for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) { + uint64_t byte = *(reinterpret_cast(p)); + p++; + if (byte & 128) { + // More bytes are present + result |= ((byte & 127) << shift); + } else { + result |= (byte << shift); + *value = result; + return reinterpret_cast(p); + } + } + return nullptr; +} + +bool GetVarint64(Slice* input, uint64_t* value) { + const char* p = input->data(); + const char* limit = p + input->size(); + const char* q = GetVarint64Ptr(p, limit, value); + if (q == nullptr) { + return false; + } else { + *input = Slice(q, limit - q); + return true; + } +} + +const char* GetLengthPrefixedSlice(const char* p, const char* limit, + Slice* result) { + uint32_t len; + p = GetVarint32Ptr(p, limit, &len); + if (p == nullptr) return nullptr; + if (p + len > limit) return nullptr; + *result = Slice(p, len); + return p + len; +} + +bool GetLengthPrefixedSlice(Slice* input, Slice* result) { + uint32_t len; + if (GetVarint32(input, &len) && input->size() >= len) { + *result = Slice(input->data(), len); + input->remove_prefix(len); + return true; + } else { + return false; + } +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/coding.h b/saraWhatsUp/Pods/leveldb-library/util/coding.h new file mode 100644 index 0000000..d9eeaa3 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/coding.h @@ -0,0 +1,104 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Endian-neutral encoding: +// * Fixed-length numbers are encoded with least-significant byte first +// * In addition we support variable length "varint" encoding +// * Strings are encoded prefixed by their length in varint format + +#ifndef STORAGE_LEVELDB_UTIL_CODING_H_ +#define STORAGE_LEVELDB_UTIL_CODING_H_ + +#include +#include + +#include + +#include "leveldb/slice.h" +#include "port/port.h" + +namespace leveldb { + +// Standard Put... routines append to a string +void PutFixed32(std::string* dst, uint32_t value); +void PutFixed64(std::string* dst, uint64_t value); +void PutVarint32(std::string* dst, uint32_t value); +void PutVarint64(std::string* dst, uint64_t value); +void PutLengthPrefixedSlice(std::string* dst, const Slice& value); + +// Standard Get... routines parse a value from the beginning of a Slice +// and advance the slice past the parsed value. +bool GetVarint32(Slice* input, uint32_t* value); +bool GetVarint64(Slice* input, uint64_t* value); +bool GetLengthPrefixedSlice(Slice* input, Slice* result); + +// Pointer-based variants of GetVarint... These either store a value +// in *v and return a pointer just past the parsed value, or return +// nullptr on error. These routines only look at bytes in the range +// [p..limit-1] +const char* GetVarint32Ptr(const char* p, const char* limit, uint32_t* v); +const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* v); + +// Returns the length of the varint32 or varint64 encoding of "v" +int VarintLength(uint64_t v); + +// Lower-level versions of Put... that write directly into a character buffer +// REQUIRES: dst has enough space for the value being written +void EncodeFixed32(char* dst, uint32_t value); +void EncodeFixed64(char* dst, uint64_t value); + +// Lower-level versions of Put... that write directly into a character buffer +// and return a pointer just past the last byte written. +// REQUIRES: dst has enough space for the value being written +char* EncodeVarint32(char* dst, uint32_t value); +char* EncodeVarint64(char* dst, uint64_t value); + +// Lower-level versions of Get... that read directly from a character buffer +// without any bounds checking. + +inline uint32_t DecodeFixed32(const char* ptr) { + if (port::kLittleEndian) { + // Load the raw bytes + uint32_t result; + memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load + return result; + } else { + return ((static_cast(static_cast(ptr[0]))) | + (static_cast(static_cast(ptr[1])) << 8) | + (static_cast(static_cast(ptr[2])) << 16) | + (static_cast(static_cast(ptr[3])) << 24)); + } +} + +inline uint64_t DecodeFixed64(const char* ptr) { + if (port::kLittleEndian) { + // Load the raw bytes + uint64_t result; + memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load + return result; + } else { + uint64_t lo = DecodeFixed32(ptr); + uint64_t hi = DecodeFixed32(ptr + 4); + return (hi << 32) | lo; + } +} + +// Internal routine for use by fallback path of GetVarint32Ptr +const char* GetVarint32PtrFallback(const char* p, const char* limit, + uint32_t* value); +inline const char* GetVarint32Ptr(const char* p, const char* limit, + uint32_t* value) { + if (p < limit) { + uint32_t result = *(reinterpret_cast(p)); + if ((result & 128) == 0) { + *value = result; + return p + 1; + } + } + return GetVarint32PtrFallback(p, limit, value); +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CODING_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/comparator.cc b/saraWhatsUp/Pods/leveldb-library/util/comparator.cc new file mode 100644 index 0000000..26d1eb3 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/comparator.cc @@ -0,0 +1,73 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include + +#include "leveldb/comparator.h" +#include "leveldb/slice.h" +#include "util/logging.h" +#include "util/no_destructor.h" + +namespace leveldb { + +Comparator::~Comparator() {} + +namespace { +class BytewiseComparatorImpl : public Comparator { + public: + BytewiseComparatorImpl() {} + + virtual const char* Name() const { return "leveldb.BytewiseComparator"; } + + virtual int Compare(const Slice& a, const Slice& b) const { + return a.compare(b); + } + + virtual void FindShortestSeparator(std::string* start, + const Slice& limit) const { + // Find length of common prefix + size_t min_length = std::min(start->size(), limit.size()); + size_t diff_index = 0; + while ((diff_index < min_length) && + ((*start)[diff_index] == limit[diff_index])) { + diff_index++; + } + + if (diff_index >= min_length) { + // Do not shorten if one string is a prefix of the other + } else { + uint8_t diff_byte = static_cast((*start)[diff_index]); + if (diff_byte < static_cast(0xff) && + diff_byte + 1 < static_cast(limit[diff_index])) { + (*start)[diff_index]++; + start->resize(diff_index + 1); + assert(Compare(*start, limit) < 0); + } + } + } + + virtual void FindShortSuccessor(std::string* key) const { + // Find first character that can be incremented + size_t n = key->size(); + for (size_t i = 0; i < n; i++) { + const uint8_t byte = (*key)[i]; + if (byte != static_cast(0xff)) { + (*key)[i] = byte + 1; + key->resize(i + 1); + return; + } + } + // *key is a run of 0xffs. Leave it alone. + } +}; +} // namespace + +const Comparator* BytewiseComparator() { + static NoDestructor singleton; + return singleton.get(); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/crc32c.cc b/saraWhatsUp/Pods/leveldb-library/util/crc32c.cc new file mode 100644 index 0000000..c2e61f7 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/crc32c.cc @@ -0,0 +1,380 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A portable implementation of crc32c. + +#include "util/crc32c.h" + +#include +#include + +#include "port/port.h" +#include "util/coding.h" + +namespace leveldb { +namespace crc32c { + +namespace { + +const uint32_t kByteExtensionTable[256] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, + 0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c, + 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, + 0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 0xaa64d611, 0x580f5512, + 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, + 0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf, + 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, + 0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f, + 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, + 0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e, + 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, + 0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x082f63b7, 0xfa44e0b4, + 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, + 0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5, + 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, + 0x0e330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905, + 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, + 0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8, + 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, + 0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6, + 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, + 0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351}; + +const uint32_t kStrideExtensionTable0[256] = { + 0x00000000, 0x30d23865, 0x61a470ca, 0x517648af, 0xc348e194, 0xf39ad9f1, + 0xa2ec915e, 0x923ea93b, 0x837db5d9, 0xb3af8dbc, 0xe2d9c513, 0xd20bfd76, + 0x4035544d, 0x70e76c28, 0x21912487, 0x11431ce2, 0x03171d43, 0x33c52526, + 0x62b36d89, 0x526155ec, 0xc05ffcd7, 0xf08dc4b2, 0xa1fb8c1d, 0x9129b478, + 0x806aa89a, 0xb0b890ff, 0xe1ced850, 0xd11ce035, 0x4322490e, 0x73f0716b, + 0x228639c4, 0x125401a1, 0x062e3a86, 0x36fc02e3, 0x678a4a4c, 0x57587229, + 0xc566db12, 0xf5b4e377, 0xa4c2abd8, 0x941093bd, 0x85538f5f, 0xb581b73a, + 0xe4f7ff95, 0xd425c7f0, 0x461b6ecb, 0x76c956ae, 0x27bf1e01, 0x176d2664, + 0x053927c5, 0x35eb1fa0, 0x649d570f, 0x544f6f6a, 0xc671c651, 0xf6a3fe34, + 0xa7d5b69b, 0x97078efe, 0x8644921c, 0xb696aa79, 0xe7e0e2d6, 0xd732dab3, + 0x450c7388, 0x75de4bed, 0x24a80342, 0x147a3b27, 0x0c5c750c, 0x3c8e4d69, + 0x6df805c6, 0x5d2a3da3, 0xcf149498, 0xffc6acfd, 0xaeb0e452, 0x9e62dc37, + 0x8f21c0d5, 0xbff3f8b0, 0xee85b01f, 0xde57887a, 0x4c692141, 0x7cbb1924, + 0x2dcd518b, 0x1d1f69ee, 0x0f4b684f, 0x3f99502a, 0x6eef1885, 0x5e3d20e0, + 0xcc0389db, 0xfcd1b1be, 0xada7f911, 0x9d75c174, 0x8c36dd96, 0xbce4e5f3, + 0xed92ad5c, 0xdd409539, 0x4f7e3c02, 0x7fac0467, 0x2eda4cc8, 0x1e0874ad, + 0x0a724f8a, 0x3aa077ef, 0x6bd63f40, 0x5b040725, 0xc93aae1e, 0xf9e8967b, + 0xa89eded4, 0x984ce6b1, 0x890ffa53, 0xb9ddc236, 0xe8ab8a99, 0xd879b2fc, + 0x4a471bc7, 0x7a9523a2, 0x2be36b0d, 0x1b315368, 0x096552c9, 0x39b76aac, + 0x68c12203, 0x58131a66, 0xca2db35d, 0xfaff8b38, 0xab89c397, 0x9b5bfbf2, + 0x8a18e710, 0xbacadf75, 0xebbc97da, 0xdb6eafbf, 0x49500684, 0x79823ee1, + 0x28f4764e, 0x18264e2b, 0x18b8ea18, 0x286ad27d, 0x791c9ad2, 0x49cea2b7, + 0xdbf00b8c, 0xeb2233e9, 0xba547b46, 0x8a864323, 0x9bc55fc1, 0xab1767a4, + 0xfa612f0b, 0xcab3176e, 0x588dbe55, 0x685f8630, 0x3929ce9f, 0x09fbf6fa, + 0x1baff75b, 0x2b7dcf3e, 0x7a0b8791, 0x4ad9bff4, 0xd8e716cf, 0xe8352eaa, + 0xb9436605, 0x89915e60, 0x98d24282, 0xa8007ae7, 0xf9763248, 0xc9a40a2d, + 0x5b9aa316, 0x6b489b73, 0x3a3ed3dc, 0x0aecebb9, 0x1e96d09e, 0x2e44e8fb, + 0x7f32a054, 0x4fe09831, 0xddde310a, 0xed0c096f, 0xbc7a41c0, 0x8ca879a5, + 0x9deb6547, 0xad395d22, 0xfc4f158d, 0xcc9d2de8, 0x5ea384d3, 0x6e71bcb6, + 0x3f07f419, 0x0fd5cc7c, 0x1d81cddd, 0x2d53f5b8, 0x7c25bd17, 0x4cf78572, + 0xdec92c49, 0xee1b142c, 0xbf6d5c83, 0x8fbf64e6, 0x9efc7804, 0xae2e4061, + 0xff5808ce, 0xcf8a30ab, 0x5db49990, 0x6d66a1f5, 0x3c10e95a, 0x0cc2d13f, + 0x14e49f14, 0x2436a771, 0x7540efde, 0x4592d7bb, 0xd7ac7e80, 0xe77e46e5, + 0xb6080e4a, 0x86da362f, 0x97992acd, 0xa74b12a8, 0xf63d5a07, 0xc6ef6262, + 0x54d1cb59, 0x6403f33c, 0x3575bb93, 0x05a783f6, 0x17f38257, 0x2721ba32, + 0x7657f29d, 0x4685caf8, 0xd4bb63c3, 0xe4695ba6, 0xb51f1309, 0x85cd2b6c, + 0x948e378e, 0xa45c0feb, 0xf52a4744, 0xc5f87f21, 0x57c6d61a, 0x6714ee7f, + 0x3662a6d0, 0x06b09eb5, 0x12caa592, 0x22189df7, 0x736ed558, 0x43bced3d, + 0xd1824406, 0xe1507c63, 0xb02634cc, 0x80f40ca9, 0x91b7104b, 0xa165282e, + 0xf0136081, 0xc0c158e4, 0x52fff1df, 0x622dc9ba, 0x335b8115, 0x0389b970, + 0x11ddb8d1, 0x210f80b4, 0x7079c81b, 0x40abf07e, 0xd2955945, 0xe2476120, + 0xb331298f, 0x83e311ea, 0x92a00d08, 0xa272356d, 0xf3047dc2, 0xc3d645a7, + 0x51e8ec9c, 0x613ad4f9, 0x304c9c56, 0x009ea433}; + +const uint32_t kStrideExtensionTable1[256] = { + 0x00000000, 0x54075546, 0xa80eaa8c, 0xfc09ffca, 0x55f123e9, 0x01f676af, + 0xfdff8965, 0xa9f8dc23, 0xabe247d2, 0xffe51294, 0x03eced5e, 0x57ebb818, + 0xfe13643b, 0xaa14317d, 0x561dceb7, 0x021a9bf1, 0x5228f955, 0x062fac13, + 0xfa2653d9, 0xae21069f, 0x07d9dabc, 0x53de8ffa, 0xafd77030, 0xfbd02576, + 0xf9cabe87, 0xadcdebc1, 0x51c4140b, 0x05c3414d, 0xac3b9d6e, 0xf83cc828, + 0x043537e2, 0x503262a4, 0xa451f2aa, 0xf056a7ec, 0x0c5f5826, 0x58580d60, + 0xf1a0d143, 0xa5a78405, 0x59ae7bcf, 0x0da92e89, 0x0fb3b578, 0x5bb4e03e, + 0xa7bd1ff4, 0xf3ba4ab2, 0x5a429691, 0x0e45c3d7, 0xf24c3c1d, 0xa64b695b, + 0xf6790bff, 0xa27e5eb9, 0x5e77a173, 0x0a70f435, 0xa3882816, 0xf78f7d50, + 0x0b86829a, 0x5f81d7dc, 0x5d9b4c2d, 0x099c196b, 0xf595e6a1, 0xa192b3e7, + 0x086a6fc4, 0x5c6d3a82, 0xa064c548, 0xf463900e, 0x4d4f93a5, 0x1948c6e3, + 0xe5413929, 0xb1466c6f, 0x18beb04c, 0x4cb9e50a, 0xb0b01ac0, 0xe4b74f86, + 0xe6add477, 0xb2aa8131, 0x4ea37efb, 0x1aa42bbd, 0xb35cf79e, 0xe75ba2d8, + 0x1b525d12, 0x4f550854, 0x1f676af0, 0x4b603fb6, 0xb769c07c, 0xe36e953a, + 0x4a964919, 0x1e911c5f, 0xe298e395, 0xb69fb6d3, 0xb4852d22, 0xe0827864, + 0x1c8b87ae, 0x488cd2e8, 0xe1740ecb, 0xb5735b8d, 0x497aa447, 0x1d7df101, + 0xe91e610f, 0xbd193449, 0x4110cb83, 0x15179ec5, 0xbcef42e6, 0xe8e817a0, + 0x14e1e86a, 0x40e6bd2c, 0x42fc26dd, 0x16fb739b, 0xeaf28c51, 0xbef5d917, + 0x170d0534, 0x430a5072, 0xbf03afb8, 0xeb04fafe, 0xbb36985a, 0xef31cd1c, + 0x133832d6, 0x473f6790, 0xeec7bbb3, 0xbac0eef5, 0x46c9113f, 0x12ce4479, + 0x10d4df88, 0x44d38ace, 0xb8da7504, 0xecdd2042, 0x4525fc61, 0x1122a927, + 0xed2b56ed, 0xb92c03ab, 0x9a9f274a, 0xce98720c, 0x32918dc6, 0x6696d880, + 0xcf6e04a3, 0x9b6951e5, 0x6760ae2f, 0x3367fb69, 0x317d6098, 0x657a35de, + 0x9973ca14, 0xcd749f52, 0x648c4371, 0x308b1637, 0xcc82e9fd, 0x9885bcbb, + 0xc8b7de1f, 0x9cb08b59, 0x60b97493, 0x34be21d5, 0x9d46fdf6, 0xc941a8b0, + 0x3548577a, 0x614f023c, 0x635599cd, 0x3752cc8b, 0xcb5b3341, 0x9f5c6607, + 0x36a4ba24, 0x62a3ef62, 0x9eaa10a8, 0xcaad45ee, 0x3eced5e0, 0x6ac980a6, + 0x96c07f6c, 0xc2c72a2a, 0x6b3ff609, 0x3f38a34f, 0xc3315c85, 0x973609c3, + 0x952c9232, 0xc12bc774, 0x3d2238be, 0x69256df8, 0xc0ddb1db, 0x94dae49d, + 0x68d31b57, 0x3cd44e11, 0x6ce62cb5, 0x38e179f3, 0xc4e88639, 0x90efd37f, + 0x39170f5c, 0x6d105a1a, 0x9119a5d0, 0xc51ef096, 0xc7046b67, 0x93033e21, + 0x6f0ac1eb, 0x3b0d94ad, 0x92f5488e, 0xc6f21dc8, 0x3afbe202, 0x6efcb744, + 0xd7d0b4ef, 0x83d7e1a9, 0x7fde1e63, 0x2bd94b25, 0x82219706, 0xd626c240, + 0x2a2f3d8a, 0x7e2868cc, 0x7c32f33d, 0x2835a67b, 0xd43c59b1, 0x803b0cf7, + 0x29c3d0d4, 0x7dc48592, 0x81cd7a58, 0xd5ca2f1e, 0x85f84dba, 0xd1ff18fc, + 0x2df6e736, 0x79f1b270, 0xd0096e53, 0x840e3b15, 0x7807c4df, 0x2c009199, + 0x2e1a0a68, 0x7a1d5f2e, 0x8614a0e4, 0xd213f5a2, 0x7beb2981, 0x2fec7cc7, + 0xd3e5830d, 0x87e2d64b, 0x73814645, 0x27861303, 0xdb8fecc9, 0x8f88b98f, + 0x267065ac, 0x727730ea, 0x8e7ecf20, 0xda799a66, 0xd8630197, 0x8c6454d1, + 0x706dab1b, 0x246afe5d, 0x8d92227e, 0xd9957738, 0x259c88f2, 0x719bddb4, + 0x21a9bf10, 0x75aeea56, 0x89a7159c, 0xdda040da, 0x74589cf9, 0x205fc9bf, + 0xdc563675, 0x88516333, 0x8a4bf8c2, 0xde4cad84, 0x2245524e, 0x76420708, + 0xdfbadb2b, 0x8bbd8e6d, 0x77b471a7, 0x23b324e1}; + +const uint32_t kStrideExtensionTable2[256] = { + 0x00000000, 0x678efd01, 0xcf1dfa02, 0xa8930703, 0x9bd782f5, 0xfc597ff4, + 0x54ca78f7, 0x334485f6, 0x3243731b, 0x55cd8e1a, 0xfd5e8919, 0x9ad07418, + 0xa994f1ee, 0xce1a0cef, 0x66890bec, 0x0107f6ed, 0x6486e636, 0x03081b37, + 0xab9b1c34, 0xcc15e135, 0xff5164c3, 0x98df99c2, 0x304c9ec1, 0x57c263c0, + 0x56c5952d, 0x314b682c, 0x99d86f2f, 0xfe56922e, 0xcd1217d8, 0xaa9cead9, + 0x020fedda, 0x658110db, 0xc90dcc6c, 0xae83316d, 0x0610366e, 0x619ecb6f, + 0x52da4e99, 0x3554b398, 0x9dc7b49b, 0xfa49499a, 0xfb4ebf77, 0x9cc04276, + 0x34534575, 0x53ddb874, 0x60993d82, 0x0717c083, 0xaf84c780, 0xc80a3a81, + 0xad8b2a5a, 0xca05d75b, 0x6296d058, 0x05182d59, 0x365ca8af, 0x51d255ae, + 0xf94152ad, 0x9ecfafac, 0x9fc85941, 0xf846a440, 0x50d5a343, 0x375b5e42, + 0x041fdbb4, 0x639126b5, 0xcb0221b6, 0xac8cdcb7, 0x97f7ee29, 0xf0791328, + 0x58ea142b, 0x3f64e92a, 0x0c206cdc, 0x6bae91dd, 0xc33d96de, 0xa4b36bdf, + 0xa5b49d32, 0xc23a6033, 0x6aa96730, 0x0d279a31, 0x3e631fc7, 0x59ede2c6, + 0xf17ee5c5, 0x96f018c4, 0xf371081f, 0x94fff51e, 0x3c6cf21d, 0x5be20f1c, + 0x68a68aea, 0x0f2877eb, 0xa7bb70e8, 0xc0358de9, 0xc1327b04, 0xa6bc8605, + 0x0e2f8106, 0x69a17c07, 0x5ae5f9f1, 0x3d6b04f0, 0x95f803f3, 0xf276fef2, + 0x5efa2245, 0x3974df44, 0x91e7d847, 0xf6692546, 0xc52da0b0, 0xa2a35db1, + 0x0a305ab2, 0x6dbea7b3, 0x6cb9515e, 0x0b37ac5f, 0xa3a4ab5c, 0xc42a565d, + 0xf76ed3ab, 0x90e02eaa, 0x387329a9, 0x5ffdd4a8, 0x3a7cc473, 0x5df23972, + 0xf5613e71, 0x92efc370, 0xa1ab4686, 0xc625bb87, 0x6eb6bc84, 0x09384185, + 0x083fb768, 0x6fb14a69, 0xc7224d6a, 0xa0acb06b, 0x93e8359d, 0xf466c89c, + 0x5cf5cf9f, 0x3b7b329e, 0x2a03aaa3, 0x4d8d57a2, 0xe51e50a1, 0x8290ada0, + 0xb1d42856, 0xd65ad557, 0x7ec9d254, 0x19472f55, 0x1840d9b8, 0x7fce24b9, + 0xd75d23ba, 0xb0d3debb, 0x83975b4d, 0xe419a64c, 0x4c8aa14f, 0x2b045c4e, + 0x4e854c95, 0x290bb194, 0x8198b697, 0xe6164b96, 0xd552ce60, 0xb2dc3361, + 0x1a4f3462, 0x7dc1c963, 0x7cc63f8e, 0x1b48c28f, 0xb3dbc58c, 0xd455388d, + 0xe711bd7b, 0x809f407a, 0x280c4779, 0x4f82ba78, 0xe30e66cf, 0x84809bce, + 0x2c139ccd, 0x4b9d61cc, 0x78d9e43a, 0x1f57193b, 0xb7c41e38, 0xd04ae339, + 0xd14d15d4, 0xb6c3e8d5, 0x1e50efd6, 0x79de12d7, 0x4a9a9721, 0x2d146a20, + 0x85876d23, 0xe2099022, 0x878880f9, 0xe0067df8, 0x48957afb, 0x2f1b87fa, + 0x1c5f020c, 0x7bd1ff0d, 0xd342f80e, 0xb4cc050f, 0xb5cbf3e2, 0xd2450ee3, + 0x7ad609e0, 0x1d58f4e1, 0x2e1c7117, 0x49928c16, 0xe1018b15, 0x868f7614, + 0xbdf4448a, 0xda7ab98b, 0x72e9be88, 0x15674389, 0x2623c67f, 0x41ad3b7e, + 0xe93e3c7d, 0x8eb0c17c, 0x8fb73791, 0xe839ca90, 0x40aacd93, 0x27243092, + 0x1460b564, 0x73ee4865, 0xdb7d4f66, 0xbcf3b267, 0xd972a2bc, 0xbefc5fbd, + 0x166f58be, 0x71e1a5bf, 0x42a52049, 0x252bdd48, 0x8db8da4b, 0xea36274a, + 0xeb31d1a7, 0x8cbf2ca6, 0x242c2ba5, 0x43a2d6a4, 0x70e65352, 0x1768ae53, + 0xbffba950, 0xd8755451, 0x74f988e6, 0x137775e7, 0xbbe472e4, 0xdc6a8fe5, + 0xef2e0a13, 0x88a0f712, 0x2033f011, 0x47bd0d10, 0x46bafbfd, 0x213406fc, + 0x89a701ff, 0xee29fcfe, 0xdd6d7908, 0xbae38409, 0x1270830a, 0x75fe7e0b, + 0x107f6ed0, 0x77f193d1, 0xdf6294d2, 0xb8ec69d3, 0x8ba8ec25, 0xec261124, + 0x44b51627, 0x233beb26, 0x223c1dcb, 0x45b2e0ca, 0xed21e7c9, 0x8aaf1ac8, + 0xb9eb9f3e, 0xde65623f, 0x76f6653c, 0x1178983d}; + +const uint32_t kStrideExtensionTable3[256] = { + 0x00000000, 0xf20c0dfe, 0xe1f46d0d, 0x13f860f3, 0xc604aceb, 0x3408a115, + 0x27f0c1e6, 0xd5fccc18, 0x89e52f27, 0x7be922d9, 0x6811422a, 0x9a1d4fd4, + 0x4fe183cc, 0xbded8e32, 0xae15eec1, 0x5c19e33f, 0x162628bf, 0xe42a2541, + 0xf7d245b2, 0x05de484c, 0xd0228454, 0x222e89aa, 0x31d6e959, 0xc3dae4a7, + 0x9fc30798, 0x6dcf0a66, 0x7e376a95, 0x8c3b676b, 0x59c7ab73, 0xabcba68d, + 0xb833c67e, 0x4a3fcb80, 0x2c4c517e, 0xde405c80, 0xcdb83c73, 0x3fb4318d, + 0xea48fd95, 0x1844f06b, 0x0bbc9098, 0xf9b09d66, 0xa5a97e59, 0x57a573a7, + 0x445d1354, 0xb6511eaa, 0x63add2b2, 0x91a1df4c, 0x8259bfbf, 0x7055b241, + 0x3a6a79c1, 0xc866743f, 0xdb9e14cc, 0x29921932, 0xfc6ed52a, 0x0e62d8d4, + 0x1d9ab827, 0xef96b5d9, 0xb38f56e6, 0x41835b18, 0x527b3beb, 0xa0773615, + 0x758bfa0d, 0x8787f7f3, 0x947f9700, 0x66739afe, 0x5898a2fc, 0xaa94af02, + 0xb96ccff1, 0x4b60c20f, 0x9e9c0e17, 0x6c9003e9, 0x7f68631a, 0x8d646ee4, + 0xd17d8ddb, 0x23718025, 0x3089e0d6, 0xc285ed28, 0x17792130, 0xe5752cce, + 0xf68d4c3d, 0x048141c3, 0x4ebe8a43, 0xbcb287bd, 0xaf4ae74e, 0x5d46eab0, + 0x88ba26a8, 0x7ab62b56, 0x694e4ba5, 0x9b42465b, 0xc75ba564, 0x3557a89a, + 0x26afc869, 0xd4a3c597, 0x015f098f, 0xf3530471, 0xe0ab6482, 0x12a7697c, + 0x74d4f382, 0x86d8fe7c, 0x95209e8f, 0x672c9371, 0xb2d05f69, 0x40dc5297, + 0x53243264, 0xa1283f9a, 0xfd31dca5, 0x0f3dd15b, 0x1cc5b1a8, 0xeec9bc56, + 0x3b35704e, 0xc9397db0, 0xdac11d43, 0x28cd10bd, 0x62f2db3d, 0x90fed6c3, + 0x8306b630, 0x710abbce, 0xa4f677d6, 0x56fa7a28, 0x45021adb, 0xb70e1725, + 0xeb17f41a, 0x191bf9e4, 0x0ae39917, 0xf8ef94e9, 0x2d1358f1, 0xdf1f550f, + 0xcce735fc, 0x3eeb3802, 0xb13145f8, 0x433d4806, 0x50c528f5, 0xa2c9250b, + 0x7735e913, 0x8539e4ed, 0x96c1841e, 0x64cd89e0, 0x38d46adf, 0xcad86721, + 0xd92007d2, 0x2b2c0a2c, 0xfed0c634, 0x0cdccbca, 0x1f24ab39, 0xed28a6c7, + 0xa7176d47, 0x551b60b9, 0x46e3004a, 0xb4ef0db4, 0x6113c1ac, 0x931fcc52, + 0x80e7aca1, 0x72eba15f, 0x2ef24260, 0xdcfe4f9e, 0xcf062f6d, 0x3d0a2293, + 0xe8f6ee8b, 0x1afae375, 0x09028386, 0xfb0e8e78, 0x9d7d1486, 0x6f711978, + 0x7c89798b, 0x8e857475, 0x5b79b86d, 0xa975b593, 0xba8dd560, 0x4881d89e, + 0x14983ba1, 0xe694365f, 0xf56c56ac, 0x07605b52, 0xd29c974a, 0x20909ab4, + 0x3368fa47, 0xc164f7b9, 0x8b5b3c39, 0x795731c7, 0x6aaf5134, 0x98a35cca, + 0x4d5f90d2, 0xbf539d2c, 0xacabfddf, 0x5ea7f021, 0x02be131e, 0xf0b21ee0, + 0xe34a7e13, 0x114673ed, 0xc4babff5, 0x36b6b20b, 0x254ed2f8, 0xd742df06, + 0xe9a9e704, 0x1ba5eafa, 0x085d8a09, 0xfa5187f7, 0x2fad4bef, 0xdda14611, + 0xce5926e2, 0x3c552b1c, 0x604cc823, 0x9240c5dd, 0x81b8a52e, 0x73b4a8d0, + 0xa64864c8, 0x54446936, 0x47bc09c5, 0xb5b0043b, 0xff8fcfbb, 0x0d83c245, + 0x1e7ba2b6, 0xec77af48, 0x398b6350, 0xcb876eae, 0xd87f0e5d, 0x2a7303a3, + 0x766ae09c, 0x8466ed62, 0x979e8d91, 0x6592806f, 0xb06e4c77, 0x42624189, + 0x519a217a, 0xa3962c84, 0xc5e5b67a, 0x37e9bb84, 0x2411db77, 0xd61dd689, + 0x03e11a91, 0xf1ed176f, 0xe215779c, 0x10197a62, 0x4c00995d, 0xbe0c94a3, + 0xadf4f450, 0x5ff8f9ae, 0x8a0435b6, 0x78083848, 0x6bf058bb, 0x99fc5545, + 0xd3c39ec5, 0x21cf933b, 0x3237f3c8, 0xc03bfe36, 0x15c7322e, 0xe7cb3fd0, + 0xf4335f23, 0x063f52dd, 0x5a26b1e2, 0xa82abc1c, 0xbbd2dcef, 0x49ded111, + 0x9c221d09, 0x6e2e10f7, 0x7dd67004, 0x8fda7dfa}; + +// CRCs are pre- and post- conditioned by xoring with all ones. +static constexpr const uint32_t kCRC32Xor = static_cast(0xffffffffU); + +// Reads a little-endian 32-bit integer from a 32-bit-aligned buffer. +inline uint32_t ReadUint32LE(const uint8_t* buffer) { + return DecodeFixed32(reinterpret_cast(buffer)); +} + +// Returns the smallest address >= the given address that is aligned to N bytes. +// +// N must be a power of two. +template +constexpr inline const uint8_t* RoundUp(const uint8_t* pointer) { + return reinterpret_cast( + (reinterpret_cast(pointer) + (N - 1)) & + ~static_cast(N - 1)); +} + +} // namespace + +// Determine if the CPU running this program can accelerate the CRC32C +// calculation. +static bool CanAccelerateCRC32C() { + // port::AcceleretedCRC32C returns zero when unable to accelerate. + static const char kTestCRCBuffer[] = "TestCRCBuffer"; + static const char kBufSize = sizeof(kTestCRCBuffer) - 1; + static const uint32_t kTestCRCValue = 0xdcbc59fa; + + return port::AcceleratedCRC32C(0, kTestCRCBuffer, kBufSize) == kTestCRCValue; +} + +uint32_t Extend(uint32_t crc, const char* data, size_t n) { + static bool accelerate = CanAccelerateCRC32C(); + if (accelerate) { + return port::AcceleratedCRC32C(crc, data, n); + } + + const uint8_t* p = reinterpret_cast(data); + const uint8_t* e = p + n; + uint32_t l = crc ^ kCRC32Xor; + +// Process one byte at a time. +#define STEP1 \ + do { \ + int c = (l & 0xff) ^ *p++; \ + l = kByteExtensionTable[c] ^ (l >> 8); \ + } while (0) + +// Process one of the 4 strides of 4-byte data. +#define STEP4(s) \ + do { \ + crc##s = ReadUint32LE(p + s * 4) ^ kStrideExtensionTable3[crc##s & 0xff] ^ \ + kStrideExtensionTable2[(crc##s >> 8) & 0xff] ^ \ + kStrideExtensionTable1[(crc##s >> 16) & 0xff] ^ \ + kStrideExtensionTable0[crc##s >> 24]; \ + } while (0) + +// Process a 16-byte swath of 4 strides, each of which has 4 bytes of data. +#define STEP16 \ + do { \ + STEP4(0); \ + STEP4(1); \ + STEP4(2); \ + STEP4(3); \ + p += 16; \ + } while (0) + +// Process 4 bytes that were already loaded into a word. +#define STEP4W(w) \ + do { \ + w ^= l; \ + for (size_t i = 0; i < 4; ++i) { \ + w = (w >> 8) ^ kByteExtensionTable[w & 0xff]; \ + } \ + l = w; \ + } while (0) + + // Point x at first 4-byte aligned byte in the buffer. This might be past the + // end of the buffer. + const uint8_t* x = RoundUp<4>(p); + if (x <= e) { + // Process bytes p is 4-byte aligned. + while (p != x) { + STEP1; + } + } + + if ((e - p) >= 16) { + // Load a 16-byte swath into the stride partial results. + uint32_t crc0 = ReadUint32LE(p + 0 * 4) ^ l; + uint32_t crc1 = ReadUint32LE(p + 1 * 4); + uint32_t crc2 = ReadUint32LE(p + 2 * 4); + uint32_t crc3 = ReadUint32LE(p + 3 * 4); + p += 16; + + // It is possible to get better speeds (at least on x86) by interleaving + // prefetching 256 bytes ahead with processing 64 bytes at a time. See the + // portable implementation in https://github.com/google/crc32c/. + + // Process one 16-byte swath at a time. + while ((e - p) >= 16) { + STEP16; + } + + // Advance one word at a time as far as possible. + while ((e - p) >= 4) { + STEP4(0); + uint32_t tmp = crc0; + crc0 = crc1; + crc1 = crc2; + crc2 = crc3; + crc3 = tmp; + p += 4; + } + + // Combine the 4 partial stride results. + l = 0; + STEP4W(crc0); + STEP4W(crc1); + STEP4W(crc2); + STEP4W(crc3); + } + + // Process the last few bytes. + while (p != e) { + STEP1; + } +#undef STEP4W +#undef STEP16 +#undef STEP4 +#undef STEP1 + return l ^ kCRC32Xor; +} + +} // namespace crc32c +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/crc32c.h b/saraWhatsUp/Pods/leveldb-library/util/crc32c.h new file mode 100644 index 0000000..98fabb0 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/crc32c.h @@ -0,0 +1,43 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_CRC32C_H_ +#define STORAGE_LEVELDB_UTIL_CRC32C_H_ + +#include +#include + +namespace leveldb { +namespace crc32c { + +// Return the crc32c of concat(A, data[0,n-1]) where init_crc is the +// crc32c of some string A. Extend() is often used to maintain the +// crc32c of a stream of data. +uint32_t Extend(uint32_t init_crc, const char* data, size_t n); + +// Return the crc32c of data[0,n-1] +inline uint32_t Value(const char* data, size_t n) { return Extend(0, data, n); } + +static const uint32_t kMaskDelta = 0xa282ead8ul; + +// Return a masked representation of crc. +// +// Motivation: it is problematic to compute the CRC of a string that +// contains embedded CRCs. Therefore we recommend that CRCs stored +// somewhere (e.g., in files) should be masked before being stored. +inline uint32_t Mask(uint32_t crc) { + // Rotate right by 15 bits and add a constant. + return ((crc >> 15) | (crc << 17)) + kMaskDelta; +} + +// Return the crc whose masked representation is masked_crc. +inline uint32_t Unmask(uint32_t masked_crc) { + uint32_t rot = masked_crc - kMaskDelta; + return ((rot >> 17) | (rot << 15)); +} + +} // namespace crc32c +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CRC32C_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/env.cc b/saraWhatsUp/Pods/leveldb-library/util/env.cc new file mode 100644 index 0000000..6cd5f2e --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/env.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +namespace leveldb { + +Env::~Env() {} + +Status Env::NewAppendableFile(const std::string& fname, WritableFile** result) { + return Status::NotSupported("NewAppendableFile", fname); +} + +SequentialFile::~SequentialFile() {} + +RandomAccessFile::~RandomAccessFile() {} + +WritableFile::~WritableFile() {} + +Logger::~Logger() {} + +FileLock::~FileLock() {} + +void Log(Logger* info_log, const char* format, ...) { + if (info_log != nullptr) { + va_list ap; + va_start(ap, format); + info_log->Logv(format, ap); + va_end(ap); + } +} + +static Status DoWriteStringToFile(Env* env, const Slice& data, + const std::string& fname, bool should_sync) { + WritableFile* file; + Status s = env->NewWritableFile(fname, &file); + if (!s.ok()) { + return s; + } + s = file->Append(data); + if (s.ok() && should_sync) { + s = file->Sync(); + } + if (s.ok()) { + s = file->Close(); + } + delete file; // Will auto-close if we did not close above + if (!s.ok()) { + env->DeleteFile(fname); + } + return s; +} + +Status WriteStringToFile(Env* env, const Slice& data, + const std::string& fname) { + return DoWriteStringToFile(env, data, fname, false); +} + +Status WriteStringToFileSync(Env* env, const Slice& data, + const std::string& fname) { + return DoWriteStringToFile(env, data, fname, true); +} + +Status ReadFileToString(Env* env, const std::string& fname, std::string* data) { + data->clear(); + SequentialFile* file; + Status s = env->NewSequentialFile(fname, &file); + if (!s.ok()) { + return s; + } + static const int kBufferSize = 8192; + char* space = new char[kBufferSize]; + while (true) { + Slice fragment; + s = file->Read(kBufferSize, &fragment, space); + if (!s.ok()) { + break; + } + data->append(fragment.data(), fragment.size()); + if (fragment.empty()) { + break; + } + } + delete[] space; + delete file; + return s; +} + +EnvWrapper::~EnvWrapper() {} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/env_posix.cc b/saraWhatsUp/Pods/leveldb-library/util/env_posix.cc new file mode 100644 index 0000000..8c74f5a --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/env_posix.cc @@ -0,0 +1,876 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "port/port.h" +#include "port/thread_annotations.h" +#include "util/env_posix_test_helper.h" +#include "util/posix_logger.h" + +namespace leveldb { + +namespace { + +// Set by EnvPosixTestHelper::SetReadOnlyMMapLimit() and MaxOpenFiles(). +int g_open_read_only_file_limit = -1; + +// Up to 1000 mmap regions for 64-bit binaries; none for 32-bit. +constexpr const int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 1000 : 0; + +// Can be set using EnvPosixTestHelper::SetReadOnlyMMapLimit. +int g_mmap_limit = kDefaultMmapLimit; + +constexpr const size_t kWritableFileBufferSize = 65536; + +Status PosixError(const std::string& context, int error_number) { + if (error_number == ENOENT) { + return Status::NotFound(context, std::strerror(error_number)); + } else { + return Status::IOError(context, std::strerror(error_number)); + } +} + +// Helper class to limit resource usage to avoid exhaustion. +// Currently used to limit read-only file descriptors and mmap file usage +// so that we do not run out of file descriptors or virtual memory, or run into +// kernel performance problems for very large databases. +class Limiter { + public: + // Limit maximum number of resources to |max_acquires|. + Limiter(int max_acquires) : acquires_allowed_(max_acquires) {} + + Limiter(const Limiter&) = delete; + Limiter operator=(const Limiter&) = delete; + + // If another resource is available, acquire it and return true. + // Else return false. + bool Acquire() { + int old_acquires_allowed = + acquires_allowed_.fetch_sub(1, std::memory_order_relaxed); + + if (old_acquires_allowed > 0) return true; + + acquires_allowed_.fetch_add(1, std::memory_order_relaxed); + return false; + } + + // Release a resource acquired by a previous call to Acquire() that returned + // true. + void Release() { acquires_allowed_.fetch_add(1, std::memory_order_relaxed); } + + private: + // The number of available resources. + // + // This is a counter and is not tied to the invariants of any other class, so + // it can be operated on safely using std::memory_order_relaxed. + std::atomic acquires_allowed_; +}; + +// Implements sequential read access in a file using read(). +// +// Instances of this class are thread-friendly but not thread-safe, as required +// by the SequentialFile API. +class PosixSequentialFile final : public SequentialFile { + public: + PosixSequentialFile(std::string filename, int fd) + : fd_(fd), filename_(filename) {} + ~PosixSequentialFile() override { close(fd_); } + + Status Read(size_t n, Slice* result, char* scratch) override { + Status status; + while (true) { + ::ssize_t read_size = ::read(fd_, scratch, n); + if (read_size < 0) { // Read error. + if (errno == EINTR) { + continue; // Retry + } + status = PosixError(filename_, errno); + break; + } + *result = Slice(scratch, read_size); + break; + } + return status; + } + + Status Skip(uint64_t n) override { + if (::lseek(fd_, n, SEEK_CUR) == static_cast(-1)) { + return PosixError(filename_, errno); + } + return Status::OK(); + } + + private: + const int fd_; + const std::string filename_; +}; + +// Implements random read access in a file using pread(). +// +// Instances of this class are thread-safe, as required by the RandomAccessFile +// API. Instances are immutable and Read() only calls thread-safe library +// functions. +class PosixRandomAccessFile final : public RandomAccessFile { + public: + // The new instance takes ownership of |fd|. |fd_limiter| must outlive this + // instance, and will be used to determine if . + PosixRandomAccessFile(std::string filename, int fd, Limiter* fd_limiter) + : has_permanent_fd_(fd_limiter->Acquire()), + fd_(has_permanent_fd_ ? fd : -1), + fd_limiter_(fd_limiter), + filename_(std::move(filename)) { + if (!has_permanent_fd_) { + assert(fd_ == -1); + ::close(fd); // The file will be opened on every read. + } + } + + ~PosixRandomAccessFile() override { + if (has_permanent_fd_) { + assert(fd_ != -1); + ::close(fd_); + fd_limiter_->Release(); + } + } + + Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const override { + int fd = fd_; + if (!has_permanent_fd_) { + fd = ::open(filename_.c_str(), O_RDONLY); + if (fd < 0) { + return PosixError(filename_, errno); + } + } + + assert(fd != -1); + + Status status; + ssize_t read_size = ::pread(fd, scratch, n, static_cast(offset)); + *result = Slice(scratch, (read_size < 0) ? 0 : read_size); + if (read_size < 0) { + // An error: return a non-ok status. + status = PosixError(filename_, errno); + } + if (!has_permanent_fd_) { + // Close the temporary file descriptor opened earlier. + assert(fd != fd_); + ::close(fd); + } + return status; + } + + private: + const bool has_permanent_fd_; // If false, the file is opened on every read. + const int fd_; // -1 if has_permanent_fd_ is false. + Limiter* const fd_limiter_; + const std::string filename_; +}; + +// Implements random read access in a file using mmap(). +// +// Instances of this class are thread-safe, as required by the RandomAccessFile +// API. Instances are immutable and Read() only calls thread-safe library +// functions. +class PosixMmapReadableFile final : public RandomAccessFile { + public: + // mmap_base[0, length-1] points to the memory-mapped contents of the file. It + // must be the result of a successful call to mmap(). This instances takes + // over the ownership of the region. + // + // |mmap_limiter| must outlive this instance. The caller must have already + // aquired the right to use one mmap region, which will be released when this + // instance is destroyed. + PosixMmapReadableFile(std::string filename, char* mmap_base, size_t length, + Limiter* mmap_limiter) + : mmap_base_(mmap_base), + length_(length), + mmap_limiter_(mmap_limiter), + filename_(std::move(filename)) {} + + ~PosixMmapReadableFile() override { + ::munmap(static_cast(mmap_base_), length_); + mmap_limiter_->Release(); + } + + Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const override { + if (offset + n > length_) { + *result = Slice(); + return PosixError(filename_, EINVAL); + } + + *result = Slice(mmap_base_ + offset, n); + return Status::OK(); + } + + private: + char* const mmap_base_; + const size_t length_; + Limiter* const mmap_limiter_; + const std::string filename_; +}; + +class PosixWritableFile final : public WritableFile { + public: + PosixWritableFile(std::string filename, int fd) + : pos_(0), + fd_(fd), + is_manifest_(IsManifest(filename)), + filename_(std::move(filename)), + dirname_(Dirname(filename_)) {} + + ~PosixWritableFile() override { + if (fd_ >= 0) { + // Ignoring any potential errors + Close(); + } + } + + Status Append(const Slice& data) override { + size_t write_size = data.size(); + const char* write_data = data.data(); + + // Fit as much as possible into buffer. + size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_); + std::memcpy(buf_ + pos_, write_data, copy_size); + write_data += copy_size; + write_size -= copy_size; + pos_ += copy_size; + if (write_size == 0) { + return Status::OK(); + } + + // Can't fit in buffer, so need to do at least one write. + Status status = FlushBuffer(); + if (!status.ok()) { + return status; + } + + // Small writes go to buffer, large writes are written directly. + if (write_size < kWritableFileBufferSize) { + std::memcpy(buf_, write_data, write_size); + pos_ = write_size; + return Status::OK(); + } + return WriteUnbuffered(write_data, write_size); + } + + Status Close() override { + Status status = FlushBuffer(); + const int close_result = ::close(fd_); + if (close_result < 0 && status.ok()) { + status = PosixError(filename_, errno); + } + fd_ = -1; + return status; + } + + Status Flush() override { return FlushBuffer(); } + + Status Sync() override { + // Ensure new files referred to by the manifest are in the filesystem. + // + // This needs to happen before the manifest file is flushed to disk, to + // avoid crashing in a state where the manifest refers to files that are not + // yet on disk. + Status status = SyncDirIfManifest(); + if (!status.ok()) { + return status; + } + + status = FlushBuffer(); + if (!status.ok()) { + return status; + } + + return SyncFd(fd_, filename_); + } + + private: + Status FlushBuffer() { + Status status = WriteUnbuffered(buf_, pos_); + pos_ = 0; + return status; + } + + Status WriteUnbuffered(const char* data, size_t size) { + while (size > 0) { + ssize_t write_result = ::write(fd_, data, size); + if (write_result < 0) { + if (errno == EINTR) { + continue; // Retry + } + return PosixError(filename_, errno); + } + data += write_result; + size -= write_result; + } + return Status::OK(); + } + + Status SyncDirIfManifest() { + Status status; + if (!is_manifest_) { + return status; + } + + int fd = ::open(dirname_.c_str(), O_RDONLY); + if (fd < 0) { + status = PosixError(dirname_, errno); + } else { + status = SyncFd(fd, dirname_); + ::close(fd); + } + return status; + } + + // Ensures that all the caches associated with the given file descriptor's + // data are flushed all the way to durable media, and can withstand power + // failures. + // + // The path argument is only used to populate the description string in the + // returned Status if an error occurs. + static Status SyncFd(int fd, const std::string& fd_path) { +#if HAVE_FULLFSYNC + // On macOS and iOS, fsync() doesn't guarantee durability past power + // failures. fcntl(F_FULLFSYNC) is required for that purpose. Some + // filesystems don't support fcntl(F_FULLFSYNC), and require a fallback to + // fsync(). + if (::fcntl(fd, F_FULLFSYNC) == 0) { + return Status::OK(); + } +#endif // HAVE_FULLFSYNC + +#if HAVE_FDATASYNC + bool sync_success = ::fdatasync(fd) == 0; +#else + bool sync_success = ::fsync(fd) == 0; +#endif // HAVE_FDATASYNC + + if (sync_success) { + return Status::OK(); + } + return PosixError(fd_path, errno); + } + + // Returns the directory name in a path pointing to a file. + // + // Returns "." if the path does not contain any directory separator. + static std::string Dirname(const std::string& filename) { + std::string::size_type separator_pos = filename.rfind('/'); + if (separator_pos == std::string::npos) { + return std::string("."); + } + // The filename component should not contain a path separator. If it does, + // the splitting was done incorrectly. + assert(filename.find('/', separator_pos + 1) == std::string::npos); + + return filename.substr(0, separator_pos); + } + + // Extracts the file name from a path pointing to a file. + // + // The returned Slice points to |filename|'s data buffer, so it is only valid + // while |filename| is alive and unchanged. + static Slice Basename(const std::string& filename) { + std::string::size_type separator_pos = filename.rfind('/'); + if (separator_pos == std::string::npos) { + return Slice(filename); + } + // The filename component should not contain a path separator. If it does, + // the splitting was done incorrectly. + assert(filename.find('/', separator_pos + 1) == std::string::npos); + + return Slice(filename.data() + separator_pos + 1, + filename.length() - separator_pos - 1); + } + + // True if the given file is a manifest file. + static bool IsManifest(const std::string& filename) { + return Basename(filename).starts_with("MANIFEST"); + } + + // buf_[0, pos_ - 1] contains data to be written to fd_. + char buf_[kWritableFileBufferSize]; + size_t pos_; + int fd_; + + const bool is_manifest_; // True if the file's name starts with MANIFEST. + const std::string filename_; + const std::string dirname_; // The directory of filename_. +}; + +int LockOrUnlock(int fd, bool lock) { + errno = 0; + struct ::flock file_lock_info; + std::memset(&file_lock_info, 0, sizeof(file_lock_info)); + file_lock_info.l_type = (lock ? F_WRLCK : F_UNLCK); + file_lock_info.l_whence = SEEK_SET; + file_lock_info.l_start = 0; + file_lock_info.l_len = 0; // Lock/unlock entire file. + return ::fcntl(fd, F_SETLK, &file_lock_info); +} + +// Instances are thread-safe because they are immutable. +class PosixFileLock : public FileLock { + public: + PosixFileLock(int fd, std::string filename) + : fd_(fd), filename_(std::move(filename)) {} + + int fd() const { return fd_; } + const std::string& filename() const { return filename_; } + + private: + const int fd_; + const std::string filename_; +}; + +// Tracks the files locked by PosixEnv::LockFile(). +// +// We maintain a separate set instead of relying on fcntrl(F_SETLK) because +// fcntl(F_SETLK) does not provide any protection against multiple uses from the +// same process. +// +// Instances are thread-safe because all member data is guarded by a mutex. +class PosixLockTable { + public: + bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) { + mu_.Lock(); + bool succeeded = locked_files_.insert(fname).second; + mu_.Unlock(); + return succeeded; + } + void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) { + mu_.Lock(); + locked_files_.erase(fname); + mu_.Unlock(); + } + + private: + port::Mutex mu_; + std::set locked_files_ GUARDED_BY(mu_); +}; + +class PosixEnv : public Env { + public: + PosixEnv(); + ~PosixEnv() override { + static char msg[] = "PosixEnv singleton destroyed. Unsupported behavior!\n"; + std::fwrite(msg, 1, sizeof(msg), stderr); + std::abort(); + } + + Status NewSequentialFile(const std::string& filename, + SequentialFile** result) override { + int fd = ::open(filename.c_str(), O_RDONLY); + if (fd < 0) { + *result = nullptr; + return PosixError(filename, errno); + } + + *result = new PosixSequentialFile(filename, fd); + return Status::OK(); + } + + Status NewRandomAccessFile(const std::string& filename, + RandomAccessFile** result) override { + *result = nullptr; + int fd = ::open(filename.c_str(), O_RDONLY); + if (fd < 0) { + return PosixError(filename, errno); + } + + if (!mmap_limiter_.Acquire()) { + *result = new PosixRandomAccessFile(filename, fd, &fd_limiter_); + return Status::OK(); + } + + uint64_t file_size; + Status status = GetFileSize(filename, &file_size); + if (status.ok()) { + void* mmap_base = + ::mmap(/*addr=*/nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0); + if (mmap_base != MAP_FAILED) { + *result = new PosixMmapReadableFile(filename, + reinterpret_cast(mmap_base), + file_size, &mmap_limiter_); + } else { + status = PosixError(filename, errno); + } + } + ::close(fd); + if (!status.ok()) { + mmap_limiter_.Release(); + } + return status; + } + + Status NewWritableFile(const std::string& filename, + WritableFile** result) override { + int fd = ::open(filename.c_str(), O_TRUNC | O_WRONLY | O_CREAT, 0644); + if (fd < 0) { + *result = nullptr; + return PosixError(filename, errno); + } + + *result = new PosixWritableFile(filename, fd); + return Status::OK(); + } + + Status NewAppendableFile(const std::string& filename, + WritableFile** result) override { + int fd = ::open(filename.c_str(), O_APPEND | O_WRONLY | O_CREAT, 0644); + if (fd < 0) { + *result = nullptr; + return PosixError(filename, errno); + } + + *result = new PosixWritableFile(filename, fd); + return Status::OK(); + } + + bool FileExists(const std::string& filename) override { + return ::access(filename.c_str(), F_OK) == 0; + } + + Status GetChildren(const std::string& directory_path, + std::vector* result) override { + result->clear(); + ::DIR* dir = ::opendir(directory_path.c_str()); + if (dir == nullptr) { + return PosixError(directory_path, errno); + } + struct ::dirent* entry; + while ((entry = ::readdir(dir)) != nullptr) { + result->emplace_back(entry->d_name); + } + ::closedir(dir); + return Status::OK(); + } + + Status DeleteFile(const std::string& filename) override { + if (::unlink(filename.c_str()) != 0) { + return PosixError(filename, errno); + } + return Status::OK(); + } + + Status CreateDir(const std::string& dirname) override { + if (::mkdir(dirname.c_str(), 0755) != 0) { + return PosixError(dirname, errno); + } + return Status::OK(); + } + + Status DeleteDir(const std::string& dirname) override { + if (::rmdir(dirname.c_str()) != 0) { + return PosixError(dirname, errno); + } + return Status::OK(); + } + + Status GetFileSize(const std::string& filename, uint64_t* size) override { + struct ::stat file_stat; + if (::stat(filename.c_str(), &file_stat) != 0) { + *size = 0; + return PosixError(filename, errno); + } + *size = file_stat.st_size; + return Status::OK(); + } + + Status RenameFile(const std::string& from, const std::string& to) override { + if (std::rename(from.c_str(), to.c_str()) != 0) { + return PosixError(from, errno); + } + return Status::OK(); + } + + Status LockFile(const std::string& filename, FileLock** lock) override { + *lock = nullptr; + + int fd = ::open(filename.c_str(), O_RDWR | O_CREAT, 0644); + if (fd < 0) { + return PosixError(filename, errno); + } + + if (!locks_.Insert(filename)) { + ::close(fd); + return Status::IOError("lock " + filename, "already held by process"); + } + + if (LockOrUnlock(fd, true) == -1) { + int lock_errno = errno; + ::close(fd); + locks_.Remove(filename); + return PosixError("lock " + filename, lock_errno); + } + + *lock = new PosixFileLock(fd, filename); + return Status::OK(); + } + + Status UnlockFile(FileLock* lock) override { + PosixFileLock* posix_file_lock = static_cast(lock); + if (LockOrUnlock(posix_file_lock->fd(), false) == -1) { + return PosixError("unlock " + posix_file_lock->filename(), errno); + } + locks_.Remove(posix_file_lock->filename()); + ::close(posix_file_lock->fd()); + delete posix_file_lock; + return Status::OK(); + } + + void Schedule(void (*background_work_function)(void* background_work_arg), + void* background_work_arg) override; + + void StartThread(void (*thread_main)(void* thread_main_arg), + void* thread_main_arg) override; + + Status GetTestDirectory(std::string* result) override { + const char* env = std::getenv("TEST_TMPDIR"); + if (env && env[0] != '\0') { + *result = env; + } else { + char buf[100]; + std::snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", + static_cast(::geteuid())); + *result = buf; + } + + // The CreateDir status is ignored because the directory may already exist. + CreateDir(*result); + + return Status::OK(); + } + + Status NewLogger(const std::string& filename, Logger** result) override { + std::FILE* fp = std::fopen(filename.c_str(), "w"); + if (fp == nullptr) { + *result = nullptr; + return PosixError(filename, errno); + } else { + *result = new PosixLogger(fp); + return Status::OK(); + } + } + + uint64_t NowMicros() override { + static constexpr uint64_t kUsecondsPerSecond = 1000000; + struct ::timeval tv; + ::gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * kUsecondsPerSecond + tv.tv_usec; + } + + void SleepForMicroseconds(int micros) override { ::usleep(micros); } + + private: + void BackgroundThreadMain(); + + static void BackgroundThreadEntryPoint(PosixEnv* env) { + env->BackgroundThreadMain(); + } + + // Stores the work item data in a Schedule() call. + // + // Instances are constructed on the thread calling Schedule() and used on the + // background thread. + // + // This structure is thread-safe beacuse it is immutable. + struct BackgroundWorkItem { + explicit BackgroundWorkItem(void (*function)(void* arg), void* arg) + : function(function), arg(arg) {} + + void (*const function)(void*); + void* const arg; + }; + + port::Mutex background_work_mutex_; + port::CondVar background_work_cv_ GUARDED_BY(background_work_mutex_); + bool started_background_thread_ GUARDED_BY(background_work_mutex_); + + std::queue background_work_queue_ + GUARDED_BY(background_work_mutex_); + + PosixLockTable locks_; // Thread-safe. + Limiter mmap_limiter_; // Thread-safe. + Limiter fd_limiter_; // Thread-safe. +}; + +// Return the maximum number of concurrent mmaps. +int MaxMmaps() { return g_mmap_limit; } + +// Return the maximum number of read-only files to keep open. +int MaxOpenFiles() { + if (g_open_read_only_file_limit >= 0) { + return g_open_read_only_file_limit; + } + struct ::rlimit rlim; + if (::getrlimit(RLIMIT_NOFILE, &rlim)) { + // getrlimit failed, fallback to hard-coded default. + g_open_read_only_file_limit = 50; + } else if (rlim.rlim_cur == RLIM_INFINITY) { + g_open_read_only_file_limit = std::numeric_limits::max(); + } else { + // Allow use of 20% of available file descriptors for read-only files. + g_open_read_only_file_limit = rlim.rlim_cur / 5; + } + return g_open_read_only_file_limit; +} + +} // namespace + +PosixEnv::PosixEnv() + : background_work_cv_(&background_work_mutex_), + started_background_thread_(false), + mmap_limiter_(MaxMmaps()), + fd_limiter_(MaxOpenFiles()) {} + +void PosixEnv::Schedule( + void (*background_work_function)(void* background_work_arg), + void* background_work_arg) { + background_work_mutex_.Lock(); + + // Start the background thread, if we haven't done so already. + if (!started_background_thread_) { + started_background_thread_ = true; + std::thread background_thread(PosixEnv::BackgroundThreadEntryPoint, this); + background_thread.detach(); + } + + // If the queue is empty, the background thread may be waiting for work. + if (background_work_queue_.empty()) { + background_work_cv_.Signal(); + } + + background_work_queue_.emplace(background_work_function, background_work_arg); + background_work_mutex_.Unlock(); +} + +void PosixEnv::BackgroundThreadMain() { + while (true) { + background_work_mutex_.Lock(); + + // Wait until there is work to be done. + while (background_work_queue_.empty()) { + background_work_cv_.Wait(); + } + + assert(!background_work_queue_.empty()); + auto background_work_function = background_work_queue_.front().function; + void* background_work_arg = background_work_queue_.front().arg; + background_work_queue_.pop(); + + background_work_mutex_.Unlock(); + background_work_function(background_work_arg); + } +} + +namespace { + +// Wraps an Env instance whose destructor is never created. +// +// Intended usage: +// using PlatformSingletonEnv = SingletonEnv; +// void ConfigurePosixEnv(int param) { +// PlatformSingletonEnv::AssertEnvNotInitialized(); +// // set global configuration flags. +// } +// Env* Env::Default() { +// static PlatformSingletonEnv default_env; +// return default_env.env(); +// } +template +class SingletonEnv { + public: + SingletonEnv() { +#if !defined(NDEBUG) + env_initialized_.store(true, std::memory_order::memory_order_relaxed); +#endif // !defined(NDEBUG) + static_assert(sizeof(env_storage_) >= sizeof(EnvType), + "env_storage_ will not fit the Env"); + static_assert(alignof(decltype(env_storage_)) >= alignof(EnvType), + "env_storage_ does not meet the Env's alignment needs"); + new (&env_storage_) EnvType(); + } + ~SingletonEnv() = default; + + SingletonEnv(const SingletonEnv&) = delete; + SingletonEnv& operator=(const SingletonEnv&) = delete; + + Env* env() { return reinterpret_cast(&env_storage_); } + + static void AssertEnvNotInitialized() { +#if !defined(NDEBUG) + assert(!env_initialized_.load(std::memory_order::memory_order_relaxed)); +#endif // !defined(NDEBUG) + } + + private: + typename std::aligned_storage::type + env_storage_; +#if !defined(NDEBUG) + static std::atomic env_initialized_; +#endif // !defined(NDEBUG) +}; + +#if !defined(NDEBUG) +template +std::atomic SingletonEnv::env_initialized_; +#endif // !defined(NDEBUG) + +using PosixDefaultEnv = SingletonEnv; + +} // namespace + +void PosixEnv::StartThread(void (*thread_main)(void* thread_main_arg), + void* thread_main_arg) { + std::thread new_thread(thread_main, thread_main_arg); + new_thread.detach(); +} + +void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) { + PosixDefaultEnv::AssertEnvNotInitialized(); + g_open_read_only_file_limit = limit; +} + +void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) { + PosixDefaultEnv::AssertEnvNotInitialized(); + g_mmap_limit = limit; +} + +Env* Env::Default() { + static PosixDefaultEnv env_container; + return env_container.env(); +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/env_posix_test_helper.h b/saraWhatsUp/Pods/leveldb-library/util/env_posix_test_helper.h new file mode 100644 index 0000000..0386960 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/env_posix_test_helper.h @@ -0,0 +1,28 @@ +// Copyright 2017 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ +#define STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ + +namespace leveldb { + +class EnvPosixTest; + +// A helper for the POSIX Env to facilitate testing. +class EnvPosixTestHelper { + private: + friend class EnvPosixTest; + + // Set the maximum number of read-only files that will be opened. + // Must be called before creating an Env. + static void SetReadOnlyFDLimit(int limit); + + // Set the maximum number of read-only files that will be mapped via mmap. + // Must be called before creating an Env. + static void SetReadOnlyMMapLimit(int limit); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/env_windows_test_helper.h b/saraWhatsUp/Pods/leveldb-library/util/env_windows_test_helper.h new file mode 100644 index 0000000..e6f6020 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/env_windows_test_helper.h @@ -0,0 +1,25 @@ +// Copyright 2018 (c) The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_ENV_WINDOWS_TEST_HELPER_H_ +#define STORAGE_LEVELDB_UTIL_ENV_WINDOWS_TEST_HELPER_H_ + +namespace leveldb { + +class EnvWindowsTest; + +// A helper for the Windows Env to facilitate testing. +class EnvWindowsTestHelper { + private: + friend class CorruptionTest; + friend class EnvWindowsTest; + + // Set the maximum number of read-only files that will be mapped via mmap. + // Must be called before creating an Env. + static void SetReadOnlyMMapLimit(int limit); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_ENV_WINDOWS_TEST_HELPER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/filter_policy.cc b/saraWhatsUp/Pods/leveldb-library/util/filter_policy.cc new file mode 100644 index 0000000..90fd754 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/filter_policy.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +namespace leveldb { + +FilterPolicy::~FilterPolicy() {} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/hash.cc b/saraWhatsUp/Pods/leveldb-library/util/hash.cc new file mode 100644 index 0000000..67dc134 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/hash.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/hash.h" + +#include + +#include "util/coding.h" + +// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through +// between switch labels. The real definition should be provided externally. +// This one is a fallback version for unsupported compilers. +#ifndef FALLTHROUGH_INTENDED +#define FALLTHROUGH_INTENDED \ + do { \ + } while (0) +#endif + +namespace leveldb { + +uint32_t Hash(const char* data, size_t n, uint32_t seed) { + // Similar to murmur hash + const uint32_t m = 0xc6a4a793; + const uint32_t r = 24; + const char* limit = data + n; + uint32_t h = seed ^ (n * m); + + // Pick up four bytes at a time + while (data + 4 <= limit) { + uint32_t w = DecodeFixed32(data); + data += 4; + h += w; + h *= m; + h ^= (h >> 16); + } + + // Pick up remaining bytes + switch (limit - data) { + case 3: + h += static_cast(data[2]) << 16; + FALLTHROUGH_INTENDED; + case 2: + h += static_cast(data[1]) << 8; + FALLTHROUGH_INTENDED; + case 1: + h += static_cast(data[0]); + h *= m; + h ^= (h >> r); + break; + } + return h; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/hash.h b/saraWhatsUp/Pods/leveldb-library/util/hash.h new file mode 100644 index 0000000..74bdb6e --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/hash.h @@ -0,0 +1,19 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Simple hash function used for internal data structures + +#ifndef STORAGE_LEVELDB_UTIL_HASH_H_ +#define STORAGE_LEVELDB_UTIL_HASH_H_ + +#include +#include + +namespace leveldb { + +uint32_t Hash(const char* data, size_t n, uint32_t seed); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_HASH_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/histogram.cc b/saraWhatsUp/Pods/leveldb-library/util/histogram.cc new file mode 100644 index 0000000..65092c8 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/histogram.cc @@ -0,0 +1,272 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/histogram.h" + +#include +#include + +#include "port/port.h" + +namespace leveldb { + +const double Histogram::kBucketLimit[kNumBuckets] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 12, + 14, + 16, + 18, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 60, + 70, + 80, + 90, + 100, + 120, + 140, + 160, + 180, + 200, + 250, + 300, + 350, + 400, + 450, + 500, + 600, + 700, + 800, + 900, + 1000, + 1200, + 1400, + 1600, + 1800, + 2000, + 2500, + 3000, + 3500, + 4000, + 4500, + 5000, + 6000, + 7000, + 8000, + 9000, + 10000, + 12000, + 14000, + 16000, + 18000, + 20000, + 25000, + 30000, + 35000, + 40000, + 45000, + 50000, + 60000, + 70000, + 80000, + 90000, + 100000, + 120000, + 140000, + 160000, + 180000, + 200000, + 250000, + 300000, + 350000, + 400000, + 450000, + 500000, + 600000, + 700000, + 800000, + 900000, + 1000000, + 1200000, + 1400000, + 1600000, + 1800000, + 2000000, + 2500000, + 3000000, + 3500000, + 4000000, + 4500000, + 5000000, + 6000000, + 7000000, + 8000000, + 9000000, + 10000000, + 12000000, + 14000000, + 16000000, + 18000000, + 20000000, + 25000000, + 30000000, + 35000000, + 40000000, + 45000000, + 50000000, + 60000000, + 70000000, + 80000000, + 90000000, + 100000000, + 120000000, + 140000000, + 160000000, + 180000000, + 200000000, + 250000000, + 300000000, + 350000000, + 400000000, + 450000000, + 500000000, + 600000000, + 700000000, + 800000000, + 900000000, + 1000000000, + 1200000000, + 1400000000, + 1600000000, + 1800000000, + 2000000000, + 2500000000.0, + 3000000000.0, + 3500000000.0, + 4000000000.0, + 4500000000.0, + 5000000000.0, + 6000000000.0, + 7000000000.0, + 8000000000.0, + 9000000000.0, + 1e200, +}; + +void Histogram::Clear() { + min_ = kBucketLimit[kNumBuckets - 1]; + max_ = 0; + num_ = 0; + sum_ = 0; + sum_squares_ = 0; + for (int i = 0; i < kNumBuckets; i++) { + buckets_[i] = 0; + } +} + +void Histogram::Add(double value) { + // Linear search is fast enough for our usage in db_bench + int b = 0; + while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) { + b++; + } + buckets_[b] += 1.0; + if (min_ > value) min_ = value; + if (max_ < value) max_ = value; + num_++; + sum_ += value; + sum_squares_ += (value * value); +} + +void Histogram::Merge(const Histogram& other) { + if (other.min_ < min_) min_ = other.min_; + if (other.max_ > max_) max_ = other.max_; + num_ += other.num_; + sum_ += other.sum_; + sum_squares_ += other.sum_squares_; + for (int b = 0; b < kNumBuckets; b++) { + buckets_[b] += other.buckets_[b]; + } +} + +double Histogram::Median() const { return Percentile(50.0); } + +double Histogram::Percentile(double p) const { + double threshold = num_ * (p / 100.0); + double sum = 0; + for (int b = 0; b < kNumBuckets; b++) { + sum += buckets_[b]; + if (sum >= threshold) { + // Scale linearly within this bucket + double left_point = (b == 0) ? 0 : kBucketLimit[b - 1]; + double right_point = kBucketLimit[b]; + double left_sum = sum - buckets_[b]; + double right_sum = sum; + double pos = (threshold - left_sum) / (right_sum - left_sum); + double r = left_point + (right_point - left_point) * pos; + if (r < min_) r = min_; + if (r > max_) r = max_; + return r; + } + } + return max_; +} + +double Histogram::Average() const { + if (num_ == 0.0) return 0; + return sum_ / num_; +} + +double Histogram::StandardDeviation() const { + if (num_ == 0.0) return 0; + double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_); + return sqrt(variance); +} + +std::string Histogram::ToString() const { + std::string r; + char buf[200]; + snprintf(buf, sizeof(buf), "Count: %.0f Average: %.4f StdDev: %.2f\n", num_, + Average(), StandardDeviation()); + r.append(buf); + snprintf(buf, sizeof(buf), "Min: %.4f Median: %.4f Max: %.4f\n", + (num_ == 0.0 ? 0.0 : min_), Median(), max_); + r.append(buf); + r.append("------------------------------------------------------\n"); + const double mult = 100.0 / num_; + double sum = 0; + for (int b = 0; b < kNumBuckets; b++) { + if (buckets_[b] <= 0.0) continue; + sum += buckets_[b]; + snprintf(buf, sizeof(buf), "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ", + ((b == 0) ? 0.0 : kBucketLimit[b - 1]), // left + kBucketLimit[b], // right + buckets_[b], // count + mult * buckets_[b], // percentage + mult * sum); // cumulative percentage + r.append(buf); + + // Add hash marks based on percentage; 20 marks for 100%. + int marks = static_cast(20 * (buckets_[b] / num_) + 0.5); + r.append(marks, '#'); + r.push_back('\n'); + } + return r; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/histogram.h b/saraWhatsUp/Pods/leveldb-library/util/histogram.h new file mode 100644 index 0000000..4da60fb --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/histogram.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ +#define STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ + +#include + +namespace leveldb { + +class Histogram { + public: + Histogram() {} + ~Histogram() {} + + void Clear(); + void Add(double value); + void Merge(const Histogram& other); + + std::string ToString() const; + + private: + enum { kNumBuckets = 154 }; + + double Median() const; + double Percentile(double p) const; + double Average() const; + double StandardDeviation() const; + + static const double kBucketLimit[kNumBuckets]; + + double min_; + double max_; + double num_; + double sum_; + double sum_squares_; + + double buckets_[kNumBuckets]; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/logging.cc b/saraWhatsUp/Pods/leveldb-library/util/logging.cc new file mode 100644 index 0000000..1ad8f1c --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/logging.cc @@ -0,0 +1,85 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/logging.h" + +#include +#include +#include +#include + +#include + +#include "leveldb/env.h" +#include "leveldb/slice.h" + +namespace leveldb { + +void AppendNumberTo(std::string* str, uint64_t num) { + char buf[30]; + snprintf(buf, sizeof(buf), "%llu", (unsigned long long)num); + str->append(buf); +} + +void AppendEscapedStringTo(std::string* str, const Slice& value) { + for (size_t i = 0; i < value.size(); i++) { + char c = value[i]; + if (c >= ' ' && c <= '~') { + str->push_back(c); + } else { + char buf[10]; + snprintf(buf, sizeof(buf), "\\x%02x", + static_cast(c) & 0xff); + str->append(buf); + } + } +} + +std::string NumberToString(uint64_t num) { + std::string r; + AppendNumberTo(&r, num); + return r; +} + +std::string EscapeString(const Slice& value) { + std::string r; + AppendEscapedStringTo(&r, value); + return r; +} + +bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { + // Constants that will be optimized away. + constexpr const uint64_t kMaxUint64 = std::numeric_limits::max(); + constexpr const char kLastDigitOfMaxUint64 = + '0' + static_cast(kMaxUint64 % 10); + + uint64_t value = 0; + + // reinterpret_cast-ing from char* to unsigned char* to avoid signedness. + const unsigned char* start = + reinterpret_cast(in->data()); + + const unsigned char* end = start + in->size(); + const unsigned char* current = start; + for (; current != end; ++current) { + const unsigned char ch = *current; + if (ch < '0' || ch > '9') break; + + // Overflow check. + // kMaxUint64 / 10 is also constant and will be optimized away. + if (value > kMaxUint64 / 10 || + (value == kMaxUint64 / 10 && ch > kLastDigitOfMaxUint64)) { + return false; + } + + value = (value * 10) + (ch - '0'); + } + + *val = value; + const size_t digits_consumed = current - start; + in->remove_prefix(digits_consumed); + return digits_consumed != 0; +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/logging.h b/saraWhatsUp/Pods/leveldb-library/util/logging.h new file mode 100644 index 0000000..8ff2da8 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/logging.h @@ -0,0 +1,45 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Must not be included from any .h files to avoid polluting the namespace +// with macros. + +#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_ +#define STORAGE_LEVELDB_UTIL_LOGGING_H_ + +#include +#include + +#include + +#include "port/port.h" + +namespace leveldb { + +class Slice; +class WritableFile; + +// Append a human-readable printout of "num" to *str +void AppendNumberTo(std::string* str, uint64_t num); + +// Append a human-readable printout of "value" to *str. +// Escapes any non-printable characters found in "value". +void AppendEscapedStringTo(std::string* str, const Slice& value); + +// Return a human-readable printout of "num" +std::string NumberToString(uint64_t num); + +// Return a human-readable version of "value". +// Escapes any non-printable characters found in "value". +std::string EscapeString(const Slice& value); + +// Parse a human-readable number from "*in" into *value. On success, +// advances "*in" past the consumed number and sets "*val" to the +// numeric value. Otherwise, returns false and leaves *in in an +// unspecified state. +bool ConsumeDecimalNumber(Slice* in, uint64_t* val); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_LOGGING_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/mutexlock.h b/saraWhatsUp/Pods/leveldb-library/util/mutexlock.h new file mode 100644 index 0000000..0cb2e25 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/mutexlock.h @@ -0,0 +1,39 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ +#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ + +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +// Helper class that locks a mutex on construction and unlocks the mutex when +// the destructor of the MutexLock object is invoked. +// +// Typical usage: +// +// void MyClass::MyMethod() { +// MutexLock l(&mu_); // mu_ is an instance variable +// ... some complex code, possibly with multiple return paths ... +// } + +class SCOPED_LOCKABLE MutexLock { + public: + explicit MutexLock(port::Mutex* mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { + this->mu_->Lock(); + } + ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); } + + MutexLock(const MutexLock&) = delete; + MutexLock& operator=(const MutexLock&) = delete; + + private: + port::Mutex* const mu_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/no_destructor.h b/saraWhatsUp/Pods/leveldb-library/util/no_destructor.h new file mode 100644 index 0000000..a0d3b87 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/no_destructor.h @@ -0,0 +1,46 @@ +// Copyright (c) 2018 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_ +#define STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_ + +#include +#include + +namespace leveldb { + +// Wraps an instance whose destructor is never called. +// +// This is intended for use with function-level static variables. +template +class NoDestructor { + public: + template + explicit NoDestructor(ConstructorArgTypes&&... constructor_args) { + static_assert(sizeof(instance_storage_) >= sizeof(InstanceType), + "instance_storage_ is not large enough to hold the instance"); + static_assert( + alignof(decltype(instance_storage_)) >= alignof(InstanceType), + "instance_storage_ does not meet the instance's alignment requirement"); + new (&instance_storage_) + InstanceType(std::forward(constructor_args)...); + } + + ~NoDestructor() = default; + + NoDestructor(const NoDestructor&) = delete; + NoDestructor& operator=(const NoDestructor&) = delete; + + InstanceType* get() { + return reinterpret_cast(&instance_storage_); + } + + private: + typename std::aligned_storage::type instance_storage_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/options.cc b/saraWhatsUp/Pods/leveldb-library/util/options.cc new file mode 100644 index 0000000..62de5bf --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/options.cc @@ -0,0 +1,14 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/options.h" + +#include "leveldb/comparator.h" +#include "leveldb/env.h" + +namespace leveldb { + +Options::Options() : comparator(BytewiseComparator()), env(Env::Default()) {} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/posix_logger.h b/saraWhatsUp/Pods/leveldb-library/util/posix_logger.h new file mode 100644 index 0000000..28e15d1 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/posix_logger.h @@ -0,0 +1,130 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Logger implementation that can be shared by all environments +// where enough posix functionality is available. + +#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ +#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ + +#include + +#include +#include +#include +#include +#include +#include + +#include "leveldb/env.h" + +namespace leveldb { + +class PosixLogger final : public Logger { + public: + // Creates a logger that writes to the given file. + // + // The PosixLogger instance takes ownership of the file handle. + explicit PosixLogger(std::FILE* fp) : fp_(fp) { assert(fp != nullptr); } + + ~PosixLogger() override { std::fclose(fp_); } + + void Logv(const char* format, va_list arguments) override { + // Record the time as close to the Logv() call as possible. + struct ::timeval now_timeval; + ::gettimeofday(&now_timeval, nullptr); + const std::time_t now_seconds = now_timeval.tv_sec; + struct std::tm now_components; + ::localtime_r(&now_seconds, &now_components); + + // Record the thread ID. + constexpr const int kMaxThreadIdSize = 32; + std::ostringstream thread_stream; + thread_stream << std::this_thread::get_id(); + std::string thread_id = thread_stream.str(); + if (thread_id.size() > kMaxThreadIdSize) { + thread_id.resize(kMaxThreadIdSize); + } + + // We first attempt to print into a stack-allocated buffer. If this attempt + // fails, we make a second attempt with a dynamically allocated buffer. + constexpr const int kStackBufferSize = 512; + char stack_buffer[kStackBufferSize]; + static_assert(sizeof(stack_buffer) == static_cast(kStackBufferSize), + "sizeof(char) is expected to be 1 in C++"); + + int dynamic_buffer_size = 0; // Computed in the first iteration. + for (int iteration = 0; iteration < 2; ++iteration) { + const int buffer_size = + (iteration == 0) ? kStackBufferSize : dynamic_buffer_size; + char* const buffer = + (iteration == 0) ? stack_buffer : new char[dynamic_buffer_size]; + + // Print the header into the buffer. + int buffer_offset = snprintf( + buffer, buffer_size, "%04d/%02d/%02d-%02d:%02d:%02d.%06d %s ", + now_components.tm_year + 1900, now_components.tm_mon + 1, + now_components.tm_mday, now_components.tm_hour, now_components.tm_min, + now_components.tm_sec, static_cast(now_timeval.tv_usec), + thread_id.c_str()); + + // The header can be at most 28 characters (10 date + 15 time + + // 3 delimiters) plus the thread ID, which should fit comfortably into the + // static buffer. + assert(buffer_offset <= 28 + kMaxThreadIdSize); + static_assert(28 + kMaxThreadIdSize < kStackBufferSize, + "stack-allocated buffer may not fit the message header"); + assert(buffer_offset < buffer_size); + + // Print the message into the buffer. + std::va_list arguments_copy; + va_copy(arguments_copy, arguments); + buffer_offset += + std::vsnprintf(buffer + buffer_offset, buffer_size - buffer_offset, + format, arguments_copy); + va_end(arguments_copy); + + // The code below may append a newline at the end of the buffer, which + // requires an extra character. + if (buffer_offset >= buffer_size - 1) { + // The message did not fit into the buffer. + if (iteration == 0) { + // Re-run the loop and use a dynamically-allocated buffer. The buffer + // will be large enough for the log message, an extra newline and a + // null terminator. + dynamic_buffer_size = buffer_offset + 2; + continue; + } + + // The dynamically-allocated buffer was incorrectly sized. This should + // not happen, assuming a correct implementation of (v)snprintf. Fail + // in tests, recover by truncating the log message in production. + assert(false); + buffer_offset = buffer_size - 1; + } + + // Add a newline if necessary. + if (buffer[buffer_offset - 1] != '\n') { + buffer[buffer_offset] = '\n'; + ++buffer_offset; + } + + assert(buffer_offset <= buffer_size); + std::fwrite(buffer, 1, buffer_offset, fp_); + std::fflush(fp_); + + if (iteration != 0) { + delete[] buffer; + } + break; + } + } + + private: + std::FILE* const fp_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/random.h b/saraWhatsUp/Pods/leveldb-library/util/random.h new file mode 100644 index 0000000..76f7daf --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/random.h @@ -0,0 +1,63 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_ +#define STORAGE_LEVELDB_UTIL_RANDOM_H_ + +#include + +namespace leveldb { + +// A very simple random number generator. Not especially good at +// generating truly random bits, but good enough for our needs in this +// package. +class Random { + private: + uint32_t seed_; + + public: + explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { + // Avoid bad seeds. + if (seed_ == 0 || seed_ == 2147483647L) { + seed_ = 1; + } + } + uint32_t Next() { + static const uint32_t M = 2147483647L; // 2^31-1 + static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 + // We are computing + // seed_ = (seed_ * A) % M, where M = 2^31-1 + // + // seed_ must not be zero or M, or else all subsequent computed values + // will be zero or M respectively. For all other values, seed_ will end + // up cycling through every number in [1,M-1] + uint64_t product = seed_ * A; + + // Compute (product % M) using the fact that ((x << 31) % M) == x. + seed_ = static_cast((product >> 31) + (product & M)); + // The first reduction may overflow by 1 bit, so we may need to + // repeat. mod == M is not possible; using > allows the faster + // sign-bit-based test. + if (seed_ > M) { + seed_ -= M; + } + return seed_; + } + // Returns a uniformly distributed value in the range [0..n-1] + // REQUIRES: n > 0 + uint32_t Uniform(int n) { return Next() % n; } + + // Randomly returns true ~"1/n" of the time, and false otherwise. + // REQUIRES: n > 0 + bool OneIn(int n) { return (Next() % n) == 0; } + + // Skewed: pick "base" uniformly from range [0,max_log] and then + // return "base" random bits. The effect is to pick a number in the + // range [0,2^max_log-1] with exponential bias towards smaller numbers. + uint32_t Skewed(int max_log) { return Uniform(1 << Uniform(max_log + 1)); } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_RANDOM_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/status.cc b/saraWhatsUp/Pods/leveldb-library/util/status.cc new file mode 100644 index 0000000..6ca8da6 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/status.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/status.h" + +#include + +#include "port/port.h" + +namespace leveldb { + +const char* Status::CopyState(const char* state) { + uint32_t size; + memcpy(&size, state, sizeof(size)); + char* result = new char[size + 5]; + memcpy(result, state, size + 5); + return result; +} + +Status::Status(Code code, const Slice& msg, const Slice& msg2) { + assert(code != kOk); + const uint32_t len1 = msg.size(); + const uint32_t len2 = msg2.size(); + const uint32_t size = len1 + (len2 ? (2 + len2) : 0); + char* result = new char[size + 5]; + memcpy(result, &size, sizeof(size)); + result[4] = static_cast(code); + memcpy(result + 5, msg.data(), len1); + if (len2) { + result[5 + len1] = ':'; + result[6 + len1] = ' '; + memcpy(result + 7 + len1, msg2.data(), len2); + } + state_ = result; +} + +std::string Status::ToString() const { + if (state_ == nullptr) { + return "OK"; + } else { + char tmp[30]; + const char* type; + switch (code()) { + case kOk: + type = "OK"; + break; + case kNotFound: + type = "NotFound: "; + break; + case kCorruption: + type = "Corruption: "; + break; + case kNotSupported: + type = "Not implemented: "; + break; + case kInvalidArgument: + type = "Invalid argument: "; + break; + case kIOError: + type = "IO error: "; + break; + default: + snprintf(tmp, sizeof(tmp), + "Unknown code(%d): ", static_cast(code())); + type = tmp; + break; + } + std::string result(type); + uint32_t length; + memcpy(&length, state_, sizeof(length)); + result.append(state_ + 5, length); + return result; + } +} + +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/testharness.cc b/saraWhatsUp/Pods/leveldb-library/util/testharness.cc new file mode 100644 index 0000000..318ecfa --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/testharness.cc @@ -0,0 +1,81 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/testharness.h" + +#include +#include +#include + +#include +#include + +#include "leveldb/env.h" + +namespace leveldb { +namespace test { + +namespace { +struct Test { + const char* base; + const char* name; + void (*func)(); +}; +std::vector* tests; +} // namespace + +bool RegisterTest(const char* base, const char* name, void (*func)()) { + if (tests == nullptr) { + tests = new std::vector; + } + Test t; + t.base = base; + t.name = name; + t.func = func; + tests->push_back(t); + return true; +} + +int RunAllTests() { + const char* matcher = getenv("LEVELDB_TESTS"); + + int num = 0; + if (tests != nullptr) { + for (size_t i = 0; i < tests->size(); i++) { + const Test& t = (*tests)[i]; + if (matcher != nullptr) { + std::string name = t.base; + name.push_back('.'); + name.append(t.name); + if (strstr(name.c_str(), matcher) == nullptr) { + continue; + } + } + fprintf(stderr, "==== Test %s.%s\n", t.base, t.name); + (*t.func)(); + ++num; + } + } + fprintf(stderr, "==== PASSED %d tests\n", num); + return 0; +} + +std::string TmpDir() { + std::string dir; + Status s = Env::Default()->GetTestDirectory(&dir); + ASSERT_TRUE(s.ok()) << s.ToString(); + return dir; +} + +int RandomSeed() { + const char* env = getenv("TEST_RANDOM_SEED"); + int result = (env != nullptr ? atoi(env) : 301); + if (result <= 0) { + result = 301; + } + return result; +} + +} // namespace test +} // namespace leveldb diff --git a/saraWhatsUp/Pods/leveldb-library/util/testharness.h b/saraWhatsUp/Pods/leveldb-library/util/testharness.h new file mode 100644 index 0000000..72cd162 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/testharness.h @@ -0,0 +1,141 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ +#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ + +#include +#include + +#include + +#include "leveldb/status.h" + +namespace leveldb { +namespace test { + +// Run some of the tests registered by the TEST() macro. If the +// environment variable "LEVELDB_TESTS" is not set, runs all tests. +// Otherwise, runs only the tests whose name contains the value of +// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are: +// TEST(Foo, Hello) { ... } +// TEST(Foo, World) { ... } +// LEVELDB_TESTS=Hello will run the first test +// LEVELDB_TESTS=o will run both tests +// LEVELDB_TESTS=Junk will run no tests +// +// Returns 0 if all tests pass. +// Dies or returns a non-zero value if some test fails. +int RunAllTests(); + +// Return the directory to use for temporary storage. +std::string TmpDir(); + +// Return a randomization seed for this run. Typically returns the +// same number on repeated invocations of this binary, but automated +// runs may be able to vary the seed. +int RandomSeed(); + +// An instance of Tester is allocated to hold temporary state during +// the execution of an assertion. +class Tester { + private: + bool ok_; + const char* fname_; + int line_; + std::stringstream ss_; + + public: + Tester(const char* f, int l) : ok_(true), fname_(f), line_(l) {} + + ~Tester() { + if (!ok_) { + fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); + exit(1); + } + } + + Tester& Is(bool b, const char* msg) { + if (!b) { + ss_ << " Assertion failure " << msg; + ok_ = false; + } + return *this; + } + + Tester& IsOk(const Status& s) { + if (!s.ok()) { + ss_ << " " << s.ToString(); + ok_ = false; + } + return *this; + } + +#define BINARY_OP(name, op) \ + template \ + Tester& name(const X& x, const Y& y) { \ + if (!(x op y)) { \ + ss_ << " failed: " << x << (" " #op " ") << y; \ + ok_ = false; \ + } \ + return *this; \ + } + + BINARY_OP(IsEq, ==) + BINARY_OP(IsNe, !=) + BINARY_OP(IsGe, >=) + BINARY_OP(IsGt, >) + BINARY_OP(IsLe, <=) + BINARY_OP(IsLt, <) +#undef BINARY_OP + + // Attach the specified value to the error message if an error has occurred + template + Tester& operator<<(const V& value) { + if (!ok_) { + ss_ << " " << value; + } + return *this; + } +}; + +#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c) +#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s)) +#define ASSERT_EQ(a, b) \ + ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a), (b)) +#define ASSERT_NE(a, b) \ + ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a), (b)) +#define ASSERT_GE(a, b) \ + ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a), (b)) +#define ASSERT_GT(a, b) \ + ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a), (b)) +#define ASSERT_LE(a, b) \ + ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a), (b)) +#define ASSERT_LT(a, b) \ + ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a), (b)) + +#define TCONCAT(a, b) TCONCAT1(a, b) +#define TCONCAT1(a, b) a##b + +#define TEST(base, name) \ + class TCONCAT(_Test_, name) : public base { \ + public: \ + void _Run(); \ + static void _RunIt() { \ + TCONCAT(_Test_, name) t; \ + t._Run(); \ + } \ + }; \ + bool TCONCAT(_Test_ignored_, name) = ::leveldb::test::RegisterTest( \ + #base, #name, &TCONCAT(_Test_, name)::_RunIt); \ + void TCONCAT(_Test_, name)::_Run() + +// Register the specified test. Typically not used directly, but +// invoked via the macro expansion of TEST. +bool RegisterTest(const char* base, const char* name, void (*func)()); + +} // namespace test +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/testutil.h b/saraWhatsUp/Pods/leveldb-library/util/testutil.h new file mode 100644 index 0000000..bb4051b --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/testutil.h @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_ +#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_ + +#include "helpers/memenv/memenv.h" +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "util/random.h" + +namespace leveldb { +namespace test { + +// Store in *dst a random string of length "len" and return a Slice that +// references the generated data. +Slice RandomString(Random* rnd, int len, std::string* dst); + +// Return a random key with the specified length that may contain interesting +// characters (e.g. \x00, \xff, etc.). +std::string RandomKey(Random* rnd, int len); + +// Store in *dst a string of length "len" that will compress to +// "N*compressed_fraction" bytes and return a Slice that references +// the generated data. +Slice CompressibleString(Random* rnd, double compressed_fraction, size_t len, + std::string* dst); + +// A wrapper that allows injection of errors. +class ErrorEnv : public EnvWrapper { + public: + bool writable_file_error_; + int num_writable_file_errors_; + + ErrorEnv() + : EnvWrapper(NewMemEnv(Env::Default())), + writable_file_error_(false), + num_writable_file_errors_(0) {} + ~ErrorEnv() override { delete target(); } + + Status NewWritableFile(const std::string& fname, + WritableFile** result) override { + if (writable_file_error_) { + ++num_writable_file_errors_; + *result = nullptr; + return Status::IOError(fname, "fake error"); + } + return target()->NewWritableFile(fname, result); + } + + Status NewAppendableFile(const std::string& fname, + WritableFile** result) override { + if (writable_file_error_) { + ++num_writable_file_errors_; + *result = nullptr; + return Status::IOError(fname, "fake error"); + } + return target()->NewAppendableFile(fname, result); + } +}; + +} // namespace test +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_TESTUTIL_H_ diff --git a/saraWhatsUp/Pods/leveldb-library/util/windows_logger.h b/saraWhatsUp/Pods/leveldb-library/util/windows_logger.h new file mode 100644 index 0000000..9296063 --- /dev/null +++ b/saraWhatsUp/Pods/leveldb-library/util/windows_logger.h @@ -0,0 +1,124 @@ +// Copyright (c) 2018 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Logger implementation for the Windows platform. + +#ifndef STORAGE_LEVELDB_UTIL_WINDOWS_LOGGER_H_ +#define STORAGE_LEVELDB_UTIL_WINDOWS_LOGGER_H_ + +#include +#include +#include +#include +#include +#include + +#include "leveldb/env.h" + +namespace leveldb { + +class WindowsLogger final : public Logger { + public: + // Creates a logger that writes to the given file. + // + // The PosixLogger instance takes ownership of the file handle. + explicit WindowsLogger(std::FILE* fp) : fp_(fp) { assert(fp != nullptr); } + + ~WindowsLogger() override { std::fclose(fp_); } + + void Logv(const char* format, va_list arguments) override { + // Record the time as close to the Logv() call as possible. + SYSTEMTIME now_components; + ::GetLocalTime(&now_components); + + // Record the thread ID. + constexpr const int kMaxThreadIdSize = 32; + std::ostringstream thread_stream; + thread_stream << std::this_thread::get_id(); + std::string thread_id = thread_stream.str(); + if (thread_id.size() > kMaxThreadIdSize) { + thread_id.resize(kMaxThreadIdSize); + } + + // We first attempt to print into a stack-allocated buffer. If this attempt + // fails, we make a second attempt with a dynamically allocated buffer. + constexpr const int kStackBufferSize = 512; + char stack_buffer[kStackBufferSize]; + static_assert(sizeof(stack_buffer) == static_cast(kStackBufferSize), + "sizeof(char) is expected to be 1 in C++"); + + int dynamic_buffer_size = 0; // Computed in the first iteration. + for (int iteration = 0; iteration < 2; ++iteration) { + const int buffer_size = + (iteration == 0) ? kStackBufferSize : dynamic_buffer_size; + char* const buffer = + (iteration == 0) ? stack_buffer : new char[dynamic_buffer_size]; + + // Print the header into the buffer. + int buffer_offset = snprintf( + buffer, buffer_size, "%04d/%02d/%02d-%02d:%02d:%02d.%06d %s ", + now_components.wYear, now_components.wMonth, now_components.wDay, + now_components.wHour, now_components.wMinute, now_components.wSecond, + static_cast(now_components.wMilliseconds * 1000), + thread_id.c_str()); + + // The header can be at most 28 characters (10 date + 15 time + + // 3 delimiters) plus the thread ID, which should fit comfortably into the + // static buffer. + assert(buffer_offset <= 28 + kMaxThreadIdSize); + static_assert(28 + kMaxThreadIdSize < kStackBufferSize, + "stack-allocated buffer may not fit the message header"); + assert(buffer_offset < buffer_size); + + // Print the message into the buffer. + std::va_list arguments_copy; + va_copy(arguments_copy, arguments); + buffer_offset += + std::vsnprintf(buffer + buffer_offset, buffer_size - buffer_offset, + format, arguments_copy); + va_end(arguments_copy); + + // The code below may append a newline at the end of the buffer, which + // requires an extra character. + if (buffer_offset >= buffer_size - 1) { + // The message did not fit into the buffer. + if (iteration == 0) { + // Re-run the loop and use a dynamically-allocated buffer. The buffer + // will be large enough for the log message, an extra newline and a + // null terminator. + dynamic_buffer_size = buffer_offset + 2; + continue; + } + + // The dynamically-allocated buffer was incorrectly sized. This should + // not happen, assuming a correct implementation of (v)snprintf. Fail + // in tests, recover by truncating the log message in production. + assert(false); + buffer_offset = buffer_size - 1; + } + + // Add a newline if necessary. + if (buffer[buffer_offset - 1] != '\n') { + buffer[buffer_offset] = '\n'; + ++buffer_offset; + } + + assert(buffer_offset <= buffer_size); + std::fwrite(buffer, 1, buffer_offset, fp_); + std::fflush(fp_); + + if (iteration != 0) { + delete[] buffer; + } + break; + } + } + + private: + std::FILE* const fp_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_WINDOWS_LOGGER_H_ diff --git a/saraWhatsUp/Pods/nanopb/LICENSE.txt b/saraWhatsUp/Pods/nanopb/LICENSE.txt new file mode 100644 index 0000000..d11c9af --- /dev/null +++ b/saraWhatsUp/Pods/nanopb/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2011 Petteri Aimonen + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held liable +for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. diff --git a/saraWhatsUp/Pods/nanopb/README.md b/saraWhatsUp/Pods/nanopb/README.md new file mode 100644 index 0000000..1a73cdd --- /dev/null +++ b/saraWhatsUp/Pods/nanopb/README.md @@ -0,0 +1,71 @@ +Nanopb - Protocol Buffers for Embedded Systems +============================================== + +[![Build Status](https://travis-ci.org/nanopb/nanopb.svg?branch=master)](https://travis-ci.org/nanopb/nanopb) + +Nanopb is a small code-size Protocol Buffers implementation in ansi C. It is +especially suitable for use in microcontrollers, but fits any memory +restricted system. + +* **Homepage:** https://jpa.kapsi.fi/nanopb/ +* **Documentation:** https://jpa.kapsi.fi/nanopb/docs/ +* **Downloads:** https://jpa.kapsi.fi/nanopb/download/ +* **Forum:** https://groups.google.com/forum/#!forum/nanopb + + + +Using the nanopb library +------------------------ +To use the nanopb library, you need to do two things: + +1. Compile your .proto files for nanopb, using `protoc`. +2. Include *pb_encode.c*, *pb_decode.c* and *pb_common.c* in your project. + +The easiest way to get started is to study the project in "examples/simple". +It contains a Makefile, which should work directly under most Linux systems. +However, for any other kind of build system, see the manual steps in +README.txt in that folder. + + + +Using the Protocol Buffers compiler (protoc) +-------------------------------------------- +The nanopb generator is implemented as a plugin for the Google's own `protoc` +compiler. This has the advantage that there is no need to reimplement the +basic parsing of .proto files. However, it does mean that you need the +Google's protobuf library in order to run the generator. + +If you have downloaded a binary package for nanopb (either Windows, Linux or +Mac OS X version), the `protoc` binary is included in the 'generator-bin' +folder. In this case, you are ready to go. Simply run this command: + + generator-bin/protoc --nanopb_out=. myprotocol.proto + +However, if you are using a git checkout or a plain source distribution, you +need to provide your own version of `protoc` and the Google's protobuf library. +On Linux, the necessary packages are `protobuf-compiler` and `python-protobuf`. +On Windows, you can either build Google's protobuf library from source or use +one of the binary distributions of it. In either case, if you use a separate +`protoc`, you need to manually give the path to nanopb generator: + + protoc --plugin=protoc-gen-nanopb=nanopb/generator/protoc-gen-nanopb ... + + + +Running the tests +----------------- +If you want to perform further development of the nanopb core, or to verify +its functionality using your compiler and platform, you'll want to run the +test suite. The build rules for the test suite are implemented using Scons, +so you need to have that installed (ex: `sudo apt install scons` on Ubuntu). To run the tests: + + cd tests + scons + +This will show the progress of various test cases. If the output does not +end in an error, the test cases were successful. + +Note: Mac OS X by default aliases 'clang' as 'gcc', while not actually +supporting the same command line options as gcc does. To run tests on +Mac OS X, use: "scons CC=clang CXX=clang". Same way can be used to run +tests with different compilers on any platform. diff --git a/saraWhatsUp/Pods/nanopb/pb.h b/saraWhatsUp/Pods/nanopb/pb.h new file mode 100644 index 0000000..236e894 --- /dev/null +++ b/saraWhatsUp/Pods/nanopb/pb.h @@ -0,0 +1,599 @@ +/* Common parts of the nanopb library. Most of these are quite low-level + * stuff. For the high-level interface, see pb_encode.h and pb_decode.h. + */ + +#ifndef PB_H_INCLUDED +#define PB_H_INCLUDED + +/***************************************************************** + * Nanopb compilation time options. You can change these here by * + * uncommenting the lines, or on the compiler command line. * + *****************************************************************/ + +/* Enable support for dynamically allocated fields */ +/* #define PB_ENABLE_MALLOC 1 */ + +/* Define this if your CPU / compiler combination does not support + * unaligned memory access to packed structures. */ +/* #define PB_NO_PACKED_STRUCTS 1 */ + +/* Increase the number of required fields that are tracked. + * A compiler warning will tell if you need this. */ +/* #define PB_MAX_REQUIRED_FIELDS 256 */ + +/* Add support for tag numbers > 255 and fields larger than 255 bytes. */ +/* #define PB_FIELD_16BIT 1 */ + +/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */ +/* #define PB_FIELD_32BIT 1 */ + +/* Disable support for error messages in order to save some code space. */ +/* #define PB_NO_ERRMSG 1 */ + +/* Disable support for custom streams (support only memory buffers). */ +/* #define PB_BUFFER_ONLY 1 */ + +/* Switch back to the old-style callback function signature. + * This was the default until nanopb-0.2.1. */ +/* #define PB_OLD_CALLBACK_STYLE */ + + +/* Don't encode scalar arrays as packed. This is only to be used when + * the decoder on the receiving side cannot process packed scalar arrays. + * Such example is older protobuf.js. */ +/* #define PB_ENCODE_ARRAYS_UNPACKED 1 */ + +/****************************************************************** + * You usually don't need to change anything below this line. * + * Feel free to look around and use the defined macros, though. * + ******************************************************************/ + + +/* Version of the nanopb library. Just in case you want to check it in + * your own program. */ +#define NANOPB_VERSION nanopb-0.3.9.8 + +/* Include all the system headers needed by nanopb. You will need the + * definitions of the following: + * - strlen, memcpy, memset functions + * - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t + * - size_t + * - bool + * + * If you don't have the standard header files, you can instead provide + * a custom header that defines or includes all this. In that case, + * define PB_SYSTEM_HEADER to the path of this file. + */ +#ifdef PB_SYSTEM_HEADER +#include PB_SYSTEM_HEADER +#else +#include +#include +#include +#include + +#ifdef PB_ENABLE_MALLOC +#include +#endif +#endif + +/* Macro for defining packed structures (compiler dependent). + * This just reduces memory requirements, but is not required. + */ +#if defined(PB_NO_PACKED_STRUCTS) + /* Disable struct packing */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed +#elif defined(__GNUC__) || defined(__clang__) + /* For GCC and clang */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed __attribute__((packed)) +#elif defined(__ICCARM__) || defined(__CC_ARM) + /* For IAR ARM and Keil MDK-ARM compilers */ +# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") +# define PB_PACKED_STRUCT_END _Pragma("pack(pop)") +# define pb_packed +#elif defined(_MSC_VER) && (_MSC_VER >= 1500) + /* For Microsoft Visual C++ */ +# define PB_PACKED_STRUCT_START __pragma(pack(push, 1)) +# define PB_PACKED_STRUCT_END __pragma(pack(pop)) +# define pb_packed +#else + /* Unknown compiler */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed +#endif + +/* Handly macro for suppressing unreferenced-parameter compiler warnings. */ +#ifndef PB_UNUSED +#define PB_UNUSED(x) (void)(x) +#endif + +/* Compile-time assertion, used for checking compatible compilation options. + * If this does not work properly on your compiler, use + * #define PB_NO_STATIC_ASSERT to disable it. + * + * But before doing that, check carefully the error message / place where it + * comes from to see if the error has a real cause. Unfortunately the error + * message is not always very clear to read, but you can see the reason better + * in the place where the PB_STATIC_ASSERT macro was called. + */ +#ifndef PB_NO_STATIC_ASSERT +#ifndef PB_STATIC_ASSERT +#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; +#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) +#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER +#endif +#else +#define PB_STATIC_ASSERT(COND,MSG) +#endif + +/* Number of required fields to keep track of. */ +#ifndef PB_MAX_REQUIRED_FIELDS +#define PB_MAX_REQUIRED_FIELDS 64 +#endif + +#if PB_MAX_REQUIRED_FIELDS < 64 +#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64). +#endif + +/* List of possible field types. These are used in the autogenerated code. + * Least-significant 4 bits tell the scalar type + * Most-significant 4 bits specify repeated/required/packed etc. + */ + +typedef uint_least8_t pb_type_t; + +/**** Field data types ****/ + +/* Numeric types */ +#define PB_LTYPE_BOOL 0x00 /* bool */ +#define PB_LTYPE_VARINT 0x01 /* int32, int64, enum, bool */ +#define PB_LTYPE_UVARINT 0x02 /* uint32, uint64 */ +#define PB_LTYPE_SVARINT 0x03 /* sint32, sint64 */ +#define PB_LTYPE_FIXED32 0x04 /* fixed32, sfixed32, float */ +#define PB_LTYPE_FIXED64 0x05 /* fixed64, sfixed64, double */ + +/* Marker for last packable field type. */ +#define PB_LTYPE_LAST_PACKABLE 0x05 + +/* Byte array with pre-allocated buffer. + * data_size is the length of the allocated PB_BYTES_ARRAY structure. */ +#define PB_LTYPE_BYTES 0x06 + +/* String with pre-allocated buffer. + * data_size is the maximum length. */ +#define PB_LTYPE_STRING 0x07 + +/* Submessage + * submsg_fields is pointer to field descriptions */ +#define PB_LTYPE_SUBMESSAGE 0x08 + +/* Extension pseudo-field + * The field contains a pointer to pb_extension_t */ +#define PB_LTYPE_EXTENSION 0x09 + +/* Byte array with inline, pre-allocated byffer. + * data_size is the length of the inline, allocated buffer. + * This differs from PB_LTYPE_BYTES by defining the element as + * pb_byte_t[data_size] rather than pb_bytes_array_t. */ +#define PB_LTYPE_FIXED_LENGTH_BYTES 0x0A + +/* Number of declared LTYPES */ +#define PB_LTYPES_COUNT 0x0B +#define PB_LTYPE_MASK 0x0F + +/**** Field repetition rules ****/ + +#define PB_HTYPE_REQUIRED 0x00 +#define PB_HTYPE_OPTIONAL 0x10 +#define PB_HTYPE_REPEATED 0x20 +#define PB_HTYPE_ONEOF 0x30 +#define PB_HTYPE_MASK 0x30 + +/**** Field allocation types ****/ + +#define PB_ATYPE_STATIC 0x00 +#define PB_ATYPE_POINTER 0x80 +#define PB_ATYPE_CALLBACK 0x40 +#define PB_ATYPE_MASK 0xC0 + +#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK) +#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK) +#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK) + +/* Data type used for storing sizes of struct fields + * and array counts. + */ +#if defined(PB_FIELD_32BIT) + typedef uint32_t pb_size_t; + typedef int32_t pb_ssize_t; +#elif defined(PB_FIELD_16BIT) + typedef uint_least16_t pb_size_t; + typedef int_least16_t pb_ssize_t; +#else + typedef uint_least8_t pb_size_t; + typedef int_least8_t pb_ssize_t; +#endif +#define PB_SIZE_MAX ((pb_size_t)-1) + +/* Data type for storing encoded data and other byte streams. + * This typedef exists to support platforms where uint8_t does not exist. + * You can regard it as equivalent on uint8_t on other platforms. + */ +typedef uint_least8_t pb_byte_t; + +/* This structure is used in auto-generated constants + * to specify struct fields. + * You can change field sizes if you need structures + * larger than 256 bytes or field tags larger than 256. + * The compiler should complain if your .proto has such + * structures. Fix that by defining PB_FIELD_16BIT or + * PB_FIELD_32BIT. + */ +PB_PACKED_STRUCT_START +typedef struct pb_field_s pb_field_t; +struct pb_field_s { + pb_size_t tag; + pb_type_t type; + pb_size_t data_offset; /* Offset of field data, relative to previous field. */ + pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */ + pb_size_t data_size; /* Data size in bytes for a single item */ + pb_size_t array_size; /* Maximum number of entries in array */ + + /* Field definitions for submessage + * OR default value for all other non-array, non-callback types + * If null, then field will zeroed. */ + const void *ptr; +} pb_packed; +PB_PACKED_STRUCT_END + +/* Make sure that the standard integer types are of the expected sizes. + * Otherwise fixed32/fixed64 fields can break. + * + * If you get errors here, it probably means that your stdint.h is not + * correct for your platform. + */ +#ifndef PB_WITHOUT_64BIT +PB_STATIC_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t), INT64_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE) +#endif + +/* This structure is used for 'bytes' arrays. + * It has the number of bytes in the beginning, and after that an array. + * Note that actual structs used will have a different length of bytes array. + */ +#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; } +#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) + +struct pb_bytes_array_s { + pb_size_t size; + pb_byte_t bytes[1]; +}; +typedef struct pb_bytes_array_s pb_bytes_array_t; + +/* This structure is used for giving the callback function. + * It is stored in the message structure and filled in by the method that + * calls pb_decode. + * + * The decoding callback will be given a limited-length stream + * If the wire type was string, the length is the length of the string. + * If the wire type was a varint/fixed32/fixed64, the length is the length + * of the actual value. + * The function may be called multiple times (especially for repeated types, + * but also otherwise if the message happens to contain the field multiple + * times.) + * + * The encoding callback will receive the actual output stream. + * It should write all the data in one call, including the field tag and + * wire type. It can write multiple fields. + * + * The callback can be null if you want to skip a field. + */ +typedef struct pb_istream_s pb_istream_t; +typedef struct pb_ostream_s pb_ostream_t; +typedef struct pb_callback_s pb_callback_t; +struct pb_callback_s { +#ifdef PB_OLD_CALLBACK_STYLE + /* Deprecated since nanopb-0.2.1 */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg); + } funcs; +#else + /* New function signature, which allows modifying arg contents in callback. */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); + } funcs; +#endif + + /* Free arg for use by callback */ + void *arg; +}; + +/* Wire types. Library user needs these only in encoder callbacks. */ +typedef enum { + PB_WT_VARINT = 0, + PB_WT_64BIT = 1, + PB_WT_STRING = 2, + PB_WT_32BIT = 5 +} pb_wire_type_t; + +/* Structure for defining the handling of unknown/extension fields. + * Usually the pb_extension_type_t structure is automatically generated, + * while the pb_extension_t structure is created by the user. However, + * if you want to catch all unknown fields, you can also create a custom + * pb_extension_type_t with your own callback. + */ +typedef struct pb_extension_type_s pb_extension_type_t; +typedef struct pb_extension_s pb_extension_t; +struct pb_extension_type_s { + /* Called for each unknown field in the message. + * If you handle the field, read off all of its data and return true. + * If you do not handle the field, do not read anything and return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*decode)(pb_istream_t *stream, pb_extension_t *extension, + uint32_t tag, pb_wire_type_t wire_type); + + /* Called once after all regular fields have been encoded. + * If you have something to write, do so and return true. + * If you do not have anything to write, just return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension); + + /* Free field for use by the callback. */ + const void *arg; +}; + +struct pb_extension_s { + /* Type describing the extension field. Usually you'll initialize + * this to a pointer to the automatically generated structure. */ + const pb_extension_type_t *type; + + /* Destination for the decoded data. This must match the datatype + * of the extension field. */ + void *dest; + + /* Pointer to the next extension handler, or NULL. + * If this extension does not match a field, the next handler is + * automatically called. */ + pb_extension_t *next; + + /* The decoder sets this to true if the extension was found. + * Ignored for encoding. */ + bool found; +}; + +/* Memory allocation functions to use. You can define pb_realloc and + * pb_free to custom functions if you want. */ +#ifdef PB_ENABLE_MALLOC +# ifndef pb_realloc +# define pb_realloc(ptr, size) realloc(ptr, size) +# endif +# ifndef pb_free +# define pb_free(ptr) free(ptr) +# endif +#endif + +/* This is used to inform about need to regenerate .pb.h/.pb.c files. */ +#define PB_PROTO_HEADER_VERSION 30 + +/* These macros are used to declare pb_field_t's in the constant array. */ +/* Size of a structure member, in bytes. */ +#define pb_membersize(st, m) (sizeof ((st*)0)->m) +/* Number of entries in an array. */ +#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) +/* Delta from start of one member to the start of another member. */ +#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2)) +/* Marks the end of the field list */ +#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0} + +/* Macros for filling in the data_offset field */ +/* data_offset for first field in a message */ +#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1)) +/* data_offset for subsequent fields */ +#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2)) +/* data offset for subsequent fields inside an union (oneof) */ +#define PB_DATAOFFSET_UNION(st, m1, m2) (PB_SIZE_MAX) +/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */ +#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \ + ? PB_DATAOFFSET_FIRST(st, m1, m2) \ + : PB_DATAOFFSET_OTHER(st, m1, m2)) + +/* Required fields are the simplest. They just have delta (padding) from + * previous field end, and the size of the field. Pointer is used for + * submessages and default values. + */ +#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Optional fields add the delta to the has_ variable. */ +#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ + fd, \ + pb_delta(st, has_ ## m, m), \ + pb_membersize(st, m), 0, ptr} + +#define PB_SINGULAR_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Repeated fields have a _count field and also the maximum number of entries. */ +#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \ + fd, \ + pb_delta(st, m ## _count, m), \ + pb_membersize(st, m[0]), \ + pb_arraysize(st, m), ptr} + +/* Allocated fields carry the size of the actual data, not the pointer */ +#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Optional fields don't need a has_ variable, as information would be redundant */ +#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Same as optional fields*/ +#define PB_SINGULAR_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Repeated fields have a _count field and a pointer to array of pointers */ +#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \ + fd, pb_delta(st, m ## _count, m), \ + pb_membersize(st, m[0]), 0, ptr} + +/* Callbacks are much like required fields except with special datatype. */ +#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_SINGULAR_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Optional extensions don't have the has_ field, as that would be redundant. + * Furthermore, the combination of OPTIONAL without has_ field is used + * for indicating proto3 style fields. Extensions exist in proto2 mode only, + * so they should be encoded according to proto2 rules. To avoid the conflict, + * extensions are marked as REQUIRED instead. + */ +#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ + 0, \ + 0, \ + pb_membersize(st, m), 0, ptr} + +#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \ + PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) + +#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \ + PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) + +/* The mapping from protobuf types to LTYPEs is done using these macros. */ +#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL +#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES +#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT +#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE +#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING +#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION +#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES + +/* This is the actual macro used in field descriptions. + * It takes these arguments: + * - Field tag number + * - Field type: BOOL, BYTES, DOUBLE, ENUM, UENUM, FIXED32, FIXED64, + * FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64 + * SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION + * - Field rules: REQUIRED, OPTIONAL or REPEATED + * - Allocation: STATIC, CALLBACK or POINTER + * - Placement: FIRST or OTHER, depending on if this is the first field in structure. + * - Message name + * - Field name + * - Previous field name (or field name again for first field) + * - Pointer to default value or submsg fields. + */ + +#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ ## rules ## _ ## allocation(tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +/* Field description for repeated static fixed count fields.*/ +#define PB_REPEATED_FIXED_COUNT(tag, type, placement, message, field, prevfield, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | PB_LTYPE_MAP_ ## type, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + 0, \ + pb_membersize(message, field[0]), \ + pb_arraysize(message, field), ptr} + +/* Field description for oneof fields. This requires taking into account the + * union name also, that's why a separate set of macros is needed. + */ +#define PB_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, u.m), \ + pb_membersize(st, u.m), 0, ptr} + +#define PB_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, u.m), \ + pb_membersize(st, u.m[0]), 0, ptr} + +#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ONEOF_ ## allocation(union_name, tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +#define PB_ANONYMOUS_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, m), \ + pb_membersize(st, m), 0, ptr} + +#define PB_ANONYMOUS_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, m), \ + pb_membersize(st, m[0]), 0, ptr} + +#define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +/* These macros are used for giving out error messages. + * They are mostly a debugging aid; the main error information + * is the true/false return value from functions. + * Some code space can be saved by disabling the error + * messages if not used. + * + * PB_SET_ERROR() sets the error message if none has been set yet. + * msg must be a constant string literal. + * PB_GET_ERROR() always returns a pointer to a string. + * PB_RETURN_ERROR() sets the error and returns false from current + * function. + */ +#ifdef PB_NO_ERRMSG +#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream) +#define PB_GET_ERROR(stream) "(errmsg disabled)" +#else +#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg)) +#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)") +#endif + +#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false + +#endif diff --git a/saraWhatsUp/Pods/nanopb/pb_common.c b/saraWhatsUp/Pods/nanopb/pb_common.c new file mode 100644 index 0000000..4fb7186 --- /dev/null +++ b/saraWhatsUp/Pods/nanopb/pb_common.c @@ -0,0 +1,97 @@ +/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c. + * + * 2014 Petteri Aimonen + */ + +#include "pb_common.h" + +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct) +{ + iter->start = fields; + iter->pos = fields; + iter->required_field_index = 0; + iter->dest_struct = dest_struct; + iter->pData = (char*)dest_struct + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + + return (iter->pos->tag != 0); +} + +bool pb_field_iter_next(pb_field_iter_t *iter) +{ + const pb_field_t *prev_field = iter->pos; + + if (prev_field->tag == 0) + { + /* Handle empty message types, where the first field is already the terminator. + * In other cases, the iter->pos never points to the terminator. */ + return false; + } + + iter->pos++; + + if (iter->pos->tag == 0) + { + /* Wrapped back to beginning, reinitialize */ + (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct); + return false; + } + else + { + /* Increment the pointers based on previous field size */ + size_t prev_size = prev_field->data_size; + + if (PB_HTYPE(prev_field->type) == PB_HTYPE_ONEOF && + PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF && + iter->pos->data_offset == PB_SIZE_MAX) + { + /* Don't advance pointers inside unions */ + return true; + } + else if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC && + PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED) + { + /* In static arrays, the data_size tells the size of a single entry and + * array_size is the number of entries */ + prev_size *= prev_field->array_size; + } + else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER) + { + /* Pointer fields always have a constant size in the main structure. + * The data_size only applies to the dynamically allocated area. */ + prev_size = sizeof(void*); + } + + if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED) + { + /* Count the required fields, in order to check their presence in the + * decoder. */ + iter->required_field_index++; + } + + iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + return true; + } +} + +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) +{ + const pb_field_t *start = iter->pos; + + do { + if (iter->pos->tag == tag && + PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) + { + /* Found the wanted field */ + return true; + } + + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + /* Searched all the way back to start, and found nothing. */ + return false; +} + + diff --git a/saraWhatsUp/Pods/nanopb/pb_common.h b/saraWhatsUp/Pods/nanopb/pb_common.h new file mode 100644 index 0000000..60b3d37 --- /dev/null +++ b/saraWhatsUp/Pods/nanopb/pb_common.h @@ -0,0 +1,42 @@ +/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c. + * These functions are rarely needed by applications directly. + */ + +#ifndef PB_COMMON_H_INCLUDED +#define PB_COMMON_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Iterator for pb_field_t list */ +struct pb_field_iter_s { + const pb_field_t *start; /* Start of the pb_field_t array */ + const pb_field_t *pos; /* Current position of the iterator */ + unsigned required_field_index; /* Zero-based index that counts only the required fields */ + void *dest_struct; /* Pointer to start of the structure */ + void *pData; /* Pointer to current field value */ + void *pSize; /* Pointer to count/has field */ +}; +typedef struct pb_field_iter_s pb_field_iter_t; + +/* Initialize the field iterator structure to beginning. + * Returns false if the message type is empty. */ +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct); + +/* Advance the iterator to the next field. + * Returns false when the iterator wraps back to the first field. */ +bool pb_field_iter_next(pb_field_iter_t *iter); + +/* Advance the iterator until it points at a field with the given tag. + * Returns false if no such field exists. */ +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif + diff --git a/saraWhatsUp/Pods/nanopb/pb_decode.c b/saraWhatsUp/Pods/nanopb/pb_decode.c new file mode 100644 index 0000000..4efe8a3 --- /dev/null +++ b/saraWhatsUp/Pods/nanopb/pb_decode.c @@ -0,0 +1,1564 @@ +/* pb_decode.c -- decode a protobuf using minimal resources + * + * 2011 Petteri Aimonen + */ + +/* Use the GCC warn_unused_result attribute to check that all return values + * are propagated correctly. On other compilers and gcc before 3.4.0 just + * ignore the annotation. + */ +#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + #define checkreturn +#else + #define checkreturn __attribute__((warn_unused_result)) +#endif + +#include "pb.h" +#include "pb_decode.h" +#include "pb_common.h" + +/************************************** + * Declarations internal to this file * + **************************************/ + +typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; + +static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); +static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size); +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension); +static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn find_extension_field(pb_field_iter_t *iter); +static void pb_field_set_to_default(pb_field_iter_t *iter); +static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); +static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof); +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_skip_varint(pb_istream_t *stream); +static bool checkreturn pb_skip_string(pb_istream_t *stream); + +#ifdef PB_ENABLE_MALLOC +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); +static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter); +static void pb_release_single_field(const pb_field_iter_t *iter); +#endif + +#ifdef PB_WITHOUT_64BIT +#define pb_int64_t int32_t +#define pb_uint64_t uint32_t +#else +#define pb_int64_t int64_t +#define pb_uint64_t uint64_t +#endif + +/* --- Function pointers to field decoders --- + * Order in the array must match pb_action_t LTYPE numbering. + */ +static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { + &pb_dec_bool, + &pb_dec_varint, + &pb_dec_uvarint, + &pb_dec_svarint, + &pb_dec_fixed32, + &pb_dec_fixed64, + + &pb_dec_bytes, + &pb_dec_string, + &pb_dec_submessage, + NULL, /* extensions */ + &pb_dec_fixed_length_bytes +}; + +/******************************* + * pb_istream_t implementation * + *******************************/ + +static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) +{ + size_t i; + const pb_byte_t *source = (const pb_byte_t*)stream->state; + stream->state = (pb_byte_t*)stream->state + count; + + if (buf != NULL) + { + for (i = 0; i < count; i++) + buf[i] = source[i]; + } + + return true; +} + +bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) +{ + if (count == 0) + return true; + +#ifndef PB_BUFFER_ONLY + if (buf == NULL && stream->callback != buf_read) + { + /* Skip input bytes */ + pb_byte_t tmp[16]; + while (count > 16) + { + if (!pb_read(stream, tmp, 16)) + return false; + + count -= 16; + } + + return pb_read(stream, tmp, count); + } +#endif + + if (stream->bytes_left < count) + PB_RETURN_ERROR(stream, "end-of-stream"); + +#ifndef PB_BUFFER_ONLY + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#else + if (!buf_read(stream, buf, count)) + return false; +#endif + + stream->bytes_left -= count; + return true; +} + +/* Read a single byte from input stream. buf may not be NULL. + * This is an optimization for the varint decoding. */ +static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) +{ + if (stream->bytes_left == 0) + PB_RETURN_ERROR(stream, "end-of-stream"); + +#ifndef PB_BUFFER_ONLY + if (!stream->callback(stream, buf, 1)) + PB_RETURN_ERROR(stream, "io error"); +#else + *buf = *(const pb_byte_t*)stream->state; + stream->state = (pb_byte_t*)stream->state + 1; +#endif + + stream->bytes_left--; + + return true; +} + +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) +{ + pb_istream_t stream; + /* Cast away the const from buf without a compiler error. We are + * careful to use it only in a const manner in the callbacks. + */ + union { + void *state; + const void *c_state; + } state; +#ifdef PB_BUFFER_ONLY + stream.callback = NULL; +#else + stream.callback = &buf_read; +#endif + state.c_state = buf; + stream.state = state.state; + stream.bytes_left = bufsize; +#ifndef PB_NO_ERRMSG + stream.errmsg = NULL; +#endif + return stream; +} + +/******************** + * Helper functions * + ********************/ + +static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof) +{ + pb_byte_t byte; + uint32_t result; + + if (!pb_readbyte(stream, &byte)) + { + if (stream->bytes_left == 0) + { + if (eof) + { + *eof = true; + } + } + + return false; + } + + if ((byte & 0x80) == 0) + { + /* Quick case, 1 byte value */ + result = byte; + } + else + { + /* Multibyte case */ + uint_fast8_t bitpos = 7; + result = byte & 0x7F; + + do + { + if (!pb_readbyte(stream, &byte)) + return false; + + if (bitpos >= 32) + { + /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */ + uint8_t sign_extension = (bitpos < 63) ? 0xFF : 0x01; + + if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension)) + { + PB_RETURN_ERROR(stream, "varint overflow"); + } + } + else + { + result |= (uint32_t)(byte & 0x7F) << bitpos; + } + bitpos = (uint_fast8_t)(bitpos + 7); + } while (byte & 0x80); + + if (bitpos == 35 && (byte & 0x70) != 0) + { + /* The last byte was at bitpos=28, so only bottom 4 bits fit. */ + PB_RETURN_ERROR(stream, "varint overflow"); + } + } + + *dest = result; + return true; +} + +bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) +{ + return pb_decode_varint32_eof(stream, dest, NULL); +} + +#ifndef PB_WITHOUT_64BIT +bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) +{ + pb_byte_t byte; + uint_fast8_t bitpos = 0; + uint64_t result = 0; + + do + { + if (bitpos >= 64) + PB_RETURN_ERROR(stream, "varint overflow"); + + if (!pb_readbyte(stream, &byte)) + return false; + + result |= (uint64_t)(byte & 0x7F) << bitpos; + bitpos = (uint_fast8_t)(bitpos + 7); + } while (byte & 0x80); + + *dest = result; + return true; +} +#endif + +bool checkreturn pb_skip_varint(pb_istream_t *stream) +{ + pb_byte_t byte; + do + { + if (!pb_read(stream, &byte, 1)) + return false; + } while (byte & 0x80); + return true; +} + +bool checkreturn pb_skip_string(pb_istream_t *stream) +{ + uint32_t length; + if (!pb_decode_varint32(stream, &length)) + return false; + + return pb_read(stream, NULL, length); +} + +bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) +{ + uint32_t temp; + *eof = false; + *wire_type = (pb_wire_type_t) 0; + *tag = 0; + + if (!pb_decode_varint32_eof(stream, &temp, eof)) + { + return false; + } + + if (temp == 0) + { + *eof = true; /* Special feature: allow 0-terminated messages. */ + return false; + } + + *tag = temp >> 3; + *wire_type = (pb_wire_type_t)(temp & 7); + return true; +} + +bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) +{ + switch (wire_type) + { + case PB_WT_VARINT: return pb_skip_varint(stream); + case PB_WT_64BIT: return pb_read(stream, NULL, 8); + case PB_WT_STRING: return pb_skip_string(stream); + case PB_WT_32BIT: return pb_read(stream, NULL, 4); + default: PB_RETURN_ERROR(stream, "invalid wire_type"); + } +} + +/* Read a raw value to buffer, for the purpose of passing it to callback as + * a substream. Size is maximum size on call, and actual size on return. + */ +static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size) +{ + size_t max_size = *size; + switch (wire_type) + { + case PB_WT_VARINT: + *size = 0; + do + { + (*size)++; + if (*size > max_size) return false; + if (!pb_read(stream, buf, 1)) return false; + } while (*buf++ & 0x80); + return true; + + case PB_WT_64BIT: + *size = 8; + return pb_read(stream, buf, 8); + + case PB_WT_32BIT: + *size = 4; + return pb_read(stream, buf, 4); + + case PB_WT_STRING: + /* Calling read_raw_value with a PB_WT_STRING is an error. + * Explicitly handle this case and fallthrough to default to avoid + * compiler warnings. + */ + + default: PB_RETURN_ERROR(stream, "invalid wire_type"); + } +} + +/* Decode string length from stream and return a substream with limited length. + * Remember to close the substream using pb_close_string_substream(). + */ +bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) +{ + uint32_t size; + if (!pb_decode_varint32(stream, &size)) + return false; + + *substream = *stream; + if (substream->bytes_left < size) + PB_RETURN_ERROR(stream, "parent stream too short"); + + substream->bytes_left = size; + stream->bytes_left -= size; + return true; +} + +bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) +{ + if (substream->bytes_left) { + if (!pb_read(substream, NULL, substream->bytes_left)) + return false; + } + + stream->state = substream->state; + +#ifndef PB_NO_ERRMSG + stream->errmsg = substream->errmsg; +#endif + return true; +} + +/************************* + * Decode a single field * + *************************/ + +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + return func(stream, iter->pos, iter->pData); + + case PB_HTYPE_OPTIONAL: + if (iter->pSize != iter->pData) + *(bool*)iter->pSize = true; + return func(stream, iter->pos, iter->pData); + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array */ + bool status = true; + pb_size_t *size = (pb_size_t*)iter->pSize; + + pb_istream_t substream; + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left > 0 && *size < iter->pos->array_size) + { + void *pItem = (char*)iter->pData + iter->pos->data_size * (*size); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + (*size)++; + } + + if (substream.bytes_left != 0) + PB_RETURN_ERROR(stream, "array overflow"); + if (!pb_close_string_substream(stream, &substream)) + return false; + + return status; + } + else + { + /* Repeated field */ + pb_size_t *size = (pb_size_t*)iter->pSize; + char *pItem = (char*)iter->pData + iter->pos->data_size * (*size); + + if ((*size)++ >= iter->pos->array_size) + PB_RETURN_ERROR(stream, "array overflow"); + + return func(stream, iter->pos, pItem); + } + + case PB_HTYPE_ONEOF: + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && + *(pb_size_t*)iter->pSize != iter->pos->tag) + { + /* We memset to zero so that any callbacks are set to NULL. + * This is because the callbacks might otherwise have values + * from some other union field. */ + memset(iter->pData, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData); + } + *(pb_size_t*)iter->pSize = iter->pos->tag; + + return func(stream, iter->pos, iter->pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +#ifdef PB_ENABLE_MALLOC +/* Allocate storage for the field and store the pointer at iter->pData. + * array_size is the number of entries to reserve in an array. + * Zero size is not allowed, use pb_free() for releasing. + */ +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) +{ + void *ptr = *(void**)pData; + + if (data_size == 0 || array_size == 0) + PB_RETURN_ERROR(stream, "invalid size"); + +#ifdef __AVR__ + /* Workaround for AVR libc bug 53284: http://savannah.nongnu.org/bugs/?53284 + * Realloc to size of 1 byte can cause corruption of the malloc structures. + */ + if (data_size == 1 && array_size == 1) + { + data_size = 2; + } +#endif + + /* Check for multiplication overflows. + * This code avoids the costly division if the sizes are small enough. + * Multiplication is safe as long as only half of bits are set + * in either multiplicand. + */ + { + const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); + if (data_size >= check_limit || array_size >= check_limit) + { + const size_t size_max = (size_t)-1; + if (size_max / array_size < data_size) + { + PB_RETURN_ERROR(stream, "size too large"); + } + } + } + + /* Allocate new or expand previous allocation */ + /* Note: on failure the old pointer will remain in the structure, + * the message must be freed by caller also on error return. */ + ptr = pb_realloc(ptr, array_size * data_size); + if (ptr == NULL) + PB_RETURN_ERROR(stream, "realloc failed"); + + *(void**)pData = ptr; + return true; +} + +/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ +static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) +{ + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || + PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) + { + *(void**)pItem = NULL; + } + else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) + { + /* We memset to zero so that any callbacks are set to NULL. + * Then set any default values. */ + memset(pItem, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); + } +} +#endif + +static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ +#ifndef PB_ENABLE_MALLOC + PB_UNUSED(wire_type); + PB_UNUSED(iter); + PB_RETURN_ERROR(stream, "no malloc support"); +#else + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + case PB_HTYPE_OPTIONAL: + case PB_HTYPE_ONEOF: + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && + *(void**)iter->pData != NULL) + { + /* Duplicate field, have to release the old allocation first. */ + pb_release_single_field(iter); + } + + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + *(pb_size_t*)iter->pSize = iter->pos->tag; + } + + if (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES) + { + return func(stream, iter->pos, iter->pData); + } + else + { + if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) + return false; + + initialize_pointer_field(*(void**)iter->pData, iter); + return func(stream, iter->pos, *(void**)iter->pData); + } + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array, multiple items come in at once. */ + bool status = true; + pb_size_t *size = (pb_size_t*)iter->pSize; + size_t allocated_size = *size; + void *pItem; + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left) + { + if (*size == PB_SIZE_MAX) + { +#ifndef PB_NO_ERRMSG + stream->errmsg = "too many array entries"; +#endif + status = false; + break; + } + + if ((size_t)*size + 1 > allocated_size) + { + /* Allocate more storage. This tries to guess the + * number of remaining entries. Round the division + * upwards. */ + size_t remain = (substream.bytes_left - 1) / iter->pos->data_size + 1; + if (remain < PB_SIZE_MAX - allocated_size) + allocated_size += remain; + else + allocated_size += 1; + + if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) + { + status = false; + break; + } + } + + /* Decode the array entry */ + pItem = *(char**)iter->pData + iter->pos->data_size * (*size); + initialize_pointer_field(pItem, iter); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + + (*size)++; + } + if (!pb_close_string_substream(stream, &substream)) + return false; + + return status; + } + else + { + /* Normal repeated field, i.e. only one item at a time. */ + pb_size_t *size = (pb_size_t*)iter->pSize; + void *pItem; + + if (*size == PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "too many array entries"); + + if (!allocate_field(stream, iter->pData, iter->pos->data_size, (size_t)(*size + 1))) + return false; + + pItem = *(char**)iter->pData + iter->pos->data_size * (*size); + (*size)++; + initialize_pointer_field(pItem, iter); + return func(stream, iter->pos, pItem); + } + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +#endif +} + +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_callback_t *pCallback = (pb_callback_t*)iter->pData; +#ifdef PB_OLD_CALLBACK_STYLE + void *arg; +#else + void **arg; +#endif + + if (pCallback == NULL || pCallback->funcs.decode == NULL) + return pb_skip_field(stream, wire_type); + +#ifdef PB_OLD_CALLBACK_STYLE + arg = pCallback->arg; +#else + arg = &(pCallback->arg); +#endif + + if (wire_type == PB_WT_STRING) + { + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + do + { + if (!pCallback->funcs.decode(&substream, iter->pos, arg)) + PB_RETURN_ERROR(stream, "callback failed"); + } while (substream.bytes_left); + + if (!pb_close_string_substream(stream, &substream)) + return false; + + return true; + } + else + { + /* Copy the single scalar value to stack. + * This is required so that we can limit the stream length, + * which in turn allows to use same callback for packed and + * not-packed fields. */ + pb_istream_t substream; + pb_byte_t buffer[10]; + size_t size = sizeof(buffer); + + if (!read_raw_value(stream, wire_type, buffer, &size)) + return false; + substream = pb_istream_from_buffer(buffer, size); + + return pCallback->funcs.decode(&substream, iter->pos, arg); + } +} + +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ +#ifdef PB_ENABLE_MALLOC + /* When decoding an oneof field, check if there is old data that must be + * released first. */ + if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) + { + if (!pb_release_union_field(stream, iter)) + return false; + } +#endif + + switch (PB_ATYPE(iter->pos->type)) + { + case PB_ATYPE_STATIC: + return decode_static_field(stream, wire_type, iter); + + case PB_ATYPE_POINTER: + return decode_pointer_field(stream, wire_type, iter); + + case PB_ATYPE_CALLBACK: + return decode_callback_field(stream, wire_type, iter); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension) +{ + /* Fake a field iterator for the extension field. + * It is not actually safe to advance this iterator, but decode_field + * will not even try to. */ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + (void)pb_field_iter_begin(iter, field, extension->dest); + iter->pData = extension->dest; + iter->pSize = &extension->found; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* For pointer extensions, the pointer is stored directly + * in the extension structure. This avoids having an extra + * indirection. */ + iter->pData = &extension->dest; + } +} + +/* Default handler for extension fields. Expects a pb_field_t structure + * in extension->type->arg. */ +static bool checkreturn default_extension_decoder(pb_istream_t *stream, + pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + pb_field_iter_t iter; + + if (field->tag != tag) + return true; + + iter_from_extension(&iter, extension); + extension->found = true; + return decode_field(stream, wire_type, &iter); +} + +/* Try to decode an unknown field as an extension field. Tries each extension + * decoder in turn, until one of them handles the field or loop ends. */ +static bool checkreturn decode_extension(pb_istream_t *stream, + uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; + size_t pos = stream->bytes_left; + + while (extension != NULL && pos == stream->bytes_left) + { + bool status; + if (extension->type->decode) + status = extension->type->decode(stream, extension, tag, wire_type); + else + status = default_extension_decoder(stream, extension, tag, wire_type); + + if (!status) + return false; + + extension = extension->next; + } + + return true; +} + +/* Step through the iterator until an extension field is found or until all + * entries have been checked. There can be only one extension field per + * message. Returns false if no extension field is found. */ +static bool checkreturn find_extension_field(pb_field_iter_t *iter) +{ + const pb_field_t *start = iter->pos; + + do { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) + return true; + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + return false; +} + +/* Initialize message fields to default values, recursively */ +static void pb_field_set_to_default(pb_field_iter_t *iter) +{ + pb_type_t type; + type = iter->pos->type; + + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + pb_extension_t *ext = *(pb_extension_t* const *)iter->pData; + while (ext != NULL) + { + pb_field_iter_t ext_iter; + ext->found = false; + iter_from_extension(&ext_iter, ext); + pb_field_set_to_default(&ext_iter); + ext = ext->next; + } + } + else if (PB_ATYPE(type) == PB_ATYPE_STATIC) + { + bool init_data = true; + if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && iter->pSize != iter->pData) + { + /* Set has_field to false. Still initialize the optional field + * itself also. */ + *(bool*)iter->pSize = false; + } + else if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + /* REPEATED: Set array count to 0, no need to initialize contents. + ONEOF: Set which_field to 0. */ + *(pb_size_t*)iter->pSize = 0; + init_data = false; + } + + if (init_data) + { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) + { + /* Initialize submessage to defaults */ + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData); + } + else if (iter->pos->ptr != NULL) + { + /* Initialize to default value */ + memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size); + } + else + { + /* Initialize to zeros */ + memset(iter->pData, 0, iter->pos->data_size); + } + } + } + else if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + /* Initialize the pointer to NULL. */ + *(void**)iter->pData = NULL; + + /* Initialize array count to 0. */ + if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + *(pb_size_t*)iter->pSize = 0; + } + } + else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) + { + /* Don't overwrite callback */ + } +} + +static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iter_t iter; + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do + { + pb_field_set_to_default(&iter); + } while (pb_field_iter_next(&iter)); +} + +/********************* + * Decode all fields * + *********************/ + +bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0}; + const uint32_t allbits = ~(uint32_t)0; + uint32_t extension_range_start = 0; + pb_field_iter_t iter; + + /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed + * count field. This can only handle _one_ repeated fixed count field that + * is unpacked and unordered among other (non repeated fixed count) fields. + */ + const pb_field_t *fixed_count_field = NULL; + pb_size_t fixed_count_size = 0; + + /* Return value ignored, as empty message types will be correctly handled by + * pb_field_iter_find() anyway. */ + (void)pb_field_iter_begin(&iter, fields, dest_struct); + + while (stream->bytes_left) + { + uint32_t tag; + pb_wire_type_t wire_type; + bool eof; + + if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) + { + if (eof) + break; + else + return false; + } + + if (!pb_field_iter_find(&iter, tag)) + { + /* No match found, check if it matches an extension. */ + if (tag >= extension_range_start) + { + if (!find_extension_field(&iter)) + extension_range_start = (uint32_t)-1; + else + extension_range_start = iter.pos->tag; + + if (tag >= extension_range_start) + { + size_t pos = stream->bytes_left; + + if (!decode_extension(stream, tag, wire_type, &iter)) + return false; + + if (pos != stream->bytes_left) + { + /* The field was handled */ + continue; + } + } + } + + /* No match found, skip data */ + if (!pb_skip_field(stream, wire_type)) + return false; + continue; + } + + /* If a repeated fixed count field was found, get size from + * 'fixed_count_field' as there is no counter contained in the struct. + */ + if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REPEATED + && iter.pSize == iter.pData) + { + if (fixed_count_field != iter.pos) { + /* If the new fixed count field does not match the previous one, + * check that the previous one is NULL or that it finished + * receiving all the expected data. + */ + if (fixed_count_field != NULL && + fixed_count_size != fixed_count_field->array_size) + { + PB_RETURN_ERROR(stream, "wrong size for fixed count field"); + } + + fixed_count_field = iter.pos; + fixed_count_size = 0; + } + + iter.pSize = &fixed_count_size; + } + + if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED + && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) + { + uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31)); + fields_seen[iter.required_field_index >> 5] |= tmp; + } + + if (!decode_field(stream, wire_type, &iter)) + return false; + } + + /* Check that all elements of the last decoded fixed count field were present. */ + if (fixed_count_field != NULL && + fixed_count_size != fixed_count_field->array_size) + { + PB_RETURN_ERROR(stream, "wrong size for fixed count field"); + } + + /* Check that all required fields were present. */ + { + /* First figure out the number of required fields by + * seeking to the end of the field array. Usually we + * are already close to end after decoding. + */ + unsigned req_field_count; + pb_type_t last_type; + unsigned i; + do { + req_field_count = iter.required_field_index; + last_type = iter.pos->type; + } while (pb_field_iter_next(&iter)); + + /* Fixup if last field was also required. */ + if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) + req_field_count++; + + if (req_field_count > PB_MAX_REQUIRED_FIELDS) + req_field_count = PB_MAX_REQUIRED_FIELDS; + + if (req_field_count > 0) + { + /* Check the whole words */ + for (i = 0; i < (req_field_count >> 5); i++) + { + if (fields_seen[i] != allbits) + PB_RETURN_ERROR(stream, "missing required field"); + } + + /* Check the remaining bits (if any) */ + if ((req_field_count & 31) != 0) + { + if (fields_seen[req_field_count >> 5] != + (allbits >> (32 - (req_field_count & 31)))) + { + PB_RETURN_ERROR(stream, "missing required field"); + } + } + } + } + + return true; +} + +bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + bool status; + pb_message_set_to_defaults(fields, dest_struct); + status = pb_decode_noinit(stream, fields, dest_struct); + +#ifdef PB_ENABLE_MALLOC + if (!status) + pb_release(fields, dest_struct); +#endif + + return status; +} + +bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + pb_istream_t substream; + bool status; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + status = pb_decode_noinit(&substream, fields, dest_struct); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + pb_istream_t substream; + bool status; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + status = pb_decode(&substream, fields, dest_struct); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + /* This behaviour will be separated in nanopb-0.4.0, see issue #278. */ + return pb_decode(stream, fields, dest_struct); +} + +#ifdef PB_ENABLE_MALLOC +/* Given an oneof field, if there has already been a field inside this oneof, + * release it before overwriting with a different one. */ +static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter) +{ + pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */ + pb_size_t new_tag = iter->pos->tag; /* New which_ value */ + + if (old_tag == 0) + return true; /* Ok, no old data in union */ + + if (old_tag == new_tag) + return true; /* Ok, old data is of same type => merge */ + + /* Release old data. The find can fail if the message struct contains + * invalid data. */ + if (!pb_field_iter_find(iter, old_tag)) + PB_RETURN_ERROR(stream, "invalid union tag"); + + pb_release_single_field(iter); + + /* Restore iterator to where it should be. + * This shouldn't fail unless the pb_field_t structure is corrupted. */ + if (!pb_field_iter_find(iter, new_tag)) + PB_RETURN_ERROR(stream, "iterator error"); + + if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER) + { + /* Initialize the pointer to NULL to make sure it is valid + * even in case of error return. */ + *(void**)iter->pData = NULL; + } + + return true; +} + +static void pb_release_single_field(const pb_field_iter_t *iter) +{ + pb_type_t type; + type = iter->pos->type; + + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + if (*(pb_size_t*)iter->pSize != iter->pos->tag) + return; /* This is not the current field in the union */ + } + + /* Release anything contained inside an extension or submsg. + * This has to be done even if the submsg itself is statically + * allocated. */ + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + /* Release fields from all extensions in the linked list */ + pb_extension_t *ext = *(pb_extension_t**)iter->pData; + while (ext != NULL) + { + pb_field_iter_t ext_iter; + iter_from_extension(&ext_iter, ext); + pb_release_single_field(&ext_iter); + ext = ext->next; + } + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && PB_ATYPE(type) != PB_ATYPE_CALLBACK) + { + /* Release fields in submessage or submsg array */ + void *pItem = iter->pData; + pb_size_t count = 1; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + pItem = *(void**)iter->pData; + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + if (PB_ATYPE(type) == PB_ATYPE_STATIC && iter->pSize == iter->pData) { + /* No _count field so use size of the array */ + count = iter->pos->array_size; + } else { + count = *(pb_size_t*)iter->pSize; + } + + if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size) + { + /* Protect against corrupted _count fields */ + count = iter->pos->array_size; + } + } + + if (pItem) + { + while (count--) + { + pb_release((const pb_field_t*)iter->pos->ptr, pItem); + pItem = (char*)pItem + iter->pos->data_size; + } + } + } + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + if (PB_HTYPE(type) == PB_HTYPE_REPEATED && + (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES)) + { + /* Release entries in repeated string or bytes array */ + void **pItem = *(void***)iter->pData; + pb_size_t count = *(pb_size_t*)iter->pSize; + while (count--) + { + pb_free(*pItem); + *pItem++ = NULL; + } + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + /* We are going to release the array, so set the size to 0 */ + *(pb_size_t*)iter->pSize = 0; + } + + /* Release main item */ + pb_free(*(void**)iter->pData); + *(void**)iter->pData = NULL; + } +} + +void pb_release(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iter_t iter; + + if (!dest_struct) + return; /* Ignore NULL pointers, similar to free() */ + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do + { + pb_release_single_field(&iter); + } while (pb_field_iter_next(&iter)); +} +#endif + +/* Field decoders */ + +bool pb_decode_bool(pb_istream_t *stream, bool *dest) +{ + return pb_dec_bool(stream, NULL, (void*)dest); +} + +bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest) +{ + pb_uint64_t value; + if (!pb_decode_varint(stream, &value)) + return false; + + if (value & 1) + *dest = (pb_int64_t)(~(value >> 1)); + else + *dest = (pb_int64_t)(value >> 1); + + return true; +} + +bool pb_decode_fixed32(pb_istream_t *stream, void *dest) +{ + pb_byte_t bytes[4]; + + if (!pb_read(stream, bytes, 4)) + return false; + + *(uint32_t*)dest = ((uint32_t)bytes[0] << 0) | + ((uint32_t)bytes[1] << 8) | + ((uint32_t)bytes[2] << 16) | + ((uint32_t)bytes[3] << 24); + return true; +} + +#ifndef PB_WITHOUT_64BIT +bool pb_decode_fixed64(pb_istream_t *stream, void *dest) +{ + pb_byte_t bytes[8]; + + if (!pb_read(stream, bytes, 8)) + return false; + + *(uint64_t*)dest = ((uint64_t)bytes[0] << 0) | + ((uint64_t)bytes[1] << 8) | + ((uint64_t)bytes[2] << 16) | + ((uint64_t)bytes[3] << 24) | + ((uint64_t)bytes[4] << 32) | + ((uint64_t)bytes[5] << 40) | + ((uint64_t)bytes[6] << 48) | + ((uint64_t)bytes[7] << 56); + + return true; +} +#endif + +static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t value; + PB_UNUSED(field); + if (!pb_decode_varint32(stream, &value)) + return false; + + *(bool*)dest = (value != 0); + return true; +} + +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + pb_uint64_t value; + pb_int64_t svalue; + pb_int64_t clamped; + if (!pb_decode_varint(stream, &value)) + return false; + + /* See issue 97: Google's C++ protobuf allows negative varint values to + * be cast as int32_t, instead of the int64_t that should be used when + * encoding. Previous nanopb versions had a bug in encoding. In order to + * not break decoding of such messages, we cast <=32 bit fields to + * int32_t first to get the sign correct. + */ + if (field->data_size == sizeof(pb_int64_t)) + svalue = (pb_int64_t)value; + else + svalue = (int32_t)value; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_int64_t)) + clamped = *(pb_int64_t*)dest = svalue; + else if (field->data_size == sizeof(int32_t)) + clamped = *(int32_t*)dest = (int32_t)svalue; + else if (field->data_size == sizeof(int_least16_t)) + clamped = *(int_least16_t*)dest = (int_least16_t)svalue; + else if (field->data_size == sizeof(int_least8_t)) + clamped = *(int_least8_t*)dest = (int_least8_t)svalue; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != svalue) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + pb_uint64_t value, clamped; + if (!pb_decode_varint(stream, &value)) + return false; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_uint64_t)) + clamped = *(pb_uint64_t*)dest = value; + else if (field->data_size == sizeof(uint32_t)) + clamped = *(uint32_t*)dest = (uint32_t)value; + else if (field->data_size == sizeof(uint_least16_t)) + clamped = *(uint_least16_t*)dest = (uint_least16_t)value; + else if (field->data_size == sizeof(uint_least8_t)) + clamped = *(uint_least8_t*)dest = (uint_least8_t)value; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != value) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + pb_int64_t value, clamped; + if (!pb_decode_svarint(stream, &value)) + return false; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_int64_t)) + clamped = *(pb_int64_t*)dest = value; + else if (field->data_size == sizeof(int32_t)) + clamped = *(int32_t*)dest = (int32_t)value; + else if (field->data_size == sizeof(int_least16_t)) + clamped = *(int_least16_t*)dest = (int_least16_t)value; + else if (field->data_size == sizeof(int_least8_t)) + clamped = *(int_least8_t*)dest = (int_least8_t)value; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != value) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + PB_UNUSED(field); + return pb_decode_fixed32(stream, dest); +} + +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + PB_UNUSED(field); +#ifndef PB_WITHOUT_64BIT + return pb_decode_fixed64(stream, dest); +#else + PB_UNUSED(dest); + PB_RETURN_ERROR(stream, "no 64bit support"); +#endif +} + +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + size_t alloc_size; + pb_bytes_array_t *bdest; + + if (!pb_decode_varint32(stream, &size)) + return false; + + if (size > PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "bytes overflow"); + + alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); + if (size > alloc_size) + PB_RETURN_ERROR(stream, "size too large"); + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (stream->bytes_left < size) + PB_RETURN_ERROR(stream, "end-of-stream"); + + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + bdest = *(pb_bytes_array_t**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "bytes overflow"); + bdest = (pb_bytes_array_t*)dest; + } + + bdest->size = (pb_size_t)size; + return pb_read(stream, bdest->bytes, size); +} + +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + size_t alloc_size; + bool status; + if (!pb_decode_varint32(stream, &size)) + return false; + + /* Space for null terminator */ + alloc_size = size + 1; + + if (alloc_size < size) + PB_RETURN_ERROR(stream, "size too large"); + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (stream->bytes_left < size) + PB_RETURN_ERROR(stream, "end-of-stream"); + + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + dest = *(void**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "string overflow"); + } + + status = pb_read(stream, (pb_byte_t*)dest, size); + *((pb_byte_t*)dest + size) = 0; + return status; +} + +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + bool status; + pb_istream_t substream; + const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + if (field->ptr == NULL) + PB_RETURN_ERROR(stream, "invalid field descriptor"); + + /* New array entries need to be initialized, while required and optional + * submessages have already been initialized in the top-level pb_decode. */ + if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) + status = pb_decode(&substream, submsg_fields, dest); + else + status = pb_decode_noinit(&substream, submsg_fields, dest); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + + if (!pb_decode_varint32(stream, &size)) + return false; + + if (size > PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "bytes overflow"); + + if (size == 0) + { + /* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */ + memset(dest, 0, field->data_size); + return true; + } + + if (size != field->data_size) + PB_RETURN_ERROR(stream, "incorrect fixed length bytes size"); + + return pb_read(stream, (pb_byte_t*)dest, field->data_size); +} diff --git a/saraWhatsUp/Pods/nanopb/pb_decode.h b/saraWhatsUp/Pods/nanopb/pb_decode.h new file mode 100644 index 0000000..3577c20 --- /dev/null +++ b/saraWhatsUp/Pods/nanopb/pb_decode.h @@ -0,0 +1,178 @@ +/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c. + * The main function is pb_decode. You also need an input stream, and the + * field descriptions created by nanopb_generator.py. + */ + +#ifndef PB_DECODE_H_INCLUDED +#define PB_DECODE_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure for defining custom input streams. You will need to provide + * a callback function to read the bytes from your storage, which can be + * for example a file or a network socket. + * + * The callback must conform to these rules: + * + * 1) Return false on IO errors. This will cause decoding to abort. + * 2) You can use state to store your own data (e.g. buffer pointer), + * and rely on pb_read to verify that no-body reads past bytes_left. + * 3) Your callback may be used with substreams, in which case bytes_left + * is different than from the main stream. Don't use bytes_left to compute + * any pointers. + */ +struct pb_istream_s +{ +#ifdef PB_BUFFER_ONLY + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + */ + int *callback; +#else + bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count); +#endif + + void *state; /* Free field for use by callback implementation */ + size_t bytes_left; + +#ifndef PB_NO_ERRMSG + const char *errmsg; +#endif +}; + +/*************************** + * Main decoding functions * + ***************************/ + +/* Decode a single protocol buffers message from input stream into a C structure. + * Returns true on success, false on any failure. + * The actual struct pointed to by dest must match the description in fields. + * Callback fields of the destination structure must be initialized by caller. + * All other fields will be initialized by this function. + * + * Example usage: + * MyMessage msg = {}; + * uint8_t buffer[64]; + * pb_istream_t stream; + * + * // ... read some data into buffer ... + * + * stream = pb_istream_from_buffer(buffer, count); + * pb_decode(&stream, MyMessage_fields, &msg); + */ +bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except does not initialize the destination structure + * to default values. This is slightly faster if you need no default values + * and just do memset(struct, 0, sizeof(struct)) yourself. + * + * This can also be used for 'merging' two messages, i.e. update only the + * fields that exist in the new message. + * + * Note: If this function returns with an error, it will not release any + * dynamically allocated fields. You will need to call pb_release() yourself. + */ +bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except expects the stream to start with the message size + * encoded as varint. Corresponds to parseDelimitedFrom() in Google's + * protobuf API. + */ +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode_delimited, except that it does not initialize the destination structure. + * See pb_decode_noinit + */ +bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except allows the message to be terminated with a null byte. + * NOTE: Until nanopb-0.4.0, pb_decode() also allows null-termination. This behaviour + * is not supported in most other protobuf implementations, so pb_decode_delimited() + * is a better option for compatibility. + */ +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +#ifdef PB_ENABLE_MALLOC +/* Release any allocated pointer fields. If you use dynamic allocation, you should + * call this for any successfully decoded message when you are done with it. If + * pb_decode() returns with an error, the message is already released. + */ +void pb_release(const pb_field_t fields[], void *dest_struct); +#endif + + +/************************************** + * Functions for manipulating streams * + **************************************/ + +/* Create an input stream for reading from a memory buffer. + * + * Alternatively, you can use a custom stream that reads directly from e.g. + * a file or a network socket. + */ +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize); + +/* Function to read from a pb_istream_t. You can use this if you need to + * read some custom header data, or to read data in field callbacks. + */ +bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); + + +/************************************************ + * Helper functions for writing field callbacks * + ************************************************/ + +/* Decode the tag for the next field in the stream. Gives the wire type and + * field tag. At end of the message, returns false and sets eof to true. */ +bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof); + +/* Skip the field payload data, given the wire type. */ +bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); + +/* Decode an integer in the varint format. This works for enum, int32, + * int64, uint32 and uint64 field types. */ +#ifndef PB_WITHOUT_64BIT +bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest); +#else +#define pb_decode_varint pb_decode_varint32 +#endif + +/* Decode an integer in the varint format. This works for enum, int32, + * and uint32 field types. */ +bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); + +/* Decode a bool value in varint format. */ +bool pb_decode_bool(pb_istream_t *stream, bool *dest); + +/* Decode an integer in the zig-zagged svarint format. This works for sint32 + * and sint64. */ +#ifndef PB_WITHOUT_64BIT +bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest); +#else +bool pb_decode_svarint(pb_istream_t *stream, int32_t *dest); +#endif + +/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to + * a 4-byte wide C variable. */ +bool pb_decode_fixed32(pb_istream_t *stream, void *dest); + +#ifndef PB_WITHOUT_64BIT +/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to + * a 8-byte wide C variable. */ +bool pb_decode_fixed64(pb_istream_t *stream, void *dest); +#endif + +/* Make a limited-length substream for reading a PB_WT_STRING field. */ +bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream); +bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/saraWhatsUp/Pods/nanopb/pb_encode.c b/saraWhatsUp/Pods/nanopb/pb_encode.c new file mode 100644 index 0000000..371d256 --- /dev/null +++ b/saraWhatsUp/Pods/nanopb/pb_encode.c @@ -0,0 +1,913 @@ +/* pb_encode.c -- encode a protobuf using minimal resources + * + * 2011 Petteri Aimonen + */ + +#include "pb.h" +#include "pb_encode.h" +#include "pb_common.h" + +/* Use the GCC warn_unused_result attribute to check that all return values + * are propagated correctly. On other compilers and gcc before 3.4.0 just + * ignore the annotation. + */ +#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + #define checkreturn +#else + #define checkreturn __attribute__((warn_unused_result)) +#endif + +/************************************** + * Declarations internal to this file * + **************************************/ +typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn; + +static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); +static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func); +static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); +static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +static void *pb_const_cast(const void *p); +static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); + +#ifdef PB_WITHOUT_64BIT +#define pb_int64_t int32_t +#define pb_uint64_t uint32_t + +static bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value); +#else +#define pb_int64_t int64_t +#define pb_uint64_t uint64_t +#endif + +/* --- Function pointers to field encoders --- + * Order in the array must match pb_action_t LTYPE numbering. + */ +static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { + &pb_enc_bool, + &pb_enc_varint, + &pb_enc_uvarint, + &pb_enc_svarint, + &pb_enc_fixed32, + &pb_enc_fixed64, + + &pb_enc_bytes, + &pb_enc_string, + &pb_enc_submessage, + NULL, /* extensions */ + &pb_enc_fixed_length_bytes +}; + +/******************************* + * pb_ostream_t implementation * + *******************************/ + +static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) +{ + size_t i; + pb_byte_t *dest = (pb_byte_t*)stream->state; + stream->state = dest + count; + + for (i = 0; i < count; i++) + dest[i] = buf[i]; + + return true; +} + +pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize) +{ + pb_ostream_t stream; +#ifdef PB_BUFFER_ONLY + stream.callback = (void*)1; /* Just a marker value */ +#else + stream.callback = &buf_write; +#endif + stream.state = buf; + stream.max_size = bufsize; + stream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + stream.errmsg = NULL; +#endif + return stream; +} + +bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) +{ + if (count > 0 && stream->callback != NULL) + { + if (stream->bytes_written + count < stream->bytes_written || + stream->bytes_written + count > stream->max_size) + { + PB_RETURN_ERROR(stream, "stream full"); + } + +#ifdef PB_BUFFER_ONLY + if (!buf_write(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#else + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#endif + } + + stream->bytes_written += count; + return true; +} + +/************************* + * Encode a single field * + *************************/ + +/* Read a bool value without causing undefined behavior even if the value + * is invalid. See issue #434 and + * https://stackoverflow.com/questions/27661768/weird-results-for-conditional + */ +static bool safe_read_bool(const void *pSize) +{ + const char *p = (const char *)pSize; + size_t i; + for (i = 0; i < sizeof(bool); i++) + { + if (p[i] != 0) + return true; + } + return false; +} + +/* Encode a static array. Handles the size calculations and possible packing. */ +static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, + const void *pData, size_t count, pb_encoder_t func) +{ + size_t i; + const void *p; +#ifndef PB_ENCODE_ARRAYS_UNPACKED + size_t size; +#endif + + if (count == 0) + return true; + + if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) + PB_RETURN_ERROR(stream, "array max size exceeded"); + +#ifndef PB_ENCODE_ARRAYS_UNPACKED + /* We always pack arrays if the datatype allows it. */ + if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) + { + if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) + return false; + + /* Determine the total size of packed array. */ + if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) + { + size = 4 * count; + } + else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) + { + size = 8 * count; + } + else + { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + p = pData; + for (i = 0; i < count; i++) + { + if (!func(&sizestream, field, p)) + return false; + p = (const char*)p + field->data_size; + } + size = sizestream.bytes_written; + } + + if (!pb_encode_varint(stream, (pb_uint64_t)size)) + return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing.. */ + + /* Write the data */ + p = pData; + for (i = 0; i < count; i++) + { + if (!func(stream, field, p)) + return false; + p = (const char*)p + field->data_size; + } + } + else +#endif + { + p = pData; + for (i = 0; i < count; i++) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + /* Normally the data is stored directly in the array entries, but + * for pointer-type string and bytes fields, the array entries are + * actually pointers themselves also. So we have to dereference once + * more to get to the actual data. */ + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && + (PB_LTYPE(field->type) == PB_LTYPE_STRING || + PB_LTYPE(field->type) == PB_LTYPE_BYTES)) + { + if (!func(stream, field, *(const void* const*)p)) + return false; + } + else + { + if (!func(stream, field, p)) + return false; + } + p = (const char*)p + field->data_size; + } + } + + return true; +} + +/* In proto3, all fields are optional and are only encoded if their value is "non-zero". + * This function implements the check for the zero value. */ +static bool pb_check_proto3_default_value(const pb_field_t *field, const void *pData) +{ + pb_type_t type = field->type; + const void *pSize = (const char*)pData + field->size_offset; + + if (PB_HTYPE(type) == PB_HTYPE_REQUIRED) + { + /* Required proto2 fields inside proto3 submessage, pretty rare case */ + return false; + } + else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + /* Repeated fields inside proto3 submessage: present if count != 0 */ + if (field->size_offset != 0) + return *(const pb_size_t*)pSize == 0; + else if (PB_ATYPE(type) == PB_ATYPE_STATIC) + return false; /* Fixed length array */ + } + else if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + /* Oneof fields */ + return *(const pb_size_t*)pSize == 0; + } + else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset != 0) + { + /* Proto2 optional fields inside proto3 submessage */ + return safe_read_bool(pSize) == false; + } + + /* Rest is proto3 singular fields */ + + if (PB_ATYPE(type) == PB_ATYPE_STATIC) + { + if (PB_LTYPE(type) == PB_LTYPE_BYTES) + { + const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData; + return bytes->size == 0; + } + else if (PB_LTYPE(type) == PB_LTYPE_STRING) + { + return *(const char*)pData == '\0'; + } + else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES) + { + /* Fixed length bytes is only empty if its length is fixed + * as 0. Which would be pretty strange, but we can check + * it anyway. */ + return field->data_size == 0; + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* Check all fields in the submessage to find if any of them + * are non-zero. The comparison cannot be done byte-per-byte + * because the C struct may contain padding bytes that must + * be skipped. + */ + pb_field_iter_t iter; + if (pb_field_iter_begin(&iter, (const pb_field_t*)field->ptr, pb_const_cast(pData))) + { + do + { + if (!pb_check_proto3_default_value(iter.pos, iter.pData)) + { + return false; + } + } while (pb_field_iter_next(&iter)); + } + return true; + } + } + + /* Compares pointers to NULL in case of FT_POINTER */ + if (PB_ATYPE(type) == PB_ATYPE_POINTER && PB_LTYPE(type) > PB_LTYPE_LAST_PACKABLE) + { + return !*(const void**)((uintptr_t)pData); + } + + { + /* Catch-all branch that does byte-per-byte comparison for zero value. + * + * This is for all pointer fields, and for static PB_LTYPE_VARINT, + * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also + * callback fields. These all have integer or pointer value which + * can be compared with 0. + */ + pb_size_t i; + const char *p = (const char*)pData; + for (i = 0; i < field->data_size; i++) + { + if (p[i] != 0) + { + return false; + } + } + + return true; + } +} + +/* Encode a field with static or pointer allocation, i.e. one whose data + * is available to the encoder directly. */ +static bool checkreturn encode_basic_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + pb_encoder_t func; + bool implicit_has; + const void *pSize = &implicit_has; + + func = PB_ENCODERS[PB_LTYPE(field->type)]; + + if (field->size_offset) + { + /* Static optional, repeated or oneof field */ + pSize = (const char*)pData + field->size_offset; + } + else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL) + { + /* Proto3 style field, optional but without explicit has_ field. */ + implicit_has = !pb_check_proto3_default_value(field, pData); + } + else + { + /* Required field, always present */ + implicit_has = true; + } + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* pData is a pointer to the field, which contains pointer to + * the data. If the 2nd pointer is NULL, it is interpreted as if + * the has_field was false. + */ + pData = *(const void* const*)pData; + implicit_has = (pData != NULL); + } + + switch (PB_HTYPE(field->type)) + { + case PB_HTYPE_REQUIRED: + if (!pData) + PB_RETURN_ERROR(stream, "missing required field"); + if (!pb_encode_tag_for_field(stream, field)) + return false; + if (!func(stream, field, pData)) + return false; + break; + + case PB_HTYPE_OPTIONAL: + if (safe_read_bool(pSize)) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + if (!func(stream, field, pData)) + return false; + } + break; + + case PB_HTYPE_REPEATED: { + pb_size_t count; + if (field->size_offset != 0) { + count = *(const pb_size_t*)pSize; + } else { + count = field->array_size; + } + if (!encode_array(stream, field, pData, count, func)) + return false; + break; + } + + case PB_HTYPE_ONEOF: + if (*(const pb_size_t*)pSize == field->tag) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + if (!func(stream, field, pData)) + return false; + } + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return true; +} + +/* Encode a field with callback semantics. This means that a user function is + * called to provide and encode the actual data. */ +static bool checkreturn encode_callback_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + const pb_callback_t *callback = (const pb_callback_t*)pData; + +#ifdef PB_OLD_CALLBACK_STYLE + const void *arg = callback->arg; +#else + void * const *arg = &(callback->arg); +#endif + + if (callback->funcs.encode != NULL) + { + if (!callback->funcs.encode(stream, field, arg)) + PB_RETURN_ERROR(stream, "callback error"); + } + return true; +} + +/* Encode a single field of any callback or static type. */ +static bool checkreturn encode_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + switch (PB_ATYPE(field->type)) + { + case PB_ATYPE_STATIC: + case PB_ATYPE_POINTER: + return encode_basic_field(stream, field, pData); + + case PB_ATYPE_CALLBACK: + return encode_callback_field(stream, field, pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +/* Default handler for extension fields. Expects to have a pb_field_t + * pointer in the extension->type->arg field. */ +static bool checkreturn default_extension_encoder(pb_ostream_t *stream, + const pb_extension_t *extension) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* For pointer extensions, the pointer is stored directly + * in the extension structure. This avoids having an extra + * indirection. */ + return encode_field(stream, field, &extension->dest); + } + else + { + return encode_field(stream, field, extension->dest); + } +} + +/* Walk through all the registered extensions and give them a chance + * to encode themselves. */ +static bool checkreturn encode_extension_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + const pb_extension_t *extension = *(const pb_extension_t* const *)pData; + PB_UNUSED(field); + + while (extension) + { + bool status; + if (extension->type->encode) + status = extension->type->encode(stream, extension); + else + status = default_extension_encoder(stream, extension); + + if (!status) + return false; + + extension = extension->next; + } + + return true; +} + +/********************* + * Encode all fields * + *********************/ + +static void *pb_const_cast(const void *p) +{ + /* Note: this casts away const, in order to use the common field iterator + * logic for both encoding and decoding. */ + union { + void *p1; + const void *p2; + } t; + t.p2 = p; + return t.p1; +} + +bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + pb_field_iter_t iter; + if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct))) + return true; /* Empty message type */ + + do { + if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION) + { + /* Special case for the extension field placeholder */ + if (!encode_extension_field(stream, iter.pos, iter.pData)) + return false; + } + else + { + /* Regular field */ + if (!encode_field(stream, iter.pos, iter.pData)) + return false; + } + } while (pb_field_iter_next(&iter)); + + return true; +} + +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + return pb_encode_submessage(stream, fields, src_struct); +} + +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + const pb_byte_t zero = 0; + + if (!pb_encode(stream, fields, src_struct)) + return false; + + return pb_write(stream, &zero, 1); +} + +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct) +{ + pb_ostream_t stream = PB_OSTREAM_SIZING; + + if (!pb_encode(&stream, fields, src_struct)) + return false; + + *size = stream.bytes_written; + return true; +} + +/******************** + * Helper functions * + ********************/ + +#ifdef PB_WITHOUT_64BIT +bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value) +{ + pb_byte_t buffer[10]; + size_t i = 0; + size_t compensation = 32;/* we need to compensate 32 bits all set to 1 */ + + while (value) + { + buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); + value >>= 7; + if (compensation) + { + /* re-set all the compensation bits we can or need */ + size_t bits = compensation > 7 ? 7 : compensation; + value ^= (pb_uint64_t)((0xFFu >> (8 - bits)) << 25); /* set the number of bits needed on the lowest of the most significant 7 bits */ + compensation -= bits; + } + i++; + } + buffer[i - 1] &= 0x7F; /* Unset top bit on last byte */ + + return pb_write(stream, buffer, i); +} +#endif + +bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value) +{ + pb_byte_t buffer[10]; + size_t i = 0; + + if (value <= 0x7F) + { + pb_byte_t v = (pb_byte_t)value; + return pb_write(stream, &v, 1); + } + + while (value) + { + buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); + value >>= 7; + i++; + } + buffer[i-1] &= 0x7F; /* Unset top bit on last byte */ + + return pb_write(stream, buffer, i); +} + +bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value) +{ + pb_uint64_t zigzagged; + if (value < 0) + zigzagged = ~((pb_uint64_t)value << 1); + else + zigzagged = (pb_uint64_t)value << 1; + + return pb_encode_varint(stream, zigzagged); +} + +bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) +{ + uint32_t val = *(const uint32_t*)value; + pb_byte_t bytes[4]; + bytes[0] = (pb_byte_t)(val & 0xFF); + bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); + bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); + bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); + return pb_write(stream, bytes, 4); +} + +#ifndef PB_WITHOUT_64BIT +bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) +{ + uint64_t val = *(const uint64_t*)value; + pb_byte_t bytes[8]; + bytes[0] = (pb_byte_t)(val & 0xFF); + bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); + bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); + bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); + bytes[4] = (pb_byte_t)((val >> 32) & 0xFF); + bytes[5] = (pb_byte_t)((val >> 40) & 0xFF); + bytes[6] = (pb_byte_t)((val >> 48) & 0xFF); + bytes[7] = (pb_byte_t)((val >> 56) & 0xFF); + return pb_write(stream, bytes, 8); +} +#endif + +bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) +{ + pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype; + return pb_encode_varint(stream, tag); +} + +bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field) +{ + pb_wire_type_t wiretype; + switch (PB_LTYPE(field->type)) + { + case PB_LTYPE_BOOL: + case PB_LTYPE_VARINT: + case PB_LTYPE_UVARINT: + case PB_LTYPE_SVARINT: + wiretype = PB_WT_VARINT; + break; + + case PB_LTYPE_FIXED32: + wiretype = PB_WT_32BIT; + break; + + case PB_LTYPE_FIXED64: + wiretype = PB_WT_64BIT; + break; + + case PB_LTYPE_BYTES: + case PB_LTYPE_STRING: + case PB_LTYPE_SUBMESSAGE: + case PB_LTYPE_FIXED_LENGTH_BYTES: + wiretype = PB_WT_STRING; + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return pb_encode_tag(stream, wiretype, field->tag); +} + +bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size) +{ + if (!pb_encode_varint(stream, (pb_uint64_t)size)) + return false; + + return pb_write(stream, buffer, size); +} + +bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + /* First calculate the message size using a non-writing substream. */ + pb_ostream_t substream = PB_OSTREAM_SIZING; + size_t size; + bool status; + + if (!pb_encode(&substream, fields, src_struct)) + { +#ifndef PB_NO_ERRMSG + stream->errmsg = substream.errmsg; +#endif + return false; + } + + size = substream.bytes_written; + + if (!pb_encode_varint(stream, (pb_uint64_t)size)) + return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing */ + + if (stream->bytes_written + size > stream->max_size) + PB_RETURN_ERROR(stream, "stream full"); + + /* Use a substream to verify that a callback doesn't write more than + * what it did the first time. */ + substream.callback = stream->callback; + substream.state = stream->state; + substream.max_size = size; + substream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + substream.errmsg = NULL; +#endif + + status = pb_encode(&substream, fields, src_struct); + + stream->bytes_written += substream.bytes_written; + stream->state = substream.state; +#ifndef PB_NO_ERRMSG + stream->errmsg = substream.errmsg; +#endif + + if (substream.bytes_written != size) + PB_RETURN_ERROR(stream, "submsg size changed"); + + return status; +} + +/* Field encoders */ + +static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + uint32_t value = safe_read_bool(src) ? 1 : 0; + PB_UNUSED(field); + return pb_encode_varint(stream, value); +} + +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + pb_int64_t value = 0; + + if (field->data_size == sizeof(int_least8_t)) + value = *(const int_least8_t*)src; + else if (field->data_size == sizeof(int_least16_t)) + value = *(const int_least16_t*)src; + else if (field->data_size == sizeof(int32_t)) + value = *(const int32_t*)src; + else if (field->data_size == sizeof(pb_int64_t)) + value = *(const pb_int64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + +#ifdef PB_WITHOUT_64BIT + if (value < 0) + return pb_encode_negative_varint(stream, (pb_uint64_t)value); + else +#endif + return pb_encode_varint(stream, (pb_uint64_t)value); +} + +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + pb_uint64_t value = 0; + + if (field->data_size == sizeof(uint_least8_t)) + value = *(const uint_least8_t*)src; + else if (field->data_size == sizeof(uint_least16_t)) + value = *(const uint_least16_t*)src; + else if (field->data_size == sizeof(uint32_t)) + value = *(const uint32_t*)src; + else if (field->data_size == sizeof(pb_uint64_t)) + value = *(const pb_uint64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_varint(stream, value); +} + +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + pb_int64_t value = 0; + + if (field->data_size == sizeof(int_least8_t)) + value = *(const int_least8_t*)src; + else if (field->data_size == sizeof(int_least16_t)) + value = *(const int_least16_t*)src; + else if (field->data_size == sizeof(int32_t)) + value = *(const int32_t*)src; + else if (field->data_size == sizeof(pb_int64_t)) + value = *(const pb_int64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_svarint(stream, value); +} + +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + PB_UNUSED(field); +#ifndef PB_WITHOUT_64BIT + return pb_encode_fixed64(stream, src); +#else + PB_UNUSED(src); + PB_RETURN_ERROR(stream, "no 64bit support"); +#endif +} + +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + PB_UNUSED(field); + return pb_encode_fixed32(stream, src); +} + +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + const pb_bytes_array_t *bytes = NULL; + size_t allocsize; + + bytes = (const pb_bytes_array_t*)src; + + if (src == NULL) + { + /* Treat null pointer as an empty bytes field */ + return pb_encode_string(stream, NULL, 0); + } + + allocsize = PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size); + if (allocsize < bytes->size || + (PB_ATYPE(field->type) == PB_ATYPE_STATIC && allocsize > field->data_size)) + { + PB_RETURN_ERROR(stream, "bytes size exceeded"); + } + + return pb_encode_string(stream, bytes->bytes, bytes->size); +} + +static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + size_t size = 0; + size_t max_size = field->data_size; + const char *p = (const char*)src; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + max_size = (size_t)-1; + + if (src == NULL) + { + size = 0; /* Treat null pointer as an empty string */ + } + else + { + /* strnlen() is not always available, so just use a loop */ + while (size < max_size && *p != '\0') + { + size++; + p++; + } + } + + return pb_encode_string(stream, (const pb_byte_t*)src, size); +} + +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + if (field->ptr == NULL) + PB_RETURN_ERROR(stream, "invalid field descriptor"); + + return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src); +} + +static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size); +} + diff --git a/saraWhatsUp/Pods/nanopb/pb_encode.h b/saraWhatsUp/Pods/nanopb/pb_encode.h new file mode 100644 index 0000000..b1d822f --- /dev/null +++ b/saraWhatsUp/Pods/nanopb/pb_encode.h @@ -0,0 +1,170 @@ +/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c. + * The main function is pb_encode. You also need an output stream, and the + * field descriptions created by nanopb_generator.py. + */ + +#ifndef PB_ENCODE_H_INCLUDED +#define PB_ENCODE_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure for defining custom output streams. You will need to provide + * a callback function to write the bytes to your storage, which can be + * for example a file or a network socket. + * + * The callback must conform to these rules: + * + * 1) Return false on IO errors. This will cause encoding to abort. + * 2) You can use state to store your own data (e.g. buffer pointer). + * 3) pb_write will update bytes_written after your callback runs. + * 4) Substreams will modify max_size and bytes_written. Don't use them + * to calculate any pointers. + */ +struct pb_ostream_s +{ +#ifdef PB_BUFFER_ONLY + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + * Also, NULL pointer marks a 'sizing stream' that does not + * write anything. + */ + int *callback; +#else + bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); +#endif + void *state; /* Free field for use by callback implementation. */ + size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ + size_t bytes_written; /* Number of bytes written so far. */ + +#ifndef PB_NO_ERRMSG + const char *errmsg; +#endif +}; + +/*************************** + * Main encoding functions * + ***************************/ + +/* Encode a single protocol buffers message from C structure into a stream. + * Returns true on success, false on any failure. + * The actual struct pointed to by src_struct must match the description in fields. + * All required fields in the struct are assumed to have been filled in. + * + * Example usage: + * MyMessage msg = {}; + * uint8_t buffer[64]; + * pb_ostream_t stream; + * + * msg.field1 = 42; + * stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + * pb_encode(&stream, MyMessage_fields, &msg); + */ +bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Same as pb_encode, but prepends the length of the message as a varint. + * Corresponds to writeDelimitedTo() in Google's protobuf API. + */ +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Same as pb_encode, but appends a null byte to the message for termination. + * NOTE: This behaviour is not supported in most other protobuf implementations, so pb_encode_delimited() + * is a better option for compatibility. + */ +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Encode the message to get the size of the encoded data, but do not store + * the data. */ +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct); + +/************************************** + * Functions for manipulating streams * + **************************************/ + +/* Create an output stream for writing into a memory buffer. + * The number of bytes written can be found in stream.bytes_written after + * encoding the message. + * + * Alternatively, you can use a custom stream that writes directly to e.g. + * a file or a network socket. + */ +pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize); + +/* Pseudo-stream for measuring the size of a message without actually storing + * the encoded data. + * + * Example usage: + * MyMessage msg = {}; + * pb_ostream_t stream = PB_OSTREAM_SIZING; + * pb_encode(&stream, MyMessage_fields, &msg); + * printf("Message size is %d\n", stream.bytes_written); + */ +#ifndef PB_NO_ERRMSG +#define PB_OSTREAM_SIZING {0,0,0,0,0} +#else +#define PB_OSTREAM_SIZING {0,0,0,0} +#endif + +/* Function to write into a pb_ostream_t stream. You can use this if you need + * to append or prepend some custom headers to the message. + */ +bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); + + +/************************************************ + * Helper functions for writing field callbacks * + ************************************************/ + +/* Encode field header based on type and field number defined in the field + * structure. Call this from the callback before writing out field contents. */ +bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field); + +/* Encode field header by manually specifying wire type. You need to use this + * if you want to write out packed arrays from a callback field. */ +bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); + +/* Encode an integer in the varint format. + * This works for bool, enum, int32, int64, uint32 and uint64 field types. */ +#ifndef PB_WITHOUT_64BIT +bool pb_encode_varint(pb_ostream_t *stream, uint64_t value); +#else +bool pb_encode_varint(pb_ostream_t *stream, uint32_t value); +#endif + +/* Encode an integer in the zig-zagged svarint format. + * This works for sint32 and sint64. */ +#ifndef PB_WITHOUT_64BIT +bool pb_encode_svarint(pb_ostream_t *stream, int64_t value); +#else +bool pb_encode_svarint(pb_ostream_t *stream, int32_t value); +#endif + +/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ +bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size); + +/* Encode a fixed32, sfixed32 or float value. + * You need to pass a pointer to a 4-byte wide C variable. */ +bool pb_encode_fixed32(pb_ostream_t *stream, const void *value); + +#ifndef PB_WITHOUT_64BIT +/* Encode a fixed64, sfixed64 or double value. + * You need to pass a pointer to a 8-byte wide C variable. */ +bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); +#endif + +/* Encode a submessage field. + * You need to pass the pb_field_t array and pointer to struct, just like + * with pb_encode(). This internally encodes the submessage twice, first to + * calculate message size and then to actually write it out. + */ +bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/saraWhatsUp/ProfilePage.swift b/saraWhatsUp/ProfilePage.swift new file mode 100644 index 0000000..42efcd5 --- /dev/null +++ b/saraWhatsUp/ProfilePage.swift @@ -0,0 +1,17 @@ +// +// ProfilePage.swift +// saraWhatsUp +// +// Created by sara al zhrani on 26/03/1443 AH. +// + +import UIKit + + +class ProfilePage: UIViewController{ + + + + + +} diff --git a/saraWhatsUp/TabBarController.swift b/saraWhatsUp/TabBarController.swift new file mode 100644 index 0000000..44006cf --- /dev/null +++ b/saraWhatsUp/TabBarController.swift @@ -0,0 +1,37 @@ +// +// TabBarController.swift +// saraWhatsUp +// +// Created by sara al zhrani on 26/03/1443 AH. +// + +import UIKit + +class TabBarController: UITabBarController { + fileprivate func createNavController(for rootViewController: LoginController, + title: String, + image: UIImage) -> UIViewController { + let navController = UINavigationController(rootViewController: rootViewController) + navController.tabBarItem.title = title + navController.tabBarItem.image = image + navController.navigationBar.prefersLargeTitles = true + rootViewController.navigationItem.title = title + return navController + } + func setupVCs() { + viewControllers = [ + createNavController(for: LoginController(), title: NSLocalizedString("Chat", comment: ""), image: UIImage(systemName: "message")!), + ] + } + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .systemBackground + UITabBar.appearance().barTintColor = .systemBackground + tabBar.tintColor = .label +// setupVCs() + // Do any additional setup after loading the view. + } + + + +} diff --git a/saraWhatsUp/saraWhatsUp.xcodeproj/project.pbxproj b/saraWhatsUp/saraWhatsUp.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d51eae5 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp.xcodeproj/project.pbxproj @@ -0,0 +1,495 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 05AD83902731B18C002BC515 /* ProfileController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AD838F2731B18C002BC515 /* ProfileController.swift */; }; + 1F38E35F272C83FF00F05378 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38E35E272C83FF00F05378 /* AppDelegate.swift */; }; + 1F38E361272C83FF00F05378 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38E360272C83FF00F05378 /* SceneDelegate.swift */; }; + 1F38E366272C83FF00F05378 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1F38E364272C83FF00F05378 /* Main.storyboard */; }; + 1F38E368272C840100F05378 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1F38E367272C840100F05378 /* Assets.xcassets */; }; + 1F38E36B272C840100F05378 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1F38E369272C840100F05378 /* LaunchScreen.storyboard */; }; + 1F38E373272C852600F05378 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1F38E372272C852600F05378 /* GoogleService-Info.plist */; }; + 1F38E375272C899C00F05378 /* LoginController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38E374272C899C00F05378 /* LoginController.swift */; }; + 1F38E37B272DC2AD00F05378 /* NewMessageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38E37A272DC2AD00F05378 /* NewMessageController.swift */; }; + 1F38E37D272DC56900F05378 /* MessagesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38E37C272DC56900F05378 /* MessagesController.swift */; }; + 1F38E37F272DCA2500F05378 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38E37E272DCA2500F05378 /* User.swift */; }; + 1F38E381272DD8BB00F05378 /* LoginController+handlers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38E380272DD8BB00F05378 /* LoginController+handlers.swift */; }; + 1F38E383272EC32D00F05378 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38E382272EC32D00F05378 /* Extensions.swift */; }; + 1FF4955A272F0AC000C358B9 /* ChatLogController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF49559272F0AC000C358B9 /* ChatLogController.swift */; }; + 1FF4955C272F0FD500C358B9 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF4955B272F0FD500C358B9 /* Message.swift */; }; + 1FF4955E272F29C800C358B9 /* UserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF4955D272F29C800C358B9 /* UserCell.swift */; }; + 1FF49560272FD90500C358B9 /* ChatMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF4955F272FD90500C358B9 /* ChatMessageCell.swift */; }; + 9B4BBA350FD11C92C10C2FBA /* Pods_saraWhatsUp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B872A1DDB07062D2640A274A /* Pods_saraWhatsUp.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 05AD838F2731B18C002BC515 /* ProfileController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileController.swift; sourceTree = ""; }; + 1F38E35B272C83FF00F05378 /* saraWhatsUp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = saraWhatsUp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1F38E35E272C83FF00F05378 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 1F38E360272C83FF00F05378 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 1F38E365272C83FF00F05378 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 1F38E367272C840100F05378 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 1F38E36A272C840100F05378 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 1F38E36C272C840100F05378 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1F38E372272C852600F05378 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 1F38E374272C899C00F05378 /* LoginController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginController.swift; sourceTree = ""; }; + 1F38E37A272DC2AD00F05378 /* NewMessageController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewMessageController.swift; sourceTree = ""; }; + 1F38E37C272DC56900F05378 /* MessagesController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesController.swift; sourceTree = ""; }; + 1F38E37E272DCA2500F05378 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + 1F38E380272DD8BB00F05378 /* LoginController+handlers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoginController+handlers.swift"; sourceTree = ""; }; + 1F38E382272EC32D00F05378 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; + 1FF49559272F0AC000C358B9 /* ChatLogController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatLogController.swift; sourceTree = ""; }; + 1FF4955B272F0FD500C358B9 /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; + 1FF4955D272F29C800C358B9 /* UserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserCell.swift; sourceTree = ""; }; + 1FF4955F272FD90500C358B9 /* ChatMessageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMessageCell.swift; sourceTree = ""; }; + 26C1F4BCD8B1E32F15CF4238 /* Pods-saraWhatsUp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-saraWhatsUp.release.xcconfig"; path = "Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.release.xcconfig"; sourceTree = ""; }; + A160D486BF264B9230657144 /* Pods-saraWhatsUp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-saraWhatsUp.debug.xcconfig"; path = "Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp.debug.xcconfig"; sourceTree = ""; }; + B872A1DDB07062D2640A274A /* Pods_saraWhatsUp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_saraWhatsUp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1F38E358272C83FF00F05378 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9B4BBA350FD11C92C10C2FBA /* Pods_saraWhatsUp.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1F38E352272C83FF00F05378 = { + isa = PBXGroup; + children = ( + 1F38E35D272C83FF00F05378 /* saraWhatsUp */, + 1F38E35C272C83FF00F05378 /* Products */, + 77590C58B6E07924119CE73B /* Pods */, + 2DDB2C90BB0DE2EA3CF1F8D7 /* Frameworks */, + ); + sourceTree = ""; + }; + 1F38E35C272C83FF00F05378 /* Products */ = { + isa = PBXGroup; + children = ( + 1F38E35B272C83FF00F05378 /* saraWhatsUp.app */, + ); + name = Products; + sourceTree = ""; + }; + 1F38E35D272C83FF00F05378 /* saraWhatsUp */ = { + isa = PBXGroup; + children = ( + 1F38E377272DBE5400F05378 /* model */, + 1F38E35E272C83FF00F05378 /* AppDelegate.swift */, + 1F38E360272C83FF00F05378 /* SceneDelegate.swift */, + 1F38E376272DBE3A00F05378 /* controller */, + 1F38E364272C83FF00F05378 /* Main.storyboard */, + 1F38E367272C840100F05378 /* Assets.xcassets */, + 1F38E369272C840100F05378 /* LaunchScreen.storyboard */, + 1F38E36C272C840100F05378 /* Info.plist */, + 1F38E372272C852600F05378 /* GoogleService-Info.plist */, + ); + path = saraWhatsUp; + sourceTree = ""; + }; + 1F38E376272DBE3A00F05378 /* controller */ = { + isa = PBXGroup; + children = ( + 1F38E374272C899C00F05378 /* LoginController.swift */, + 1F38E37C272DC56900F05378 /* MessagesController.swift */, + 1FF4955D272F29C800C358B9 /* UserCell.swift */, + 1F38E37A272DC2AD00F05378 /* NewMessageController.swift */, + 1F38E380272DD8BB00F05378 /* LoginController+handlers.swift */, + 1FF49559272F0AC000C358B9 /* ChatLogController.swift */, + 05AD838F2731B18C002BC515 /* ProfileController.swift */, + ); + path = controller; + sourceTree = ""; + }; + 1F38E377272DBE5400F05378 /* model */ = { + isa = PBXGroup; + children = ( + 1FF4955B272F0FD500C358B9 /* Message.swift */, + 1F38E37E272DCA2500F05378 /* User.swift */, + 1FF4955F272FD90500C358B9 /* ChatMessageCell.swift */, + 1F38E382272EC32D00F05378 /* Extensions.swift */, + ); + path = model; + sourceTree = ""; + }; + 2DDB2C90BB0DE2EA3CF1F8D7 /* Frameworks */ = { + isa = PBXGroup; + children = ( + B872A1DDB07062D2640A274A /* Pods_saraWhatsUp.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 77590C58B6E07924119CE73B /* Pods */ = { + isa = PBXGroup; + children = ( + A160D486BF264B9230657144 /* Pods-saraWhatsUp.debug.xcconfig */, + 26C1F4BCD8B1E32F15CF4238 /* Pods-saraWhatsUp.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1F38E35A272C83FF00F05378 /* saraWhatsUp */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1F38E36F272C840100F05378 /* Build configuration list for PBXNativeTarget "saraWhatsUp" */; + buildPhases = ( + BBE6214271FCB0E4B252EAA6 /* [CP] Check Pods Manifest.lock */, + 1F38E357272C83FF00F05378 /* Sources */, + 1F38E358272C83FF00F05378 /* Frameworks */, + 1F38E359272C83FF00F05378 /* Resources */, + C01B3E2077808378D11B8977 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = saraWhatsUp; + productName = saraWhatsUp; + productReference = 1F38E35B272C83FF00F05378 /* saraWhatsUp.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 1F38E353272C83FF00F05378 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1300; + LastUpgradeCheck = 1300; + TargetAttributes = { + 1F38E35A272C83FF00F05378 = { + CreatedOnToolsVersion = 13.0; + }; + }; + }; + buildConfigurationList = 1F38E356272C83FF00F05378 /* Build configuration list for PBXProject "saraWhatsUp" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 1F38E352272C83FF00F05378; + productRefGroup = 1F38E35C272C83FF00F05378 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1F38E35A272C83FF00F05378 /* saraWhatsUp */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1F38E359272C83FF00F05378 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F38E373272C852600F05378 /* GoogleService-Info.plist in Resources */, + 1F38E36B272C840100F05378 /* LaunchScreen.storyboard in Resources */, + 1F38E368272C840100F05378 /* Assets.xcassets in Resources */, + 1F38E366272C83FF00F05378 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + BBE6214271FCB0E4B252EAA6 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-saraWhatsUp-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C01B3E2077808378D11B8977 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-saraWhatsUp/Pods-saraWhatsUp-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1F38E357272C83FF00F05378 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1FF4955A272F0AC000C358B9 /* ChatLogController.swift in Sources */, + 1F38E37B272DC2AD00F05378 /* NewMessageController.swift in Sources */, + 1F38E375272C899C00F05378 /* LoginController.swift in Sources */, + 1F38E37F272DCA2500F05378 /* User.swift in Sources */, + 05AD83902731B18C002BC515 /* ProfileController.swift in Sources */, + 1F38E383272EC32D00F05378 /* Extensions.swift in Sources */, + 1F38E35F272C83FF00F05378 /* AppDelegate.swift in Sources */, + 1F38E381272DD8BB00F05378 /* LoginController+handlers.swift in Sources */, + 1FF4955C272F0FD500C358B9 /* Message.swift in Sources */, + 1F38E361272C83FF00F05378 /* SceneDelegate.swift in Sources */, + 1FF49560272FD90500C358B9 /* ChatMessageCell.swift in Sources */, + 1FF4955E272F29C800C358B9 /* UserCell.swift in Sources */, + 1F38E37D272DC56900F05378 /* MessagesController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 1F38E364272C83FF00F05378 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 1F38E365272C83FF00F05378 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 1F38E369272C840100F05378 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 1F38E36A272C840100F05378 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1F38E36D272C840100F05378 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 1F38E36E272C840100F05378 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 1F38E370272C840100F05378 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A160D486BF264B9230657144 /* Pods-saraWhatsUp.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = VVJKC8N3PQ; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = saraWhatsUp/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.sara-alzhrani.saraWhatsUp"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 1F38E371272C840100F05378 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 26C1F4BCD8B1E32F15CF4238 /* Pods-saraWhatsUp.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = VVJKC8N3PQ; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = saraWhatsUp/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.sara-alzhrani.saraWhatsUp"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1F38E356272C83FF00F05378 /* Build configuration list for PBXProject "saraWhatsUp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1F38E36D272C840100F05378 /* Debug */, + 1F38E36E272C840100F05378 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1F38E36F272C840100F05378 /* Build configuration list for PBXNativeTarget "saraWhatsUp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1F38E370272C840100F05378 /* Debug */, + 1F38E371272C840100F05378 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 1F38E353272C83FF00F05378 /* Project object */; +} diff --git a/saraWhatsUp/saraWhatsUp.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/saraWhatsUp/saraWhatsUp.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/saraWhatsUp/saraWhatsUp.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/saraWhatsUp/saraWhatsUp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/saraWhatsUp/saraWhatsUp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/saraWhatsUp/saraWhatsUp.xcworkspace/contents.xcworkspacedata b/saraWhatsUp/saraWhatsUp.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..cfd20db --- /dev/null +++ b/saraWhatsUp/saraWhatsUp.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/saraWhatsUp/saraWhatsUp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/saraWhatsUp/saraWhatsUp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/saraWhatsUp/saraWhatsUp/AppDelegate.swift b/saraWhatsUp/saraWhatsUp/AppDelegate.swift new file mode 100644 index 0000000..5de82da --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/AppDelegate.swift @@ -0,0 +1,36 @@ +// +// AppDelegate.swift +// saraWhatsUp +// +// Created by sara al zhrani on 23/03/1443 AH. +// + +import UIKit +import Firebase + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + FirebaseApp.configure() + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/saraWhatsUp/saraWhatsUp/Assets.xcassets/22.imageset/Contents.json b/saraWhatsUp/saraWhatsUp/Assets.xcassets/22.imageset/Contents.json new file mode 100644 index 0000000..b8abb08 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/Assets.xcassets/22.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "png-clipart-computer-icons-conversation-online-chat-speech-buble-miscellaneous-cdr.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/saraWhatsUp/saraWhatsUp/Assets.xcassets/22.imageset/png-clipart-computer-icons-conversation-online-chat-speech-buble-miscellaneous-cdr.png b/saraWhatsUp/saraWhatsUp/Assets.xcassets/22.imageset/png-clipart-computer-icons-conversation-online-chat-speech-buble-miscellaneous-cdr.png new file mode 100644 index 0000000000000000000000000000000000000000..ed97d936f64aacc03cbbf7347e3a459232dfbdc3 GIT binary patch literal 11069 zcmb`tWmr^S)HY6ghMXC?8DQu}8U=>#kd_)62?+^l;m|3Kl%#Y^D1r}#qGd2EKVdK0eS6#dkG)61Opc0u6Ou5wq{G*O2yK$-@TkeI5h zG6+2X-^D#d@C|p-Z9)IG(jCyu9^?~2sSJMU{oh0j7-DXvV`GGs&Hg1!1XW0?GWfrW zQ*{4#EIVapA#I`%ftOrzw&qgX*hokG56QF4;A`tN7y(E10P~M>eykrV>30gw!iSd( zS2fa4>L}POG=mK-KDTk##&mdJUs|p#w6=Emmz{XmlKG8J};YiuvD6~sML4g|Lvh+@?BqbXFiQrOt?q2+}B zu;7*oT()cW-CYAE(ZkE9Di@j=F9_h_qugv3^`#M}uzO>G^(Rf(Dzv~b@tC{1BGx@K!bt=JXP)%h01g7mm3|~ z5kB%X=IMf7l)|{+Ujug8WLg%jyfx8bUHbJ-wcuD)grpf*&7H>WD$ z2G6|?R*6fMw=>t~;u<{2xI>D}mQ<4_nH8o&SM!yfNFaV777B-VVOyN@1!9(K74HK`Gqtey47Og5VM-#g zbCaxa&~W|JkNB)Vu<6`KFd`J4lOge*@D;rs)Ll!!mjY0yLc!+W4jO#fSe9nQ#^9on zLJZ*f6*U(NlhHBYN+)4>FD7*tp7df-p|qYF-XVfrU~$8dmXCcq7!dRL{Jl^6 zDQd;B4wJyLT_D1D5Kt!_lOjl*{4n*MhN-0|NqjtB5-(v=iuZSy8mAjb5hFRQ2Yc6T z#+jLjU3?|*Qp6CXHc`EA<9JkJXFaKMFYb7)I>JZ^u(bT*1Ts^hBt#ciAu6EWd&>!y zXe^kxPB9oCzQ8=Slj-XTSh8XSs2q=m=&0@9>AyhK_Cb8JwPrhlJ3bH+7Wbhp0D>P% zrt0@539BUkicz8S?o>3k*45WP(^F3>g*)nO~(gEnVMw@XnYXCM7m4n zu%I-fB_6$FML94|zKNX_S&*xZpBzqHxynsfavo@$;bpC@gK)%8dZ;8n5d+1s>u3x! zg-|u!T|N$l#Lz_{*=kBCkBs&Gd!RV+CLz%7XKhXe@bei~QK^~=y6}D{CmYG-as{2O z9h>q#VW9rvOk*VgSr%T4LhS06ui*%*+hnh6CN1g|qG2Lt0bi#o3LPXt+^EeanL`oc zuc6Y4;6-;ES^;#bjT?j^Li_qns%PX-&%B>anz6R#S1LnUGhI-$D64NianhA2>jx%>t#k|xQYp3=BjF5CUs!6UxKa41f^72%un!Y5CY zvrX?AJ;clAW7i*|rkf?}Ub%gO@>hNdMR^Y4G@Fn_H1_g$pK9l1){&F*pc*5&oS{sq zH6*?g?^&^E=rDxuBn#A_g~i>8Db!h6UTa$uQm>8a)`mUFzF5F;#@bS?>IrHE@rUN| z=1B1G^W$QpY?QnV9{Ncg5tjTClmx}Dmwc4BUF_JDl!|P{e+$RVr3VlUP$mOphJTZ( z&+V~@U{4?K4AHLVKKa@o5Ap1;hY)eDwE|r_~ZOtvnZMD+HY` z1d<;F0CZK?8#w$!vGJYtI==7Q`3zPz_EmwlkQ2cyGZv*QPDF|Oz)hCbzvpwWccWGh zpfVjT&Soe0b?vPWNIWicc;9X5@-VWBzVB{!@|z??Y%@#3LNm`YFDniLX&;K#9O|G` z8l(R`wDeCbhf$ieTsEt6aDejsO)3G=|76Yl6OH($lI_ZS{3`onpk>kJ%}SNw8ak&M z;v;K)0o6G<9}-?q7@M=oV)^Df=i$AwSyCO^*Tx$=nS!s=(vTZ;!53e`3KD&Owd_t5 z?KKH7Tz#&RK7Q#NmxrS=vac;Guc#=C!JSz~1|TVV^KhzTb3Y_N#qy;DUVA?BEO~D! zjCVvxBOyvuq&Uw~`+^tI&lE|pg)wwN;Bk-Gyf~JtgiH6}=G)A@=^eFA=s#Uq!XT}l zXK`hD4jtZpOC=OdP^$RIR*SYK=*?1KQJ7MFg~E+}oQhOFbW2OM&crJy(TfOa6qCb& zl?l$L3EDfVpY?tO{0!bCLQ8~j5}+rR#F}DPZHiAu-Nx&fJpshf+vyNy;@Hc0H+$ZVrOH6= zbjHEch{Q*@VZoF){hq|^6hR}$i4Y%)VVZuQ5q~=C{AV*e3CKl!z@L+PIM7#N{h=jJY$##-!F@~c0>J?~TCU8q<%^c0cvPGP zq%yJiTaVPm;(Z)Xby8uo;r)|fBf-WFUy=8?Qz+CP{AqD+gK{S2-ak^QNy4Ko?p(Z? zh@HHqoPW5PNc)d<5E#p9y^k=&l6i8TA?j#2n0PnXR2b6;z|X0ezY$(halRr{Nq9O( z!0NlSw(!a6YIboum3x_*cgqzW|Bhq#hN}gk=2GYz7tzI4%Ge$QE|Q_jto@4k!j1Nz3{pHK%>LrCeMuZ zw}~Sp_lPA1b`vWzZ+k&o9FdEDHnKQQF)fOrZu+c$k#vmJT)I8*>ePY2@oXq)U;%^U z5T$FJB6iur>39ZPr)s4MRdL41nLaRn@Wo?r^kJ-+v+#AS9wJgBN3tA5isnI+s@XYV zOsQ3jIi|Wl+j1B1F#H_7C-IXP68G{3UTJ(F8+9|dZ#Es44rs3=e)Y)gvzQYXz2dVK z`Pu+zYZfn?DUhr;ze;j$j_HARQxrWZ#s56_v7#h!2p=OgwUJ3oj$Dm|J-BJ&DEUh+ znn$Tk@JsTAXTpIE-s#QZU?`8^FSmzv-^npQ!_LOVM)VmW7)$_m&O0J`e4>w|1T?Gv zj$9Tec<74(1Y*B%JIw1{^#*y-BMt69z_M!Bv!ka~1yu4SLkc@8&c8BPPwmEn)6!X# z-R8Tt;H04YaV{O#!8PHFoJ-^`ya1q=rG{KH9J27?$2F1?M@Nyb$5Q*^$i)P)GvLLg z@{c+(0CDACKMG%tJo2Gn?@@{@CPGt(>M?73{9X9!t`L!HGf^mbr7#aSihn(^PKr@T zl{703c8qVtD56nXbR#oSejhZ zLs>Rk*$!e^?IyRj^Oq}GrhwkTv+W6{KbR~j7-chw>rB>LNl3(#oQ&X_Pwgg)xhtlr zrY`F*E}cM@yoII7NbIkpCv7ZKX{Zxk!XN^vTPce$-S?z@_R8O&*YpTq$(&n;gKvdm z3MEK2-EM2BUqFM(;Fc#+G)Nzko@IL?Kd+~t8I~-tP*r*Bw8Q+(PY~dJvTZLH!<);k zgfvVx)OfpQMIXi6=|i#&x14ig>-y*p z^J_Lr-~uun$PcqbuFdkJlpkJE1nD8Y7;pTC+HtYzXFVGjFRC`wzRCG0&!@?_S4PX6 z?^agwrIL8Xj8d*scdjP6%r|xT!84q~YFI>orMq<~FFNk=s zd0>fBprqb|;UlNhveV99NcVahLbE5ce{sxb z8hsf^siGyNN*MK^>jGu#<4rj1#9sQQ#XAuSk5Uk2>ly=r=_3T%izMb)l2P|%r7wsS z^YVrAFxHQ z$XAc;85L;K21!Q`NX7%Uc}$LEWy)V!m$kAi;{hY#(REh_B-TT*wYy0w^#FE;f>ENStz5GrvL6iKUQt+n@--=&v>**`Xp>uHh zz3d}S#d%!=GxT7@@rG)^cbLv2Gqf5~Mh+uDg6X@TNf~W8&FuJ@zAPaHWZn$Y*kRni z1}+DXi!LuUXqs7MD^T-VybPFBNU{IoAX{z4A1kyP$A=NYIB2&Pk>+I~$+`z4n7!$B zXC3I*@7RK!p)ULpe4tQOZ5Qz2cI1ud7nfq84U}Xc5v7~ii1e(n(Qi$T5a4`|MRw>s zqj~&ABRS@vq|q7|&A+;ex88Uvg@0LS{MYYWb`8sn%wrT6HyD=dM$IP6AI$hfaMg$P zKI-CTIt=@U4j{S%-lRVuj5@|G^?c@rLrs9lNK`c?S|3nFJf00)@NatbQn0QS#RZ}+ zngCaXAq8Py3@gLNd#J|4A%^t$VXuR1p{dEI-f^_dPg11zJV?}ZU=_`eH>ryaf%Sv5!OqtQ74Q5$o}v2POFeU_YEUuT(woyRWa>C2lVpGLMcxPwLs}kO;(GAX>iNdM7_pVl_gq z72Jm;l29KmPO$X>0sfbnN3f_LwqTIi>adI za8CK(xaM_h_SW37%;&x-6XkEhaPYQgSfK_Yf8Bn3{ciaTj+cv#e&Vnh#3qXXgAm`W zjP(J{yDIrcD)QHxTGRzW^LaxN?d`YK!Qm9ufV9lVnqd;p6(kAQ?}Y9+7-{oK9gNBe zTjaLgkhu{JJ)*fM$4@!~x$}p2ReQ9HT40U9>bZT(=2msBgtF2W-n5d+-M7 zO^Utd3NA1j940BpUg9Cf$X0r^*MY9{1io!DW}S85LWKgiE`ql`lO(cH*jb{n_M6sU z>WOh(UfTQrB$~Y+gAdGa?>oZ|o5}QzJz}8a)Wp?}7H5dz;W7JrP6q_zvVQ+X&b&$L z4?fUPci41nelb!+P>(rq*o>YoO0|lI64Xa!-(kQ9-+l%u%)ibsH1>#|{20;o!gu{Q zPgU(Vjlbm6KXB2U;1SPb3l$O1yd|lkmznhHN7|5f+e6=mr(}e5)l2S3)eIM_nlqMz z%RX~s4`h&OLV49F9C(@xEh~%6Uq=0%b3B|gq>De-8TUYRu8-+`IJEjt zV*kyQl++u=o%u^db5d+&;Nz0+mED=2e_Z|;uR_F0#2sB#D$m-_aNC|>Se#~fA-`GTlY38(^t7O(P(}+al7=t_f=Q+&-gHxm zcTZ2^#tLBZh}M;w*; znJ7R{(Iq0C$6j$y0CX1mHnd;?|B1XOfw~VKIy@6FgK0VlfHv;ePJKyfjAoOiy`_Be76QMAMAdGC|%Dg!m z+fWOpLue9Ut{+@e-JbU8XAwt_jB-GDnDV)70|&38IVtRW{xm$x3l zze=uAadcGygCjyNQG@4T+PHiN7ki+=@>Zs4b18Kkl$y!6$YhuPy-FK%0n0P$`q&-` zehYOKHP+nDqVyQ#>PSx(MDemv4?Z;N2`CJnmZ|a*53$=__(M?@ocvKj1#TCi8A*3C zBZ$b|hrGvy!AtixVv{xu%pP^BvYoh+yM_KJp**h$@xP8eQMVLWv2tPfcVt!ePgK2o`uDWj!3TMdiwil>6 z`ivxwLTF4Y8VjLzM~X|&e>K~Y4|sxEL+Ru1Bcc#01`6Bnc|Qm2no?3m8;kXDxu|D5 z-DZ#>DAy~fqPf)Zhj$u@5iR>ZHxYm$SQc@7Nw)?C`KhBz;E1ZOFiAe;3-|5L;>udz z+Vd^*D`lXnAyy|*MQs>;o4FkdTI$in-)+r_&*Ze$R0omwE2uIZ()NB1OB0|e;dgED z3|WnTX4zPr^y+g+qlZknI$N{beM+I;MvCVn)?u(A~wbf4f9<%asX(ac7C8VW4)`E>t|H3K6um{vePLfFfAJkT3b7tijT z3nXVL%bVGYPPCtMV0ybk0nn4DP66;#Hvu23UmDS=1tu0}Hb9#7bmwU4Y#t7xU~=11 zjLTI#`?*_(8hO;SmcR@m^>_4QZ_0qnH9=Ql%^&PnU9`2-E9}hCLGFjitKA_5vp!+D z%7ZDY-(2{#JlrtGl7qQNHy5gYdcsx>a z>vq~)yT!qNzt43L$FT>ldJgiqu|nam&?GI#pQg4}=wuMZw5)Z{l)i8KMCKKxP7*IK zq=;%UER)lt@lYC~hC)~RWzR}ABwhmCW1d8qr^=YX?=XjWc{P{l6m4^;mH&N-4HcTG z)JbZ?Y6+HLDmjSJ+^YaEqrt$)75Xqf!^3du2AY&A!fx_)Jp9<$;!*b%|I1XG(?t_X zuTqjcR`+GIrdGQSJT`Jp*V5qZa*#B}iP~DYtM+VCKP3j+Lif5OvqUo-fWnAlj7nl8-P( z%1^;5NC?^A+W@SuvXHpG@q?k#DTvFD-yy3ZS>Q}H;Z73@P=CL?HP<_u>B)TJpsS$v z&%?5!+=rc=kY}lkm0hCGXU!!VoO$v@TLh)}FYsl%2d91+;jB0Ut(foppykv_Nv*#0 zVXBZ2L0e_@>+=5K?@{&&M?ONOsO|~Y=PEuDN;#o63NJHKzfGkGaK#I&x3^xerUT_1o2NQp`%I5Q-bJnWthE*#S9q)hnP^x(^qTd>GzsgRds?KdkzPT*VqF9UdcNlel8rgVdY zm==E*0*fYU&Zqs(LcFVdY7e-tDMjyXFx@ML>}V_vL8FOg+h{PU_}#Av(c4Nt4e&Ri z;(L>jqyUU(uMY`@Qss{24!g%NQQ_b>R&jh7!L#xwIN*r3SOq~@ z8h^@R1R&`u_%uFwN9joPqy*S0R$MqYO5VNGu$fSw!)Y(~8#b`kD>>AHo!!2r9_4^- ze#V!JVICtHDr$_R6YAR{kOAM44bJ2WHg>WY5s15JJ^6?IU)dUJmW*d`QRM?Kd-5*( z5eiK;3&yq+;GnsN25$uEcA6$hqoFCvuoR=BR_ee}=D@;*2HC!Az|t2wAujYQ7-@rO z4w`i}hz!C-n1Wp%E#N6ouyOs($mMo!AL zw2I>Zy5U8#;a|l+hdrf09l2Ctp}MI|jbxT$5vR*8kNW+~W8551A1Xxy1z^} z>vbMUKUZ;q99s18UX9#hRzMZLFzA(t0XQzz!C8m_?-#U_KD$ zQ4K_t0RQ|nmqZ}hT_nd%qCAO{BgY@)QGLr;6C)6|^vS+PA&g`wXK#*fc8bQf6;m|y z3FD^d-fxQ58r!b%dkW=nX_D2-p3CcrlK@$!@#N3PW7ax7;>oN0KlJ#DM^e=)$9yU( z{RT8A27VnAx5$1zdB2r7jC|(yWfBNGkSL-dOSu(YQ+zdYE3HC%TNt4tUfkEn@$aXc zgr=eYfl(auNrnHu?TOLc`(%)ulzvu=AhTAN`7? z@Q2Shz{nBI+_@nILy6w|Z;o-0IRy~kiRq9|MikQd%-MumS~T#-w=-UCHF60s4z zGxtS(y-GOGS^&O=P|CCzOLp)DdtENS8#U9aO8J$d-2q|Y6LPPUp|H=&@(eJ%x}usg zinDuNz`yQUJp)kHH|%`;5@QrjS#6Yuj3b!U zBg+giye#LeGy5-V9cNajQaNAPXFk<2&>~i!NIF{YOXVC^PB4>z$;yGcvILpq4NYw} zEoC5cq*1xc^S(F^A*Y_^u{1d8gm!GF!H_swemgJf>`FuB2vDY9x8-|F?`w@QgxuTP zKbQ*&*%I0P>;F(@c86%94oS{t@dfxmO>uNSYn%Op_G{Dxp@^n>hj%?UM&!8Y&7xo? zbKnoqU^(RWQHGfYCdxaEKKIYz zcAzc1)2iBU-^#SmeEE_fq3_3Jrd~@1NS`7V_vXC4?(1CG`Q!KIR#szkbDOTEQF%yq z3llulEfRfnCA>eE?J};o#Xbs$*MB3Q9w58oto!O1L0k?OxKppl$lKbN2*4^GaVe%3 zbD{sxx1EVR;vN$HsSU1bS7}#!J@u~WtmMh5=I)BGhw4dCunLG_(;mj#ylE5CRO|59 z<~x$p>a>JAazkR!D@Af$EaE6A2kZUJ0r2#?5A-nX>W8W?W54x*!yPmg- z!a_cp1{0CH zeG_Bmjas>9vc{kli2C4!oDtI09h9cw^&*D9jP%80>yMKnnn z16b=r%i_SYVL|EfBI8ABhG{JEH7kTRn}R>p8(QDFB_gk(H5d?8v-=_=%5$Pa5Vwqv zk=rg2qGkqMMq`-No&yV66k#jKNZVjk8!~EIepqpEHl>X~tq>gbs-@gZgTi`=5vvbO zBnZnaz%ChAc@5o;@5^Sm27#!GP(xg9`t@iRCla+zU`}h9E43LGdW^>vo{{3&_azC3 zo4y#mtMVcv$+Q3M|L_?!<5%R7Y>3FU@&77CxoSQ`5x59@YBdwjGt~G;N|O_D)`(nG zw`=qtJi}(V0L?79-jGHI+EiB_$yvNUZyKqggK5%?r@PeYgq$#@a+_=*tD zJQd<7nS>l`2x9fvXk8~#K^$Gzt4FZT8X$!oEdnSqi!3Q)T`I!w=Cjd(k4H9{0FcC)`j9-_wDG0@`uo-Pxa0)fTPVnkyKe0Tp4egH# zCNY8%dzYSx?OFyL64w{r{dL~Vb9fO*U7%XsM)k*vuXw_yQfEYACa4o6N>SpB3>3`u zJaCJcV<(ykY66p`cGxrt{#XgD5C4*@bl=3c%&Fd#<57G{p-&zr}R&ydZf_Ur0++s^g`eEiRm%?!h%9?Dgehco^9{&6M z@cc6P!&^okb3Q~oixLd{uW&^`m7)KY5&%W<4+0BP9Hjmq1zI94AIl2p;~@Zj#{VA) mR+9b?F7p2|PBGyYyW;`rwOIAW=ezr`SnA3;O7$q4i2nlw4mlqH literal 0 HcmV?d00001 diff --git a/saraWhatsUp/saraWhatsUp/Assets.xcassets/AccentColor.colorset/Contents.json b/saraWhatsUp/saraWhatsUp/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/saraWhatsUp/saraWhatsUp/Assets.xcassets/Afnan.imageset/Afnan.jpeg b/saraWhatsUp/saraWhatsUp/Assets.xcassets/Afnan.imageset/Afnan.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..82c4cf40d882c223dfb3a7f1897a464ad4c6a2a9 GIT binary patch literal 6010 zcmZ8l2Q*yG-@a@0606r}K@w#JtG6X;@QN-32_jZ6Q5R7oA_$V`y)U9I(W48(>SeWP zQKDNS1mEWU|Ic^6^Ua)lXU?6OXP$HKJilk|T+dv82OtmBwbTI+2mnC%3|!9v5db*} zDI+5T^M5Xuo6IaMEUc`|?2OC|%*-t8?98kz?A%a3b`C*KW>$V_enAmY2?+^SUOBiN zObH5;5Cu_EQbMR99JI8Ya3Nkn1u01-2^dUC7A6W)fc=}KC1Ei9BN$8pU%`(M#TTOZ zn$o{_*mXNVLkhHjD8V2efPe-BrU6}d18e{Q2Ec!*{%-;ifQdN=vBxG?a*#jz`}kS4<_Ly2HT6bM%0O{#ICG&GMmmQeNlS3WH%d z9)cAQjfelg_yk}=A`mgYO_&BCAOH~pgoOWM|0RH*n}(2;3D}`_=L&HxdN-cVdw1(g*fVUoa4Uc!6N6U70f6pA6r#Ef7pq`; z2=_o0&uC9y*Fa8P!`rgbSKJ>1_L&{DJ9XZm*@duq4E8Mxbo5XT%!S6`;%N zM;bF8@I$?UPX4$c=rGJOY&TzeIM1-mw&|i!b)%0w`D#&$5~O>-26f z1J0rzC}wfv1Wu1tPI{7Qg;QH5IxmMT?zt(lLvEypK%9*b;-ZKwgH+eDhzmX6Eqf9szSs)|Xkb-P#E+FH}4V0ml@ z$%;neM1V$-;Pf>RW4y;{|Mbhq3`fkeN~<#TZDNhVZZwQrGlZKIPF~tNB%8J}P05(Z zE)!F#0=C_3YjlCVo=~%o#hm7c_gsm64u17hm#W~^_RhAeZ4PblR##gf6Q4>%E~5q8 zI%n#_{G}uZD)Jt3?)c>rq@4nEO8kg9Tk#kpS+bZ>2 zT~Ud7`W`!T6u0;~aCPV9L6E&YsWVi`2w@BZeWmzI30hmKNw3XfwBqoNXQwwAF;Q66 zC>>MukC4O#DUMR9*33nAeckR9DY8klTFW~!%=pvovKp49EPpl0Fy8r+3419W&-Y-b z6SH%H9TIvY2LiP>Jr#?5Al;|LnpMURw;|BDF&7q1Dc$2nU@Mb{>V0EGDnXCff@$yC zg(mtb=pR2GP@>T|tCwA*f>dfm|D>}Dfg_c=+SGq!CF_#8<>Tc)G(y|^&h9nHG05|$ zSuxCkrF37;TM@h;*fKpm4Xp{@*SoK@D(@S->f3TSFZ~;8vZ9q}m!9aUwfLYOf)N_> zo>`_E=1tV%olo-A>c8!;MQWPTL28u@$GPn@+^4RR!zj7C9`nzi-5GYI@l4h{74>wy zGc?j_U5fT?ee=>eIvXFesmX;@VV@iabq{&g`XM^xqAHE{fVt=f1~H+41#v+jU6t0%`nY6YDimnt=SeWLz4 zajsW7#MKlYqc`LKF$*-yzK)pOY>X2^YCj$)WDjfFo<5%&<*5+Y&p&(Ledt9r=+~>E z#4tMMRM@EA_x{f%Wk9TuPotXGrWcNz0_~+7uwcEloi4cE`a=%;RMP#B3}z)zU-#3+^_J~0#~j*>u1_42aVJwvfgtN+KC8R@Lb9PQUlA8w@5R! zIl+2A?S9&K3e65eO|E@HhL8H#p%b&BHv0#zRCswavZSCfd}?Wx5k6Tv?&o(t#_rvK zK#j)szF`e1#{+YIHE2vPR8ci8V*tR9;Uo>-7x zF1-OYr7*FOn|qu6p5>>LN?DCGR=u&G2a>@$%kPzL|+H zjpY#yCq@Tc-FlQIg)f~Z0j$L1-;V-Yxj)xON=^9Iv}+wI0v`M%5;&vkdTC*b)7Y`Z zN3~M!)TQ0&qQw(^jHPPNzDFj`F%Bse_)JfgoX4ML*h|4&9ljGKe~S>-kZ1{mL;y`p zhD}Pfx#e+}|NJ_leiF!g4Tz04Nj;NrtV#Jb5Bfgea0GlRp9%p8fGQ5)3Di1z?sbWX zqAph8`1b8J823}GPf;!Z6&Aezn zP~s%fIAO@IEF7~qbkzMdE}cAGhZAE$dwyWu23`o z$hMmk_URD!ki5pYuLO&RXNTvlq2&y=+8!o1tz_e?lY@AphsaJbS4Y%B42UC-h9Klo50KucBKMZrtD zAUgbz_6PC&Gd)*7o>bl?cK2F@TL=!Wokbd&n3po{W#<#%CQg=wnpq4nCN7I9b83fp z(uWt#E+#)m9ls}VA{BFIFp@3*YtMOnT(Bjv5O9}r5{rDkVoWsd6V}P3)aYUl%FgyG zP8aaBG_062iA}7HjCKuO72*DJn=@>U{5;vYuQXYJD}vkHo{*cAD!-%|ii$6B@7>~z z-Z(;>RbUXGn8!9#V*D$aN|B10=_bEghu7r7FZ6nZb2luy*WUTdF7X{>iw{L!LT~(t z`!ZD4K`~^8>_yo2yX9T2fUNKP@0{Zv3yX-p5}VP?R((dd8pF2&rc3% z+HR$-TdK^#TwK_)rmKGUR&Rg((UkpsUyl>fvaxmZ z))j;`ewV)}Gc}euNFDRe3GE z-nnDNH^rYxry;2{w(mcNo8jLWsR~Y3AjAX81Fy=^x(p~8urSf=U$(mlkV!L>*U64k z;6?=b6|&v8JWUxND(qUP2sZb%o(+J0KfH_x9LNfLnbqbmlZNTBu+NF$4g&Sz7ZP=I z4hn(2BiC6db0h+s(>ANuiZ-)XHTZmex}y}7J4VgYO-t0%~Lmcj+ARF zHB4>kV-F}c^~v(MV&KnJ=qVy*aG;Sp#@s2U@yn7q(f41X>%DaZmy~Yk=xpoeGvFDO z7vHSbZu^BIz;;q*5H5O~@nId&s>Q{+$ITtUy{+nFt#7u;rjbuNqQ5eDw<{%&G@oEN6DmfDqb@;h-$x!+!XO4?j$bR4z# z!%s2APpZNY$yMXL+P2ialwvk%_(GbKfV#b8Fn@A(dO+)aa(^2pM?oZC*l~L z_>#k^5(nFb^(wm>wGWln7-#A@z9==Tdib9aQ=^*iU;JD;6LtK8NOOcl;-Z)#5nPIK zv364h@>U&(NR{1%)YJv>e$N}FJLjhZ!Uw^%U2y1cG_(tgtnLhAU_6aYd)8&^6&^uZ zFudoRub%!bAG^$ceDy&+L7}i$oxzEQ?GQueH13>__pY}AIdrUe8QJZI#RgPF_^<~- zsJ;Q3Uk$oYJ^Wz2Z{0(El55Le2C`nv2snXgJ@vJ3?i^kN0_>Dn+lWq3-CBzD-4;ZH z(GmXJisdCQo?HWWsM8B1m91jc*;_x^ozV*U(+R$AEMVp#t>z%KgYKHx&n&O@d&V{4 zd~MMUp$nyd)PFb6aRe0nmKH<>t6S>$8OY;Bv&zM5r~)qEVW=Cky&7lUk5PU!)jHAI zp!g~bInmGI?7>&Odh4A9`EQHmntl;=UngWvs>D5$FJoCVe{TISts9eI$Le|68k%pA zb))HU=B>iH7zbp&VMt2VTA_}WFRN2b@4ihTsmh4Cvn2bwc$2KtdRS%e%RiCfxkcNeC)$ne=ZSeW*d<<;{>N zc^WVuf2`D<9o(Wl?TtxiH@MViSy--n|YyLsuOmtS-cwl8SQ6i;Rq`H*0)&`Z8JD=aHOtpVD_9u*X5?) zCRnA|vEz?Gln?W<=OVD?#TGU>Rnk(PG27F#9QJj}uTaPGnVGk#mO`~+R0ob>Sc%n1 z{vcapVWipD_ECJ+&X(`8PcWl=@`J}Ip9-s_({yh0Rowm-Dwq(kl}QzZcv_ijVdN0F zs$D#&Wv-!Wl=j5UB|f3y(%pi|ya{fYXGR^6BMjclMl9;PiJ@Jxnp2(?AKhxNM8sfc z#viU5WtXka%sy0!B~O)%LF3Xhxbrn-S`roC?1;~7mAg@~Q5!o(nU-tJI&i={ z&V>uTvO?w}S% z$y89*n+#1q=a>w4ca9fZRpP3v3zB(jXqk?l=oowd(Qu!isfNBB!)RvuT+b=Pf0t8q zrAc~g*CHVB5`+vg*vwv(d==g%f4n-?&RyR71mh0R%lqIu2t-oE z(qivE3XI>RDlCfQt^o(oCn|_%v2yA{)*~Yp)R{K=mu=K2F#mlSEPw=eSj9>WSmW(d z+e#}u43#tP@l1~^oJOABu=)!MG|n24Uh4Jr-aWcfFE=%3_fXM0pufSxP-lB+q6(t= z&7%|b`7{VZo}bfRfATaWnrF-4o=BDe$GBt)4jy=6GK~G^EgNROOc<=;L44fd8C?B> z?$kWZ5^7seeUTwg9scTY$VcOyTAtstKnvIQ0etT+L(5g08!O`t@eFqcodoI&C61*l zxN0hGi<=rQQ?i4j6{bU@yDXU%qelIHGVF^xpT|?ZiTfyOeXQ6PJ9D7{Y!Fvj?s)*j zXIhKC!j%QGqgvs*+!dW&+~HYzB5%g%9%ayHJqmg+$eYn*rEXb?@YY~bz-9yku7E2$ zBQLjJ9xl-g9>GnmjLf8%Vj2Z~BEt15j%zGr#F4DDz(n{M_+FVl^Qe)ti>)k18DLYU z4UpQi3gZi2X*O^YUe&obleD`240TVAP;Kl!8zI*6u4`>gu#64jy24?PkP+Ubc4+8i zaOoRfW0ZvPpt||6_`X~m@jgSdmT;r=qLkGMrK0J9oomigC}{Zkf1`(;CtoZU@GU!(hE ztZ3=5th{EW#fzye!JqkbAZ~He#wLeMM{wY9s)%{ZAYc{l`tFiNHdqegk9} zS4OpXmprY4=59jK%27yEb(8jEaOhVqh%y@Di5^bh))c$U2$kBIM}8Ub^=I>-@Btei zHlG}7qhr*C^6!*FwGnME21Q?v_V`qMz%AtEv-kN)s~(aNdQi~rT3B`Wp`)rR-Dceh z1HM<-I&Z5n^%rayC~}Mk6JM3dmpJ8D>%CDvl!&^D^NXx;$<)T0A)5rKu$F~OB=8d} z7uOK1MH++Bhr*>ffzMqw@j${|Z z#84amQdAXjvfnP6`lBz*0ri5P>70vL+inYPoYk2xLE0a`EFI+}C@M=jx|>y#;>)+& zUzFI|_Ii6L;9zBOIQ3VSnBq^*edQjv%bSxGSyBGw6U+N@EnA0l_D7(AuGVywdis|M z!(Y1RR_gYyf&76@*O0>6&u2D|Rb@7?O7FfiRbqi#!7|HQKIzXChmqrb+m%{Sn*NN! z+o|%^5|N+r|3W*ihw$LCrzFiWn9%@LFnZ?v?#{RE{}&$)ep2SP&hH<54;zviAVEsT zSDwRfxR$-WjU|me+lYw4&E46#+*&<>Q@N&R2<-MTaGzI1T!27#g#AE=I>HZttUIQ!__np_kG<$n{ zBO@a$EG$GsL>wF(6%`dJDJeQSI*pBuGBPq?dScN402docL_t(|ob6qCcj_z?r;&u< zl4#vq*K2Rv+xGi^zBd?!nE|q^ea?CLr#T&m@MD`5!k8*N$O=C{_Ohp5sGh>}RAjmb-`WB&-Z|3OY%2sGK24rrs(prKdq#YzY-vi zqwU{z=<@P08L-X)X45q)n&V~kfb;&c3v_vT?Z@@r@1^%xuY*M$u->*iba^=q;>zzY zqIV$ZrI_yu+xq$Xyjf3Y^LaWNjbsoh!GG9JUS2;7*%mP}Wgj1;r6w~hPp_ApN_ zf}F{$#QB{^zK4%Xw4fyM>@1IHdX{ZLMnYnPXafPD6QTO(r~At@t{` z^&4Q*rHF=h-;ERA&goQZ3IuFsw_p`EnLD7R>7lfS zZ#RfVW&R3u#^x5pF=q|xZz3jAs)0O@YVlX1%WztAoJLb(UVe>k3{cF8<~Tfys2h64zR4iY>jHGIL63bU`egC( zhW2B1I#0=zS=ZywOVvfYA&Wk&zvvs#r?gjt+c=#B!#npb;y0L*E;`3Ae$P>Lt;xvV zD;~al`Q8H{V?*@nx9A1{`3RXaul%m@KapbXZB!Rv=^EiFdcilP-*OEqy5vXHfI;Oo zSk1m-7~fP`Xm^hPu>)$tJnk|+$VRa4k0@+nKenZ_IYL-bxvwPX@%&uI4~n_-1X=vE zO8iv-@&T;(bTa^@bSaVkUCFIjVTwvLKeyf~bdL}D^<9N zpu#(3lwQW)Ej>oMX~atTFDQ$)X*lr@4^I;j&{}(of)f4;sv1<2roSN3M?kISRhICV zYBJ#j<9j^703m#C2@u&whx-61rH3$-wXO!xV_$J7TZcCN2KHYSx_~>)tdPG~EG7h! z4|fm)73ndQ79&|GCJF^TFs4tBo02Z;0!aKX7%Hfz$$+`OeBhdM(IpUGC(#UG2sE^R z_Xbc3Fah4LDJuZzb^Hbas3NlI56%xo`=9jlyW@lEk%7SbDz@o4liPl~2OZjn<5>9k z*#)t^Ypuuz`b+XZfqi&1E$s8!@j)OV7QbN4x#;4@v@!9-5B&ha1m(XJpagdKIII~T z1WS1Kc){+WLq&4RJyXVkE0;GG+rlhQDW1ang;tJQkG!g54=}c0i^oNtwrW)l+U(qg=FG z&;#iJ06bzdS1`!A22HPcd@x};$jV3+^)OIrgroESz(2dEr&3&86d-)O5Fgar za4+CShj|q}i_T@=pI&(Dvh4S)J;8)!R`!&(^beszq@OBrUtHAQL8Edg~{DWr3J7!xA#6}$zuf2>@%+w;)8)1@sqFw zXXmNejmnAPP0#fD%yv4d6Jb~TNj(BbZ=!OeIG~3E*XtfoX5qC_=k^(~w!GT6ntm1& z*CADQyisEEeu@BHba-;0Rr$)yKcmV8;#pJXbVgD^FN`O9blFvndGcEZFdIS%H636# z9qFE8`9<|lcQFOX@e2HN=x1f9O23aEhvcz6efo~xJrPKiV`d0NF+gto{+ARxU|$I$ z;3w+85;#7xl4}}aZgX`=CmDcWAr7&dxi!qEXyAzthT7e@40HQR8hT7mI6P;DmBjX! zr1o1UbX)ooex`GHepq3A&`jo)!~UXgd0Ldl=en`~o~<_v%+HN&Ka)lAL9@lU%oFQ1 zPk$1+sBd8&IW})jts6}_i6Tu#Pr_|AfKMO6%>jn4(-ah-FnNN#0)R$~Nh$)&GXZW1 zP&!YSbN`yUv#!5K(MljUpA=C^l0vHDZA8Po% z2|%0%yOdHC0W{GjkJBkO8&Ng^9D)}B%rtncTpT-h><00cydj%)0HDQh)aa40;)ANh zy2BPs|5F&c(7Wi1q7&oyInUVyTo!*lI#JIiEc>TXL;{=1sB3G`er9?!el|bIr;JZk z8|Pej1}#jF0{hZAVwLDvJ==y@(-Jm+s1@?DX+KoeOhj;weIAyezf>T|9w6GTIY`I5 zSU)7HBo*|k{YIpi_5)2unur$WT10F=zpKD{aI*tLEbAJi`J)U%C4F=6Os_qruOd^}<-;i>LofIYJ{t)vZ5PvA*CfXLOT%BBs#5DV8Mc8Zk&)Vjf%+p3x- zPCfQn3;>e+P3-eJHn#t0Uwza3RRGYzZ#*+cPU3^vFlfm-mzU^GP$CBnJ;nzo$FZCL z+T*_ZY3ynpQaTb7HoxAU7T5ZX92D9eGxFMJ1R$UbyfZ9fC%=EnUg%go>kEtDC+IJ9 zZ4>UV^&3q_y9Pe|YsL>S5cpuxA5mYE5kx(kIg$#BH5tY}DP03JPMdccL9GNZ;P`a? zKB@~)M%Yb|G6#PdK<(fkQB}>jD|W&wmpy}v1L9}O{W#TFehE&Gq7`3!~P@Qr9V;VvL9m&Fml?L=HSop%CF;t+I&6O zJ#NcECq0l@saX+vk^P79Eqc;vKYCO(L)XK!;Z#-A8}!V(W_*Gk2x2`&bYE37kFeeK ztS)kL)?X~>1Fjd^Nl;BjJCV{B0HFt6m31|M|OQS}b3|KS7kD=7IqSIm6gFFz0Yqm_#$GRe_$!LK4 zf?Kt!0Sx#EDK$UB4^WaAz^G(XDg$WzPF{c?1sT2-0R~bcrDop?Jpg(11AnNZsVxEO zt|b5?15o8By-U|J}}Uoqi*e@T2$J?b=yPe$T{ z#%DSTy!PAmCm{ajP}S_UrHi^rAybLNmH%GfgYdtI_|WeYDi`!x*}fjC)|!k-m7KK$i1vSH}x=IvKC`N_y=#2S94yA=B=dY0i#JL0ptF9wUosB4S_t#qmLqS98(; zFZNle-8FrI?K@+?S@A(akIB_}o0zL(N5v;CRL*G(5+KeU!#NFi*DkBTK3A?@j*rB&~)7oIHj+M zM11-)rE5qc@BLd+yapZiWuT|wURd$L(8LG1ZQnWNAfR)UZSfJ={9Md8ru}c~s~}eW zjKhqEtd}U=jt^pbVSG^U=6!ApdaoSJ>0t_Wub+g{`FSN~-94YK*Xol}?)vFEo^whs zi4W@d{)sW7$$&hdlc=r9p#5PH6n&H?KOEtwBQS;2XJhTByz06FS6CG z%~+NmL@j`NoewBLbnGnZ)pPtJA#mjFE*9uvOL2(l#g1R&+~wE$b$l?hwX_nfu61|i zce>+)II(5oHx&!xgV5+h`s|Pax&i2l51QkRe`8%gI6tW8M!!yc5T}rAL)VDa%^yWw zwlU^YNqo>m2X{i(4-#!O`MHjuN9uK-ZVC<4E77Dsg+VnzZ}Q03Cg&UgG>SwGfM~%? z9jCS%0Su91y3^)UF+h`TH2cy@p@aDWJ#biu=#=3@HF;QVl;t7+{4j(Cjbe z03)bgp94dkk08lPNs9p*zu<}60CW4!Y|dKM@x=#`cRrI;H#t8@9Q=c#_#l{}Q)%k& zq4=8X{2-u%_#l!~lh9*768m>*wSW&9R5 zF9lo}GmQl;j#JnJX8o%B5-0Y@LW2-D+)U&FrZCcD<}QnZ_~5mCjCk|&fpzG;ANp#- zZ=!!+IKBu~wet&1bkC79P2zfAJ#o261l%41uVvMbZRxQjj^i(e)+|VgAL2wN>(VNd z>~*vOk~>e~?Yhio! z901Kce6|463lJVrc0|!4ye6srJ?0^eEtj&Y8 z%ga|&yR`4Rq=Wt9$&s|s)A2!4z+Ew)q4O8NqlD(b&ePfh#UUoL9s`$|9sMUlA3vgI zg1)iX$?y5*3mp2XBkSUqtVz(yxrg8PQJWAXsU}6A{dpun;3V4l_`M&N0{hIucfZVe z3VHbNK?ljUp^yI(UprS|owdnva|R_H=k_*2>GD7iVn1EMT<^@A+-B zYINW)RY?cFZ=dBAxaPb7ZjkgA(W7>Bu!i=5m%r%qe6WlDxf4_$2@r%Q2fpKb#Q;NS zzc0lv0|?wh+XDW=?+^AksO2br(HewqCS^nveSc6&YF{z43&Ci_mf3V>*#N7vGh>~GT4(q!}t&}H67-YV(59Ub}A)wznQ088W! zI&`y$B&FX=E~4;V$}8|+0hVYE_-i&FDI@f|Xf|<#f(B_N&B_rUJTq9j9S-hJz4q4) zbyIwVZNRJXmkRppoW_^xPsH8LCls38r;bFWW}1wyAV3r3HQ{#!$kE}ww-K+(UmYO5 zIr+fu1~72k8e17)#Wl!Ojy4XP?Lthy*&5^#zJvCKiR%1$sp{pz_h&s#Lw*l08p+0+ zgf;l>_+YV|!WZy9y(GLIe{Fh?3G%@_oW5CA4pv?hDY=DWTa&*gopW-6dq1eBD%J+b z5|Rw`*MApcYk*R$NEY5Ql=bR&#|MkF`GC`J5ROwOs`FQ;Gclma0PEWId*Xw|7S@2K zZ|+joc@!~Ip6J&qKj%$aTV@eEd+hjRL-fSwnvJLw1M6d)#~yD`e+@wo(-)`KjW^@@ znX4N?AFp0${ZBJ|C)5oz85AImtU-MG8b(5P<29p~3aDEy8*W-9eo?>N5;H5!`0431 z7ghP)^h{c(j_a&`2DRIV;)AyR1v8&Kbnd)3?C(0M$ZylR2-Ec+N2QnJa`oDG9l`t` zO?1bYC(g{gukC5DMe57U`}#hl{1TG#^DAXIT5arIB`?cayY{sPsOX+iRAs;1Ow&Nk zX3p(gG!Z0&!*=YyV{JSWRt9fFfbHxzOXtAl^Yvx2Jxph55(QGF5zgnc>3Z}0Y9DBU z9>0$tXckTqnNi-_1ddyPI_jZ&NeMGx<9@Ljo#N62)#Judu${AvHbTdyLeXWuGStP4%1fG*GeeUYsC>&-^ tKfp&fuoG47_a6LcPtQwD`|rO*{~r&dFAuGMWO@Jq002ovPDHLkV1hdN_3;1z literal 0 HcmV?d00001 diff --git a/saraWhatsUp/saraWhatsUp/Assets.xcassets/logo.imageset/Contents.json b/saraWhatsUp/saraWhatsUp/Assets.xcassets/logo.imageset/Contents.json new file mode 100644 index 0000000..5f670ca --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/Assets.xcassets/logo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "logo.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/saraWhatsUp/saraWhatsUp/Assets.xcassets/logo.imageset/logo.png b/saraWhatsUp/saraWhatsUp/Assets.xcassets/logo.imageset/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..458b1ef4b4654782db276d225354477de741f12a GIT binary patch literal 21257 zcmeFYWl$YYw>JvG-6gma+fe%HJ=489MomQ)4VefT3JMBMUQS8_3JRL}pA!)ta>q9? z(G&8ArDs;q1f;v~)JNV)b!yflxz10YrUV zfEEr`9u($QHg+Iks`HK>DhfMGVJcl7Wp-s3Nh@1BIX^cmO+OVa3qJ=70ZS@T5ek5h zAcTRFl?RZ*$H@`oF6bjn^&fl%A=m%hW}~9`4-yXtVJh)|8l=!uR-=$~cC(`3Wo2iv zU}xu~;1giw;N|Ax;bf-ZWangOW9MMwVrSvt5#(VP{csUmT>Y+%4Sf zTs-WYK@|UR1e!a0dI(cNkp8C#PA>mu3v&OLnji{e^8vcBaj>%gBhr5nDl7k=Nu8Yj zP3`U>?FDJ&UwHqQjNP?-U98wNtlXVF-7Ku6y{teU)c@6(rNzJNx_G)d{)eQN7Hn3I zR!$HycL*?!e>de~>+Ip|ZtMKNk>lTw|1FJ+pro4>(8JkH%h}oSzYL}JUtB0SAzS%_y^O!s#r+@J*#K% z^IBR$oK1iq$i>gY$!=x+AGjd(rJOB1|54yS_5agxEuAeOJpQdCK}&NE0d`(1YZg9k zh>Vs%ZhjVi9!owJPN0A_FDJhRuQjjbe{oZFvxD>w*U_}i-3g{Cj=D`Xf43b$-%`AL1k$nXzlFg1cZ2sofFW;ip>RNLq+j_qmguW zbaqpAwuI=M>%ZTZmy}dg2mzLz^5a8uy;bi6b$MGRBAmYl|xkIe% z`>(E~Y32H_D@Qwu|L{*ipv6DkLYT_pAAhid2=<@1?fw^P{+|i-pY^?MtsqSQ4_@-0 zWbV$^9^ODVD{&i$N&W|Z$o9X3?+*0(KZF0D`N;pP;Qyss3tJ$_#tIT=*{J>zhwYz; z^q+=d`+wT(Kc4-!==ERZkdXM#<-cPwr10-(ZUus{c7w#~WuY=+C@7^?c`0!%pWM?f z-$o-{&x7}+=T$~wWz`}U{RPX>AC8Kdn9Y5>@HoWbp-||*X)qBfe~TeX&Wy6H9o7jl z=^xI6CzDJGl}U1wLn9!^;Gj}{cuY>850r0j5wl@4t^N<|Lp0B+^&Zj53P05!0J}=v zbMTa#zH_zUeYby4)4hm4rgxdzCtN@1)4LDIkrG>N8n9JrpKeg4>ma2mwg12H{~aA@ zw-BiP4df-M+r&hbNZ@vXf_Cjy2k@r!&6e7pTxp;PC${>xEUFO>yja%Wo+k+U%Q}^v z*l~D!$N37`mPSC}CN(RWR0qYRvc3_fo`zJa7ar0aC3isbCvX8st zpAqyL>S^8Y1*H^|fY9!}gdAU`W(IzOOy6{6xqU+9 zP3R4yYsnXwcQ%=!KmMY6wW4~O=C7l=2p)OL#T^!ruA@W5IK9949a7t7gF&z^^fS^M z{nro%M!iR{B4Ifg+KiAKi#jBmMj@N*gHNJj47B;TesP7pA~GjjDOlG&Xq;agKg0F} z*5~nMmQ}w>m}Gp?3}+YUor5a7tq1DQF0vh8uS|i5Ji5|A zoWV%?tqc3#^mllz4BfZf%+N<=7*8*q=6(P6G9ZCp@&e}?EiW$Bt9^Y>GJ+MyP{WFs z8Cm}7;Dp2leR<=~8e57H{a6-xGcXgRO)w7SsRipjvYPe{T7G&ayG&4tz-HQ#-zj#Z z(K>s*)r)h(fOpAR)ISRUlBf)~kH}`#yO-|Wr?zwZ?DcI%=-%b>6~?I5^XDHyR1=2s zu#(NRC>ms^K{(0O6*>y@=sA6QTq6!uw_;LFxrQ%%N4`>G4I{QPsdOLf2d=LDy^t{6 zNQQ*q30M!?I-QnEzPQqSG_|Hkgx%VOiem&W;r7@mi}KavvGV0DjGQ`@{<_<7$wo0Q zL|owCdR}o_I)yR1TET#N2Kjup3sU|J)Be_n!#j)_&OfgG&BeWAP9u%$rd@<$x%+_;9(^bE6 z%t|64UFVnljQ+5DetyGLyD`cZ5S(OMZ>L81*T**2_HGlZ#C;17W8f$ioc~5px!FO`u9b|!U-sW5T z-QP`)FcEr=V(^3^(xXTLS(lPQ*1nT^2|HcPO?J(7Ds0Ww0Y*7=sjsar-_V3lR^;`^ zQh@6tE<^u3HE!P#G}#~L3Fq_OgPtcE@^;^r>J|LRb|(ROmGSXVj}IZ6o=>_T5XuPS z=?BG0FLMWpG_NWV|?4!!f=;T{|cxj^ngJ$`I1zTR`93PK=*<7`8m5siE$W*qL z7{YjlAJax&gx|ZtEgQ`_if7~?gyF6<0$P61W~qEGqvYVl-_6jnlivwkMgWv%icF7= zG~Li518RdUIz5j$IJhG*`ky_mVV<*Xd!FtOH*73(J%6{iaPuOm^eobY|Crad1(m(e z+zR>5zCO$Kom&$YVo-GT{_0TCuzbYt83ecSq-d}F;Y zb_+4WD zfzl$RSLJW`pMU7u=V$A_Ac1HfzI999^xoU>HQ1;noQYiM8^haNwA@9CagQspz&RZ_ zeO}$1ppVK24lj54z(~Nb`=QzQN{C=0)7;7PE0vz{{%q1P#_I%r(7kMj)q)r}LOx9V zr;fHzv=M($qw&7ct}=JAmr?49u=I!H(y=?!tSRTNdk=;M9Rh~1d0Nm47QxGe%WX^0z3Y0gicQ*00z;r-1I88qF8J$((|m z_Qq`_Wvpsem(%8_nJLlI;EPihxAn=~(&VET3Molpr;f5P(+TL^{!1}tV!hKlUe3z! zNO4K%?{-6o_*sJTzC(>Z&ukO78$Pe8`)F&1kAuaC3rPD7NsS^Gkt3BGuWusx4wY&G zg1OF_3N9Lk1f%CKtOZiFiPY3#89nS{+eZPlz;fA6t5#h(kIC~zVP`|Cp8FK(tNOF* z0CNr4V_4S%llWQyR&LF0?nS9A6J3wQeGd1ukcq?)faB?%Kq-yrBVOGz)sr$p%T+q|lb+FRhW zD=c9Zp>b-jCOC7S0dVq}1X$ifzqp%sWLZh%oQXE)|0YIJm>kgIX+L!fVpB;Cea=`4 zoFrDgbJ!40GVR)=S^EtR&*I1J6Pye6 zfxaBfHP>8+yjHZP*!1dc>-6AsbTrYbvk@CS;BdXj8cXXEtfA2+*2>L{#N?vXWX*LW5N*T znfoxCaA};swwvGPnXe)f8byH>{h`m*v$4jt;uB1(Kfy@B*uB~>ePQXxO>_VE=gf$z zj*cIf@>tb7y=8n$pKJUEMIY0IX{r>&i7J|>sugB!-NMR?5WH`hZ_rQCMTxLbtC-lg zZVo4FS@v{A>ZEFp&OVHgTWP&=>{lW@^xBZ!s;+aTf9CN)Yuj7^v_OA%Zvl?NIqnG; z$-3fx7HoRJO7KAh)FFsmV&+#A@riaSiL9S$C(_57kxGhOM+g4Z#JC*wzZcIssql2( zYqfWSqpsL88o*MO7qLUA)6?sU_92Scs%$MbHl_&?ygv<35~T{py&SG(NfSM}GZ;ak z^>K@TczL~>oC2KWced9s8O=| z{WJX5(ZpS_$bDT`*@^=x8!pN*;YFnKB}@L&N&f4oh}ehe-a;{Lp!$rEGuIxI56d5y zGvYKx=UD4o#?usAEDAHkLY_hyZAoL@RpPCr2@wJPz^N62NH$O3Az@Xdc5>SH3%%ED zQJ;m?^UA4vyTwbvq)e5iBlE03q=x=E>eTJe_t##5D z_)JhrrG@jMY0jYtRIIn??Nx6+9R4=?wJ-QClKyaK&BT;VBkWA}XTI|`M)zHWDPU9K zBBU|ZaI>HviDA)RqLGdjKz$|`zu6Bp=DD)FE$XlLwgF?8}?*+w*(l+D5x> zu9%dC)R3z(7~hf~Z?<$U5>(s#8;?YZ5+2imvWYUIq1Nr~P(Jwhd~M|Y=nmUIWgA;W zRpednb&?HW@Oozf!;n9=7TqVVndu%)v0LlQy7o!Q$PH(hJ9Iob>e7ehWzXVjWB<1P zGBBV=$wAgD|29@OO<_J5wS`tEDcgighfalvRUa)M z840DX$+R@)AFd4C7g;fapX*-l!2a9S zAU20;O{0FBt(>Goe^5X_o1Gm<-$?Py6%UIC5T#+R>GS48l*$CV8hH-rqjj+UTU&E> z;N9NUSg(XtZL^t^b1MD*(E9SUPidA)0ZXXhemq0?h*(+?sKn8PJcWWlFi6Zj?-QW+ z@XT_xF`1{oaTE2Z?TVHk1+g_w1pR zc;)fr=MDQkj%Ym!TXqa#x7;tcFmIW}Ex!!y0ZRpEavl=2<)sP%En@8#$dS}yP|68p zOa#>>FC!LL*;5z^B&I2L%j zYMfS-9)4z2LD}l)(7R8d-wj+dS=WP%ij=GMYx_YvuImk_P~YUU%<<_63cyXPSe4sY z_=(9USQ2O|3K`G`;4Q}sS-OHg34H4_pRBwHZcki7e1Z+v2*Wf&%h8_!k+0x9Q(*f!Z%(JX_jEw z76;7_`)AtzV&eN-&B`4vlLI#`h6C<A@&ST^n%Zy>Ze~c=g3RI$$jP()xH#Zlc zuHxgcMdv{?_`A84Rjip6XlcK;%PFZ=QoiO}qv$8xL@spmL$n#`+3EqPR+j@6eZS|k zi%JliYqc6IijQr}XJ_ZFgBEml?2fCutWr>I&98XDp!%CE_JcuL((8s7qXXC0TG5qr z3565)P{KMw3aGOaz~*XWWDB6K79?_hnHBj@CFF7YzRo`i-eHpgRfKzu~x>H4lm@W_8^i)ZFGlN_qJTYt0B{vgxIZD>t3 zDo!@N5VxrhL!?#@in}atx&TH3sV`JE3;<=%QM) zZ5yYMnoPdSOMcl#&tt@8wNdAO4C>fMSPA%ulZ(Wr*K)caE9CWz422Y?jO%^iOM%FW zTqCDMKXTQ)AjPj-VxS8KZJT?(+A!7M&ZA67OK2Hm7 zx@e|07JBP}UgcG95dLbrZVi7_?QeG_Ta;sZ|Ceog!@PD*DRJh6ocrdG7_OSn$W1WA zu3C38iG&?YVVL6_eB+U`PcYXuh!~_U&5j86@*kH^({^W;z7mjJO)h5Pv8Y;cjG8+- z2PZy_^a-zIQ8DON?&YqsPi7Mn>g;t3*Y!wi+zyZ)Pm}ly5z;Y~m_H}GADFO0KmJh% zIH+;~;f@neUC-7!_WHY;tox`Y@M(r>R*7~*5fuN%tLegoZDM0_6>8fea-+hJ3s_ZN z#VMvMs(8LRm0f=o|IX5+s)i;mL^{aOfw@n^yf4y4dU@vKW>>?M%#mKA*oE@Wml9=;822 z-R^W5bvyl*9j}y>*AJlgQl}^6W7m{|;fBSNrS={43t6`N%P!jS$M^kXU4V=fJH85j zkX7Wx+iZfqCd~ngbngX4xokNpy=pJnzyZf8d`qu=IWZv`Jh94m9w>TM9Frco$3M%x z=e2nFO89S2A_u0t3>` z#hA-wM2wAW59-_90~!FOEEG-H6O>Xa*{}zbo+e##Z2@G}C*EZ1=K&`w2XPok{)H0Z zDg3jSg`@U9gQDP^*kA46N1l%Yx#!P8L8rBfr|PgXUL zE-UCFg^Ou2cZ=T+hAJ9sqJpN*$A0MZq+IB2&(gOO09336m0U?HD!p_%hhM6(np==Q zc(vUw@Sloac%%dv|O*K>NLHnQ7aKexoBoJ9AH$x7AZf^mI5hW^|Nd zQfHJ(K-RfjvJbsSA-KM@yI)gt17k2U>2kt^Rkfd z{I0wF3lcbn?R?3ykU(CD>gu*OBV>mmwxj1dQNfEv8FY+q-EjlFSDnmn)Y%7ur{QhIrjx>Z#v=DWHL59x!o83JY z3T*FObT(&e(r_8JYCVs-^t^l@|A5{8?&6$AU+!*BHdkP*`&-2%F+M}>*D~g>+uXR{ z6b>Z8^ic^@&X{jEL0c(-Vcbj?$u$``gp$$7(|9de8p?>MQhO;tQ_p^Uj;Jh`Fweyr zeurlf(?78Sz{XcrQFIoT3Kju20aZC+y2UA2ds!NS%cxkz1A!hd-cIuZI)cFricu>P z0WPN{h4<#P)uQm2X%BuI`~ce~PS^m?G*13GiQ>|(4oVKX1WwA`lPjO%gLO0@q54RP zd_zf=E^1n&0W}%y5s`fnM@8R}ekc=xV6Aa+t^iD_4ipw(TPqsYt0}jqd!u!qesaLy zEidD6_IS><(_X!r2@hpiMN-?Vj~%DzCynaic0pm@e1MiF{7F1HlmsjGnsF zisn`pCx(n&M(2uW&f#?64`aVIL_Z)q8TCumGn;X)?I6t;CU7{1BZDoHA;Mtf8(ME}i<5y}30ixn@UOr86i=m=B9eRgVFgMS;3qV3I65nDO_qJRHcT{m0Fdo&G#tf!FnTtr@E1t|N__-nc>E&{5GHNZ=i)dM9z94p9o>gS#Run-{ zTh;A%+p;i4TpnS1iOs;%&cl&KA`-pc3i{7}aQGve=v#bcxXT23ieW7Akl3uop%N1T zcRru)!|x@R$BN&m5>7I|qc^3J0RDvrgMe?v#QuZ@F&C)^m+}DZ4 z4o4x$9p)sL8-27Lb_|Ku89N^qIFD?9YfT<{n{ykKcK(v}KdYKP!Q(*&!6GmZLF?E+s0QXoiiLeG27HMCST= znTc_8uZ(|SyAkv46<9zP9-$(nJSUQo3Y(de#NRAS)jlLzTTFjrnYpk_Q74!f{GToj}kO|AwRzl7CHw0zH zpxL%C!(NHMZ<&YYT1kdgija-6dLX^0Q8oh@y=YgawmE)y5z4js-KO`Z)GTwA%Tt-C zEE5ES^uX09uHug;zdHy=pSmpaN#*E~V9s~`WiFc*z1N#paxL~Zw~@rMfMX8F72pWn zy~}T$7;*L~w}GISSOuph_q;lb$S#6La9}AHWR38PJ42NB>O6QyeGg-iX=5c@lb4Ps z74MIIT;=W;z^+oR?e(wG30k!4-bqS3-^uVxnjBl%7CJIE zmD9lsX@cdhE8cjRV%l=D`NWl@)`2CZj*)Cw*@}o)ERHf|7HAKe+Afqr3MtH6zOseQ zAo3QMYIB61^JKhyOqvK4j7moZQcF;PMaO1?Y1*X9yBdV#6SS`rm{c@_{IIIOZYh1& zpgUm?lal7SJ&a}5!d9o6V6J?BBQ$Cv>+V@{=bJ{3OHC7Z$M+}Lm=+w#zaAMxONy$h za|rQWGt~FaQVa7uC(CKC%4{Q>y-WA^IqI;kr4(4O^j%aXDT!2+_E(S)ny?%7IQXKA zc&@iKo_mB!El^gu_Dg;_$DG0b*0D^6=JYK=!8@5btCFIy%_(6v`6m;;gfbjIpOd2yvI;UZ5v3E!! zrF^FCG9>+YKQVc}Q4-+ouB1#{m24i!5f{9&BAEE~WD4$==FgHfeJKr-g&M)}F7G5& z<0ZD|j*fnukqGSSzt~asqEo_MFiFkiG6!Mz9}sB0JFHryuj({qt0UEbpBi(Q(lT0V zB3f!A(n?EBbYrn)2+qhl-6!3Js0EMSi}DnpKAh#PD(OB+>}toMO7fcxV>A~taA`wv z9k=q=YAP!!fP5cKs0xHrgOcIKKCC}G|L24jxdRqp;vZ1 zFN(Zcl{ArlTRL4HMTT~H#!p{KO04JBP%)!vKe(odGN-#8T>xFOS9{UbkuoW-9C- z?37PczoiNNJr!G>y>%xpQ~K0r|CQ&nGW)CwsbQ_Y4#HMNtS-%3Y^y~LBJ`KJP@qcw zwL8;hcvY^|to?-;&1rfGAZjP@CJ{R{b{VEGVU+TUOOdH?KpVg96sgZh6Gps#SEjl5 z2nx~tIbQoZQkMnS#J$pGl0-2RTZM_hvM4($*FY-dQ)p(HqaO~X93#0&kLJUi@mLQi zg5OaN6QIR#w+KpGyNnU~{9AZ=z`*_0hCT(?wnVNsVwo;iEzBxqbAXc*9^m}w4Ouw1 z>R_*(r=>-fCl!Y=feS1CLEwz^nzqSOCe#zqTwlG>r$NQA{Ik#Nm%#c60>KFPN&|Wm zN+I6aFn8p8BY#G2zzaI?6(<%+u3Cuq{ARTOhyEB|nP9EyNvBKA^dcgmwnEF8#ZGwf zf$GyKlBlW#!rFfl|si_PTh!#f!z`rhDb;1s2}?^F~FXBHf{7`8gYVv2UL*HN_n zY_)Ead0^c3J8S%kU80ZQuEvEzWhI5ktV=)j(@;$(7{KTV%@X%#C`P^xOwvciBS02g zW*m{@Yy@jgoP$>v_;l(z)B)n+b43Eu^%h|1aScowSLgW1Lny0Cv+B=Q0V-`dh3mnGAFzj!Y4L zA5n|k%KDVJHqes5cD%4cg*8VK%+}J7I^*R{^o@)~EaX>aZ*6r#=Y{1IRaRtf&7L)-Kr*L2UW-C!g7WTxiJ@dq~&<|v79fG z!KP1NuMY^zl%1zhLvL0xXGv!av}TI)bI*{s2^mD_m)w*dZBm}^81lOeA6A5@RL@|t zCH#MQ|Io9fNrcSvRPL*gd6Wdy4fNrgkR7Fb4lL#+=5$k5#iUC&gR^Y4up!57Aad%6 zr@SJXM|C~NJxW}adc5Z6vkYJG-BWp@ zOTpg4$UkGP%*)ACfmQ90KdqHUs08d+4r+5K zV<*gzy{Db#cWTFp&>FB_m#3CPsv5cQ5z0ZDn!r1jtK@bGMV7_OBf)*!rk~8O;p07r zrqiuJGDR!j2Fa~|3~0Xfer><7Jn$0|9~V4l<<^vq`EyE}CkJr^o^aF~zQ912g}KtA zr`iN{E=3x8VFj{X%*cYvSsKSZMlpg#1zQPRl!ep30|> z`)8;ugyGRNioeC{X>@q>xM-us)Z(u9As<%VS6pQu6EF#>)V8QUt_WBRbgcnqdso_2 zDD@pfEKW%ALF-g6JFopcPHwy>oMHSz7Mnf1V1h|3?g*_S8~B1}Vyz0=Nldv-vFe8$ zwEp?ytpei@3EV`#K2zpP(fAnzmlWBfB+c6voT7*IqZ@uktYkZc*!v9gZHIEJig;626}iKJI_`I6 zKV}qsd{2*TG8DN!Le;Y-qqvLzuyOxR!ZvqEpl5h+yXwPD67W?=4og&dXuL+gT-I9< zaS3mH0;c1!C75?P@0*RH9y3z4PXCPvLt6fb&}*7y2jl3EAL=WM#(Ij&&`K<7GR-sY z)6RLeJG(JG8Jk$P(wXCt-d$oov&cYeP1`;14P=BEOd`F+DVo07bPU=L1@gZl&{n|5 zTb}or^_aWE!-eu{brlv4VHv2qO;M74}3&oXl&hdN);^{1 z7`u`ojJb^drfe|<{V)S&UrWH~gvy+fThgAMMXcZCQP(W2^eZkD9^6K>Fkb3(kxzI> zmFH;DqZW@@-;GipE(0aKxH!P|O(z>`V`&r}G)gY_El-E2O9)2cDY}tpu3|9SL>!izr=EEojpf%mTggGHZ81fG2@)2zWppyNmP*aQ@JlH=KF=!P+S~v|e z4;@%u7{9?oSgN(5Oe2T5N3f%Mri^m=KYvp2(X zZIa7!$10cu!f;LV*K=P2Bx8M8iRF>9L1-%Av(9Jcoj{v@c})tUa1iF(p2)%3nnZk9IW?tCz35s3lh_3yx=}(ZWfM?O{&rL&*MRkq!P6gB z0bf9sT?pb{gaLf96373&p&_nAuAGGp4_82B4t>HfoQzK)m#mN2A*!bQFW2>I_ zJ8_F}z9A+1KEbF~FQQzjHbNlHO4D1{d;6cBrcZSz|jN*Vl=z;&39<*~`ZQ3qH)<7&Mj<582=^L~5*oNCmNGG1_y zWcisDZoYblY^`(t@jb{a;8Z+3nHQ!w5fc_=scXT=R6xZ(98J0_$~O9w`?Ke)yk?wP zg1^qVrP-EcN13X}p;>y(RQ_+HsRLF9OlEm8DaP?gedUKou7vlO4|?p9AK7i?kO78d zw>9euw_yfAvR0cimsj`$2ja~Ir{U&64pJM*>-2psIU5bydi#3>Ayn(I8M7ayeU;%H z^zrZqqoiZnEreMY>+ZRanz`9fI@Ie_wlKRth0Kff8uoT4p$J<|+hGfGf#Hm<7q%Xr}f+5X8M zDPDb9vKK@tA#L00SpdBCA2UAh1{RN~l!98HG6<&=vJMb+7{!LD5z?KVT;BGecNQkb z_F*d2zE&zo?D1q3w@V>WH^p4sgxVlT*`k#Nu#esbRmSRD9<%OndDHNnblD)6DQVj? zavMfd$>x>q31C!@?Mb%?+r3PmPWG%GqsofY!;Qn*M>1mcmLKoR$P0c3yRW7-?quh6 z$kJTqYe=i)R37_3^d@FO)-@DuMxVOndpFB_kL7gwG?`43_S^YauM^&y<;tkYxtQsy z%)D^cTUQ@5nq2ltG%%O|Yn=;Jaul{>qJMaCAI>cLo9>19KoJOcG*$F)g?JdFC1bM` z8q*CQ!D}65SWJ|+IwQcJcuuOIm_)@$Sn06KL6wJDL!cWZA!J0r_lKDQmU?38PL_X1 zQKHK^YwMHO!@+aloTK3q4IqVGGf>r90;f#=*Y1uAr1dH4D#1q zT%e^ZHe<;dP1;w9V(AcG9K4*%xzls#Xs zw)OD~TP8f2TqTjW;*qv6ui;rtglyXea^_lUP{#`6pPyo^81jV}!6Fqxvn zUD)2gB3E2CShpHlKEC^Wu6qv=dL@=DQNy)ga zOfGi`VeX~}(M}T|;A-C*`;+!y#4`Asoh!yEe$8Y3g|2sRBD8!1vazdjo9QWfAFIS9 zg1kvOX|DZz&MtRKzGf}H3(LcKNj_iWiR~5?VtTtOWwa#d)@o@tL^!zp%yyJOpfY!etM8v}r_o0MX|ssr|vu zfbD?Wpw?UUKO%_V?)pT2U0qxE$_4FFGJNp0Z*UMBitcOk z{&H2ZLRy>q-Z=AhdfXX)U16a>bu1<~&%HBUY_JP%ef(hj_cuUy%QjoE3>RvRl3YsEr1itW&CJ1*Lg~==AFOWEFGMMH1;Vzy z;P1~{#KaM7>s2piRghN?v*~NO%H2GD{}~ijO- zV|0Y2v6SvbuVN-q&m+~&46Sy}kfQ&el{+RrC%5h!%z$Tgt7Fy+o$*JlVi~_(HKVh? z?As2mCxeHFzjIf!z7%V_Sp>gCT*Z)=s^2&RU`iw4n-B)6C6oFSDT zUzUt7mR53=JK%^$b$+x%`y$lsJRLSfyC?1BUEiRx+pKHZoRV}EtQ;TVY=*jKUT5^A+m)6^=peFcSaCdUu+X)6^1w0t}%%`TKB2Oj) zw-Ay9-~D>7!LkwgC)h`V&T$p{VJ06BZ_FwJhK${bCsV|3E~Tz0KHoK3--l>zHo31@ zKNOv#SWo6mMle7doRVE1&87Mm#KPby=hA=9nA*U5*jX{#Q3*GLMMw(s{b`52?o01_ z@5-WA(Q8DBT<(5^dM4-uFM4$MqkSj>uR4Rv^8IMZYgRc;ugQjDC^)q#HQl~Zrm5-p zk=Wp|?T2DT1wZCu2nGZ255G;p_15(!+Ak{QNFWXWy6yq}L8b@dVUgnUf=Y10mX zCvcIltuDLG=c@ulAlDzNx7;=2KZx#!?6F$8AnaqywBfJC^TjGbebw%o_Xm~e5UM%vm|R>%afhc*ObiP8wfU2 zcR4EO`Fg^2GLTFH6ti3TRi7~>-;KOJKxFZ$#NMCjpMfsBsgcieO~M?sPUwuNi@6PI z4-*6fQ#D$JLM@_O0SD?^?FbR%AWkpzU3uOF?t)=sp{dBZR$VZdBX^EfT4pi7sc3IR z_6ICN(~BQu3Io!|Zqt7rerN$41?Ye)Dm%>uZelQ%f7^nM>boQ-zntNSJWIBE$At{1 z4^OWjxyzR@WNtvYhMwnoL35;-(Rj8c6FKV)%;Oo!Bb?t zz;cegfm#N=?+y1awO`((wU(?n9MRzz)UjsO5-;T9I=`&LbUVJ+6?1|C8FaKdoT&)z zQpJR6wxD7g1sFZo%8OqFj9*ynFUfNlyWOg;or!@1E($kV2@FDA!ZLv#Q>^p}hd++K zF~^644ALeKMrQRDwz?TdYBjK{<+JbCRaP+F8^b6u0-h=Riqye2o#r38!`an@7DY}1 zp1kyW1VrtmC*SQ2-5zh8t!`V-vak`7;6m@RVBJ{J+Lc!;99S}Pk(dGi=9|tjrjQlYGjmm_Re3f!a zlaP5?CmDZ0k!TP+sc-?GEB*-9x$m6A2v!Cj$C1va5XK%7xd#S=*NxaV8~ohaNjL$Ne>4EuJ>UukoLQ;il+c|3C`jqt2Z)lxS}oITd3H1XSkF@CCa|4i8;yrIUL< z(*I(q+UEpb*Dfph^cnc4I(BVp)x6$+=6Aji#ih|1J=L>4?@aw*C!3OcVug$q- zd<)-d-jwld_u>_6CgMru)+jxx{jZK-1{JGJ&>zdul5g#csbS+qM|Xb6lm~K6?o7Bv z3Sbp1cn3m&*fMSIZbhDk#-*1+{Z$G{)%3(TJ@TnI13Ht^_b|u) zo+8mPo58p!PtN*B7&dD#?~rVK88r40OD9}?hFeTO4K;U2mVhULqGQ^z3$VEuE z@pABwLR~(0l7(#-Wa+dzY+Bn4hfeh#H_qvsc&|btbc!HghZeUF+kO zuH$4g?%!YqgEe3@oJ^VK+dP}g^A2$KiFr4g1TcOHWy&0xC9kT^XI(WdhjRd4Rq~|Q za~7mmIFV1k0vYJaO{k@4_POJ|1T!2e*|esFTbS{5RHcrQ1=pkrCL_ME-m!W43s^vQ zzN^UVX8=iq+Ro_YoMdyW z1nJ~PPYCf$A{(D=HnH6bJhJs|Gq*i=-Dw-?jrb_J{q7&~nTnE}Z<;-_kNe{G-FKEB zZzH~w0@ASuh=!OluOE-eub6mGkp>lJp(1i~eYi;)Uq!|Y>b!XWmcs`NOySZuu2|pl z^61$p1(3n}tEohJ2u4Ye`SWI9x}c+fPD9?DuhSu{|5-m7HPv}I?4bLkT{dx&ll3w3>4mNrnNET7nUmo9=D@Y#*X<|P)-gIO&~oTVyb zzfSy=n_hr`b$kC>6^-_fNGz3J5r1G5de0Mco8KF^8GGEqUvNJpJJ;eVnLBV*_`ayt zmBgT*A#n2e%k?Ff^-risbV#=CmQ~#2HXO=psk}rimo~$h@h1{@z+q;2Lc0D(Zlv2#`mxL%Abp0v!h+o8Lv7;@RF#mM=0u zY|fAkkH>aCdjdfd6NWyg6BzoUXu{|$2FN(1pS3s-C%ET$Wpr3BUv;Z9t2(-x>lIv) z@}m}6YC%2|U;S=7578x6EldP<{OPM)ZsNOTAgeEJC!b`>snua?9jtGOzku=Hwwuay z`Mg|*EV9jk!Z5mdl;j;d(>|kL&g0pxba1`{zMfTv}6ko&_4>u*sO5?2_ zX^}5OO{Y(&mOaU}U2vcIy?zYn?5HAJfow+jsMjIZ{B|SoR8d0zdG3Cc)V8F8Z%LZj zK%1W=tk^(HRrnZ4n6jk>ilm@})djQ&nFy--Tr<87#O)tOfPUXQ;`aIB2e~>u^ye&S zEh=Sa&ycLr(mn}D!Qq@ffi!*NyAYDsC!|u%hUN&A!=T_j$2Ge$L_F66noX~3c&-R= z^ZrT0M}U;yYtNnTn0owMCT}wfl{L^4npW<|xJ1Q)VTJr50{dvN;>xb7!WY6V>0Lgd z&JRlsyZ7y#fAS!kZ`?P-;M%tc7Kb6Y9P$DJ&I>PBxFj#O) zMF)TNw7DuVN-`a_N_azTzjlRd7R);tQ5{FUXySu68)7a znwX8#ZlY&MHuB1mJrJ-V@5(sZKvYtx!Tf7W`d7fL5bJhPl?u8L1HeWB_1O0++sbct znBdBA#e39-*D=nAx(Q*LS%(e_OB_JKZ=zIpnFQ5Vbn;Wne&&ITG9k&KnH`s0Mmu~J?Fh_v_b%+*EK#K(DG6iuX4b*h(IRH<`f-HI$)OTF znr9syuV<>FU{#JAgGC$y_j*y|{@8V&J95xbx1CppxPWzaN3blr@gtK>$stU(%!_{8 zhm;*hi5a{mY5ae+b6#CdFk2XwCPJtJQl%q3fEWpgplGBwksf*p2tuFvIM%$iwy?b+{|wfFnHBp!aElZH&EndycO zSylN3V)<5!u%CFZBC9P!$Nl)u#utVV{{?2ooxog|eYRbf{-G zltoFqWq!due8#Nq>u9HQ4)L7emFwLMAA8VL4L9DAQ>3ncGzLghAGKzN1Q`z5p#vJ6^s z|9Gb1Eb*w#KW~2Gac{g7U)mF?wDDoL_6d{+DM^@3TI(U``lRIdcF!{ZJRRgxw(i>b(r9L2=`u&hv9gR1OX5ui1macMeRI2KePAFm5Kh%p}Efut6&(#E;mvaDMS~zM|8`BD1yrj|)fgT7KiIQq)JS5eq z*%SHbc+)uIAPYumYOUMcN(`r*MhzYHeB2_M#}G{^IWo#P(je%APhp+ve@2@WaYC7z#NTWgcPan`ZdgvEWdXsOGW` z7iAMnrY*kSQRmQVdobtCl_o^g(Q=xkU2mdsHgeBeiVzT_8yCIKxt@N?fC7O?ms)Q- zEw6TYtN}b;HZrfq8vr%{Tm`C`p>)38lPh4xXs~Jni!H8ESmz{Y;q+bihuSJXv0j?3 z1spsZ>bObPm=QZURbEb#X1Gu?J79vs+he^j<-*Jy-P@1NGQ^l6Cq%3^JF#7&41OIH_J>sh9*pSk;GST0?-a@UjvQ3Qx~*+*>a+S&V1yJVK+8nD_wTZ zpc0Q1-9vuJx4m!@m#dx7uk>sSW8dfl1Fb2 zoJ0oXj)0boRRCUL}N>*SvDSToa<*F$8X{23nz#O09w-|BzWH^~$V}r8a zDti@D(`pLLS4Pl{u2h4sDUtdl4ymjTW4e&=e~cD4SAt1r?HleN^F!65iv4)I6ii$h zDZ6KC+FCkapU4%)V74%zXzHHd&t(-CT-gLsp!kA~ti`FZiABw}Sm*JBd*q%?SsQ)+Sao;PCa51~%89k_Teih+SGm*;;2rAT&Md5x z_|Qh&Sa^`$Kv4A0kb9tFKXRSj-{0mraM zmHe2bF+Ej7CuWY9gMnsKJZKwUnTl92%76ovaZIW}1G8VJAzs;+rVB(Io3Lq@FV@ye zC1_1lXepYxeNR%~%^w`i^m8UajS4Z$|Kbb+%@3-YC9;DWS#CX{&0kAgzaNomFmUH# z*rc}Q$JJS;o|oe2^O4P8Dw%5IQJY3lPl4d1B=PL@83k?&FFUq&WG^c=%~>Bwpp5)F zBAkW5epdi>XQ^w%?w~Ukt#P8-+Y2^1X=}L4MRQ6L2|S;Dt*dusMm2OQ=kc(rL9f!_ z7eBkh`P&S^(txDUFms4@GTf+;-tw-{PeSAq9#E4a-0)(R8&U@xf(u-@2=DNrNrh`- zG|9`Dgi9|Ui=qJ$Mm_O7VIo~1@p5UEfz84&X@iSHsD=z?g#?5~{}f*-eLqiwuRfNZ z@%Dpz?Y>O55*z@wGBL^qzgf}m!nPN9Xg!qB4lj=LTbFNb@JH+dAvHbf{U(OBBIfY4 z`oAaf+Id zK({p$;Cua3DTCff@Ojkx$C>}$vbiK%S&m_-CU>fm^^JIY+b!IEL&@7S+ve)(W&$N1 z8w=EqrjT->yi;4@$#aIKD?^XX@_gUd`gzw41;AXi{+A|~muGtL?oTooMH-hrFO}z~ILuge zq@B^s*zoUg`}f){PrLGTrg9gU)yowsMoIf1z-dn~|KE^`BIzb9T5Q0R6iD;oq1`fr z?5I$%fyvCW;|tGRSNexTXwir*O5`XXd3B1mF}t^MFi$sfNF~m-06)81iumZG6Pay9Um7DhN3Y~<>$qj_X2*B@9EacJ+OZ6{lqth*q%4? z%szA!W3^j8RneDXO#XT-6Wsi}-d;k76arXIr4tYZ;u{*HQ&KcayJh{cgKp>=SyHX5xt#|W)+)4zOuecM{N@muT5 z#(qs$^#5{UCOA*xFxw zU~2(kxW@2;_4se0y;Wh$#K{(UJ>94Gq#NHRe!gc*`B6ebaQ9hq>}{@Y72s55ZOZe>?fekM|TuSMqa|r$2c=QYmoi z_Nudw>%ST_?&*5E9QcRluP0?W%C44l%dRnoKRNVI7E{#ulaRLauih}!gsF~Wn8IL- zspCmp4-)>V)SuM?%0IXyu66C1dcb`llNoPOgGPuY;s^KyH`h<6pW>P z=%|}({n~{6$r{j2dzM`OB-fB47#B|Z9_4(m%xk03FWGlw=&Z^_8O6?B(S#{o1Kt?y z*v+paVTznjPxMRi_FRn&vu>Wag?QQDs$bJ98I<4D!g5=pnDaoYYp2hZ^BQ3WD?J9P z`i}p|7F_nPMqPfla820%Ne-!UDZu1o_ zaMwr6sP;-NW)0rcgSXzS>iN?>ENrxB{*HjRyR+N6v_lE?{@J2+1##aB73ib3JtowZ zcJnxX_!4Yd5&Y;IG?>S;)X zL%6Zdo%fgUO$<{ZZ{sk*Bff;wEb=NSr>HV6bjjVw6zVodE5^*K2iM#cgoceYJ&Jc` zf_E{B(_6KG?7nz79&Z7*q&;t``raQ$tEs5x1-B6O7qg3a!$}VbhZBA$R(WLk@Jk$QqH)*N)?rtl`EVq~0dR!}`$ib0D;n>K4!^zR=DLf)<9jSLf6CIhm z=RkMwx2Sb-(c$^T%)Gz!2fqQBk@p8}`^heZ`-GZfX=N{2yFuvTFkRKqzGbxKmSZNzCFOs%P|B@t_eU-s7L6>&oeephMm9~`$i1SOHba#7s z;~3xe5u@jZr3DrMtuItjK@U6SV8=RchNbD;32-j95J(BPtzhG2MG}K6G6(osk!YG$ n7h9|fCb{zcfAK%ZVCjrGgB54N&9nsh7glKqF}sV?bA9$7hJjc@ literal 0 HcmV?d00001 diff --git a/saraWhatsUp/saraWhatsUp/Assets.xcassets/new_message_icon.imageset/Contents.json b/saraWhatsUp/saraWhatsUp/Assets.xcassets/new_message_icon.imageset/Contents.json new file mode 100644 index 0000000..b876f7a --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/Assets.xcassets/new_message_icon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "new_message_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/saraWhatsUp/saraWhatsUp/Assets.xcassets/new_message_icon.imageset/new_message_icon@3x.png b/saraWhatsUp/saraWhatsUp/Assets.xcassets/new_message_icon.imageset/new_message_icon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..adfed53da40fa3cc7b39b896800caefe87dde8c8 GIT binary patch literal 1880 zcmcgtYfuwc6kfwqS}L7E1+lmU2Sp(-0wEEEkOWCJ6d@F}V@pUDh>&bZ76{tTq|_JM ziufvzYOz((DpVX)6cO5@Ra=!hQ$Y|53W60Y0`d@Ywi^WOkJ6vLGrRYmbIWB?`EM`NbT)81t$yd=smZL#N0Y#v}2nA}?q-hNTV=#T3S3sRDY9<{W zHz87k>92x{mqno>T#upt41ZrGi^E2FdcY(HN%U%=%GSS)m6 z(J60wRgxfD96sTTl7i_e1fdf!nORv`j4VF}u1{vN`FuW;#bI(dzLbTpAzMo*jJ{ff z=Olv|Gbr_H9ihgxsD)9Hh-VPNbSlzUDQI+4v|7VNnW%y>jS3x;&0twlnlzNj{@YZe znX)zz(b(&F|CQJv&(>kgXv~0T=#^CCk~}T0bOMncQxLdbj^k;QRg6l(3EYr^>rjzs zylUuTnL?@7T9n@7D49$k)fxzeR*6Z)!E}m;p;oH|LJ2pV8_wf%_*@B_EeYU@Sbic7 zKY+^<`S}Nk{U@H<@TTRP zz^bN?C2(3SlM04uY41PUJ*lE*$a0(-UP_o6e@siwyq+5FhW;2FL1u`fR>>uAe?d~q z45af;a&{hh? zg^TxL%Vmfwhxf}N<|M2>0V|F|)CovB3&u;3aS=NEKv@aBLohN1>T}T12gNrb^CGzJ zA_qr7a~|F;h3cg1Y-?c?}Y9FIMZUj+5v`YsJaIiTA{MVysiQY zZvcJ)I0wkkZ=v7@jG9SRC2XvPoK;ZYwreNG~qEY)MOrQcH@nlvIhGR7kRPYc-}vqnz!5u{?F+}PZ6CoYD@ zcCyoj=6lhP9czmEfi}3^rl)4;eyX;XtiIb2*;V(j$?fODv5y$D&X0NRxvTO`$n=Tc zmE#O$Z9!Fz1xwQWBnpoc**|*O8P}I3&HRnqy9agt&c{_avzT5LYu#Uro?I9gTW?i! zYM;DmzA0E#e|7Vb^_P0~`ma2Np4nw}+q$K6xjKY4*M8f&_=Crv2oa@ypzTg%t-1Dh z?oy8@A491_R8!&3V&(^hwOg}?2d-UDo4w3-KHi<&ylfcuCo-D`uoaH5Nwja&0dV}U7she3JHn6Or$2!r& zR9Augxq}vNGh@>LVr%1DC-N3M*>{mC)w&BZnHc-)hpjS1pCO$2o|Xbwi$M z);62btdd{s>T{4s>2lsTwC+t|NTEsgPK#6MGP@#yDc-5BYEJ0Fj!(DTUx4JdJ*Zph zZcjVY*7?cJBgopo23Kpn;=R@7Wj4sX_5;lMc7bzEZrwI+0iXFC4D9?`%PT;|x63+; zyh7=}cD{^tG>HSR4gR#%npjqBwd@CPi3k%G|(M*k_$B`9N5Jk#kl;q*8T4dakUP26)GqL-@!jJgP4~$UKeUb zt{{5^PX1y4jp9rCpk@yDu8ioq1gS=xk5onUUHrG}{68)C;LK>L%Va1U`2>gtzHb6gg-4s}1qm(p26}P6{po#$f@b@gBf3of48nqO@6|Ly#*NzV zQwmKW;{7NDVVbtc`a6hAkmU5IO1X-0fgC7yWFD&)mYVQ-i2N@FrinH@#|6T~=6I5- zSK-Q5DRc>e_dUoQIgEyh&EIVx004xqUK1wsN==iCy_b+n;#07fQ4rXIF&bC3j35`f z6hH{`@5tJ2xh*7Xlw@E_daBAHtasG@8U)f9*zNHJV+3O`Tq@H+u>Ds#IsI^I2j34O z?tCyy#C`)E^Rk{>-~WQr>kwxDAp`*UN@80vOMel9&5==(J=Pq>R}=t%6BDdv#`O3a z1`6?kswV*4U?q*c#y@L7?JQ-CRA(?2fsnc`yI+Bp*Fb1i_B5!VZ@m^8Le~W64X}Hf z@Gd(u8UIKu?4+382EBtF@&IDgVN!?ojX5&*|<< z@~LS_v;SDVu*Uo=wM!vj>~w$X%CcT|SG4-lISc?i{5R4sd4DI6o063mJOQ|=Fad4P z3$dBKRu`DqjKc?}|2}2_K(|jd%J&4m43Mh$F#~||T0*r=^#>1#7U(?Xq!$2Sk$8g( z(q!vu5@TCJcdOP`V5x^NfO~{0ufh)(nsy4fhdroMkPrf3 z>kj?g0VrZ>SOw4!ZQtOD3b=lux*RzjJORzzcXnUEE@-mmLne&`ppX4o{SQ4sj=jJe z4SKM~*(Ajb18e9Ar(o`hje0OXt6CipGq?;J0ypacoDo;;UI0FLbAEI~Ssnm(`>JZI zz`fS~Am_ah*d04d2n55x+jjk^_TcmMH~{vkZ0|{Vf=rC$2iP}qRs7TLP{3GyF&zh4 z06@QcCl6jB-qjOc>mI4=>Ga!MMRdpk0E$W>Wc9=G%zm3M=mK5%@Ng%|-vhv1nf#mt zz!G#gDmU$I$VsGCdaA++#6k+5+k;0r0KoATK^i=dRwqDujQyEwI_$EV4C3cC8`uGqs&0RVTHM;eyS`6`ww(4_z{VL(a%<~2S}wtd+{ z0B8$zpcBybxK)3(_Zbbdz(ZF84K62R1R+jV&vO9nez21`08mdnSpWdYCF2>x2_iUR zgXX(sB&BoeLg%>43TApwfGpe6)Dr-hnmacy_~hKrMHfL0*4D3WKpy4o7KWd$X-Puh zmO{ss1Fr3B1x7VneYvC_~*5LgaDWnsU}E(VdN*| z^<`5QYYZn9M;WuxytD~pC(VvnYuykc2GFT2iSuRhG^u+Q1wwdWWhA6d7bgIOMZJrg zczkIEI>2V3B@}?yNtCSub%KQ`VdVV6Qlgjw06%l2Y0S9lA(G2NSYYV1Nd4oo4M63q znhSu7{}xJQ>>2l(uV_kUl_;17&3`(86tSvEfkD~)y|XBtiJ+uP?0W$~d!>%#e76Gk z<1W9g$T(U+i4u)Tx;7Fgp}f0WDwJeGb1I7mNvTy7zx4aX@snG2UrE&nI}-0gbx*<|JGXP}C+a$%Zm4bF9v{X*k~^iQq& znuvp(0swBKRz6Siyx^br4y9VOu*)n2rvZTSy=_-0d9>*LwyJmO8TY}*Z)pMPAv`}E z*%kX;FS?!A0_2XoT8y?WL83b@F3Sx&L0S( z;qy*6=Ne+q6`fTG0!w_w;0gwI?bw*WL&6`S{_x~Q1J)8JbCslvnh0bVRSftk?RGI{ zya}MakVEQu52dJN@Tyd|T9t9@s^F3)GvkD6j~Q1e1UaY?Hqb{*9W05$_am4Pg9c0? zS%pE9nH0uSAb!K}=9C2pg6iN&W)J{3G7hQ9&`UMf2zZjuQMxN7e*BVWNsllYq*oKo zCiV8EFaN!GL;!{Z%PDzYiF&I5-2KqihPd_S04Up1)$g9y)ck26w7P_K&sOIP3qJ(U z%ohbJ?yD53%KfVN|HUV;6MSKBzOaLEdm_uN^n8VMH^>ZtgOcmH*2Z%tG|0&rm6HW?iRZ$Qt!#kDnXUA-S;a1#0l)IYH>*yDxfKk&$K`TZZqe| zPF*(uh(L_~b5XirV?rUGkx)Vxtm`$_X%n*>3_7HI2Cwb_AW{$c{>Ost`G+kk0--Ul zaL#226d-|foeu-ij0q83D+FNcAI9Mc-lv>GkdOkG`_=X}n&O&8Fao&O#8(?gU>yFm zp~2Pc`KS38N(dBPN?|F$<2UfX6)*&k{~ZY#m(Yb65|jTbo~Kisatfh1146-4c%D+w zuxE^OC&4*_qyz)MwoxVL!v(KNUeF=bcW;Q<>*^WNg653xRA16OxK>5Var& z!UOMoAQhxQrWs=Hv-s02uvayogRfWTD!`7&5EIPT zrB_=}7uo0uazW4ktB{;)f;}IV$iIWZ^gCPrARz>?4~hA|7SIVu0o5`?$aD3lyz5^S z7tuNEQG6P@>ySUKiwQk74e|M3!T>`7KvDeZRu4c60Z=G^7*{AT0+(9OM}!IPfmaZh zBsNIZpSR9Efkg$|p69$PRqNI8aGeQGH)Dz`pi}ZR2Rtvikk~?si05f__3M=L_>yxu z&6nGh2td(*2nfTTJ!-?Ozk~u57mkB-2No#My{o13N(1yq;;cyvss1v_z7%J&({C_z zkm!L0q88!WTu`)9Km=C`7}e7Pszn3|OjHU?Ay{S+Oz3m|MFsz7^ZaLTFMy}>M&Nng zgn0Ycas5F;hH+^KqBi)C>@O6=PxMP3Eg%b_VMLh0$03*8GXe`Tjz6P@_CBXU4N#|( z{Ra=Rk0|t~eMv#CiO|=V2gHGYEU1hi8w&Mw69JDGkj6jaP9^8gVm2UBfH#NWzyB!E zf0^cgR|_hE0vMS+FO-3s-v6gyegZJ-VKL?ZKd@_JifgU^Zru8B@ii$d+qLF@HxMBi z^}m+CrpEu&@7nnhbEk*z&j*c!xqT`=4EcEG;>3g+7B0Y85L5m)G|{4*L7in9+mQ~xzCzJVUdaP&{X zN@rcVnFr)fy9a^NQzGQTG??v8wC9>b&P<%nPWP?z$anBmY6JZ_%})@o)Wer1cQ&GnQJ-l(^%?BDeY!>;K^)_|Q3&~wm@ zOXd}#jbx{rx zr#W-ZzXkCY^a0X5%b6=m#IMk&_~Nr(;9{4%CYn7(Lgwh~b8TjELFQ~1^8gy#4hD0? z86e~W*#k+!b0&DzF^#H|1;P#RofV#64*a#yUrs3*@*sfb%x{~8!M>iuOEo=t**aj zh4)`!ryW}$v%LM8YXFpXvYp2hvVr{5r~OPPBlE=!f_SBWM1nf6E{z6e$hG6&)Pfqo z3A)sCO8=YMQy7VD4~b0+s(laNCS=3E()Uuy-v}i+2<$)AUh0A5(*LM-rvtKO{cmc) z&7AFjRSP=M!F;avYHMb%95GXc$;H03HjQlKGx64lcz_1w}nuDi(Gj5&6e)=aog3wzmk(db?m=>S77AlCkG|gg(Qas_Pfuh7~j3WYlfPZ!@=pB^=tMJXR~q* zPVS`V2hFsxdDIOtqnzhP)?p$-jKR<{Lk+jra`=j>QcHxQIDl{FN{N^4=47if7q zgGH9N+z)ZC1!`sEU6O6olL3F>!z>ih+KAZBY3a7Z@e?N>7rl>fzGvd?mW61?Ibu-J zWn`GnOSZHj4ZV^tL9fRBwuzN6?zrsYoJp*gz7v(G8pZU}yd!iafnR_!hBuT|rfbp$ykNMXmbH%7WCy&~8$33hp zI_(mfDm$&2x0pL^iPmIm?Pk8kd~~*6P2wyZ9PgAophjtZx-=5|6Md$C9Qlj9lvt@O ze)g2FW)o&u4MT!G%})8s%Qx-Kq8Xy`#jbp6GPT&#-(t|$M{agM*UqU>FYD*L0oa?H zjm!~JQiR(;4@tK-x+`EJd|7m+nl;^->()_@L9W6ncCNaWJ`*lX{2)gyYM9x|X<1SHL)T=S*O6r#ncWBclc@L~B_Cst8RN64K8NuGJyIt!0W8?h7h2vCyU9)bC zJ9monW8$@p!$i@yU(+oGuZMl1RTG;~v?gY;u`)uf>-d)J7oy{cTAoEJFNKpIuX>mM zOS@UJKUSXOxN8-oV(T8Kk=&wyn$MH%-CU&E--OHr) zYFBMr|t$;&iLwYElo<@KtUe793mR z`^bg7K(+EGe$-@t_G46HulSx>1HsE zEHn3*YF{&fsrkJ^YBh(e5PI9MuSmDBhh-KW7qqGW#5eqfwlWJrq*R&(ufk6a6zNyU zmco)euLM}$&}G{W{_rtKdB%~il9a=p{HlIU>tLC#{EZ46S{otL$;}GQ#HXo^vs|1F z33-HdI=AD|UKbchS}(P8ar9XPh$iH>%SODOI3Z8#T{C!MzAVJBT+vjU~;j|y%~^S0tXVf36Z9@TqU<&HV{yVLr=@bW ziOA1n2J;*R;!RP61w#HhZmKEVa@4u3Ny)dWf36T?v&mBma&HbgJaI~Vy;?!^s)-i? z!yuxEm#0=wJ*`ARQq7b~-}|fSW|B8W1tk}$pWaHJyje$PomYvnV-kxC&x1F%7#uM~ z@``u~STi|x#IH%^1o9(q54i?J(P_Qip)eBRhW8J+@0wya5}@$&z zGM0F>H~IMK6ts40q^kLf;y^P)|G=H zs4|L(Ay1v_Eoww>f5_g!+dY*^mDq=5H{}fYvLYTl&4x;O!x|9~*E_c9dgyK?Bu^12 zTrrcn@yMW&)cdm>>vo@Zb>VLyq>6VZy7_rNx4VqXN=>uCOxwwHUu+1h-BRH^h8t{K zbW+c^tT#Uo<^shKREnr^T(jH!lP7yDl8on511MWdF?VR-G6% zLVfUIy-PH5Tl0}0b(_`(8BaG4aoPPZif`-&#$=uPx|UbB#-N0}?!k`)2i4xFY3U&p zS7TnXT9e*&@89P+4L`~G-bvRxst?;tXI3o{tmQ(q zEz#d)evwebWu_RflUCu7yMf32p-*QGtv7qUlOQ;+lylr6YkLcCC3{1{Ex@>pKR$_SqkE5!d{PIc{&B;PBE{gLC)GVyn)fFHCMbDlzBmF#Ft~;g{+BM z@Se~Tz!RBlwmw)tn6=Ue`SND%)pw8}2QqkGJl6s|XOzUre6iSlu>N)yjnze7SWYyAce6!#Mqcq)N|_v=`KS`MQN#_gMnz>% zF<*FYV{a*aR2Sx^DywW3ZxDU(=Hqe~pWCw`508TiSV}2{PjmzkW`P+pajPqv-FmGY zCU+vyHc;I2ozyBEXpZ+?&|H^~`klUy+ZcX7k(x-U8sMbM4NhxvFxsiv-s_n9(bYu* zS8L}%{Jc964j=zFkj>HaV&ZOBF##%k5oI3p%R{%o1J}MqbuT2?$Kq&y$_;DP!DGnC z`2O1l&6aacd9rFAQ&n0s`ROo?1_tg9H^k8QU)1C~iSL|DCf(Or(wa)GNq6GhIa#Yl zdBfoFa?a7*WQHfiQP2sEnm7{+RCkSLQy4hiztRzBNHTiANjF;-{MM`RWJ5|H z4a=+4R@E}AHE;C>UG%MVrz}dHHMp*@Y9*BWfthM~DT@dDT{0)T@}YaTd>E%gZg-Os z2^{8%n*=JVyj~$Z4#*Yz>aagLp1!a;mQoeY$rCGQ8~Y}AB6y<+kq;l>9o0>V={m6(h`T$R(g}nd_1=H_^i{{GUNr>+ zdPz!nP`7CILUw@m%Ji%IE(Wnjc%8@j;kcpcp~BsW{a^hAOs4qeu~v?MU}{cn#+sX9 z;>;Ot8at%pEqs?o-goLYUT-H-7Zze z4^78ZwD;mzz8kll+XnN=1fy|txnO+=u`5x^mSR^wGg%=3c((lwxdAgQAzr%93j4ko zcI5Xv#vFE=$}zvvpnAg$)XXG?ZY7m_o9t(5GEat1qzzii7Kz5C1il@}`lK^exD`Q} zU0@YXf+$W`zB>3a?=}wib8Q#D+#VhJfY@&3m{QRM)*zK6Z9HAB_tBW~bR#BF>T~27x9T=0AhnuX< z=O@FX#jH=ajQojeSdOAXv*_mA58SQB`ub{%pM97PvDL1{#ujJfIy7^FH(wprK=u7W!pQ7JP~sKWg`GenlMTq%*ao=8?a zc{?wqx|A=f&w|y;hBal!+v*sF`#$0oM|!u62sXK_evWA9G6P*}-a~|C<>zFi?SemP ze7icP*s#^AB^`}5Bjw;%hFOYz=yVOzPO9lY`{$M+aqX$NIX@+&y7OeuGi*$Nj!|Hf|eR#gI1Vfw)G`+Zs75_Sj>8Zn8S+c{iv0);Y=6U6ataK0Y++ zT;sg)WoXs#P^QRzQ++>uA%Th!QQi6Wytm|SP7%cf<Hp%b3UN{ncnV2J>w0r@Mr$%$IojXZ%3pUujqi1WrhIB-tXdzEvab zl9IMbo;=xp2VZ2DxRlSh%0$3oeT zBiSf;fB*4MZ$AfL_RK?U(1)K~3KD>`6>M_jQ8}kb)-Rvg{xN}WQmyI;fw5;(q~Il5 zYhUohWTm8Xo_miYhr4>uWZmG&mmB1QO{!L@zeuU2?!D$-kn_r))M8WP;8<2rnjn&! zafoT>SX7XnAeEb8Qyy)8w4hFgUAAj_SFicqhLBvDpS@C)s=`7!NU3|q1>S7qrbnQo z$?PYzMrs2cvLOjEs_^*v-GR4p^EM|&{|t428P~iyZ`A9aT(IdJozv;8>d-Xt+D6ycl0fl zzE)?ow3^aq8+*Z|9jbUL!K&cKaJ$LOz_9qB3Hg{wC5vAsqN*m5rd+29omi$|5qmJ-W6psTZuD&=ZfA4?-Z2}w zRoqUW^vljyNt|1l96y%s>=G(XqJId#i6N#dR18G{FvCb{sH$k{2}-3NY_7A|cdAa& z?k!mx-nFyo(&G<$PS@+=z^U`>IO`?j%nqN5qXi%F)YOB=dCQo1>-#qApSKxoOSoWO z9kZ3rvNL%NzJ#L~&vHsd&yrt|sefr@X+L5nL+5XXKJTBP zW>HoodwFZ6`TdD>fFqF}yEwGnbJ3gxaceTP)|XgusFz8yh6{84{%>GKa&L@+ znvxEHiiOH>F&v4WsmPA9S(jq=Jc^f&b@f|JbxG&zk9VY$kgpF=NhwTbw-u*^77y{A>48UI%&-!8!e=B`T4axnZlRK!R`Siw z8e8phHw4c{EM$+}aEeQ`h;qyyXBW6-9U43?cZcxAV`0|BmirDhgWOGD4ksU38}~0X z8MgvZDrH;dhM)Z`!+nKHqUAp&s1>vZIbIfSQ(?UrGG4|c=c>Z1eO7d1%zCW)>AmMY zMkdM&#h;lK4i||z#))O6O{H*J!+hh?r_GY78xwG&2gP-WP_joKV1={i=ZKHIt##NK z#&q_E9FXP2e3v`FvQ4&$-yoPd0BJzumevRbyMrAhiSUuj8wW`j;TE4hja6T03{{L5T(9A+FiaTDAjtm>Bs!Z~2a>ic8m8E4cNXy;@0r|rl>gdF zj3e$C)VZT&26S8-`rq)3DtMkmO&m7^RpgpR_@Z?u^fcmnQ9t0E<*=e#mmysTfK5Rb1rHsY)c-Ij84bh zRn3y=NrIyab;e)@N&0=$Ng>;cRP9_}_(Rt3rFUfro(=Z;a8a1ZYHc-a%f zIh3``vZ{0|eD@$1@fcbe&yHD5KjI?mup94m_A{+SE1l;KIhO7?Shgo*g;;EVg!)Cc zS+})MRH*656Ivu&NC0`pi#IvNaA&6%Z}o(8_>Pm|t>?`}PF@Q#ZH}$x+%YZUI$w9v zS_3*bpDB-oyAeOSzd2?pTkYF7LHmt~FtR0hf_6lgzTqdswSpoHFcVW#s=L?A zRqbaK{N;*%4BxaKH}8Dm-`d3QinyNRH{tkU5`k8e`;fOJ{ zMsXdl#m328xLtGxsxAK6N5)UnrNo{MFmQ@Jck-I!4K!u4SH)ZX4HUx7`PHrz8UzyC z2Pf|o3ELabz0Z~32si}Ijrg4;vg!Jl2|l!ZRX?6 zu8o_ZO28FFhxSyIQiejf2R~#I-<+~ahRCPXmr^}My2xo~vv;G+k<_o16F+)Fao9#m z?ACY*w+d2+^K4iSOsL77e9~oEbXq61gT*}Kp951*n+Vx$T-LnT$ks{Wy4p*yM3W;{ zyFS%zayok{nNkl|Om~4#Nup0)zklz>O9iv*cQ;h+L)Pml#)Jmmmu_sh1iZiAzGRq- zXx3G8)pgLj&6=-O51qt9ga|t^@dNBL~@mPicF#b9Ddo-norlp)sOT_$l4dX9N-_W9N>gr48ww zUjZAxfuGa;ZaElhVQbSmanFvttKac5a33~LqJ7EzRTLJw%sbXSv67?(jSGc<>F&WI zZA(?K7>p>BtMn+D$-1htf~2o4rFwAfC#RE*6Tba!-s26et!)Jisk$#0e)D$7PO+9) zI3YNSnK48koO}JaSZKs;(ice<8+Xmj1aV2~UkYAM< zRH~}-wiEX*(bi$j9nv2N8$(yBA(pLCUb#D{)8V1v2YLR@P$oVlv+)|~WLndY`ROMv zRM|WUhdRm;*^2BuKilz}d|6I(!U9D{ec&Io<%l;CAR(^F-F=WC5@#!6OU)qr1lF*O0JbP)LG>y}reDvPFCX-lxQN)AB_`@hIl3~=fH&D+6cmF?9n^G! z!Xj8SoyW%|#|FN#S5_iF%s6?NtYZl`Xu|oxWKDx!;A4lRv&m;S!vz34;=}`AQ3_YF zSmgA%_=K%hpFUj^9)p1Wu)8+o7qOYBJf^jvEZupt3>}sG-&RUBN5>sa)+bR&-qps;0JkkEnLTY| zqvk7>Q|`LH5?$Mm)#={YuXxVcUA{UBEolNtbq^j06Q`-)l$hvVE$iZH$hDlqW#akN ztNmW;`oqr4&}D zm|jKz>6jdRtgvQxhXQSZlCS2bo#bX!o%T=Hd23h2&=E{$O22qU#C0Cw>b1p}jN>8awV&I#6r89I%6NBNFqG3ewz86&ya&x5LH z!V2%s7PeE1<6%pVI}FA>^bbEGXfq&V^*in{bL97T<4tf_9ZoCIK5{eM@PA`LMny$4 zQ0a#iaa-wOmgXRiQ7^HG{0lEdW|&&~$&NRB4B)}+qfMH}#ySs=j|d-p>D*m`#^BNM zl1E|kO-SDretKJLzX?Agzqu3i)Bk1{c0LZ_QQmoeIQX{00hL@u54xMJxk9Qrfv##kJ|b8{ zcLaX}!g}=FgGajEj4_yHUijgz7|V+NVg8Z8GKX^Z@>;TqW4`)eDyr=pa?WF~jzT4c zLPZZCp4Y{634FgG$qe#-0keP@tN%{0Tyu|3)&0b_Xn7vn+dXP#ccD?EZg~jd7;D?k z8}iM3QKJv$|HhgCU!$rBNw&&ybm z)0AV*l_QSr{FLR+GPfOKXK%e@(pKKnJI13$V=3oJza&}z#8I=v1+$q+_)`lz-T~FD z@s#a8N(hs*#<;uO!wkvnyy7hQz4ryG8477izKUX6UnRibRX*64PTglCX`L-90Wx9$`9vH$l&i_+xK79h{gTqam{|aWCjv?DS(Jii#Syo_u8Le6^O-~a) zJhUAd6_weOvx@SlXv(^D-sP3;&{

*hQr#hV{GJ_lwo+%(~d(HTB338r(9jrkw8URG|oVbum+^WLDIOkx<#Vt(57yM^+lf7rrvc8f2BKNUHWWZ8@w96Zg?sBFYu8 zDR{ICfMo^8cb;vQh5WMC7lqy0RL6AsITEGo<#WOGv1*DTpW9QE`|nLnWzfv(KTN>r zoO`~*p=EAeDH1WvR*!81gJZP3L(*`QVUDy40fqIc*&VC^NejE2C!Ld=65qE&BX)73 zjP5kT_ZUoSFDVx9X@Ym+7KzQgl2i(9J*!(Xv$_86mR)5>9o_-E;!MHzuSXh0q=vCQ zr6O%W&#;r|dKJHJp*toe{kT|oDk74euk>6PX&z6Eq-FF{%X~5?4&a+N=NB0qH!yRx z2@bwDTwzS(JIlno9hCaarnxy8an+CfHxOI8R6d`urS-$8^7{$vN#$GN23#yjO??jfKAr3fYpgp}TyXXhDHtRA-T z$73gYo7Ml;!rz_Esf2+1uqizB_;u3)kC6M0RHl3 zc=tIUR~oAaO-!BH+3x!^i02J`N@4w19JB6JGi_)_zNq({#y{H!dHh0^4B3%cl04LJ zJ>$pE>9$LyljF_%B*$h#TfVDolu@#+&+8Yek=Z+7YFYj=l?p&`9XeZG1I@wTV?-ZP z6c|6Qp#M%u8lLj>fd`QzdJQF#B^3Db1(iHZD_ywe*$>w!s`OTa>4ruA<8JruObAS^ zt9|2S6$fpg2VGt1dK)CW%M#7z`PWp}AN7>zmPtXjPsPH4o^Nyg8rE;7$$j45e?shn z6(?=FG%-ig#&kb8D_KOpzs~$;9c^T<>I@*p9iogxm(hs5{iwhHItWf`|V} zoRl`U@^O@2Rq^vzMUFX9OW%`$qs4eDY|A*F@0$zeG8wy zWK}^<`_>_>iEv!*+Ywgs zF(|Xc)qH*orCqH|)M=^NtnoDrV%yN}Z-4>Hv)*jO|J);ZP1}7Ki&SZi(J(XZk-_-~ zx`*K&nOz*dTGE!cD3JycLMv*Tqf3mSknPRm5!9HXE4WH4!ZS$b649W8a|5cZW@6ih zT_*7@kt~r!;E^Qi(SM$2ZA1Fx7FB z@VDD)2Y2$Tc?PV8yfsOy*q=99=xLx{51CcW8F4T*KrOmVAs&oB%F3vzmar+%=4DfR=4*_3oS;NtvG_~X zw7h&=e*DyjqjMh)^+cbU*CZIV4}GtoUt=W?;Y9ed0A6q(Lkj_q5uB%pFe9RF6MXs& zAd&nAx*IVisG!-D+wYLH8;&CQ0)w4X4E!=}vf|1cX_n%|PqETgv@^eX5|PLul> zBQ9Js|NRY)FPgcuo65+U%4g@7t5VD?eC(G|v@6hqHN_R*=5`HemIjIjOun;2-cOOj zw=fuVMa(N=m9#Hz5IoCc7u0-6kbDnX( zO~YE%DkeYb6rf6nF%a{b&;qB)#_dOFR@=*beV%l?Aiq8{$0d=?`*Q|lu8x|#YZ78w z=+uoTN;B*W8mrTjhk~m&Gu|&q({hop$BP9Is){P~V!kMLUN(__MQ2MX$@2-nV6urb zU~p44sKAo+QMD?Wt&dOXOlYBU0u%C1yD=0corgf0$x~n0Kf|#(XgUy zue;DV z?$#!6Ua3e%t}Tdi&ka*zawZ!s1G#0hjMG2i8$oqu&&_^|NfF{$1F6RmWsH!A%&I=- z()u@WvAHEnS3>2v`bU2-67##zbpy_xse6Z?5S`}UPPF5j3)`as(HGa*E9a&}o^EV9o`RL_JLEqBCn z>7WYZM%==I=~Y>s9^@ zeEAKCJi|Xp$@vXb{d#%KnA`P0oUf9fFyGAn_0PGGU%uV#p&RWVR*vT*8Um=73c+^` znTjGc!<@&WyzMp(*L7i+h9=0){h5PP48nK5m1Xa?jANFF{|Hq%eLcwICcCQ(pQw0| zAOid(`0k&d`bs%rzKpp;U~y_?q>0)@-o*sCK#Nhq2Y}@T>aVd!4@?HjK*=lvebz zaCCEBymQXw*9K*#Pyp*9V}=K>htnHJO#24std**y{-uFg{TNayIc^ejlJTQG#+bJ? z)#5hqJ}8*+&lu^TwSS7Ka>x0kX5oC{OBhS4Sk#U$=7(_BahVa{1z!IIlf$NTZ4J7{ z;vFjolIEViT-3e3M*_ygV;8@xOmUIiYv8=&AEq0I0?QxJX@`^GsEIm!yP{f5U4Ein zP&%2m@M8Yw%);>#q5yHqvhr;7y*|RDoQ5%Dt08WWToUUp-R5p>u9mquo@8DaLv1QQ ze4}Sz0`StWNNtio-ko7OV&GlYe}3;kebV1o@Ux)n*D^=4CxS_z*Oa*nLOvQynl>71 zA+0JLsB3G~Xosu{qHsDS3ewRb?I;C>IYfkz=~1QD^6xzuddX`{u9oi3=nuy(xLmTT zP-b(J)AznA!WVo^>>1=o5{k0L4{}Eg>6_Y}kOc2Lx}qhSHj^;bp1z{!%NX;dmQ>FW z1wU=-w!zB^R`}$h5U(P?CHr~2k%lUA*09B++LUCu5dPXXXx^;_Z-+EtW7P|4b@da% z5*&l@$ZC&KiS0{U783Py+t-3gc*AzM$)4A=(-%yI+{J78j zCTKs_^OLFjfUlO^&Dr6%E}L871D3FrAD zipD7Y;@e?O$sjyxsanHeeS>bUKv2vvIFE^5#9tLznHAGXbI!e6Jb8V)Jx3Be5g5u! zgYl`+9;MIP$iy%Hz(o=Kkhcf?GXe%o@TGnzI0QH-umF$(g+&Q~e;%NqXZs>7wPce* zNd8mb<7v#T%fA4iJTUThPKV3#E>)w`Fyrzckg82L0AaIZh3B*VQ~ku2)71-Ob|@|kFwWL6}wuGV_|-d z!7p>eS<;%D#0Tg^yAa1U1ffT-93JP-XR+uSsukh*5evmhgwG5QB2V3hUocM0K4c+F zPqZw42z6YbiW!UYFvY-&Tvjz^C~K2U`Vo}vz9-=hL>qc{Sd;p`etMH94j$=iL1{;iU?5pE7e#oVX<7)9U;qgkC17qO z_K@W_AP&VCYx~fjl4R;`!!0bh`{gAlwD4Tks~mZx<(vkazsL#&eMu~vUo>pI9l!BO zW*8$NleLudS%EkV8^XTdrh&R*9-zTDCiU(&ki{#~%7QzYOme&A<;&tm)YzwExox(@ zow9=U1PR!7id&`Kx!*(ZYdun_Z$p_K5fG8gG`}KMiqMZ#O3-O;-1X|Z_sPG_rT=7H zQC1->(Wl88g|#1rqdwD-6n}a5gsB3(a%2pSv+HpmE2Bf;r@dcaemSs~=R%KWOR2k& zj;@z++|Tnrf@UDB=x;9W;Ih8AY|y&rKP5XH6*1cF)&FUNAt7Jh8t|;cQ__V0R*;1E ziXP3D-}26D9MnpJ#C(Z|`T?&Ed`YbPUOtYHvtAxxAhKz`r+HhKZHZ>fpQ*mJR(#vB$FP`B=Dpw3~fB+*5SR!sRQB4)znG+fEsu zm6c2v7r>i0HlknfH8x+v>$tg9^V}qaUvkHy@ZoPc7c~zw%scMJpp*TmK>iJk+?(Z) z%yoWbhR{GXGvI?htd$6QAFcJxfLxsB%2*Sglb6ek zijjjbvA%N*rrr_BFiqU(jJ~u6c6#?B|Jpaeiw3$Fi$<>_QpUToz4iueJV(#Phth$ISyqd1EiCZlUSOrx)12WNE9*R(Oi$Gf+$#JB9K$*3fj99j2m&g2(3oP z7#<(Uzg!Jz+v|%xSdjkgLNOcdSFZh{wI^x?M$jNVPf!v6>X9dw^5kO}amYQXpERiJ zE6{X^rb;cz$wz{gjOn19!vXn%l}kMsu7JH561h~;BR9G$?O@G2H?-D|%v@@F?QJ)) z^o8PLX7BJQ*Z!Nr@99c$t2PFRMC8`|(Z?a4F{x3MssXcrHLe-o9ryX8-trsn@2^b& zKryU*z)qH)g?8P%m4}1TNatPD@)@oEkKA{C09n@aIL#OL${iy`w>NQqD;1*@{=fbJ zuTc{c&MdbEv8(0icXrbGIQ@3}AJN;!ix2}aT!>mI(RGK1fN!S49v+!_C~@BQHKIj2 z#o$1ig%;E#l7!v{-u7eti@|u+BY*rbFT_ zG5L`c`A%O`koQE}5&8RhoFMA;!`c4bBLLaXJFdY!MP4`$3Wwe=(WW(!u-1{z!ZedU z9rB)u&`a0Ph~J2DpQqb0>PCN3*~xL~?Im0QU|RF- zlgKn>yl>r;Tzzo}nS&6;$n1%cEt_BHUN~x);h376mHbjFO$|GB3Ibnkfb$=29^gW< zECe=B1GkWTpyWnde04sb81Y%q6fkh9lMB@Z2lW*+_BfEGf}mJ#JHk#@!$*v`YfP0e zPuPx`75}FmrUTTD{*iwHPy!TXgt==shtjQD0(#q zfpHH@2d-LIdg;r%jvZ~s=@&QS@(rA)N%Gs#=p8T>oQKQBl;jtyPKOUiheFC}RRW3|4w(}hvrcSrNYFl;_2&m@OKEqRiha3 zWO+$sjeq9OtMIxC#>n>nnaO2wacG$#nMz^%Ic|f$TTtlDu`usd#$=DFE(xZ^e1eal zUAS3l3P&UqQ`9)|Wlk2J2qZqWgqUr8=d!fVH-wV16-NJzP7m@xUzaE)3M9Gnm8+J8 z7Yvi0nUY4LU>|c)@+BV}vKy;csKy`A^VlDAycLl&CoJegYo^4-0APlk!P0Q;{sJz1 zubBpt*2ecMX6yz8{0m=P{qn!`KW`ZN)Dj?i>S*1=Y_gM5BA=y3@1zwXn&4L*wbgGg zoe8xO-K1ZJpEtHd?T+Xk&OC)&3!fw9Yiu1)&rXDc6#W( z2~*atMaTC7+^7#=+9JzO6)f+&#k-*Nqd~w})id`-fIrfl_;X~G=yx^r_(;C-@o_D_l)Z3v`u;#m+6uKas9K*x{xu< z@_1TmeKx6El|qF__E=~IXnHp(XU%(?>H(OVDjP>!n>1(N0mt2+okNxeo>n4~c}nh4 z+z&t9g=r_rUKvK@_pW!_zeTM(z1Y;W=9|CBfoD87;i1hiuItK3Et4$L3*vBX9Cf@a z8!t_WTH8kr>B@1X=w3m|c7hDtwd_@JmflNX<8F+LUe0=aat)?GPop>6X6)&Qla48& z|CtNqgcoml-%~cBEi~w|GM3WU6>h=rH$leFEgbqIck#!Az|)J*7wfrZj`)!`r)adC z`(CPL1d_j80e+bBG1G?x^2algd}Nh37=-hqLv6;&2e|*}`%j$G$ZWt5MC>A>dT>`If12qc;@GxV}23+oy24|TDb2jvU%^!$+Al^8`!#MYY zcpAh_0fzA|WVl+OUBIaQfUuY=)i0td_=^`9lA(#-7>wjSEQ&jG-pfl>1B=)lX660t zM1c1S`wNiGZ*7snnu4d`R^d+;_yJ*E`G|JjFaPkK(9Z`Y8a1=FN=(9@`Oc1(BwtY%Ux}9eH&bar7@5fJKzrit!0H$fK z9|Prdps*HWQ>$=*TAG4n`DVFY*Vj*#5_L?X7;G@K9Y_;{LzuF>1E;d1d`_SV;eH_1 zm}a-Mj`@8hg1Vl5!_MmoJVE)xC0TCTpc=c6FRyBA(4*a5_Elj2n^H_8DT=_g`7J5; zPp}C74t*Z>vQ*yVP#BHd;^kdNF=m${2aUV~k-*z0gRHmbY1q4FarFKwHCPnSD4{~$ zibnP_6l(j(HsTwr-DOc9gGSH68b_a1>eaE{{miw{ot@aY*oqMjStWg9sFTU z4Ydc6cwh+}htlNsB8|LRKsxEi!sf9aoS&Zs8ET!p%)!dF?mOOX$k_ zama>t=&@SAG}(EqbeBmYqXRSU$VC5M@O#4G5pmtXoY)!s$h)ND&h*jLY~_OBShbrc zgK@#9r(Uxr{p7I7{?I4==a#V6!F?=g%v!=93xE2|+Enm_vT$Mr%bt?12&_^?Q5YVAw(zI;6G&$;#3D<_fCkre zhwfzPd++7e&lT$Da_mVjF(?!Y#&0b|zVCT!$#>@D_E7q;419ld7*r{FB8v-Sk-~b5 z1Sj+i7RQtJ>`*_C6tQN&=7YZXBgtLhchCvu8;Pjc!bN3&{sItWoltGFHh0}gtK#B2 zcQ43^^AANk5*JS1j?-|pp*iGyHUHh)sW;)~MwF0}lR;F!e6_<^lM(r$VPS3RQ?z3K zyC`N2%?8}v%f72#n<5>d@{5DMOWiNpmQ4lsE-(yB&CT#lYHMa`cHKUQQ%Q&)c{2PL z$zQ<3T9!0{+PhKvyRRdA91CTh-()T?rql}HT!aB!&h!Z-Z2tb9ozXV<>*57G4ST=S zVJV=QCuc-h$WO=64l$(Z`eSXM4iI|w3Tc4(zU%kGD;TQH(1)9uF6Swv+%Gq>`wAMq z-@Yh7H0c<%@64F0-n$ZZ>GBPsLtgWZDG`&i4SyNH$F1$h&yP0b&6sesW?@a*`g-`U zUay;R_#oAnrXfvqAALTk%FPYVVkK%~OIz=s>X^z{Qil??3np1UIvI5!*5gj=CLoWD z*z^SUi9LT62|1JGl*)hZs^rJ&v4gba7IiQMmb0Oakkb})sZCl=xT3DkUdVMkPBlyo zBQxoaP;z~;Tk(D%WDkqZay4unaDVyOvS@BPFf$Y5M*jR!-}iXA61Dm$NL1BSB)%>v za@|hFjIF4Hij{B;T2`%hAN)12pBhlx^^OSt%HZw*_&oUPG7W~&BL!Wnd+@k49*wH1 zc-5;V#OgRI1>2MY#FBvJ#Sh^bB#FXnt}TxrjOx7ejJ#>Ts|d<Npeq%CFAqTSqICTAhVDAcFI2$0$kguNqFBH-t=r(Wj~rjw8 z!~BsYPskbaXY>a`A!oa5AI{d$@F2aD+f>P(Mua%~(+Z2iEjeX7_KLbFult^`eT>3OPp_gp z{Bfn%)yqWzsK21`{LQx4Pdo{OX>_mm>!ujg_Zf?C=$tHdf2qT#^k;zD33Xm5+kF`~Mo-!WWE49%4CR zHK?A>T{P1KgY`&QQp?TS)t`m8#z8}s&lao?97Cvt{PEzR;VHZYhnzq273#*S8?@cwj93O1A z@YN6IT`B|nFgCJ9E0h${M#Juw2Qm25_>l#_hEnWkj6XUJ;*lhx-(Plm^uQgQjF7!n zC4Tq3*6t&Hmtf2}hGy|>n|WfAPg*D5W`m+Ad?|am%vd{*rSa6ZU=ea=2|v5!)xvs> zbGqrb_n4XnXgg|I>|X{opP98e6nY2IQ)a*g2sv+Bl`_}% zHLvy4sUlRXY+nc`+3$ba(82zBrdxkAgw|vu6ecy;X&{1te$FI%SEveJ znp{Pi-`hDin{i32{1RP1*Ak_It^~s~c4f@2I~~zTJ-f9<@;R3*44;4Q zNc`>xM$m>E?mUxA`#9ye!s9B?8ytpfGtSODY-16TaSpG{ zjLzv-?<_pZrRd>AJfABW%3L8cE0hHO0%D3a#l|634E& z#H4}qtat0EAIviw@6vWC`Bu`LHw244;et5aVQO9os{&Yi`DkY(%eKZYHKoq!Wj^TawGXvjbXeA$t(Wa zrky#zu>N%A#hu2p9pOYvLXG9U|LIA*ySECnJwceV&XVOG)@VUveRXmIU0|bbAuYmz z?_kG2XbSgRjyazg?!Vh!olVB_ajGD%XWk71M15SZm`#?ZqQ)j34^~I&xmo)QIES1z zOMS32WNK;p=~_AUFJ?ctlmk~glhaSHf)i=HlT6kB0?3xR1n7<`_HBooyVUh@94^GN z$8w6VHvZMJ5Br~1s{$}}R`i#fD;xbm;rkg)*iB<(AGhuFQ4#^%Yje9@IJBscZkzEG zE)r&RfYCS1=it4eD7oD;=emsRYeC(C12>1FKqS+EBKUf7>P$5WDZ$3F^&ES!?Vl(Y zpGXQj3kH%tD+;puG)k3GRH!h`P-wfm2jW4nHFF?x|{0jrK*gngo>+4&@77M(t; zXJf39jDMzgf4{<3rI$2p;oWpQeelSIBy%?K6dx3scM(O`%koQxXHQ?HB5e$lVcBUc zFqP1~m)sNujTKV<`s1)d=3wCV2mWBgLR3<}HTeS2tC^?vKxGz0w+0*ncqX7 z@hT=4H;4#H&6md@%xwO1Ti<5x%3>JaQL+@%AM*VZ2^7xn353|U$AS+G?LO9B8}d6! zt(wP?!W|Kw*rECf_k*u2jr_?F^M0A_ZI@9 z-bqhxy*D&-4PkhFKA9zT^D%U~23@XlEZmBiePyb)%gH0rMlyT;ApCptj=V4G1+Y#J zG@5W1IsmC8e)0A~Pm^iLKv#EApkPBEkLKi^#9_@mpib zUjRC75u*@DUU#X*g>*_0iajTXh9EBI`Wew)MM`>lWv${*_2x&+v7)N#yIZk6{pS69 z!j-nKxm-?B_d_9s^4q${Pp|a{Rn!y~Jj}f2N)@C+-g*BC9K7|9B%`@(d)R#3X?CJh z_B?n+pSop)x$MU`!bP0kK7!=_NWme;PY1GoO&YM?|AMBHx^Qg39KY(k%yp%NHBwn8 zF<~q3lq4QX_iLF=S0PkohE+?HE_}`Ky~R>pb615sTcY_M-Hc5W&vruvP~(BewQ}Rj z4|SNN#~4P#Wc;oXIgBjO0G74W3e+%9Q{(ywcr-OrsXsBMqg{y`c{A;G1D`hghG4Hj zcGw+>uAC*limUMa{VMFJXOZqZ4xY~$Kvxf1&*Pi3lE|aoM@{mT`QJ|eBRxYMY;{8@?#X+OWqc#ynQP0aD%gmLK+^CfNuARCI{}{q$uy;n{trwhgie*EgSND?%$WDVrCW77gR9G|qE9 zVCU#5y`@b-+60Lh^x@X7M+zi$%5+~d>dW+7H$g?&N?d`7a!;#5vs^jT1D*t&_qkGP zBK4W1^QlFvgi(GX%2vEJm470aV9QG%e*od8*}x5TCYMT5vuMjq5B3xOMxpD1B}|&u?}-v=JIlE+Xg)4>Ox(MoE9nM8f8w$sSvA zK|_Ml>Ga#hN&r*2&|dI8c!AlI0G86wpO?Qqo>3$PafnL^(R#Yf;E%{Jc@gEq*M}s1 zK=+88F5{ZIfMpjV{KS$FZeJ=+RdNP;!j|e9v8J_5Ob$+9JJ%bLsQRm>Q%&s}nK@oK1hV0* zar@y=$)fEk8SDuHEOFr?F&R)Uu_orEc)8+|5a&cJ6?3a1<3!ju7LCtXuh}5xkaDVi z{lTU(yUrtf4UIb~=8vYuX|ytUxtMRl5e}m()%tP@w2)ecOvk!y{eLe?&r?otVJ8)k zHiizYFrL;@>Sgg>{!oeJ0-}m5O<*}o@Y^T!;y63dt;^ON@q5f5)s>5j4+;t$r)vq6 zO9~*b74sQpX=u#o_6SZ;i+UMx_YPW{NX{Ea5{fyb`8$7Y&$5peI$6>7nwB5?DMYn^ zgMJ{3G)FA0Ufz)6xaH(!HHgal6_xGD0V19GEc|9pd^ zwlG~AeRMMVxW8mZpjBn)K0G$Fm>gqUxl`YqozKP5h~~W-e`L}d+w^mQ#7tD8XcVw9nX+0>0&dA zKJe`3TH}WY!LR`Z(7i+KCu7_$pTWt1{?4+Wi_THNjgH@PiN7wu{{(;%f+kfH!RhD- z9~a!jbG>GOGWmWWwYJ-ZiZ~nbL`t*`;2OPkd_|`dXHphDzb%%gleLd<|1`v)o$>K1 zqoceN7f#0wF=T-qsL;M)-f5%15gqNqh_7};wE^u%k~U%e$VH2kf{AcQqxTY!S2-!+ia2m2L$;PA z!}zkBqQXR{&Ic9js3hDH;-Sl@KC0QOGUtqO)Ib4+2b7HD1Eg#0;C_f#Olw9!4skJ} zG74ie$FXHoD&0nn!|g0)0MxK6bTy6=zgLD0+UXfO2~~9O;UyGMp{$JWXbL-DkYF)L zv(%_kKFHcq3yQ!4wEKy?aH2sTQrpNn-2t0!`fo#!6XoQQ8X!aOAM3rq5D>N1><$#W zo|A0?^GKfZ12bHAKabRm1{}M!#4#mYC19$of7b))F}VK2fTK1FD1|p$jk+iKumi(F zh@ByBX51wPCrV1$+a>`ma*|e-V*(ONOdU++&xsZ?SM5cIIa~`5WJ8j!jIrRNIZR$f zYn_=vLrSKCjGs6))9YAnz8?T@h~RE(W@=aEsd@I=eX0%*85EWCz@>s!4^Y3umhNWU zMD?e>a`#;25Mil;FjKwpVRG1-{Np_S0W);aDPeVN3DFIXAVt>*)lG0zQ;w=I2DfF9 zYmi`(aSgS}a1jn*h9xSkfemcgg|4Pq$&mHYQk@+W212;KAi$`hmM+Pd&dNwdd+eRz zPYk}PY2%!o{o@&RfoNXHt&VMXL+qzLxA04GP;Ap|j79!gSA%~2Noe}yd!6lb0M`e& z2_wQi^x>%s$ZQz$^DPODO)oGvUU8K?AcP2{OWE>N9_udxC@ndS1fX|2GHRvZfCjX> z8~zMZe_&t8@ri6QYS1fYtbPKf;9$m4yCH`vL4e?X<)rT_bKuYrP0C6@p8B@DSE)r5 zNEjfDBr!34Rd#&CLO*scN?tLS?iXtZDz%VQ5jX z1Q#Q28-%tJ+Uw1dp^hh~3KN^fY%&Ceg+ywFPY|ZQkHks2e=`uS!VzjE&<~kaei0}~ zRKCYchm0+ij0YscnSxXEy)eX6m=!V=sL!)x8pJ6P0na4y3Bx*lL-xD&8tS(o-`p}^Bc8{3)R9GU-D^v#@=p0)0LZI^eV6QrU1*kyYTUZp!5E!1 z>tn)?K0xZvvk%X#p-I$a6YC{FR*B1Cf<^!EiPR`bH3eVeP(Scrz{xYW8$2W&uy1X` zl~1V|-uT0LP8zkK)=+nIaUy@F(~%bq z@Cgswk5SDd6Gwl)JSprL_d=VebI{n@a!IiYnWdQ^5TS%NXaj0eNBq>1a@G@>rM)IJ z4ZNp`5aVL<(Q%$?6J<^AV@g1oQf|esih&f$H>YE5_BU3Qd7%<#wUO>6zLX8|aB;3B zbV;}h`slTG_yv^13WR9p=9QWkbxxttJd#p^IrS%{R$+*7;xBdRt+C>6;U>URf4Hot_4S*I z=p)b}rq!#&qx4{QBp*&XgbDjcWtgU5Cb_6g(%jg;hvyCu_+*xT0sd(hobiG6r&8d(y)13#> zO&vAgD+`{6GvQw=S4b7E>uN||EhV~V8x<#XgvELY+d9|t;D zRoDXDN#e$cXwkCN<2Zoq&iv1~@Z#e+yaRh<+*%x7r~WEZw8V;J15dx^v&S(qGUDta zP8lC-Vq%V|Ox5HUz_a7MAr}f5Kp&xh zSif3u4*ju*wubMorlKX;lsM>($IHTe$)VZ?f@)FpKjnNWu~&*D7NPp)5{j)~#EOWg zeIWBr{?~p=xG=To+dbrY1Yy0TMIH*}|CsmR{&eSO(0M#F)jZ&$LHF_9shAp~6nV zE(}|sDY1tfd5hLh58L6iP&uP?-SF%{HtQ}MgDI|%o}$jizNoPzKx@BsPAi96-I~>l z)3PP^Qye8uU^PjI{QhuC=K+50w>lG2>C z0F@GFf}Z?{!mMN|qOqOm9B;soHM)#vGC!^Z(N$!UC&9;oe)-&bfHsUt>e6bgkFzD>_#SM*W?1Lp%A ztdO-86>=#BBuLQlu>j&g=&2Ypxj`vRo0hxuz}4<^gc*7C&?lkXNmkGRPh)R*Qrf@6lVw(M+e@@G^o>JN-wHQGZ&sVY>WNU+v?MD ziM>sFkeMVxr4Yw#{-m}Dl7Qq&^N67I!e7A^&~~}y&$) z^;HY!tw?tYget80-l9QjB!<}X*Tu>HfHJcr!KXV8>d+&L><}&omAlLs?E^Jw)sRBJ z(MjuZSk3?}l@t*ej)Awt_{}A3P<>yyJ=pZu`9R*VRv6uZR;=%?GW(2y9$C~`tpb($ zs^U%(Y2_=tQ(vyb$mMDk1(Hi?{ngP;!Y+`M(`43UYuh?vbX;Ar4(g>FvK!*~^KnJd z^Ci%o;V-~gV}~#OGcBVyVHf>VV5tz;oFbSA!#o;fNr1x8m)KbrP8&q=>?TL}DdN1L zb-zeL6kG0KKFA20($tdHDdk?H`7DN{q8sctCP}V&#uKTF=YI!vHJ{ho2@rXLuhCwW zM_SMo4xS~PIZV#8ET&!W7pDbf=G==;(l$wR%c0GMd*0t*z#$gXH(%zSlh<+vAn7Bi z6Zn+0zrvNLGX3d~2>$gKAYUP#%1rtmGgK@RoEJRo$FWM~-hzu=yFy8$3e zBE~lWa+BKVKU{oAOedU-c=RTx(&Edwiho>|UunwxoN!5wN^j$VYq?@^+3Of0O@)Je z>fK-b23eSJIQr^d=H}0IGN{DCn@KRUAukZ;m~L-`Dn-!c?eok39wx$#L^l8Z7tm-! z2RN9yK*B>}5Z~__NTkvnoWztnkEHCHgyZAS*hF|7nQCT+>h(n@L*>m4XMcV`{2A>>v9}~;pR@3&ew$g zLJ|jL{+J^HfO1^%LI+ zQj%A7LVce2BTW`zUGNEAxY-AuZTt6NXcLz=Mx%`9eFPH=eDMTw$t+5)E{eMiq7iQF zYvlh-Kb=RhxhH%k-b$*BoYeN?3MsSIur;P=!ZQ;$>jUmvTS<9|(w5&uyWr+>!NnAg z4}kiMSr8qRzCV7Jh#ha}oSGr^A}7m^g>EoK2rJKInsF^*K0dT3kR~?Ima*a4XM4Z0 z2*HMPHmSP%kjB%y@5KJ#SkYehE@hRvphe$-_qdSkJ*w&r9nC%Ht{DLD2O!*(#iP%T zLSXFDF*ugxrWN=2%pw*-E`_=p;T%oaX)PbJisr|vL8wU`wgYY>l9Gk_svZ#(Y+<+EU%PNQh`!`yB%LsD~@uJ%|y~qk~Su@S8YLz9%hU z7umR&YvQm1(_6nu{QA+r9_dXw<r9rC+ndm8lsMs1vKK*tZ?oT)WLz16FndZZylp z;p(c;Q{Wc7TtnVrUwh%BSjQGbt96Ii*~4rt`&6iw3kDP*nnP-kWW5h{*C*}&^ZR&y z6@+4eWF-~QvVd0E3H8Uk(QZr7w-mSWaz?a*KB;@@dPx*jfhTe4J81_?bW9- zzI(GE^dm_C@Hi2T*@&-FxP52~hBlr&{spIJF2s3J!N$0EF2P(6!L?%keP5{vH?JYl!{OsdnwQ zOluvr2nFn4YJEos;O-*$Gk8m9_yvC=n(K4X^~nM`A3+Z^y&w&Id@br%Ezt~toG`DP zhbbNb?tdQm5XEZxNTl>cO3C6&N)7%z{siL0S-3zu+fiMQ6Ldg2^@ml2;F26Y`@FRS z)IhnW<#&jvG$El2@X(AbsWLw`zz|a)Mo5&l&cQ5#<(mRK|WM|$dTwM=9qF0eO)Yxvq0lh5DmVC4Y~!j z;x2@gnoiUj1N_L`1s#cQTb#Xx&_L)?ZDJ@B=rI+3O*oz{_)>^y0}N{cc4aLRb@cPx z&Oa%%6R5dT(5~%86wRn*S>k<%S&}VG^m?UU5_=WEyF^+(2~I7pqQ;n{;^uz=w3vlt z(06?BN-3OQ7p`(cfHbHYvT8aNBcvo{65Y%3eJbbHMuyCgCap7SRH*W@laHd$F^^Dn zdz?Gu^jF(;eq-vurrlCntw|zW67u6`r_q_Tz$cILEQw5PqM6(+48h>P(UV{?HPVY`8#vZoQNc{0c><}ycLdh3AYw)Fxn0ljT#zN zdHsVRgAd4So<2OLnW&+qDW1s-OGyTLMWZ55f46FSSk~w?kgxkCPMcGUY@i||F*k;IQg8;h1xIQuX4(!Al zM!wjhOi){KqCu>XJec9M_8LsszwMS+%QzGi5+WgGMVRas_ufRZ5K_TT@MZEcL^IW1 zotaG4!PKEd%QX!U5K~;Qq$OND2al}m#PR~7#vp8kB0~`X+JS+`owTwTk#yKY@Xdym zCi03pp>b}$N5PPi5S{eYi(o1>G$-&V|LolRaMA?Yu8f7yYXqQ#T$;t}rNq?0W&;ss zY_M6A3+*$8WbW*)8SNyHS(oi6j-H7u2R}DC9F>&_f}MQC%xn6A@2j7$DXUBm74#xI z#>^#GdNzfR=1sdUB!VLi1b6T)8j(0>XAz-V=958QQqw8!augbnUL8fV*);_ulMWv_ zP>p`Y%vs%uC#mDnn3SF{qWjE-6b3UpP)b05po6cHVYN7VU8!*$AbzCj56P*>f)66* zK$FHncp*x47xa4|7Xb!bkG5s&V+n zrB69GbCMy140Kr*PENi`1skd%&u5`+AHEl_QQ*BpL7cbo?A1}P$@s~rZk=9S(Cd@8 zAe}m4wTt|P=39H?RVsb7n@neEqYAj3{vPnt+IAzE(VB1E2lr#>N8{+sU_-&MsO74N z3zhJiBrAc9$~7MI9v8HJCtT-w?hl%WfKR@>p<1aP*0=8kbBNv0SH%++_=&k)Io}d^ zQ54*s_5`{xDm*SQEO`Erw%>6#`}|vIa*)!Y(QNMW4XlsQ?o3$tXw%zjzjqpCM*V&% z>$Xxk#RkoG;M>eMsJ3tjU#G9U11iLK;M`f)J+z~!dH;K(iT2TM>c9;31YWqIh!Co6 z;N{}0g|}iA=|NAZX)$B*?G~4GOGz$nxD2YjSNLWW;6 z9LtcftC9 zIW=MQc0m*gS_Z(uqmlYf&HD%-eJ1sV!-*|bG;LuSQT5gnjh_@okXM5u|Gl6Tl>BPWXl zEy-Tld$16JDmA?L2Wp=K?Q4%*l(vwb^6wxvbk1H4I8wv^>FSC^+r`Xy$2*FnVmRn3 z4$D-i$*jg~NYpUnQX6SK(AmNIC*@S0Do{dOS+OyN!3Y(|+zC=HrDR%`joY%DFHml_ zL2&HIpo`$t6&=E;a`BPrUik~)or5S~YGw7D>q)Cr2--QV??9A$V}!!2KAm^TkriLs zBfDCq?uK3)aW<|b=jAkqaRzOWoVq#F5wtBPD`Y{DB%+X0Ts~4Nx?E#XGsu2T$}uEg z^&!KC$1}(B5{6w*W3gtn&d2mEj4e7HsTGj|vG^iGSH~m*{xpS;Yyxv%Y4$&GLa7Rs zBu#Kc9B^zd%`jBSunfeq=6OR5=KWB7+2~!=YT^)-Q6h<0d6-mv$|*BXv8x8Gu7k4EoXGg&<oOMjk|;Vc6Pw_4BUA@1R-ifwjg0gES0+? z3pOw0mB#-g1SjMEJwD1iW8;yqCF|Tw-Ae-0m181wd4aAXOx+uFmi9S}Y%S==m^l&n zfTx4&9qeK~7fvp=Hl=cvW#$jNQDhN$T4e}f{a}EZXr$!~O~%NSt4?ifR578n+imDO zJg52+(OXXCjC!-p@bG#-uMu_<6ULibniULr;tjmTL+0{)AA|wfn&X~xR9PPF05)$vD;=xYovt?8bfo3aTVBK! z)XJ>#CxYq7N9IrjTm*EL*SBz0^irH2Q$&g>RO4SGa!De{(vYdis93>^+}zCKW^|Ss z^Kb@P=GRo*)eQuRVOYuXzZpZKBQzjEQOCzJnxX0i`wc5}<{@+M$>C@Q0{e9~&64=x zZ1j}KW5#S)73bLj_&Z|W{AlQ2N51;g(JfkdT=Wx_8RFqRl27|4U(uNfn+uYgVYee5 zSdatMUDrol5iywPWy4(xX*>?Hm^YWK)tLLdi8YlH71fM|I?E`gy96lXH2;lONmu`D zETLEa9*7%&9UGmUvTChtm9wBUYxO**u<6HZHK@otg6i}W>&)ZvFW}42H+`rR?n!Z1 zdID`W2HT*i6&advw#3J#h7=zg^Ay_iGjsqV<(}e0X84~jbZ&HntFVIA&S5=w2rp(f z&6jbJGMNTg2^r*g`+%}?&v1c$AbG(*u7kL_GP;IrZ1{`|lOx}1Jpo`GSGbxoa;&V0 z)sD|$k45jbeQZD=$ee%BBJCHQf*Ru;_!7Lm`(sjp4nGf`s=1lO>z6AHXFl+E$c5Iw zw7+Qhjt_313b-nCs7ZX`l!tWV(pGW+IiwH9m2}&cq?ipp1Mb(AlZ=xdft4dbMB1D< z;m2;UrQZOkN)Qx-%yR8RBzf^+$?E7YQn#=!HeZI$k+r!6=6qvj9^w{2 zxZ?~q9&B|LKS@IYU%PxRKhg*xY9PAN>m=>Qn#910(9OP3JUj-58ZNEK9uei0oec5154qQz+E zXRkNpKH*#8DE6%AuLj4Yi1tddhIOXV%`gLVPrl5yuzTnTPFO`hrk0l@8f*(^t^bD*7H0gie0cL05FE8y#j?}%p4dwuURN=H zisq`cPo4b(EO+tK@O!tOD%X4TR!8%Kq4oBh&dY~KB6(w=o3v@=HCASD@FwG5Q<-$KDQyRZ-ZW#|e}|0XazpMJt-?QH}# zWy0FF-5~AB#GyiZ>G1A%*dHPy3K4UyDv@@>Wqc^urT1bE#Yn~p9gxa8{tNi~2LJ;6 GUHyNZv6#^S literal 0 HcmV?d00001 diff --git a/saraWhatsUp/saraWhatsUp/Base.lproj/LaunchScreen.storyboard b/saraWhatsUp/saraWhatsUp/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/saraWhatsUp/saraWhatsUp/Base.lproj/Main.storyboard b/saraWhatsUp/saraWhatsUp/Base.lproj/Main.storyboard new file mode 100644 index 0000000..25a7638 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/saraWhatsUp/saraWhatsUp/GoogleService-Info.plist b/saraWhatsUp/saraWhatsUp/GoogleService-Info.plist new file mode 100644 index 0000000..cbdac23 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/GoogleService-Info.plist @@ -0,0 +1,34 @@ + + + + + CLIENT_ID + 715372563006-ncrs30hrt18bss2mhci011723e4juads.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.715372563006-ncrs30hrt18bss2mhci011723e4juads + API_KEY + AIzaSyDAgoHWOWj6s6Zqk6OFPNHXYBE-i3LPQoQ + GCM_SENDER_ID + 715372563006 + PLIST_VERSION + 1 + BUNDLE_ID + com.sara-alzhrani.saraWhatsUp + PROJECT_ID + sarachat-664cd + STORAGE_BUCKET + sarachat-664cd.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:715372563006:ios:2ccc980bb50f2d2557df6f + + \ No newline at end of file diff --git a/saraWhatsUp/saraWhatsUp/Info.plist b/saraWhatsUp/saraWhatsUp/Info.plist new file mode 100644 index 0000000..dd3c9af --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/Info.plist @@ -0,0 +1,25 @@ + + + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/saraWhatsUp/saraWhatsUp/SceneDelegate.swift b/saraWhatsUp/saraWhatsUp/SceneDelegate.swift new file mode 100644 index 0000000..c5f5522 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/SceneDelegate.swift @@ -0,0 +1,80 @@ +// +// SceneDelegate.swift +// saraWhatsUp +// +// Created by sara al zhrani on 23/03/1443 AH. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate, UITabBarControllerDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + + guard let windowScene = (scene as? UIWindowScene) else { return } + window?.windowScene = windowScene + window?.makeKeyAndVisible() + + let tabBar = UITabBarController() + + let profile = UINavigationController(rootViewController: ProfileController()) + profile.tabBarItem.title = "Profile" + profile.tabBarItem.image = UIImage(systemName: "person")! + + let home = UINavigationController(rootViewController: MessagesController()) + home.tabBarItem.title = "Chat" + home.tabBarItem.image = UIImage(systemName: "message")! + + tabBar.delegate = self + tabBar.viewControllers = [home,profile] + + tabBar.selectedIndex = 0 + tabBar.tabBar.tintColor = .blue + tabBar.tabBar.backgroundColor = .white + tabBar.tabBar.layer.shadowColor = UIColor.black.cgColor + tabBar.tabBar.layer.shadowOpacity = 0.3 + tabBar.tabBar.layer.shadowOffset = .zero + tabBar.tabBar.layer.shadowRadius = 1 + window?.windowScene = windowScene + window?.makeKeyAndVisible() + window?.rootViewController = tabBar + +// let Controller = MessagesController() +// let navController = UINavigationController(rootViewController: Controller) +// window?.rootViewController = navController + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + diff --git a/saraWhatsUp/saraWhatsUp/controller/ChatLogController.swift b/saraWhatsUp/saraWhatsUp/controller/ChatLogController.swift new file mode 100644 index 0000000..dfba9ec --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/controller/ChatLogController.swift @@ -0,0 +1,320 @@ +// +// ChatLogController.swift + +// saraWhatsUp +// +// Created by sara al zhrani on 26/03/1443 AH. + + + +import UIKit +import Firebase + +class ChatLogController: UICollectionViewController, UITextFieldDelegate, UICollectionViewDelegateFlowLayout { + + var user: User? { + didSet { + navigationItem.title = user?.name + + observeMessages() + } + } + + var messages = [Message]() + + func observeMessages() { + guard let uid = Auth.auth().currentUser?.uid, let toId = user?.id else { + return + } + + let userMessagesRef = Database.database().reference().child("user-messages").child(uid).child(toId) + userMessagesRef.observe(.childAdded, with: { (snapshot) in + + let messageId = snapshot.key + let messagesRef = Database.database().reference().child("messages").child(messageId) + messagesRef.observeSingleEvent(of: .value, with: { (snapshot) in + + guard let dictionary = snapshot.value as? [String: AnyObject] else { + return + } + + let message = Message(dictionary: dictionary) + + //do we need to attempt filtering anymore? + self.messages.append(message) + DispatchQueue.main.async(execute: { + self.collectionView?.reloadData() + }) + + }, withCancel: nil) + + }, withCancel: nil) + } + + lazy var inputTextField: UITextField = { + let textField = UITextField() + textField.placeholder = "Enter message..." + textField.translatesAutoresizingMaskIntoConstraints = false + textField.delegate = self + return textField + }() + + let cellId = "cellId" + + override func viewDidLoad() { + super.viewDidLoad() + + collectionView?.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0) + collectionView?.alwaysBounceVertical = true + collectionView?.backgroundColor = UIColor.white + collectionView?.register(ChatMessageCell.self, forCellWithReuseIdentifier: cellId) + + collectionView?.keyboardDismissMode = .interactive + +// + } + + lazy var inputContainerView: UIView = { + let containerView = UIView() + containerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 50) + containerView.backgroundColor = UIColor.white + + let sendButton = UIButton(type: .system) + sendButton.setTitle("Send", for: UIControl.State()) + sendButton.translatesAutoresizingMaskIntoConstraints = false + sendButton.addTarget(self, action: #selector(handleSend), for: .touchUpInside) + containerView.addSubview(sendButton) + //x,y,w,h + sendButton.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true + sendButton.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true + sendButton.widthAnchor.constraint(equalToConstant: 80).isActive = true + sendButton.heightAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true + + containerView.addSubview(self.inputTextField) + + self.inputTextField.leftAnchor.constraint(equalTo: containerView.leftAnchor, constant: 8).isActive = true + self.inputTextField.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true + self.inputTextField.rightAnchor.constraint(equalTo: sendButton.leftAnchor).isActive = true + self.inputTextField.heightAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true + + let separatorLineView = UIView() + separatorLineView.backgroundColor = UIColor(r: 220, g: 220, b: 220) + separatorLineView.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(separatorLineView) + + separatorLineView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true + separatorLineView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true + separatorLineView.widthAnchor.constraint(equalTo: containerView.widthAnchor).isActive = true + separatorLineView.heightAnchor.constraint(equalToConstant: 1).isActive = true + + return containerView + }() + + override var inputAccessoryView: UIView? { + get { + return inputContainerView + } + } + + override var canBecomeFirstResponder : Bool { + return true + } + + func setupKeyboardObservers() { + NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + NotificationCenter.default.removeObserver(self) + } + + @objc func handleKeyboardWillShow(_ notification: Notification) { + let keyboardFrame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue + let keyboardDuration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as AnyObject).doubleValue + + containerViewBottomAnchor?.constant = -keyboardFrame!.height + UIView.animate(withDuration: keyboardDuration!, animations: { + self.view.layoutIfNeeded() + }) + } + + @objc func handleKeyboardWillHide(_ notification: Notification) { + let keyboardDuration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as AnyObject).doubleValue + + containerViewBottomAnchor?.constant = 0 + UIView.animate(withDuration: keyboardDuration!, animations: { + self.view.layoutIfNeeded() + }) + } + + override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return messages.count + } + + override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ChatMessageCell + + let message = messages[indexPath.item] + cell.textView.text = message.text + + setupCell(cell, message: message) + + + cell.bubbleWidthAnchor?.constant = estimateFrameForText(message.text!).width + 32 + + return cell + } + + fileprivate func setupCell(_ cell: ChatMessageCell, message: Message) { + if let profileImageUrl = self.user?.profileImageUrl { + cell.profileImageView.loadImageUsingCacheWithUrlString(profileImageUrl) + } + + if message.fromId == Auth.auth().currentUser?.uid { + + cell.bubbleView.backgroundColor = ChatMessageCell.blueColor + cell.textView.textColor = UIColor.white + cell.profileImageView.isHidden = true + + cell.bubbleViewRightAnchor?.isActive = true + cell.bubbleViewLeftAnchor?.isActive = false + + } else { + + cell.bubbleView.backgroundColor = UIColor(r: 240, g: 240, b: 240) + cell.textView.textColor = UIColor.black + cell.profileImageView.isHidden = false + + cell.bubbleViewRightAnchor?.isActive = false + cell.bubbleViewLeftAnchor?.isActive = true + } + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + collectionView?.collectionViewLayout.invalidateLayout() + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + + var height: CGFloat = 80 + + if let text = messages[indexPath.item].text { + height = estimateFrameForText(text).height + 20 + } + + let width = UIScreen.main.bounds.width + return CGSize(width: width, height: height) + } + + fileprivate func estimateFrameForText(_ text: String) -> CGRect { + let size = CGSize(width: 200, height: 1000) + let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin) + return NSString(string: text).boundingRect(with: size, options: options, attributes: convertToOptionalNSAttributedStringKeyDictionary([convertFromNSAttributedStringKey(NSAttributedString.Key.font): UIFont.systemFont(ofSize: 16)]), context: nil) + } + + var containerViewBottomAnchor: NSLayoutConstraint? + + func setupInputComponents() { + let containerView = UIView() + containerView.backgroundColor = UIColor.white + containerView.translatesAutoresizingMaskIntoConstraints = false + + view.addSubview(containerView) + + + containerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true + + containerViewBottomAnchor = containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + containerViewBottomAnchor?.isActive = true + + containerView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true + containerView.heightAnchor.constraint(equalToConstant: 50).isActive = true + + let sendButton = UIButton(type: .system) + sendButton.setTitle("Send", for: UIControl.State()) + sendButton.translatesAutoresizingMaskIntoConstraints = false + sendButton.addTarget(self, action: #selector(handleSend), for: .touchUpInside) + containerView.addSubview(sendButton) + + sendButton.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true + sendButton.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true + sendButton.widthAnchor.constraint(equalToConstant: 80).isActive = true + sendButton.heightAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true + + containerView.addSubview(inputTextField) + + inputTextField.leftAnchor.constraint(equalTo: containerView.leftAnchor, constant: 8).isActive = true + inputTextField.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true + inputTextField.rightAnchor.constraint(equalTo: sendButton.leftAnchor).isActive = true + inputTextField.heightAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true + + let separatorLineView = UIView() + separatorLineView.backgroundColor = UIColor(r: 220, g: 220, b: 220) + separatorLineView.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(separatorLineView) + + separatorLineView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true + separatorLineView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true + separatorLineView.widthAnchor.constraint(equalTo: containerView.widthAnchor).isActive = true + separatorLineView.heightAnchor.constraint(equalToConstant: 1).isActive = true + } + + @objc func handleSend() { + let ref = Database.database().reference().child("messages") + let childRef = ref.childByAutoId() + + let toId = user!.id! + let fromId = Auth.auth().currentUser!.uid + let timestamp = Int(Date().timeIntervalSince1970) + let values = ["text": inputTextField.text!, "toId": toId, "fromId": fromId, "timestamp": timestamp] as [String : Any] + + + childRef.updateChildValues(values) { (error, ref) in + if error != nil { + print(error!) + return + } + + self.inputTextField.text = nil + + guard let messageId = childRef.key else { return } + + let userMessagesRef = Database.database().reference().child("user-messages").child(fromId).child(toId).child(messageId) + userMessagesRef.setValue(1) + + let recipientUserMessagesRef = Database.database().reference().child("user-messages").child(toId).child(fromId).child(messageId) + recipientUserMessagesRef.setValue(1) + } + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + handleSend() + return true + } +} + + + + + + + + + + + + + + +fileprivate func convertToOptionalNSAttributedStringKeyDictionary(_ input: [String: Any]?) -> [NSAttributedString.Key: Any]? { + guard let input = input else { return nil } + return Dictionary(uniqueKeysWithValues: input.map { key, value in (NSAttributedString.Key(rawValue: key), value)}) +} + +fileprivate func convertFromNSAttributedStringKey(_ input: NSAttributedString.Key) -> String { + return input.rawValue +} diff --git a/saraWhatsUp/saraWhatsUp/controller/LoginController+handlers.swift b/saraWhatsUp/saraWhatsUp/controller/LoginController+handlers.swift new file mode 100644 index 0000000..6aa13dd --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/controller/LoginController+handlers.swift @@ -0,0 +1,118 @@ +// +// LoginController+handlers.swift +// saraWhatsUp +// +// Created by sara al zhrani on 24/03/1443 AH. +// + + +import UIKit +import Firebase + +extension LoginController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { + + func handleRegister() { + guard let email = emailTextField.text, let password = passwordTextField.text, let name = nameTextField.text else { + print("Form is not valid") + return + } + + Auth.auth().createUser(withEmail: email, password: password, completion: { (user, error) in + + if error != nil { + print(error!) + return + } + + guard let uid = user?.user.uid else { + return + } + + //successfully authenticated user + let imageName = UUID().uuidString + let storageRef = Storage.storage().reference().child("profile_images").child("\(imageName).jpg") + + if let profileImage = self.profileImageView.image, let uploadData = profileImage.jpegData(compressionQuality: 0.1) { + + storageRef.putData(uploadData, metadata: nil, completion: { (_, err) in + + if let error = error { + print(error) + return + } + + storageRef.downloadURL(completion: { (url, err) in + if let err = err { + print(err) + return + } + + guard let url = url else { return } + let values = ["name": name, "email": email, "profileImageUrl": url.absoluteString] + + self.registerUserIntoDatabaseWithUID(uid, values: values as [String : AnyObject]) + }) + + }) + } + }) + } + + fileprivate func registerUserIntoDatabaseWithUID(_ uid: String, values: [String: AnyObject]) { + let ref = Database.database().reference() + let usersReference = ref.child("users").child(uid) + + usersReference.updateChildValues(values, withCompletionBlock: { (err, ref) in + + if err != nil { + print(err!) + return + } + + let user = User(dictionary: values) + self.messagesController?.setupNavBarWithUser(user) + + self.dismiss(animated: true, completion: nil) + }) + } + + @objc func handleSelectProfileImageView() { + let picker = UIImagePickerController() + + picker.delegate = self + picker.allowsEditing = true + + present(picker, animated: true, completion: nil) + } + + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { +let info = convertFromUIImagePickerControllerInfoKeyDictionary(info) + + + var selectedImageFromPicker: UIImage? + + if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage { + selectedImageFromPicker = editedImage + } else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage { + + selectedImageFromPicker = originalImage + } + + if let selectedImage = selectedImageFromPicker { + profileImageView.image = selectedImage + } + + dismiss(animated: true, completion: nil) + + } + + func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { + print("canceled picker") + dismiss(animated: true, completion: nil) + } + +} + +fileprivate func convertFromUIImagePickerControllerInfoKeyDictionary(_ input: [UIImagePickerController.InfoKey: Any]) -> [String: Any] { + return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)}) +} diff --git a/saraWhatsUp/saraWhatsUp/controller/LoginController.swift b/saraWhatsUp/saraWhatsUp/controller/LoginController.swift new file mode 100644 index 0000000..6f5ae93 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/controller/LoginController.swift @@ -0,0 +1,249 @@ +// +// LoginController.swift +// saraWhatsUp +// +// Created by sara al zhrani on 23/03/1443 AH. +// +import UIKit +import Firebase + +class LoginController: UIViewController { + + var messagesController: MessagesController? + + let inputsContainerView: UIView = { + let view = UIView() + view.backgroundColor = UIColor.white + view.translatesAutoresizingMaskIntoConstraints = false + view.layer.cornerRadius = 5 + view.layer.masksToBounds = true + return view + }() + + lazy var loginRegisterButton: UIButton = { + let button = UIButton(type: .system) + button.backgroundColor = UIColor(r: 80, g: 101, b: 161) + button.setTitle("Register", for: UIControl.State()) + button.translatesAutoresizingMaskIntoConstraints = false + button.setTitleColor(UIColor.white, for: UIControl.State()) + button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16) + + button.addTarget(self, action: #selector(handleLoginRegister), for: .touchUpInside) + + return button + }() + + @objc func handleLoginRegister() { + if loginRegisterSegmentedControl.selectedSegmentIndex == 0 { + handleLogin() + } else { + handleRegister() + } + } + + func handleLogin() { + guard let email = emailTextField.text, let password = passwordTextField.text else { + print("Form is not valid") + return + } + + Auth.auth().signIn(withEmail: email, password: password, completion: { (user, error) in + + if error != nil { + print(error ?? "") + return + } + + + self.messagesController?.fetchUserAndSetupNavBarTitle() + + self.dismiss(animated: true, completion: nil) + + }) + + } + + let nameTextField: UITextField = { + let tf = UITextField() + tf.placeholder = "Name" + tf.translatesAutoresizingMaskIntoConstraints = false + return tf + }() + + let nameSeparatorView: UIView = { + let view = UIView() + view.backgroundColor = UIColor(r: 220, g: 220, b: 220) + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + let emailTextField: UITextField = { + let tf = UITextField() + tf.placeholder = "Email" + tf.translatesAutoresizingMaskIntoConstraints = false + return tf + }() + + let emailSeparatorView: UIView = { + let view = UIView() + view.backgroundColor = UIColor(r: 220, g: 220, b: 220) + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + let passwordTextField: UITextField = { + let tf = UITextField() + tf.placeholder = "Password" + tf.translatesAutoresizingMaskIntoConstraints = false + tf.isSecureTextEntry = true + return tf + }() + + lazy var profileImageView: UIImageView = { + let imageView = UIImageView() + imageView.image = UIImage(named: "logo") + imageView.translatesAutoresizingMaskIntoConstraints = false + imageView.contentMode = .scaleAspectFill + + imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectProfileImageView))) + imageView.isUserInteractionEnabled = true + + return imageView + }() + + lazy var loginRegisterSegmentedControl: UISegmentedControl = { + let sc = UISegmentedControl(items: ["Login", "Register"]) + sc.translatesAutoresizingMaskIntoConstraints = false + sc.tintColor = UIColor.white + sc.selectedSegmentIndex = 1 + sc.addTarget(self, action: #selector(handleLoginRegisterChange), for: .valueChanged) + return sc + }() + + @objc func handleLoginRegisterChange() { + let title = loginRegisterSegmentedControl.titleForSegment(at: loginRegisterSegmentedControl.selectedSegmentIndex) + loginRegisterButton.setTitle(title, for: UIControl.State()) + + inputsContainerViewHeightAnchor?.constant = loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 100 : 150 + + nameTextFieldHeightAnchor?.isActive = false + nameTextFieldHeightAnchor = nameTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 0 : 1/3) + nameTextFieldHeightAnchor?.isActive = true + nameTextField.isHidden = loginRegisterSegmentedControl.selectedSegmentIndex == 0 + + emailTextFieldHeightAnchor?.isActive = false + emailTextFieldHeightAnchor = emailTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 1/2 : 1/3) + emailTextFieldHeightAnchor?.isActive = true + + passwordTextFieldHeightAnchor?.isActive = false + passwordTextFieldHeightAnchor = passwordTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 1/2 : 1/3) + passwordTextFieldHeightAnchor?.isActive = true + } + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = UIColor(r: 61, g: 91, b: 151) + + view.addSubview(inputsContainerView) + view.addSubview(loginRegisterButton) + view.addSubview(profileImageView) + view.addSubview(loginRegisterSegmentedControl) + + setupInputsContainerView() + setupLoginRegisterButton() + setupProfileImageView() + setupLoginRegisterSegmentedControl() + } + + func setupLoginRegisterSegmentedControl() { + + loginRegisterSegmentedControl.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + loginRegisterSegmentedControl.bottomAnchor.constraint(equalTo: inputsContainerView.topAnchor, constant: -12).isActive = true + loginRegisterSegmentedControl.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor, multiplier: 1).isActive = true + loginRegisterSegmentedControl.heightAnchor.constraint(equalToConstant: 36).isActive = true + } + + func setupProfileImageView() { + + profileImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + profileImageView.bottomAnchor.constraint(equalTo: loginRegisterSegmentedControl.topAnchor, constant: -12).isActive = true + profileImageView.widthAnchor.constraint(equalToConstant: 150).isActive = true + profileImageView.heightAnchor.constraint(equalToConstant: 150).isActive = true + } + + var inputsContainerViewHeightAnchor: NSLayoutConstraint? + var nameTextFieldHeightAnchor: NSLayoutConstraint? + var emailTextFieldHeightAnchor: NSLayoutConstraint? + var passwordTextFieldHeightAnchor: NSLayoutConstraint? + + func setupInputsContainerView() { + + inputsContainerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + inputsContainerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true + inputsContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true + inputsContainerViewHeightAnchor = inputsContainerView.heightAnchor.constraint(equalToConstant: 150) + inputsContainerViewHeightAnchor?.isActive = true + + inputsContainerView.addSubview(nameTextField) + inputsContainerView.addSubview(nameSeparatorView) + inputsContainerView.addSubview(emailTextField) + inputsContainerView.addSubview(emailSeparatorView) + inputsContainerView.addSubview(passwordTextField) + + + nameTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true + nameTextField.topAnchor.constraint(equalTo: inputsContainerView.topAnchor).isActive = true + + nameTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true + nameTextFieldHeightAnchor = nameTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3) + nameTextFieldHeightAnchor?.isActive = true + + + nameSeparatorView.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true + nameSeparatorView.topAnchor.constraint(equalTo: nameTextField.bottomAnchor).isActive = true + nameSeparatorView.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true + nameSeparatorView.heightAnchor.constraint(equalToConstant: 1).isActive = true + + emailTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true + emailTextField.topAnchor.constraint(equalTo: nameTextField.bottomAnchor).isActive = true + + emailTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true + + emailTextFieldHeightAnchor = emailTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3) + + emailTextFieldHeightAnchor?.isActive = true + + emailSeparatorView.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true + emailSeparatorView.topAnchor.constraint(equalTo: emailTextField.bottomAnchor).isActive = true + emailSeparatorView.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true + emailSeparatorView.heightAnchor.constraint(equalToConstant: 1).isActive = true + + passwordTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true + passwordTextField.topAnchor.constraint(equalTo: emailTextField.bottomAnchor).isActive = true + + passwordTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true + passwordTextFieldHeightAnchor = passwordTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3) + passwordTextFieldHeightAnchor?.isActive = true + } + + func setupLoginRegisterButton() { + + loginRegisterButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + loginRegisterButton.topAnchor.constraint(equalTo: inputsContainerView.bottomAnchor, constant: 12).isActive = true + loginRegisterButton.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true + loginRegisterButton.heightAnchor.constraint(equalToConstant: 50).isActive = true + } + + override var preferredStatusBarStyle : UIStatusBarStyle { + return .lightContent + } +} + +extension UIColor { + + convenience init(r: CGFloat, g: CGFloat, b: CGFloat) { + self.init(red: r/255, green: g/255, blue: b/255, alpha: 1) + } + +} diff --git a/saraWhatsUp/saraWhatsUp/controller/MessagesController.swift b/saraWhatsUp/saraWhatsUp/controller/MessagesController.swift new file mode 100644 index 0000000..5cb14f7 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/controller/MessagesController.swift @@ -0,0 +1,290 @@ +// +// MessagesController.swift +// saraWhatsUp +// +// Created by sara al zhrani on 24/03/1443 AH. +// + +import UIKit +import Firebase +// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. +fileprivate func < (lhs: T?, rhs: T?) -> Bool { + switch (lhs, rhs) { + case let (l?, r?): + return l < r + case (nil, _?): + return true + default: + return false + } +} + +// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. + + +fileprivate func > (lhs: T?, rhs: T?) -> Bool { + switch (lhs, rhs) { + case let (l?, r?): + return l > r + default: + return rhs < lhs + } +} + + +class MessagesController: UITableViewController { + + let cellId = "cellId" + + override func viewDidLoad() { + super.viewDidLoad() + + navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(handleLogout)) + + let image = UIImage(named: "new_message_icon") + navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(handleNewMessage)) + + checkIfUserIsLoggedIn() + + tableView.register(UserCell.self, forCellReuseIdentifier: cellId) + + tableView.allowsMultipleSelectionDuringEditing = true + + +// observeMessages() + } + + + override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + + return true + } + + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { + guard let uid = Auth.auth().currentUser?.uid else { + return + } + let message = self.messages[indexPath.row] + + if let chatPartnerId = message.chatPartnerId() { + Database.database().reference().child("user-message").child(uid).child(chatPartnerId).removeValue (completionBlock: { (error, ref) in + + if error != nil { + print("filed to delet message", error) + return + + } + + self.messages.remove(at: indexPath.row) + self.tableView.deleteRows(at: [indexPath], with: .automatic) + + } + + )} + } + + + var messages = [Message]() + var messagesDictionary = [String: Message]() + + func observeUserMessages() { + guard let uid = Auth.auth().currentUser?.uid else { + return + } + + let ref = Database.database().reference().child("user-messages").child(uid) + ref.observe(.childAdded, with: { (snapshot) in + + let userId = snapshot.key + + print(uid, userId) + Database.database().reference().child("user-messages").child(uid).child(userId).observe(.childAdded, with: { (snapshot) in + + let messageId = snapshot.key + self.fetchMessageWithMessageId(messageId) + + }, withCancel: nil) + + }, withCancel: nil) + } + + fileprivate func fetchMessageWithMessageId(_ messageId: String) { + let messagesReference = Database.database().reference().child("messages").child(messageId) + + messagesReference.observeSingleEvent(of: .value, with: { (snapshot) in + + if let dictionary = snapshot.value as? [String: AnyObject] { + let message = Message(dictionary: dictionary) + + if let chatPartnerId = message.chatPartnerId() { + self.messagesDictionary[chatPartnerId] = message + } + + self.attemptReloadOfTable() + } + + }, withCancel: nil) + } + + fileprivate func attemptReloadOfTable() { + self.timer?.invalidate() + + self.timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.handleReloadTable), userInfo: nil, repeats: false) + } + + var timer: Timer? + + @objc func handleReloadTable() { + self.messages = Array(self.messagesDictionary.values) + self.messages.sort(by: { (message1, message2) -> Bool in + + return message1.timestamp?.int32Value > message2.timestamp?.int32Value + }) + + //this will crash because of background thread, so lets call this on dispatch_async main thread + DispatchQueue.main.async(execute: { + self.tableView.reloadData() + }) + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return messages.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! UserCell + + let message = messages[indexPath.row] + cell.message = message + + return cell + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 72 + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let message = messages[indexPath.row] + + guard let chatPartnerId = message.chatPartnerId() else { + return + } + + let ref = Database.database().reference().child("users").child(chatPartnerId) + ref.observeSingleEvent(of: .value, with: { (snapshot) in + guard let dictionary = snapshot.value as? [String: AnyObject] else { + return + } + + let user = User(dictionary: dictionary) + user.id = chatPartnerId + self.showChatControllerForUser(user) + + }, withCancel: nil) + } + + @objc func handleNewMessage() { + let newMessageController = NewMessageController() + newMessageController.messagesController = self + let navController = UINavigationController(rootViewController: newMessageController) + present(navController, animated: true, completion: nil) + } + + func checkIfUserIsLoggedIn() { + if Auth.auth().currentUser?.uid == nil { + perform(#selector(handleLogout), with: nil, afterDelay: 0) + } else { + fetchUserAndSetupNavBarTitle() + } + } + + func fetchUserAndSetupNavBarTitle() { + guard let uid = Auth.auth().currentUser?.uid else { + return + } + + Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in + + if let dictionary = snapshot.value as? [String: AnyObject] { +// self.navigationItem.title = dictionary["name"] as? String + + let user = User(dictionary: dictionary) + self.setupNavBarWithUser(user) + } + + }, withCancel: nil) + } + + func setupNavBarWithUser(_ user: User) { + messages.removeAll() + messagesDictionary.removeAll() + tableView.reloadData() + + observeUserMessages() + + let titleView = UIView() + titleView.frame = CGRect(x: 0, y: 0, width: 100, height: 40) + + + let containerView = UIView() + containerView.translatesAutoresizingMaskIntoConstraints = false + titleView.addSubview(containerView) + + let profileImageView = UIImageView() + profileImageView.translatesAutoresizingMaskIntoConstraints = false + profileImageView.contentMode = .scaleAspectFill + profileImageView.layer.cornerRadius = 20 + profileImageView.clipsToBounds = true + if let profileImageUrl = user.profileImageUrl { + profileImageView.loadImageUsingCacheWithUrlString(profileImageUrl) + } + + containerView.addSubview(profileImageView) + + + profileImageView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true + profileImageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true + profileImageView.widthAnchor.constraint(equalToConstant: 40).isActive = true + profileImageView.heightAnchor.constraint(equalToConstant: 40).isActive = true + + let nameLabel = UILabel() + + containerView.addSubview(nameLabel) + nameLabel.text = user.name + nameLabel.translatesAutoresizingMaskIntoConstraints = false + //need x,y,width,height anchors + nameLabel.leftAnchor.constraint(equalTo: profileImageView.rightAnchor, constant: 8).isActive = true + nameLabel.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor).isActive = true + nameLabel.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true + nameLabel.heightAnchor.constraint(equalTo: profileImageView.heightAnchor).isActive = true + + containerView.centerXAnchor.constraint(equalTo: titleView.centerXAnchor).isActive = true + containerView.centerYAnchor.constraint(equalTo: titleView.centerYAnchor).isActive = true + + self.navigationItem.titleView = titleView + +// titleView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(showChatController))) + } + + func showChatControllerForUser(_ user: User) { + let chatLogController = ChatLogController(collectionViewLayout: UICollectionViewFlowLayout()) + chatLogController.user = user + navigationController?.pushViewController(chatLogController, animated: true) + } + + @objc func handleLogout() { + + do { + try Auth.auth().signOut() + } catch let logoutError { + print(logoutError) + } + + let loginController = LoginController() + loginController.messagesController = self + present(loginController, animated: true, completion: nil) + } + +} + diff --git a/saraWhatsUp/saraWhatsUp/controller/NewMessageController.swift b/saraWhatsUp/saraWhatsUp/controller/NewMessageController.swift new file mode 100644 index 0000000..a55591f --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/controller/NewMessageController.swift @@ -0,0 +1,83 @@ +// +// NewMessageController.swift +// saraWhatsUp +// +// Created by sara al zhrani on 24/03/1443 AH. + + + + +import UIKit +import Firebase + +class NewMessageController: UITableViewController { + + let cellId = "cellId" + + var users = [User]() + + override func viewDidLoad() { + super.viewDidLoad() + + navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(handleCancel)) + + tableView.register(UserCell.self, forCellReuseIdentifier: cellId) + + fetchUser() + } + + func fetchUser() { + Database.database().reference().child("users").observe(.childAdded, with: { (snapshot) in + + if let dictionary = snapshot.value as? [String: AnyObject] { + let user = User(dictionary: dictionary) + user.id = snapshot.key + self.users.append(user) + + + DispatchQueue.main.async(execute: { + self.tableView.reloadData() + }) + + } + + }, withCancel: nil) + } + + @objc func handleCancel() { + dismiss(animated: true, completion: nil) + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return users.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! UserCell + + let user = users[indexPath.row] + cell.textLabel?.text = user.name + cell.detailTextLabel?.text = user.email + + if let profileImageUrl = user.profileImageUrl { + cell.profileImageView.loadImageUsingCacheWithUrlString(profileImageUrl) + } + + return cell + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 72 + } + + var messagesController: MessagesController? + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + dismiss(animated: true) { + print("Dismiss completed") + let user = self.users[indexPath.row] + self.messagesController?.showChatControllerForUser(user) + } + } + +} diff --git a/saraWhatsUp/saraWhatsUp/controller/ProfileController.swift b/saraWhatsUp/saraWhatsUp/controller/ProfileController.swift new file mode 100644 index 0000000..4424b4c --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/controller/ProfileController.swift @@ -0,0 +1,109 @@ +// +// ProfileController.swift +// saraWhatsUp +// + + +import UIKit +import Firebase +class ProfileController: UIViewController { + + lazy var image :UIImageView = { + let image = UIImageView() + image.layer.cornerRadius = 50 + image.layer.borderColor = UIColor.blue.cgColor + image.layer.borderWidth = 1 + image.translatesAutoresizingMaskIntoConstraints = false + return image + }() + lazy var text : UITextField = { + let text = UITextField() + text.placeholder = "Enter Your Bio" + text.textAlignment = .center + text.translatesAutoresizingMaskIntoConstraints = false + return text + }() + lazy var name : UILabel = { + let text = UILabel() + text.font = .boldSystemFont(ofSize: 15) + text.textColor = .blue + text.translatesAutoresizingMaskIntoConstraints = false + return text + }() + lazy var saveButton : UIButton = { + let button = UIButton() + button.tintColor = .white + button.backgroundColor = .blue + button.layer.cornerRadius = 25 + button.setTitle("Save", for: .normal) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + setup() + view.backgroundColor = .white + checkIfUserIsLoggedIn() + + } + func setup() { + + view.addSubview(image) + view.addSubview(name) + view.addSubview(text) + view.addSubview(saveButton) + + image.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + image.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true + image.widthAnchor.constraint(equalToConstant: 100).isActive = true + image.heightAnchor.constraint(equalToConstant: 100).isActive = true + + name.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50).isActive = true + name.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 50).isActive = true + name.topAnchor.constraint(equalTo: image.bottomAnchor, constant: 20).isActive = true + + text.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50).isActive = true + text.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 50).isActive = true + text.topAnchor.constraint(equalTo: name.bottomAnchor, constant: 50).isActive = true + + + saveButton.topAnchor.constraint(equalTo: text.bottomAnchor, constant: 50).isActive = true + saveButton.heightAnchor.constraint(equalToConstant: 50).isActive = true + saveButton.widthAnchor.constraint(equalToConstant: 200).isActive = true + saveButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + } + + + func checkIfUserIsLoggedIn() { + if !(Auth.auth().currentUser?.uid == nil) { + fetchUserAndSetupNavBarTitle() + } + } + func fetchUserAndSetupNavBarTitle() { + guard let uid = Auth.auth().currentUser?.uid else { + //for some reason uid = nil + return + } + + Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in + + if let dictionary = snapshot.value as? [String: AnyObject] { + // self.navigationItem.title = dictionary["name"] as? String + + let user = User(dictionary: dictionary) + self.setupNavBarWithUser(user) + } + + }, withCancel: nil) + } + func setupNavBarWithUser(_ user: User) { + + if let profileImageUrl = user.profileImageUrl { + image.loadImageUsingCacheWithUrlString(profileImageUrl) + } + name.text = user.name + let nameLabel = UILabel() + } + +} diff --git a/saraWhatsUp/saraWhatsUp/controller/UserCell.swift b/saraWhatsUp/saraWhatsUp/controller/UserCell.swift new file mode 100644 index 0000000..ee4af7e --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/controller/UserCell.swift @@ -0,0 +1,95 @@ +// +// UserCell.swift +// saraWhatsUp +// +// Created by sara al zhrani on 25/03/1443 AH. +import UIKit +import Firebase + + +class UserCell: UITableViewCell { + + var message: Message? { + didSet { + setupNameAndProfileImage() + + detailTextLabel?.text = message?.text + + if let seconds = message?.timestamp?.doubleValue { + let timestampDate = Date(timeIntervalSince1970: seconds) + + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "hh:mm:ss a" + timeLabel.text = dateFormatter.string(from: timestampDate) + } + + + } + } + + fileprivate func setupNameAndProfileImage() { + + if let id = message?.chatPartnerId() { + let ref = Database.database().reference().child("users").child(id) + ref.observeSingleEvent(of: .value, with: { (snapshot) in + + if let dictionary = snapshot.value as? [String: AnyObject] { + self.textLabel?.text = dictionary["name"] as? String + + if let profileImageUrl = dictionary["profileImageUrl"] as? String { + self.profileImageView.loadImageUsingCacheWithUrlString(profileImageUrl) + } + } + + }, withCancel: nil) + } + } + + override func layoutSubviews() { + super.layoutSubviews() + + textLabel?.frame = CGRect(x: 64, y: textLabel!.frame.origin.y - 2, width: textLabel!.frame.width, height: textLabel!.frame.height) + + detailTextLabel?.frame = CGRect(x: 64, y: detailTextLabel!.frame.origin.y + 2, width: detailTextLabel!.frame.width, height: detailTextLabel!.frame.height) + } + + let profileImageView: UIImageView = { + let imageView = UIImageView() + imageView.translatesAutoresizingMaskIntoConstraints = false + imageView.layer.cornerRadius = 24 + imageView.layer.masksToBounds = true + imageView.contentMode = .scaleAspectFill + return imageView + }() + + let timeLabel: UILabel = { + let label = UILabel() + label.font = UIFont.systemFont(ofSize: 13) + label.textColor = UIColor.darkGray + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: .subtitle, reuseIdentifier: reuseIdentifier) + + addSubview(profileImageView) + addSubview(timeLabel) + + + profileImageView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 8).isActive = true + profileImageView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true + profileImageView.widthAnchor.constraint(equalToConstant: 48).isActive = true + profileImageView.heightAnchor.constraint(equalToConstant: 48).isActive = true + + timeLabel.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true + timeLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 18).isActive = true + timeLabel.widthAnchor.constraint(equalToConstant: 100).isActive = true + timeLabel.heightAnchor.constraint(equalTo: (textLabel?.heightAnchor)!).isActive = true + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} diff --git a/saraWhatsUp/saraWhatsUp/controller/ViewController.swift b/saraWhatsUp/saraWhatsUp/controller/ViewController.swift new file mode 100644 index 0000000..b8163e5 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/controller/ViewController.swift @@ -0,0 +1,58 @@ +// +// ViewController.swift +// saraWhatsUp +// +// Created by sara al zhrani on 23/03/1443 AH. +// + +import UIKit +import Firebase + +class ViewController: UITableViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(handleLogout)) + + let image = UIImage(named: "new_message_icon") + navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(handleNewMessage)) + + checkIfUserIsLoggedIn() + } + + @objc func handleNewMessage() { + let newMessageController = NewMessageController() + let navController = UINavigationController(rootViewController: newMessageController) + present(navController, animated: true, completion: nil) + } + + func checkIfUserIsLoggedIn() { + if Auth.auth().currentUser?.uid == nil { + perform(#selector(handleLogout), with: nil, afterDelay: 0) + } else { + let uid = Auth.auth().currentUser?.uid + Database.database().reference().child("users").child(uid!).observeSingleEvent(of: .value, with: { (snapshot) in + + if let dictionary = snapshot.value as? [String: AnyObject] { + self.navigationItem.title = dictionary["name"] as? String + } + + }, withCancel: nil) + } + } + + @objc func handleLogout() { + + do { + try Auth.auth().signOut() + } catch let logoutError { + print(logoutError) + } + + let loginController = LoginController() + present(loginController, animated: true, completion: nil) + } + +} + diff --git a/saraWhatsUp/saraWhatsUp/model/ChatMessageCell.swift b/saraWhatsUp/saraWhatsUp/model/ChatMessageCell.swift new file mode 100644 index 0000000..14d037a --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/model/ChatMessageCell.swift @@ -0,0 +1,92 @@ +// +// ChatMessageCell.swift +// saraWhatsUp +// +// Created by sara al zhrani on 26/03/1443 AH. +// + + + +import UIKit + +class ChatMessageCell: UICollectionViewCell { + + let textView: UITextView = { + let tv = UITextView() + tv.text = "SAMPLE TEXT FOR NOW" + tv.font = UIFont.systemFont(ofSize: 16) + tv.translatesAutoresizingMaskIntoConstraints = false + tv.backgroundColor = UIColor.clear + tv.textColor = .white + return tv + }() + + static let blueColor = UIColor(r: 0, g: 137, b: 249) + + let bubbleView: UIView = { + let view = UIView() + view.backgroundColor = blueColor + view.translatesAutoresizingMaskIntoConstraints = false + view.layer.cornerRadius = 16 + view.layer.masksToBounds = true + return view + }() + + let profileImageView: UIImageView = { + let imageView = UIImageView() + imageView.image = UIImage(named: "nedstark") + imageView.translatesAutoresizingMaskIntoConstraints = false + imageView.layer.cornerRadius = 16 + imageView.layer.masksToBounds = true + imageView.contentMode = .scaleAspectFill + return imageView + }() + + var bubbleWidthAnchor: NSLayoutConstraint? + var bubbleViewRightAnchor: NSLayoutConstraint? + var bubbleViewLeftAnchor: NSLayoutConstraint? + + override init(frame: CGRect) { + super.init(frame: frame) + + addSubview(bubbleView) + addSubview(textView) + addSubview(profileImageView) + + profileImageView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 8).isActive = true + profileImageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + profileImageView.widthAnchor.constraint(equalToConstant: 32).isActive = true + profileImageView.heightAnchor.constraint(equalToConstant: 32).isActive = true + + + bubbleViewRightAnchor = bubbleView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -8) + + bubbleViewRightAnchor?.isActive = true + + bubbleViewLeftAnchor = bubbleView.leftAnchor.constraint(equalTo: profileImageView.rightAnchor, constant: 8) + + + bubbleView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + + bubbleWidthAnchor = bubbleView.widthAnchor.constraint(equalToConstant: 200) + bubbleWidthAnchor?.isActive = true + + bubbleView.heightAnchor.constraint(equalTo: self.heightAnchor).isActive = true + + + + textView.leftAnchor.constraint(equalTo: bubbleView.leftAnchor, constant: 8).isActive = true + textView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + + textView.rightAnchor.constraint(equalTo: bubbleView.rightAnchor).isActive = true + + + + textView.heightAnchor.constraint(equalTo: self.heightAnchor).isActive = true + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} diff --git a/saraWhatsUp/saraWhatsUp/model/Extensions.swift b/saraWhatsUp/saraWhatsUp/model/Extensions.swift new file mode 100644 index 0000000..cbcfdce --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/model/Extensions.swift @@ -0,0 +1,43 @@ +// +// Extensions.swift +// saraWhatsUp +// +// Created by sara al zhrani on 25/03/1443 AH. +// + +import UIKit + +let imageCache = NSCache() + +extension UIImageView { + + func loadImageUsingCacheWithUrlString(_ urlString: String) { + + self.image = nil + + if let cachedImage = imageCache.object(forKey: urlString as AnyObject) as? UIImage { + self.image = cachedImage + return + } + + let url = URL(string: urlString) + URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in + + if error != nil { + print(error ?? "") + return + } + + DispatchQueue.main.async(execute: { + + if let downloadedImage = UIImage(data: data!) { + imageCache.setObject(downloadedImage, forKey: urlString as AnyObject) + + self.image = downloadedImage + } + }) + + }).resume() + } + +} diff --git a/saraWhatsUp/saraWhatsUp/model/Message.swift b/saraWhatsUp/saraWhatsUp/model/Message.swift new file mode 100644 index 0000000..ab7e299 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/model/Message.swift @@ -0,0 +1,28 @@ +// +// Message.swift +// saraWhatsUp +// +// Created by sara al zhrani on 25/03/1443 AH. +// +import UIKit +import Firebase + +class Message: NSObject { + + var fromId: String? + var text: String? + var timestamp: NSNumber? + var toId: String? + + init(dictionary: [String: Any]) { + self.fromId = dictionary["fromId"] as? String + self.text = dictionary["text"] as? String + self.toId = dictionary["toId"] as? String + self.timestamp = dictionary["timestamp"] as? NSNumber + } + + func chatPartnerId() -> String? { + return fromId == Auth.auth().currentUser?.uid ? toId : fromId + } + +} diff --git a/saraWhatsUp/saraWhatsUp/model/TabController.swift b/saraWhatsUp/saraWhatsUp/model/TabController.swift new file mode 100644 index 0000000..64f96e2 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/model/TabController.swift @@ -0,0 +1,8 @@ +// +// TabController.swift +// saraWhatsUp +// +// Created by sara al zhrani on 26/03/1443 AH. +// + +import Foundation diff --git a/saraWhatsUp/saraWhatsUp/model/User.swift b/saraWhatsUp/saraWhatsUp/model/User.swift new file mode 100644 index 0000000..386dfb0 --- /dev/null +++ b/saraWhatsUp/saraWhatsUp/model/User.swift @@ -0,0 +1,23 @@ +// +// User.swift +// saraWhatsUp +// +// Created by sara al zhrani on 24/03/1443 AH. +// + +import UIKit + + +class User: NSObject { + var id: String? + var name: String? + var email: String? + var profileImageUrl: String? + init(dictionary: [String: AnyObject]) { + self.id = dictionary["id"] as? String + self.name = dictionary["name"] as? String + self.email = dictionary["email"] as? String + self.profileImageUrl = dictionary["profileImageUrl"] as? String + } +} + From cdf0564e2c356c6403004febf2b0f8eb5496b61d Mon Sep 17 00:00:00 2001 From: sara al zhrani Date: Wed, 3 Nov 2021 09:21:57 +0300 Subject: [PATCH 2/3] change color --- .DS_Store | Bin 0 -> 6148 bytes .../controller/MessagesController.swift | 4 ++-- .../controller/ProfileController.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9ef6613a5ddedd1ebe9ff865c9ca761d54d909bf GIT binary patch literal 6148 zcmeHKyG{c^3>=dbkh10tSOA#O9r5mAY<})Ova8A%k zpEk$CoU z0CCE67}qgN5Su56y>LimhGt16Ce>=hu%t8Js;(CfiAjgm@L~02s|m&8>Ab&1Ijkot zN&zWwuD~R>3-A9o^dIK`bCPyaKnnaT1#G(BtXF)c>aC-f^IqHNJG$3=(A~HW3PZGG kVzgs!yd5v2DC?T9dEN_$#Go@DbfSI+To;)X_-h3|0X8xf!T message2.timestamp?.int32Value }) - //this will crash because of background thread, so lets call this on dispatch_async main thread + DispatchQueue.main.async(execute: { self.tableView.reloadData() }) @@ -253,7 +253,7 @@ class MessagesController: UITableViewController { containerView.addSubview(nameLabel) nameLabel.text = user.name nameLabel.translatesAutoresizingMaskIntoConstraints = false - //need x,y,width,height anchors + nameLabel.leftAnchor.constraint(equalTo: profileImageView.rightAnchor, constant: 8).isActive = true nameLabel.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor).isActive = true nameLabel.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true diff --git a/saraWhatsUp/saraWhatsUp/controller/ProfileController.swift b/saraWhatsUp/saraWhatsUp/controller/ProfileController.swift index 4424b4c..a6a6b3f 100644 --- a/saraWhatsUp/saraWhatsUp/controller/ProfileController.swift +++ b/saraWhatsUp/saraWhatsUp/controller/ProfileController.swift @@ -33,7 +33,7 @@ class ProfileController: UIViewController { lazy var saveButton : UIButton = { let button = UIButton() button.tintColor = .white - button.backgroundColor = .blue + button.backgroundColor = UIColor(r: 80, g: 101, b: 161) button.layer.cornerRadius = 25 button.setTitle("Save", for: .normal) button.translatesAutoresizingMaskIntoConstraints = false From de374cbd8435f59950ca81f932a4054450aa2945 Mon Sep 17 00:00:00 2001 From: sara al zhrani Date: Fri, 12 Nov 2021 22:08:42 +0300 Subject: [PATCH 3/3] add new chat --- .../saraWhatsUp/{model => controller}/ChatMessageCell.swift | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename saraWhatsUp/saraWhatsUp/{model => controller}/ChatMessageCell.swift (100%) mode change 100644 => 100755 diff --git a/saraWhatsUp/saraWhatsUp/model/ChatMessageCell.swift b/saraWhatsUp/saraWhatsUp/controller/ChatMessageCell.swift old mode 100644 new mode 100755 similarity index 100% rename from saraWhatsUp/saraWhatsUp/model/ChatMessageCell.swift rename to saraWhatsUp/saraWhatsUp/controller/ChatMessageCell.swift