./.codecov.yml .clang-format .gitmodules .ruby-version Cartfile Cartfile.resolved Carthage/Checkouts/Bolts-ObjC Carthage/Checkouts/OCMock Carthage/Checkouts/facebook-ios-sdk Gemfile Gemfile.lock LICENSE PATENTS Parse.podspec Parse.xcworkspace/contents.xcworkspacedata Parse.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist Parse.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings Parse/Configurations/Parse-iOS-Dynamic.xcconfig Parse/Configurations/Parse-iOS.xcconfig Parse/Configurations/Parse-macOS.xcconfig Parse/Configurations/Parse-tvOS-Dynamic.xcconfig Parse/Configurations/Parse-tvOS.xcconfig Parse/Configurations/Parse-watchOS-Dynamic.xcconfig Parse/Configurations/Parse-watchOS.xcconfig Parse/Configurations/ParseUnitTests-iOS.xcconfig Parse/Configurations/ParseUnitTests-macOS.xcconfig Parse/Configurations/Shared Parse/Parse.xcodeproj/project.pbxproj Parse/Parse.xcodeproj/project.xcworkspace/contents.xcworkspacedata Parse/Parse.xcodeproj/xcshareddata/xcschemes/Parse-iOS-Dynamic.xcscheme Parse/Parse.xcodeproj/xcshareddata/xcschemes/Parse-iOS.xcscheme Parse/Parse.xcodeproj/xcshareddata/xcschemes/Parse-macOS.xcscheme Parse/Parse.xcodeproj/xcshareddata/xcschemes/Parse-tvOS-Dynamic.xcscheme Parse/Parse.xcodeproj/xcshareddata/xcschemes/Parse-tvOS.xcscheme Parse/Parse.xcodeproj/xcshareddata/xcschemes/Parse-watchOS-Dynamic.xcscheme Parse/Parse.xcodeproj/xcshareddata/xcschemes/Parse-watchOS.xcscheme Parse/Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.h Parse/Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.m Parse/Parse/Internal/ACL/PFACLPrivate.h Parse/Parse/Internal/ACL/State/PFACLState.h Parse/Parse/Internal/ACL/State/PFACLState.m Parse/Parse/Internal/ACL/State/PFACLState_Private.h Parse/Parse/Internal/ACL/State/PFMutableACLState.h Parse/Parse/Internal/ACL/State/PFMutableACLState.m Parse/Parse/Internal/Analytics/Controller/PFAnalyticsController.h Parse/Parse/Internal/Analytics/Controller/PFAnalyticsController.m Parse/Parse/Internal/Analytics/PFAnalytics_Private.h Parse/Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.h Parse/Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.m Parse/Parse/Internal/BFTask+Private.h Parse/Parse/Internal/BFTask+Private.m Parse/Parse/Internal/CloudCode/PFCloudCodeController.h Parse/Parse/Internal/CloudCode/PFCloudCodeController.m Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunning.h Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunning.m Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.h Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.m Parse/Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.h Parse/Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.m Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.h Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.m Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner_Private.h Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.h Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.m Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession_Private.h Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.h Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.m Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate_Private.h Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.h Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.m Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.h Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.m Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.h Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.m Parse/Parse/Internal/Commands/PFRESTAnalyticsCommand.h Parse/Parse/Internal/Commands/PFRESTAnalyticsCommand.m Parse/Parse/Internal/Commands/PFRESTCloudCommand.h Parse/Parse/Internal/Commands/PFRESTCloudCommand.m Parse/Parse/Internal/Commands/PFRESTCommand.h Parse/Parse/Internal/Commands/PFRESTCommand.m Parse/Parse/Internal/Commands/PFRESTCommand_Private.h Parse/Parse/Internal/Commands/PFRESTConfigCommand.h Parse/Parse/Internal/Commands/PFRESTConfigCommand.m Parse/Parse/Internal/Commands/PFRESTFileCommand.h Parse/Parse/Internal/Commands/PFRESTFileCommand.m Parse/Parse/Internal/Commands/PFRESTObjectBatchCommand.h Parse/Parse/Internal/Commands/PFRESTObjectBatchCommand.m Parse/Parse/Internal/Commands/PFRESTObjectCommand.h Parse/Parse/Internal/Commands/PFRESTObjectCommand.m Parse/Parse/Internal/Commands/PFRESTPushCommand.h Parse/Parse/Internal/Commands/PFRESTPushCommand.m Parse/Parse/Internal/Commands/PFRESTQueryCommand.h Parse/Parse/Internal/Commands/PFRESTQueryCommand.m Parse/Parse/Internal/Commands/PFRESTSessionCommand.h Parse/Parse/Internal/Commands/PFRESTSessionCommand.m Parse/Parse/Internal/Commands/PFRESTUserCommand.h Parse/Parse/Internal/Commands/PFRESTUserCommand.m Parse/Parse/Internal/Config/Controller/PFConfigController.h Parse/Parse/Internal/Config/Controller/PFConfigController.m Parse/Parse/Internal/Config/Controller/PFCurrentConfigController.h Parse/Parse/Internal/Config/Controller/PFCurrentConfigController.m Parse/Parse/Internal/Config/PFConfig_Private.h Parse/Parse/Internal/FieldOperation/PFFieldOperation.h Parse/Parse/Internal/FieldOperation/PFFieldOperation.m Parse/Parse/Internal/FieldOperation/PFFieldOperationDecoder.h Parse/Parse/Internal/FieldOperation/PFFieldOperationDecoder.m Parse/Parse/Internal/File/Controller/PFFileController.h Parse/Parse/Internal/File/Controller/PFFileController.m Parse/Parse/Internal/File/Controller/PFFileStagingController.h Parse/Parse/Internal/File/Controller/PFFileStagingController.m Parse/Parse/Internal/File/Controller/PFFileUploadResult.m Parse/Parse/Internal/File/FileDataStream/PFFileDataStream.h Parse/Parse/Internal/File/FileDataStream/PFFileDataStream.m Parse/Parse/Internal/File/PFFileObject_Private.h Parse/Parse/Internal/File/State/PFFileState.h Parse/Parse/Internal/File/State/PFFileState.m Parse/Parse/Internal/File/State/PFFileState_Private.h Parse/Parse/Internal/File/State/PFMutableFileState.h Parse/Parse/Internal/File/State/PFMutableFileState.m Parse/Parse/Internal/HTTPRequest/PFHTTPRequest.h Parse/Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.h Parse/Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.m Parse/Parse/Internal/HTTPRequest/PFURLConstructor.h Parse/Parse/Internal/HTTPRequest/PFURLConstructor.m Parse/Parse/Internal/Installation/Constants/PFInstallationConstants.h Parse/Parse/Internal/Installation/Constants/PFInstallationConstants.m Parse/Parse/Internal/Installation/Controller/PFInstallationController.h Parse/Parse/Internal/Installation/Controller/PFInstallationController.m Parse/Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.h Parse/Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.m Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.h Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.m Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore_Private.h Parse/Parse/Internal/Installation/PFInstallationPrivate.h Parse/Parse/Internal/KeyValueCache/PFKeyValueCache.h Parse/Parse/Internal/KeyValueCache/PFKeyValueCache.m Parse/Parse/Internal/KeyValueCache/PFKeyValueCache_Private.h Parse/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.h Parse/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.m Parse/Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.h Parse/Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.m Parse/Parse/Internal/LocalDataStore/Pin/PFPin.h Parse/Parse/Internal/LocalDataStore/Pin/PFPin.m Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.h Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.m Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.h Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.m Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.h Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.m Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase_Private.h Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.h Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.m Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.h Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.m Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.h Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.m Parse/Parse/Internal/Object/BatchController/PFObjectBatchController.h Parse/Parse/Internal/Object/BatchController/PFObjectBatchController.m Parse/Parse/Internal/Object/Coder/File/PFObjectFileCoder.h Parse/Parse/Internal/Object/Coder/File/PFObjectFileCoder.m Parse/Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.h Parse/Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.m Parse/Parse/Internal/Object/Constants/PFObjectConstants.h Parse/Parse/Internal/Object/Constants/PFObjectConstants.m Parse/Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.h Parse/Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.m Parse/Parse/Internal/Object/Controller/PFObjectController.h Parse/Parse/Internal/Object/Controller/PFObjectController.m Parse/Parse/Internal/Object/Controller/PFObjectController_Private.h Parse/Parse/Internal/Object/Controller/PFObjectControlling.h Parse/Parse/Internal/Object/CurrentController/PFCurrentObjectControlling.h Parse/Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.h Parse/Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.m Parse/Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.h Parse/Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.m Parse/Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.h Parse/Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.m Parse/Parse/Internal/Object/OperationSet/PFOperationSet.h Parse/Parse/Internal/Object/OperationSet/PFOperationSet.m Parse/Parse/Internal/Object/PFObjectPrivate.h Parse/Parse/Internal/Object/PinningStore/PFPinningObjectStore.h Parse/Parse/Internal/Object/PinningStore/PFPinningObjectStore.m Parse/Parse/Internal/Object/State/PFMutableObjectState.h Parse/Parse/Internal/Object/State/PFMutableObjectState.m Parse/Parse/Internal/Object/State/PFObjectState.h Parse/Parse/Internal/Object/State/PFObjectState.m Parse/Parse/Internal/Object/State/PFObjectState_Private.h Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.h Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.m Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.h Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m Parse/Parse/Internal/Object/Utilities/PFObjectUtilities.h Parse/Parse/Internal/Object/Utilities/PFObjectUtilities.m Parse/Parse/Internal/PFAlertView.h Parse/Parse/Internal/PFAlertView.m Parse/Parse/Internal/PFApplication.h Parse/Parse/Internal/PFApplication.m Parse/Parse/Internal/PFAssert.h Parse/Parse/Internal/PFAsyncTaskQueue.h Parse/Parse/Internal/PFAsyncTaskQueue.m Parse/Parse/Internal/PFBase64Encoder.h Parse/Parse/Internal/PFBase64Encoder.m Parse/Parse/Internal/PFBaseState.h Parse/Parse/Internal/PFBaseState.m Parse/Parse/Internal/PFCategoryLoader.h Parse/Parse/Internal/PFCategoryLoader.m Parse/Parse/Internal/PFCommandCache.h Parse/Parse/Internal/PFCommandCache.m Parse/Parse/Internal/PFCommandCache_Private.h Parse/Parse/Internal/PFCommandResult.h Parse/Parse/Internal/PFCommandResult.m Parse/Parse/Internal/PFCoreDataProvider.h Parse/Parse/Internal/PFCoreManager.h Parse/Parse/Internal/PFCoreManager.m Parse/Parse/Internal/PFDataProvider.h Parse/Parse/Internal/PFDateFormatter.h Parse/Parse/Internal/PFDateFormatter.m Parse/Parse/Internal/PFDevice.h Parse/Parse/Internal/PFDevice.m Parse/Parse/Internal/PFErrorUtilities.h Parse/Parse/Internal/PFErrorUtilities.m Parse/Parse/Internal/PFEventuallyPin.h Parse/Parse/Internal/PFEventuallyPin.m Parse/Parse/Internal/PFEventuallyQueue.h Parse/Parse/Internal/PFEventuallyQueue.m Parse/Parse/Internal/PFEventuallyQueue_Private.h Parse/Parse/Internal/PFFileManager.h Parse/Parse/Internal/PFFileManager.m Parse/Parse/Internal/PFGeoPointPrivate.h Parse/Parse/Internal/PFHash.h Parse/Parse/Internal/PFHash.m Parse/Parse/Internal/PFInternalUtils.h Parse/Parse/Internal/PFInternalUtils.m Parse/Parse/Internal/PFJSONSerialization.h Parse/Parse/Internal/PFJSONSerialization.m Parse/Parse/Internal/PFKeychainStore.h Parse/Parse/Internal/PFKeychainStore.m Parse/Parse/Internal/PFLocationManager.h Parse/Parse/Internal/PFLocationManager.m Parse/Parse/Internal/PFLogging.h Parse/Parse/Internal/PFMacros.h Parse/Parse/Internal/PFMemoryEventuallyQueue.h Parse/Parse/Internal/PFMemoryEventuallyQueue.m Parse/Parse/Internal/PFMulticastDelegate.h Parse/Parse/Internal/PFMulticastDelegate.m Parse/Parse/Internal/PFNetworkCommand.h Parse/Parse/Internal/PFPinningEventuallyQueue.h Parse/Parse/Internal/PFPinningEventuallyQueue.m Parse/Parse/Internal/PFPolygonPrivate.h Parse/Parse/Internal/PFReachability.h Parse/Parse/Internal/PFReachability.m Parse/Parse/Internal/PFSystemLogger.h Parse/Parse/Internal/PFSystemLogger.m Parse/Parse/Internal/PFTaskQueue.h Parse/Parse/Internal/PFTaskQueue.m Parse/Parse/Internal/PFWeakValue.h Parse/Parse/Internal/PFWeakValue.m Parse/Parse/Internal/ParseClientConfiguration_Private.h Parse/Parse/Internal/ParseInternal.h Parse/Parse/Internal/ParseManager.h Parse/Parse/Internal/ParseManager.m Parse/Parse/Internal/ParseManagerPrivate.h Parse/Parse/Internal/ParseModule.h Parse/Parse/Internal/ParseModule.m Parse/Parse/Internal/Parse_Private.h Parse/Parse/Internal/Persistence/Group/PFFilePersistenceGroup.h Parse/Parse/Internal/Persistence/Group/PFFilePersistenceGroup.m Parse/Parse/Internal/Persistence/Group/PFPersistenceGroup.h Parse/Parse/Internal/Persistence/Group/PFUserDefaultsPersistenceGroup.h Parse/Parse/Internal/Persistence/Group/PFUserDefaultsPersistenceGroup.m Parse/Parse/Internal/Persistence/PFPersistenceController.h Parse/Parse/Internal/Persistence/PFPersistenceController.m Parse/Parse/Internal/Product/PFProduct+Private.h Parse/Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.h Parse/Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.m Parse/Parse/Internal/PropertyInfo/PFPropertyInfo.h Parse/Parse/Internal/PropertyInfo/PFPropertyInfo.m Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Private.h Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.h Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.m Parse/Parse/Internal/Purchase/Controller/PFPurchaseController.h Parse/Parse/Internal/Purchase/Controller/PFPurchaseController.m Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.h Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.m Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver_Private.h Parse/Parse/Internal/Push/ChannelsController/PFPushChannelsController.h Parse/Parse/Internal/Push/ChannelsController/PFPushChannelsController.m Parse/Parse/Internal/Push/Controller/PFPushController.h Parse/Parse/Internal/Push/Controller/PFPushController.m Parse/Parse/Internal/Push/Manager/PFPushManager.h Parse/Parse/Internal/Push/Manager/PFPushManager.m Parse/Parse/Internal/Push/PFPushPrivate.h Parse/Parse/Internal/Push/State/PFMutablePushState.h Parse/Parse/Internal/Push/State/PFMutablePushState.m Parse/Parse/Internal/Push/State/PFPushState.h Parse/Parse/Internal/Push/State/PFPushState.m Parse/Parse/Internal/Push/State/PFPushState_Private.h Parse/Parse/Internal/Push/Utilites/PFPushUtilities.h Parse/Parse/Internal/Push/Utilites/PFPushUtilities.m Parse/Parse/Internal/Query/Controller/PFCachedQueryController.h Parse/Parse/Internal/Query/Controller/PFCachedQueryController.m Parse/Parse/Internal/Query/Controller/PFOfflineQueryController.h Parse/Parse/Internal/Query/Controller/PFOfflineQueryController.m Parse/Parse/Internal/Query/Controller/PFQueryController.h Parse/Parse/Internal/Query/Controller/PFQueryController.m Parse/Parse/Internal/Query/PFQueryConstants.h Parse/Parse/Internal/Query/PFQueryConstants.m Parse/Parse/Internal/Query/PFQueryPrivate.h Parse/Parse/Internal/Query/State/PFMutableQueryState.h Parse/Parse/Internal/Query/State/PFMutableQueryState.m Parse/Parse/Internal/Query/State/PFQueryState.h Parse/Parse/Internal/Query/State/PFQueryState.m Parse/Parse/Internal/Query/State/PFQueryState_Private.h Parse/Parse/Internal/Query/Utilities/PFQueryUtilities.h Parse/Parse/Internal/Query/Utilities/PFQueryUtilities.m Parse/Parse/Internal/Relation/PFRelationPrivate.h Parse/Parse/Internal/Relation/State/PFMutableRelationState.h Parse/Parse/Internal/Relation/State/PFMutableRelationState.m Parse/Parse/Internal/Relation/State/PFRelationState.h Parse/Parse/Internal/Relation/State/PFRelationState.m Parse/Parse/Internal/Relation/State/PFRelationState_Private.h Parse/Parse/Internal/Session/Controller/PFSessionController.h Parse/Parse/Internal/Session/Controller/PFSessionController.m Parse/Parse/Internal/Session/PFSession_Private.h Parse/Parse/Internal/Session/Utilities/PFSessionUtilities.h Parse/Parse/Internal/Session/Utilities/PFSessionUtilities.m Parse/Parse/Internal/ThreadSafety/PFThreadsafety.h Parse/Parse/Internal/ThreadSafety/PFThreadsafety.m Parse/Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.h Parse/Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.m Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.h Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.m Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousUtils_Private.h Parse/Parse/Internal/User/Coder/File/PFUserFileCodingLogic.h Parse/Parse/Internal/User/Coder/File/PFUserFileCodingLogic.m Parse/Parse/Internal/User/Constants/PFUserConstants.h Parse/Parse/Internal/User/Constants/PFUserConstants.m Parse/Parse/Internal/User/Controller/PFUserController.h Parse/Parse/Internal/User/Controller/PFUserController.m Parse/Parse/Internal/User/CurrentUserController/PFCurrentUserController.h Parse/Parse/Internal/User/CurrentUserController/PFCurrentUserController.m Parse/Parse/Internal/User/PFUserPrivate.h Parse/Parse/Internal/User/State/PFMutableUserState.h Parse/Parse/Internal/User/State/PFMutableUserState.m Parse/Parse/Internal/User/State/PFUserState.h Parse/Parse/Internal/User/State/PFUserState.m Parse/Parse/Internal/User/State/PFUserState_Private.h Parse/Parse/PFACL.h Parse/Parse/PFACL.m Parse/Parse/PFAnalytics.h Parse/Parse/PFAnalytics.m Parse/Parse/PFAnonymousUtils+Deprecated.h Parse/Parse/PFAnonymousUtils.h Parse/Parse/PFAnonymousUtils.m Parse/Parse/PFCloud+Deprecated.h Parse/Parse/PFCloud+Synchronous.h Parse/Parse/PFCloud.h Parse/Parse/PFCloud.m Parse/Parse/PFConfig+Synchronous.h Parse/Parse/PFConfig.h Parse/Parse/PFConfig.m Parse/Parse/PFConstants.h Parse/Parse/PFConstants.m Parse/Parse/PFDecoder.h Parse/Parse/PFDecoder.m Parse/Parse/PFEncoder.h Parse/Parse/PFEncoder.m Parse/Parse/PFFileObject+Deprecated.h Parse/Parse/PFFileObject+Synchronous.h Parse/Parse/PFFileObject.h Parse/Parse/PFFileObject.m Parse/Parse/PFFileUploadController.h Parse/Parse/PFFileUploadResult.h Parse/Parse/PFGeoPoint.h Parse/Parse/PFGeoPoint.m Parse/Parse/PFInstallation.h Parse/Parse/PFInstallation.m Parse/Parse/PFNetworkActivityIndicatorManager.h Parse/Parse/PFNetworkActivityIndicatorManager.m Parse/Parse/PFObject+Deprecated.h Parse/Parse/PFObject+Subclass.h Parse/Parse/PFObject+Synchronous.h Parse/Parse/PFObject.h Parse/Parse/PFObject.m Parse/Parse/PFPolygon.h Parse/Parse/PFPolygon.m Parse/Parse/PFProduct.h Parse/Parse/PFProduct.m Parse/Parse/PFPurchase.h Parse/Parse/PFPurchase.m Parse/Parse/PFPush+Deprecated.h Parse/Parse/PFPush+Synchronous.h Parse/Parse/PFPush.h Parse/Parse/PFPush.m Parse/Parse/PFQuery+Deprecated.h Parse/Parse/PFQuery+Synchronous.h Parse/Parse/PFQuery.h Parse/Parse/PFQuery.m Parse/Parse/PFRelation.h Parse/Parse/PFRelation.m Parse/Parse/PFRole.h Parse/Parse/PFRole.m Parse/Parse/PFSession.h Parse/Parse/PFSession.m Parse/Parse/PFSubclassing.h Parse/Parse/PFUser+Deprecated.h Parse/Parse/PFUser+Synchronous.h Parse/Parse/PFUser.h Parse/Parse/PFUser.m Parse/Parse/PFUserAuthenticationDelegate.h Parse/Parse/Parse.h Parse/Parse/Parse.m Parse/Parse/ParseClientConfiguration.h Parse/Parse/ParseClientConfiguration.m Parse/Parse/Resources/Parse-OSX.Info.plist Parse/Parse/Resources/Parse-iOS.Info.plist Parse/Parse/Resources/Parse-tvOS.Info.plist Parse/Parse/Resources/Parse-watchOS.Info.plist Parse/Parse/Resources/en.lproj/Parse.strings Parse/ParseUnitTests-iOS-host/AppDelegate.h Parse/ParseUnitTests-iOS-host/AppDelegate.m Parse/ParseUnitTests-iOS-host/Assets.xcassets/AppIcon.appiconset/Contents.json Parse/ParseUnitTests-iOS-host/Info.plist Parse/ParseUnitTests-iOS-host/Main.storyboard Parse/ParseUnitTests-iOS-host/ViewController.h Parse/ParseUnitTests-iOS-host/ViewController.m Parse/ParseUnitTests-iOS-host/main.m Parse/Tests/Other/Cache/TestCache.h Parse/Tests/Other/Cache/TestCache.m Parse/Tests/Other/ExtensionDataSharing/PFExtensionDataSharingTestHelper.h Parse/Tests/Other/ExtensionDataSharing/PFExtensionDataSharingTestHelper.m Parse/Tests/Other/FileManager/TestFileManager.h Parse/Tests/Other/FileManager/TestFileManager.m Parse/Tests/Other/LocationManager/CLLocationManager+TestAdditions.h Parse/Tests/Other/LocationManager/CLLocationManager+TestAdditions.m Parse/Tests/Other/NetworkMocking/PFMockURLProtocol.h Parse/Tests/Other/NetworkMocking/PFMockURLProtocol.m Parse/Tests/Other/NetworkMocking/PFMockURLResponse.h Parse/Tests/Other/NetworkMocking/PFMockURLResponse.m Parse/Tests/Other/OCMock/OCMock+Parse.h Parse/Tests/Other/OCMock/OCMock+Parse.m Parse/Tests/Other/StoreKitMocking/PFTestSKPaymentQueue.h Parse/Tests/Other/StoreKitMocking/PFTestSKPaymentQueue.m Parse/Tests/Other/StoreKitMocking/PFTestSKPaymentTransaction.h Parse/Tests/Other/StoreKitMocking/PFTestSKPaymentTransaction.m Parse/Tests/Other/StoreKitMocking/PFTestSKProduct.h Parse/Tests/Other/StoreKitMocking/PFTestSKProduct.m Parse/Tests/Other/StoreKitMocking/PFTestSKProductsRequest.h Parse/Tests/Other/StoreKitMocking/PFTestSKProductsRequest.m Parse/Tests/Other/StoreKitMocking/PFTestSKProductsResponse.h Parse/Tests/Other/StoreKitMocking/PFTestSKProductsResponse.m Parse/Tests/Other/Swift/SwiftSubclass.swift Parse/Tests/Other/Swizzling/PFTestSwizzledMethod.h Parse/Tests/Other/Swizzling/PFTestSwizzledMethod.m Parse/Tests/Other/Swizzling/PFTestSwizzlingUtilities.h Parse/Tests/Other/Swizzling/PFTestSwizzlingUtilities.m Parse/Tests/Other/TestCases/TestCase/PFTestCase.h Parse/Tests/Other/TestCases/TestCase/PFTestCase.m Parse/Tests/Other/TestCases/UnitTestCase/PFUnitTestCase.h Parse/Tests/Other/TestCases/UnitTestCase/PFUnitTestCase.m Parse/Tests/Resources/ParseUnitTests-OSX-Info.plist Parse/Tests/Resources/ParseUnitTests-iOS-Info.plist Parse/Tests/Unit/ACLDefaultTests.m Parse/Tests/Unit/ACLStateTests.m Parse/Tests/Unit/ACLTests.m Parse/Tests/Unit/AlertViewTests.m Parse/Tests/Unit/AnalyticsCommandTests.m Parse/Tests/Unit/AnalyticsControllerTests.m Parse/Tests/Unit/AnalyticsUnitTests.m Parse/Tests/Unit/AnalyticsUtilitiesTests.m Parse/Tests/Unit/AnonymousAuthenticationProviderTests.m Parse/Tests/Unit/AnonymousUtilsTests.m Parse/Tests/Unit/BaseStateTests.m Parse/Tests/Unit/CloudCodeControllerTests.m Parse/Tests/Unit/CloudCommandTests.m Parse/Tests/Unit/CloudUnitTests.m Parse/Tests/Unit/CommandResultTests.m Parse/Tests/Unit/CommandURLRequestConstructorTests.m Parse/Tests/Unit/CommandUnitTests.m Parse/Tests/Unit/ConfigCommandTests.m Parse/Tests/Unit/ConfigControllerTests.m Parse/Tests/Unit/ConfigUnitTests.m Parse/Tests/Unit/CurrentConfigControllerTests.m Parse/Tests/Unit/DateFormatterTests.m Parse/Tests/Unit/DecoderTests.m Parse/Tests/Unit/DefaultACLControllerTests.m Parse/Tests/Unit/DeviceTests.m Parse/Tests/Unit/ExtensionDataSharingMobileTests.m Parse/Tests/Unit/ExtensionDataSharingTests.m Parse/Tests/Unit/FieldOperationDecoderTests.m Parse/Tests/Unit/FieldOperationTests.m Parse/Tests/Unit/FileCommandTests.m Parse/Tests/Unit/FileControllerTests.m Parse/Tests/Unit/FileDataStreamTests.m Parse/Tests/Unit/FileStateTests.m Parse/Tests/Unit/FileUnitTests.m Parse/Tests/Unit/GeoPointLocationTests.m Parse/Tests/Unit/GeoPointUnitTests.m Parse/Tests/Unit/HashTests.m Parse/Tests/Unit/IncrementUnitTests.m Parse/Tests/Unit/InstallationIdentifierUnitTests.m Parse/Tests/Unit/InstallationUnitTests.m Parse/Tests/Unit/KeyValueCacheTests.m Parse/Tests/Unit/KeychainStoreTests.m Parse/Tests/Unit/LocationManagerMobileTests.m Parse/Tests/Unit/LocationManagerTests.m Parse/Tests/Unit/ObjectBatchCommandTests.m Parse/Tests/Unit/ObjectBatchControllerTests.m Parse/Tests/Unit/ObjectCommandTests.m Parse/Tests/Unit/ObjectEstimatedDataTests.m Parse/Tests/Unit/ObjectFileCoderTests.m Parse/Tests/Unit/ObjectFileCodingLogicTests.m Parse/Tests/Unit/ObjectFilePersistenceControllerTests.m Parse/Tests/Unit/ObjectLocalIdStoreTests.m Parse/Tests/Unit/ObjectOfflineTests.m Parse/Tests/Unit/ObjectPinTests.m Parse/Tests/Unit/ObjectStateTests.m Parse/Tests/Unit/ObjectSubclassPropertiesTests.m Parse/Tests/Unit/ObjectSubclassTests.m Parse/Tests/Unit/ObjectSubclassingControllerTests.m Parse/Tests/Unit/ObjectUnitTests.m Parse/Tests/Unit/ObjectUtilitiesTests.m Parse/Tests/Unit/OfflineQueryControllerTests.m Parse/Tests/Unit/OfflineQueryLogicUnitTests.m Parse/Tests/Unit/OperationSetUnitTests.m Parse/Tests/Unit/ParseClientConfigurationTests.m Parse/Tests/Unit/ParseModuleUnitTests.m Parse/Tests/Unit/ParseSetupUnitTests.m Parse/Tests/Unit/PinUnitTests.m Parse/Tests/Unit/PinningObjectStoreTests.m Parse/Tests/Unit/PolygonUnitTests.m Parse/Tests/Unit/ProductTests.m Parse/Tests/Unit/PropertyInfoTests.m Parse/Tests/Unit/PurchaseControllerTests.m Parse/Tests/Unit/PurchaseUnitTests.m Parse/Tests/Unit/PushChannelsControllerTests.m Parse/Tests/Unit/PushCommandTests.m Parse/Tests/Unit/PushControllerTests.m Parse/Tests/Unit/PushManagerTests.m Parse/Tests/Unit/PushMobileTests.m Parse/Tests/Unit/PushStateTests.m Parse/Tests/Unit/PushUnitTests.m Parse/Tests/Unit/QueryCachedControllerTests.m Parse/Tests/Unit/QueryControllerUnitTests.m Parse/Tests/Unit/QueryPredicateUnitTests.m Parse/Tests/Unit/QueryStateUnitTests.m Parse/Tests/Unit/QueryUnitTests.m Parse/Tests/Unit/QueryUtilitiesTests.m Parse/Tests/Unit/RelationStateTests.m Parse/Tests/Unit/RelationUnitTests.m Parse/Tests/Unit/RoleUnitTests.m Parse/Tests/Unit/SQLiteDatabaseTest.m Parse/Tests/Unit/SessionControllerTests.m Parse/Tests/Unit/SessionUnitTests.m Parse/Tests/Unit/SessionUtilitiesTests.m Parse/Tests/Unit/URLConstructorTests.m Parse/Tests/Unit/URLSessionCommandRunnerTests.m Parse/Tests/Unit/URLSessionDataTaskDelegateTests.m Parse/Tests/Unit/URLSessionTests.m Parse/Tests/Unit/URLSessionUploadTaskDelegateTests.m Parse/Tests/Unit/UserCommandTests.m Parse/Tests/Unit/UserControllerTests.m Parse/Tests/Unit/UserFileCodingLogicTests.m Parse/Tests/Unit/UserUnitTests.m Parse/Tests/testServer.config ParseFacebookUtils/Configurations/ParseFacebookTestApplicationV4.xcconfig ParseFacebookUtils/Configurations/ParseFacebookUtilsV4-UnitTests.xcconfig ParseFacebookUtils/Configurations/ParseFacebookUtilsV4-iOS-Dynamic.xcconfig ParseFacebookUtils/Configurations/ParseFacebookUtilsV4-iOS.xcconfig ParseFacebookUtils/Configurations/ParseFacebookUtilsV4-tvOS-Dynamic.xcconfig ParseFacebookUtils/Configurations/ParseFacebookUtilsV4-tvOS.xcconfig ParseFacebookUtils/Configurations/Shared ParseFacebookUtils/ParseFacebookUtils.xcodeproj/project.pbxproj ParseFacebookUtils/ParseFacebookUtils.xcodeproj/project.xcworkspace/contents.xcworkspacedata ParseFacebookUtils/ParseFacebookUtils.xcodeproj/xcshareddata/xcschemes/ParseFacebookUtilsV4-iOS-Dynamic.xcscheme ParseFacebookUtils/ParseFacebookUtils.xcodeproj/xcshareddata/xcschemes/ParseFacebookUtilsV4-iOS.xcscheme ParseFacebookUtils/ParseFacebookUtils.xcodeproj/xcshareddata/xcschemes/ParseFacebookUtilsV4-tvOS-Dynamic.xcscheme ParseFacebookUtils/ParseFacebookUtils.xcodeproj/xcshareddata/xcschemes/ParseFacebookUtilsV4-tvOS.xcscheme ParseFacebookUtils/ParseFacebookUtils/Internal/AuthenticationProvider/PFFacebookAuthenticationProvider.h ParseFacebookUtils/ParseFacebookUtils/Internal/AuthenticationProvider/PFFacebookAuthenticationProvider.m ParseFacebookUtils/ParseFacebookUtils/Internal/AuthenticationProvider/iOS/PFFacebookMobileAuthenticationProvider.h ParseFacebookUtils/ParseFacebookUtils/Internal/AuthenticationProvider/iOS/PFFacebookMobileAuthenticationProvider.m ParseFacebookUtils/ParseFacebookUtils/Internal/AuthenticationProvider/iOS/PFFacebookMobileAuthenticationProvider_Private.h ParseFacebookUtils/ParseFacebookUtils/Internal/AuthenticationProvider/tvOS/PFFacebookDeviceAuthenticationProvider.h ParseFacebookUtils/ParseFacebookUtils/Internal/AuthenticationProvider/tvOS/PFFacebookDeviceAuthenticationProvider.m ParseFacebookUtils/ParseFacebookUtils/Internal/PFFacebookPrivateUtilities.h ParseFacebookUtils/ParseFacebookUtils/Internal/PFFacebookPrivateUtilities.m ParseFacebookUtils/ParseFacebookUtils/Internal/PFFacebookUtils_Private.h ParseFacebookUtils/ParseFacebookUtils/PFFacebookUtils.h ParseFacebookUtils/ParseFacebookUtils/PFFacebookUtils.m ParseFacebookUtils/ParseFacebookUtils/ParseFacebookUtilsV4.h ParseFacebookUtils/Resources/Info-iOS.plist ParseFacebookUtils/Resources/Info-tvOS.plist ParseFacebookUtils/Resources/Localizable.strings ParseFacebookUtils/Tests/Other/TestCase/PFFacebookTestCase.h ParseFacebookUtils/Tests/Other/TestCase/PFFacebookTestCase.m ParseFacebookUtils/Tests/Resources/Info.plist ParseFacebookUtils/Tests/TestApplication/Classes/main.m ParseFacebookUtils/Tests/TestApplication/Resources/Info.plist ParseFacebookUtils/Tests/Unit/FacebookAuthenticationProviderTests.m ParseFacebookUtils/Tests/Unit/FacebookUtilsTests.m ParseStarterProject/OSX/ParseOSXStarterProject-Swift/ParseOSXStarterProject-Swift.xcodeproj/project.pbxproj ParseStarterProject/OSX/ParseOSXStarterProject-Swift/ParseOSXStarterProject-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata ParseStarterProject/OSX/ParseOSXStarterProject-Swift/ParseOSXStarterProject/AppDelegate.swift ParseStarterProject/OSX/ParseOSXStarterProject-Swift/Resources/Base.lproj/MainMenu.xib ParseStarterProject/OSX/ParseOSXStarterProject-Swift/Resources/Images.xcassets/AppIcon.appiconset/Contents.json ParseStarterProject/OSX/ParseOSXStarterProject-Swift/Resources/Info.plist ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject.xcodeproj/project.pbxproj ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject/AppDelegate.h ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject/AppDelegate.m ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject/main.m ParseStarterProject/OSX/ParseOSXStarterProject/Resources/Base.lproj/MainMenu.xib ParseStarterProject/OSX/ParseOSXStarterProject/Resources/Info.plist ParseStarterProject/OSX/ParseOSXStarterProject/Resources/en.lproj/Credits.rtf ParseStarterProject/OSX/ParseOSXStarterProject/Resources/en.lproj/InfoPlist.strings ParseStarterProject/iOS/ParseStarterProject-Swift/ParseStarterProject-Swift.xcodeproj/project.pbxproj ParseStarterProject/iOS/ParseStarterProject-Swift/ParseStarterProject-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata ParseStarterProject/iOS/ParseStarterProject-Swift/ParseStarterProject/AppDelegate.swift ParseStarterProject/iOS/ParseStarterProject-Swift/ParseStarterProject/ViewController.swift ParseStarterProject/iOS/ParseStarterProject-Swift/Resources/Base.lproj/Main.storyboard ParseStarterProject/iOS/ParseStarterProject-Swift/Resources/Images.xcassets/AppIcon.appiconset/Contents.json ParseStarterProject/iOS/ParseStarterProject-Swift/Resources/Images.xcassets/Contents.json ParseStarterProject/iOS/ParseStarterProject-Swift/Resources/Info.plist ParseStarterProject/iOS/ParseStarterProject-Swift/Resources/Launch.storyboard ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject.xcodeproj/project.pbxproj ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectAppDelegate.h ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectAppDelegate.m ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectViewController.h ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectViewController.m ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/main.m ParseStarterProject/iOS/ParseStarterProject/Resources/Base.lproj/MainWindow.xib ParseStarterProject/iOS/ParseStarterProject/Resources/Base.lproj/ParseStarterProjectViewController.xib ParseStarterProject/iOS/ParseStarterProject/Resources/Info.plist ParseStarterProject/iOS/ParseStarterProject/Resources/en.lproj/InfoPlist.strings ParseStarterProject/tvOS/ParseStarterProject-Swift/ParseStarter-Swift.xcodeproj/project.pbxproj ParseStarterProject/tvOS/ParseStarterProject-Swift/ParseStarter-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata ParseStarterProject/tvOS/ParseStarterProject-Swift/ParseStarter/AppDelegate.swift ParseStarterProject/tvOS/ParseStarterProject-Swift/ParseStarter/Base.lproj/Main.storyboard ParseStarterProject/tvOS/ParseStarterProject-Swift/ParseStarter/Info.plist ParseStarterProject/tvOS/ParseStarterProject-Swift/ParseStarter/ViewController.swift ParseStarterProject/watchOS/ParseStarterProject-Swift/ParseStarter Extension/ExtensionDelegate.swift ParseStarterProject/watchOS/ParseStarterProject-Swift/ParseStarter Extension/Info.plist ParseStarterProject/watchOS/ParseStarterProject-Swift/ParseStarter Extension/InterfaceController.swift ParseStarterProject/watchOS/ParseStarterProject-Swift/ParseStarter-Swift.xcodeproj/project.pbxproj ParseStarterProject/watchOS/ParseStarterProject-Swift/ParseStarter-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata ParseStarterProject/watchOS/ParseStarterProject-Swift/ParseStarter/Assets.xcassets/AppIcon.appiconset/Contents.json ParseStarterProject/watchOS/ParseStarterProject-Swift/ParseStarter/Base.lproj/Interface.storyboard ParseStarterProject/watchOS/ParseStarterProject-Swift/ParseStarter/Info.plist ParseStarterProject/watchOS/ParseStarterProject-Swift/ParseStarterProject/AppDelegate.swift ParseStarterProject/watchOS/ParseStarterProject-Swift/ParseStarterProject/ViewController.swift ParseStarterProject/watchOS/ParseStarterProject-Swift/Resources/Base.lproj/Main.storyboard ParseStarterProject/watchOS/ParseStarterProject-Swift/Resources/Images.xcassets/AppIcon.appiconset/Contents.json ParseStarterProject/watchOS/ParseStarterProject-Swift/Resources/Images.xcassets/LaunchImage.launchimage/Contents.json ParseStarterProject/watchOS/ParseStarterProject-Swift/Resources/Info.plist ParseTwitterUtils/Configurations/ParseTwitterTestApplication.xcconfig ParseTwitterUtils/Configurations/ParseTwitterUtils-Tests.xcconfig ParseTwitterUtils/Configurations/ParseTwitterUtils-iOS-Dynamic.xcconfig ParseTwitterUtils/Configurations/ParseTwitterUtils-iOS.xcconfig ParseTwitterUtils/Configurations/Shared ParseTwitterUtils/ParseTwitterTestApplication.entitlements ParseTwitterUtils/ParseTwitterUtils.xcodeproj/project.pbxproj ParseTwitterUtils/ParseTwitterUtils.xcodeproj/project.xcworkspace/contents.xcworkspacedata ParseTwitterUtils/ParseTwitterUtils.xcodeproj/xcshareddata/xcschemes/ParseTwitterUtils-iOS-Dynamic.xcscheme ParseTwitterUtils/ParseTwitterUtils.xcodeproj/xcshareddata/xcschemes/ParseTwitterUtils-iOS.xcscheme ParseTwitterUtils/ParseTwitterUtils/Internal/Dialog/PFOAuth1FlowDialog.h ParseTwitterUtils/ParseTwitterUtils/Internal/Dialog/PFOAuth1FlowDialog.m ParseTwitterUtils/ParseTwitterUtils/Internal/OAuthCore/PF_OAuthCore.h ParseTwitterUtils/ParseTwitterUtils/Internal/OAuthCore/PF_OAuthCore.m ParseTwitterUtils/ParseTwitterUtils/Internal/PFTwitterAlertView.h ParseTwitterUtils/ParseTwitterUtils/Internal/PFTwitterAlertView.m ParseTwitterUtils/ParseTwitterUtils/Internal/PFTwitterAuthenticationProvider.h ParseTwitterUtils/ParseTwitterUtils/Internal/PFTwitterAuthenticationProvider.m ParseTwitterUtils/ParseTwitterUtils/Internal/PFTwitterLocalization.h ParseTwitterUtils/ParseTwitterUtils/Internal/PFTwitterPrivateUtilities.h ParseTwitterUtils/ParseTwitterUtils/Internal/PFTwitterPrivateUtilities.m ParseTwitterUtils/ParseTwitterUtils/Internal/PFTwitterUtils_Private.h ParseTwitterUtils/ParseTwitterUtils/Internal/PF_Twitter_Private.h ParseTwitterUtils/ParseTwitterUtils/PFTwitterUtils.h ParseTwitterUtils/ParseTwitterUtils/PFTwitterUtils.m ParseTwitterUtils/ParseTwitterUtils/PF_Twitter.h ParseTwitterUtils/ParseTwitterUtils/PF_Twitter.m ParseTwitterUtils/ParseTwitterUtils/ParseTwitterUtils.h ParseTwitterUtils/Resources/Info.plist ParseTwitterUtils/Resources/en.lproj/ParseTwitterUtils.strings ParseTwitterUtils/Tests/Other/PFTwitterTestMacros.h ParseTwitterUtils/Tests/Other/TestCase/PFTwitterTestCase.h ParseTwitterUtils/Tests/Other/TestCase/PFTwitterTestCase.m ParseTwitterUtils/Tests/Resources/Info.plist ParseTwitterUtils/Tests/TestApplication/Classes/main.m ParseTwitterUtils/Tests/TestApplication/Resources/Info.plist ParseTwitterUtils/Tests/Unit/OAuth1FlowDialogTests.m ParseTwitterUtils/Tests/Unit/OAuthCoreTests.m ParseTwitterUtils/Tests/Unit/TwitterAuthenticationProviderTests.m ParseTwitterUtils/Tests/Unit/TwitterTests.m ParseTwitterUtils/Tests/Unit/TwitterUtilsTests.m ParseUI/Classes/Cells/PFCollectionViewCell.h ParseUI/Classes/Cells/PFCollectionViewCell.m ParseUI/Classes/Cells/PFPurchaseTableViewCell.h ParseUI/Classes/Cells/PFPurchaseTableViewCell.m ParseUI/Classes/Cells/PFTableViewCell.h ParseUI/Classes/Cells/PFTableViewCell.m ParseUI/Classes/Internal/Cells/PFActivityIndicatorCollectionReusableView.h ParseUI/Classes/Internal/Cells/PFActivityIndicatorCollectionReusableView.m ParseUI/Classes/Internal/Cells/PFActivityIndicatorTableViewCell.h ParseUI/Classes/Internal/Cells/PFActivityIndicatorTableViewCell.m ParseUI/Classes/Internal/Extensions/PFColor.h ParseUI/Classes/Internal/Extensions/PFColor.m ParseUI/Classes/Internal/Extensions/PFImage.h ParseUI/Classes/Internal/Extensions/PFImage.m ParseUI/Classes/Internal/Extensions/PFRect.h ParseUI/Classes/Internal/Extensions/PFRect.m ParseUI/Classes/Internal/Extensions/PFUIAlertView.h ParseUI/Classes/Internal/Extensions/PFUIAlertView.m ParseUI/Classes/Internal/PFImageCache.h ParseUI/Classes/Internal/PFImageCache.m ParseUI/Classes/Internal/PFLocalization.h ParseUI/Classes/Internal/PFLocalization.m ParseUI/Classes/Internal/Views/Buttons/PFActionButton.h ParseUI/Classes/Internal/Views/Buttons/PFActionButton.m ParseUI/Classes/Internal/Views/Buttons/PFDismissButton.h ParseUI/Classes/Internal/Views/Buttons/PFDismissButton.m ParseUI/Classes/Internal/Views/Buttons/PFPrimaryButton.h ParseUI/Classes/Internal/Views/Buttons/PFPrimaryButton.m ParseUI/Classes/Internal/Views/Buttons/PFTextButton.h ParseUI/Classes/Internal/Views/Buttons/PFTextButton.m ParseUI/Classes/Internal/Views/PFLoadingView.h ParseUI/Classes/Internal/Views/PFLoadingView.m ParseUI/Classes/LogInViewController/PFLogInView.h ParseUI/Classes/LogInViewController/PFLogInView.m ParseUI/Classes/LogInViewController/PFLogInViewController.h ParseUI/Classes/LogInViewController/PFLogInViewController.m ParseUI/Classes/LogInViewController/PFLogInView_Private.h ParseUI/Classes/ProductTableViewController/PFProductTableViewController.h ParseUI/Classes/ProductTableViewController/PFProductTableViewController.m ParseUI/Classes/QueryCollectionViewController/PFQueryCollectionViewController.h ParseUI/Classes/QueryCollectionViewController/PFQueryCollectionViewController.m ParseUI/Classes/QueryTableViewController/PFQueryTableViewController.h ParseUI/Classes/QueryTableViewController/PFQueryTableViewController.m ParseUI/Classes/SignUpViewController/PFSignUpView.h ParseUI/Classes/SignUpViewController/PFSignUpView.m ParseUI/Classes/SignUpViewController/PFSignUpViewController.h ParseUI/Classes/SignUpViewController/PFSignUpViewController.m ParseUI/Classes/Views/PFImageView.h ParseUI/Classes/Views/PFImageView.m ParseUI/Classes/Views/PFTextField.h ParseUI/Classes/Views/PFTextField.m ParseUI/Configurations/ParseUI-iOS-Dynamic.xcconfig ParseUI/Configurations/ParseUI-iOS.xcconfig ParseUI/Configurations/Shared ParseUI/Generated/PFResources.h ParseUI/Generated/PFResources.m ParseUI/Other/ParseUI.h ParseUI/Other/ParseUIConstants.h ParseUI/ParseUI.xcodeproj/project.pbxproj ParseUI/ParseUI.xcodeproj/project.xcworkspace/contents.xcworkspacedata ParseUI/ParseUI.xcodeproj/xcshareddata/xcschemes/ParseUI-Dynamic.xcscheme ParseUI/ParseUI.xcodeproj/xcshareddata/xcschemes/ParseUI.xcscheme ParseUI/ParseUI.xcodeproj/xcshareddata/xcschemes/ParseUIDemo-Swift.xcscheme ParseUI/ParseUI.xcodeproj/xcshareddata/xcschemes/ParseUIDemo.xcscheme ParseUI/ParseUIDemo/Classes/AppDelegate.h ParseUI/ParseUIDemo/Classes/AppDelegate.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/LogInViewController/CustomLogInViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/LogInViewController/CustomLogInViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/DeletionCollectionViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/DeletionCollectionViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/PaginatedCollectionViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/PaginatedCollectionViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/SectionedCollectionViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/SectionedCollectionViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/SimpleCollectionViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/SimpleCollectionViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/StoryboardCollectionViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/StoryboardCollectionViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/SubtitleImageCollectionViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryCollectionViewController/SubtitleImageCollectionViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/CustomProductTableViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/CustomProductTableViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/DeletionTableViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/DeletionTableViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/PaginatedTableViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/PaginatedTableViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/SectionedTableViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/SectionedTableViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/SimpleTableViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/SimpleTableViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/StoryboardTableViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/StoryboardTableViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/SubtitleImageTableViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/QueryTableViewController/SubtitleImageTableViewController.m ParseUI/ParseUIDemo/Classes/CustomViewControllers/SignUpViewController/CustomSignUpViewController.h ParseUI/ParseUIDemo/Classes/CustomViewControllers/SignUpViewController/CustomSignUpViewController.m ParseUI/ParseUIDemo/Classes/PFUIDemoViewController.h ParseUI/ParseUIDemo/Classes/PFUIDemoViewController.m ParseUI/ParseUIDemo/Images.xcassets/LaunchImage.launchimage/Contents.json ParseUI/ParseUIDemo/Other/Info.plist ParseUI/ParseUIDemo/Other/main.m ParseUI/ParseUIDemo/ParseUIDemo.entitlements ParseUI/ParseUIDemo/Resources/SimpleQueryCollectionStoryboard.storyboard ParseUI/ParseUIDemo/Resources/SimpleQueryTableStoryboard.storyboard ParseUI/ParseUIDemo/Swift/AppDelegate.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/LogInViewController/CustomLogInViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/ProductTableViewController/CustomProductTableViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryCollectionViewController/DeletionCollectionViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryCollectionViewController/PaginatedCollectionViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryCollectionViewController/SectionedCollectionViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryCollectionViewController/SimpleCollectionViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryCollectionViewController/StoryboardCollectionViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryCollectionViewController/SubtitleImageCollectionViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryTableViewController/DeletionTableViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryTableViewController/PaginatedTableViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryTableViewController/SectionedTableViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryTableViewController/SimpleTableViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryTableViewController/StoryboardTableViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/QueryTableViewController/SubtitleImageTableViewController.swift ParseUI/ParseUIDemo/Swift/CustomViewControllers/SignUpViewController/CustomSignUpViewController.swift ParseUI/ParseUIDemo/Swift/Resources/SimpleQueryCollectionStoryboard-Swift.storyboard ParseUI/ParseUIDemo/Swift/Resources/SimpleQueryTableStoryboard-Swift.storyboard ParseUI/ParseUIDemo/Swift/UIDemoViewController.swift ParseUI/Resources/Info.plist ParseUI/Resources/Localization/de.lproj/ParseUI.strings ParseUI/Resources/Localization/en.lproj/ParseUI.strings ParseUI/Resources/Localization/fr.lproj/ParseUI.strings ParseUI/Resources/Localization/he.lproj/ParseUI.strings ParseUI/Resources/Localization/pt-BR.lproj/ParseUI.strings ParseUI/Resources/Localization/sv.lproj/ParseUI.strings ParseUI/Scripts/convert_images.rb ParseUI/Sign In With Apple/PFAppleAuthenticationProvider.h ParseUI/Sign In With Apple/PFAppleAuthenticationProvider.m ParseUI/Sign In With Apple/PFAppleUtils.h ParseUI/Sign In With Apple/PFAppleUtils.m ParseUI/SignInWithAppleTests/Info.plist ParseUI/SignInWithAppleTests/SignInWithAppleTests.m Rakefile Scripts/build_third_party.rb Scripts/jazzy.sh Vendor/xctoolchain <<<<<< network # path=Parse#Internal#Commands#CommandRunner#URLSession#Session#TaskDelegate#PFURLSessionUploadTaskDelegate.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.m <<<<<< EOF # path=./OCMock.framework.coverage.txt /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/NSInvocation+OCMAdditions.m: 1| |/* 2| | * Copyright (c) 2006-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#import "NSInvocation+OCMAdditions.h" 19| |#import "OCMArg.h" 20| |#import "OCMFunctionsPrivate.h" 21| |#import "NSMethodSignature+OCMAdditions.h" 22| | 23| |#if (TARGET_OS_OSX && (!defined(__MAC_10_10) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_10)) || \ 24| | (TARGET_OS_IPHONE && (!defined(__IPHONE_8_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0)) 25| |static BOOL OCMObjectIsClass(id object) { 26| | return class_isMetaClass(object_getClass(object)); 27| |} 28| |#define object_isClass OCMObjectIsClass 29| |#endif 30| | 31| |static NSString *const OCMArgAnyPointerDescription = @"<[OCMArg anyPointer]>"; 32| | 33| | 34| |@implementation NSInvocation(OCMAdditions) 35| | 36| |+ (NSInvocation *)invocationForBlock:(id)block withArguments:(NSArray *)arguments 37| 0|{ 38| 0| NSMethodSignature *sig = [NSMethodSignature signatureForBlock:block]; 39| 0| NSInvocation *inv = [self invocationWithMethodSignature:sig]; 40| | 41| 0| NSUInteger numArgsRequired = sig.numberOfArguments - 1; 42| 0| if((arguments != nil) && ([arguments count] != numArgsRequired)) 43| 0| [NSException raise:NSInvalidArgumentException format:@"Specified too few arguments for block; expected %lu arguments.", (unsigned long) numArgsRequired]; 44| | 45| 0| for(NSUInteger i = 0, j = 1; i < numArgsRequired; ++i, ++j) 46| 0| { 47| 0| id arg = [arguments objectAtIndex:i]; 48| 0| [inv setArgumentWithObject:arg atIndex:j]; 49| 0| } 50| | 51| 0| return inv; 52| | 53| 0|} 54| | 55| | 56| |static NSString *const OCMRetainedObjectArgumentsKey = @"OCMRetainedObjectArgumentsKey"; 57| | 58| |- (void)retainObjectArgumentsExcludingObject:(id)objectToExclude 59| 0|{ 60| 0| if(objc_getAssociatedObject(self, OCMRetainedObjectArgumentsKey) != nil) 61| 0| { 62| | // looks like we've retained the arguments already; do nothing else 63| 0| return; 64| 0| } 65| | 66| 0| NSMutableArray *retainedArguments = [[NSMutableArray alloc] init]; 67| | 68| 0| id target = [self target]; 69| 0| if((target != nil) && (target != objectToExclude) && !object_isClass(target)) 70| 0| { 71| | // Bad things will happen if the target is a block since it's not being 72| | // copied. There isn't a very good way to tell if an invocation's target 73| | // is a block though (the argument type at index 0 is always "@" even if 74| | // the target is a Class or block), and in practice it's OK since you 75| | // can't mock a block. 76| 0| [retainedArguments addObject:target]; 77| 0| } 78| | 79| 0| NSUInteger numberOfArguments = [[self methodSignature] numberOfArguments]; 80| 0| for(NSUInteger index = 2; index < numberOfArguments; index++) 81| 0| { 82| 0| const char *argumentType = [[self methodSignature] getArgumentTypeAtIndex:index]; 83| 0| if(OCMIsObjectType(argumentType)) 84| 0| { 85| 0| id argument; 86| 0| [self getArgument:&argument atIndex:index]; 87| 0| if((argument != nil) && (argument != objectToExclude)) 88| 0| { 89| 0| if(OCMIsBlockType(argumentType) && OCMIsBlock(argument)) 90| 0| { 91| | // The argument's type is block and the passed argument is a block. In this 92| | // case we can't retain the argument because it might be stack block, which 93| | // must be copied. Further, non-escaping blocks have a lifetime that is stack- 94| | // based and they treat copy/release as a no-op. Keeping a reference to these 95| | // would result in a dangling pointer, which is why they are ignored here. 96| | // Note: even when the argument's type is block the argument could be 97| | // something else, e.g. an instance of OCMConstraint. Such cases are handled 98| | // like regular objects in the last else branch below. 99| 0| if(OCMIsNonEscapingBlock(argument) == NO) 100| 0| { 101| 0| id blockArgument = [argument copy]; 102| 0| [retainedArguments addObject:blockArgument]; 103| 0| [blockArgument release]; 104| 0| } 105| 0| } 106| 0| else if(OCMIsClassType(argumentType) && object_isClass(argument)) 107| 0| { 108| | // The argument's type is class and the passed argument is a class. In this 109| | // case do not retain the argument. Note: Even though the type is class the 110| | // argument could be a non-class, e.g. an instance of OCMArg. 111| 0| } 112| 0| else 113| 0| { 114| 0| [retainedArguments addObject:argument]; 115| 0| } 116| 0| } 117| 0| } 118| 0| } 119| | 120| 0| objc_setAssociatedObject(self, OCMRetainedObjectArgumentsKey, retainedArguments, OBJC_ASSOCIATION_RETAIN); 121| 0| [retainedArguments release]; 122| 0|} 123| | 124| | 125| |- (void)setArgumentWithObject:(id)arg atIndex:(NSInteger)idx 126| 0|{ 127| 0| const char *typeEncoding = [[self methodSignature] getArgumentTypeAtIndex:idx]; 128| 0| if((arg == nil) || ([arg respondsToSelector:@selector(isKindOfClass:)] && [arg isKindOfClass:[NSNull class]])) 129| 0| { 130| 0| if(typeEncoding[0] == '^') 131| 0| { 132| 0| void *nullPtr = NULL; 133| 0| [self setArgument:&nullPtr atIndex:idx]; 134| 0| } 135| 0| else if(typeEncoding[0] == '@') 136| 0| { 137| 0| id nilObj = nil; 138| 0| [self setArgument:&nilObj atIndex:idx]; 139| 0| } 140| 0| else if(OCMNumberTypeForObjCType(typeEncoding)) 141| 0| { 142| 0| NSUInteger argSize; 143| 0| NSGetSizeAndAlignment(typeEncoding, NULL, &argSize); 144| 0| void *argBuffer = calloc(1, argSize); 145| 0| [self setArgument:argBuffer atIndex:idx]; 146| 0| free(argBuffer); 147| 0| } 148| 0| else 149| 0| { 150| 0| [NSException raise:NSInvalidArgumentException format:@"Unable to create default value for type '%s'.", typeEncoding]; 151| 0| } 152| 0| } 153| 0| else if(OCMIsObjectType(typeEncoding)) 154| 0| { 155| 0| [self setArgument:&arg atIndex:idx]; 156| 0| } 157| 0| else 158| 0| { 159| 0| if(![arg isKindOfClass:[NSValue class]]) 160| 0| [NSException raise:NSInvalidArgumentException format:@"Argument '%@' should be boxed in NSValue.", arg]; 161| | 162| 0| char const *valEncoding = [arg objCType]; 163| | 164| | /// @note Here we allow any data pointer to be passed as a void pointer and 165| | /// any numerical types to be passed as arguments to the block. 166| 0| BOOL takesVoidPtr = !strcmp(typeEncoding, "^v") && valEncoding[0] == '^'; 167| 0| BOOL takesNumber = OCMNumberTypeForObjCType(typeEncoding) && OCMNumberTypeForObjCType(valEncoding); 168| | 169| 0| if(!takesVoidPtr && !takesNumber && !OCMEqualTypesAllowingOpaqueStructs(typeEncoding, valEncoding)) 170| 0| [NSException raise:NSInvalidArgumentException format:@"Argument type mismatch; type of argument required is '%s' but type of value provided is '%s'", typeEncoding, valEncoding]; 171| | 172| 0| NSUInteger argSize; 173| 0| NSGetSizeAndAlignment(typeEncoding, &argSize, NULL); 174| 0| void *argBuffer = malloc(argSize); 175| 0| [arg getValue:argBuffer]; 176| 0| [self setArgument:argBuffer atIndex:idx]; 177| 0| free(argBuffer); 178| 0| } 179| | 180| 0|} 181| | 182| | 183| |- (id)getArgumentAtIndexAsObject:(NSInteger)argIndex 184| 0|{ 185| 0| const char *argType = OCMTypeWithoutQualifiers([[self methodSignature] getArgumentTypeAtIndex:(NSUInteger)argIndex]); 186| | 187| 0| if((strlen(argType) > 1) && (strchr("{^", argType[0]) == NULL) && (strcmp("@?", argType) != 0)) 188| 0| [NSException raise:NSInvalidArgumentException format:@"Cannot handle argument type '%s'.", argType]; 189| | 190| 0| if(OCMIsObjectType(argType)) 191| 0| { 192| 0| id value; 193| 0| [self getArgument:&value atIndex:argIndex]; 194| 0| return value; 195| 0| } 196| | 197| 0| switch(argType[0]) 198| 0| { 199| 0| case ':': 200| 0| { 201| 0| SEL s = (SEL)0; 202| 0| [self getArgument:&s atIndex:argIndex]; 203| 0| return [NSValue valueWithBytes:&s objCType:":"]; 204| 0| } 205| 0| case 'i': 206| 0| { 207| 0| int value; 208| 0| [self getArgument:&value atIndex:argIndex]; 209| 0| return @(value); 210| 0| } 211| 0| case 's': 212| 0| { 213| 0| short value; 214| 0| [self getArgument:&value atIndex:argIndex]; 215| 0| return @(value); 216| 0| } 217| 0| case 'l': 218| 0| { 219| 0| long value; 220| 0| [self getArgument:&value atIndex:argIndex]; 221| 0| return @(value); 222| 0| } 223| 0| case 'q': 224| 0| { 225| 0| long long value; 226| 0| [self getArgument:&value atIndex:argIndex]; 227| 0| return @(value); 228| 0| } 229| 0| case 'c': 230| 0| { 231| 0| char value; 232| 0| [self getArgument:&value atIndex:argIndex]; 233| 0| return @(value); 234| 0| } 235| 0| case 'C': 236| 0| { 237| 0| unsigned char value; 238| 0| [self getArgument:&value atIndex:argIndex]; 239| 0| return @(value); 240| 0| } 241| 0| case 'I': 242| 0| { 243| 0| unsigned int value; 244| 0| [self getArgument:&value atIndex:argIndex]; 245| 0| return @(value); 246| 0| } 247| 0| case 'S': 248| 0| { 249| 0| unsigned short value; 250| 0| [self getArgument:&value atIndex:argIndex]; 251| 0| return @(value); 252| 0| } 253| 0| case 'L': 254| 0| { 255| 0| unsigned long value; 256| 0| [self getArgument:&value atIndex:argIndex]; 257| 0| return @(value); 258| 0| } 259| 0| case 'Q': 260| 0| { 261| 0| unsigned long long value; 262| 0| [self getArgument:&value atIndex:argIndex]; 263| 0| return @(value); 264| 0| } 265| 0| case 'f': 266| 0| { 267| 0| float value; 268| 0| [self getArgument:&value atIndex:argIndex]; 269| 0| return @(value); 270| 0| } 271| 0| case 'd': 272| 0| { 273| 0| double value; 274| 0| [self getArgument:&value atIndex:argIndex]; 275| 0| return @(value); 276| 0| } 277| 0| case 'D': 278| 0| { 279| 0| long double value; 280| 0| [self getArgument:&value atIndex:argIndex]; 281| 0| return [NSValue valueWithBytes:&value objCType:@encode(__typeof__(value))]; 282| 0| } 283| 0| case 'B': 284| 0| { 285| 0| bool value; 286| 0| [self getArgument:&value atIndex:argIndex]; 287| 0| return @(value); 288| 0| } 289| 0| case '^': 290| 0| case '*': 291| 0| { 292| 0| void *value = NULL; 293| 0| [self getArgument:&value atIndex:argIndex]; 294| 0| return [NSValue valueWithPointer:value]; 295| 0| } 296| 0| case '{': // structure 297| 0| { 298| 0| NSUInteger argSize; 299| 0| NSGetSizeAndAlignment([[self methodSignature] getArgumentTypeAtIndex:(NSUInteger)argIndex], &argSize, NULL); 300| 0| if(argSize == 0) // TODO: Can this happen? Is frameLength a good choice in that case? 301| 0| argSize = [[self methodSignature] frameLength]; 302| 0| NSMutableData *argumentData = [[[NSMutableData alloc] initWithLength:argSize] autorelease]; 303| 0| [self getArgument:[argumentData mutableBytes] atIndex:argIndex]; 304| 0| return [NSValue valueWithBytes:[argumentData bytes] objCType:argType]; 305| 0| } 306| | 307| 0| } 308| 0| [NSException raise:NSInvalidArgumentException format:@"Argument type '%s' not supported", argType]; 309| 0| return nil; 310| 0|} 311| | 312| | 313| |- (NSString *)invocationDescription 314| 0|{ 315| 0| NSMethodSignature *methodSignature = [self methodSignature]; 316| 0| NSUInteger numberOfArgs = [methodSignature numberOfArguments]; 317| | 318| 0| if (numberOfArgs == 2) 319| 0| return NSStringFromSelector([self selector]); 320| | 321| 0| NSArray *selectorParts = [NSStringFromSelector([self selector]) componentsSeparatedByString:@":"]; 322| 0| NSMutableString *description = [[NSMutableString alloc] init]; 323| 0| NSUInteger i; 324| 0| for(i = 2; i < numberOfArgs; i++) 325| 0| { 326| 0| [description appendFormat:@"%@%@:", (i > 2 ? @" " : @""), [selectorParts objectAtIndex:(i - 2)]]; 327| 0| [description appendString:[self argumentDescriptionAtIndex:(NSInteger)i]]; 328| 0| } 329| | 330| 0| return [description autorelease]; 331| 0|} 332| | 333| |- (NSString *)argumentDescriptionAtIndex:(NSInteger)argIndex 334| 0|{ 335| 0| const char *argType = OCMTypeWithoutQualifiers([[self methodSignature] getArgumentTypeAtIndex:(NSUInteger)argIndex]); 336| | 337| 0| switch(*argType) 338| 0| { 339| 0| case '@': return [self objectDescriptionAtIndex:argIndex]; 340| 0| case 'B': return [self boolDescriptionAtIndex:argIndex]; 341| 0| case 'c': return [self charDescriptionAtIndex:argIndex]; 342| 0| case 'C': return [self unsignedCharDescriptionAtIndex:argIndex]; 343| 0| case 'i': return [self intDescriptionAtIndex:argIndex]; 344| 0| case 'I': return [self unsignedIntDescriptionAtIndex:argIndex]; 345| 0| case 's': return [self shortDescriptionAtIndex:argIndex]; 346| 0| case 'S': return [self unsignedShortDescriptionAtIndex:argIndex]; 347| 0| case 'l': return [self longDescriptionAtIndex:argIndex]; 348| 0| case 'L': return [self unsignedLongDescriptionAtIndex:argIndex]; 349| 0| case 'q': return [self longLongDescriptionAtIndex:argIndex]; 350| 0| case 'Q': return [self unsignedLongLongDescriptionAtIndex:argIndex]; 351| 0| case 'd': return [self doubleDescriptionAtIndex:argIndex]; 352| 0| case 'f': return [self floatDescriptionAtIndex:argIndex]; 353| 0| case 'D': return [self longDoubleDescriptionAtIndex:argIndex]; 354| 0| case '{': return [self structDescriptionAtIndex:argIndex]; 355| 0| case '^': return [self pointerDescriptionAtIndex:argIndex]; 356| 0| case '*': return [self cStringDescriptionAtIndex:argIndex]; 357| 0| case ':': return [self selectorDescriptionAtIndex:argIndex]; 358| 0| default: return [@""]; // avoid confusion with trigraphs... 359| 0| } 360| | 361| 0|} 362| | 363| |- (NSString *)objectDescriptionAtIndex:(NSInteger)anInt 364| 0|{ 365| 0| id object; 366| | 367| 0| [self getArgument:&object atIndex:anInt]; 368| 0| if (object == nil) 369| 0| return @"nil"; 370| 0| else if(![object isProxy] && [object isKindOfClass:[NSString class]]) 371| 0| return [NSString stringWithFormat:@"@\"%@\"", [object description]]; 372| 0| else 373| | // The description cannot be nil, if it is then replace it 374| 0| return [object description] ?: @""; 375| 0|} 376| | 377| |- (NSString *)boolDescriptionAtIndex:(NSInteger)anInt 378| 0|{ 379| 0| bool value; 380| 0| [self getArgument:&value atIndex:anInt]; 381| 0| return value? @"YES" : @"NO"; 382| 0|} 383| | 384| |- (NSString *)charDescriptionAtIndex:(NSInteger)anInt 385| 0|{ 386| 0| unsigned char buffer[128]; 387| 0| memset(buffer, 0x0, 128); 388| | 389| 0| [self getArgument:&buffer atIndex:anInt]; 390| | 391| | // If there's only one character in the buffer, and it's 0 or 1, then we have a BOOL 392| 0| if (buffer[1] == '\0' && (buffer[0] == 0 || buffer[0] == 1)) 393| 0| return (buffer[0] == 1 ? @"YES" : @"NO"); 394| 0| else 395| 0| return [NSString stringWithFormat:@"'%c'", *buffer]; 396| 0|} 397| | 398| |- (NSString *)unsignedCharDescriptionAtIndex:(NSInteger)anInt 399| 0|{ 400| 0| unsigned char buffer[128]; 401| 0| memset(buffer, 0x0, 128); 402| | 403| 0| [self getArgument:&buffer atIndex:anInt]; 404| 0| return [NSString stringWithFormat:@"'%c'", *buffer]; 405| 0|} 406| | 407| |- (NSString *)intDescriptionAtIndex:(NSInteger)anInt 408| 0|{ 409| 0| int intValue; 410| | 411| 0| [self getArgument:&intValue atIndex:anInt]; 412| 0| return [NSString stringWithFormat:@"%d", intValue]; 413| 0|} 414| | 415| |- (NSString *)unsignedIntDescriptionAtIndex:(NSInteger)anInt 416| 0|{ 417| 0| unsigned int intValue; 418| | 419| 0| [self getArgument:&intValue atIndex:anInt]; 420| 0| return [NSString stringWithFormat:@"%d", intValue]; 421| 0|} 422| | 423| |- (NSString *)shortDescriptionAtIndex:(NSInteger)anInt 424| 0|{ 425| 0| short shortValue; 426| | 427| 0| [self getArgument:&shortValue atIndex:anInt]; 428| 0| return [NSString stringWithFormat:@"%hi", shortValue]; 429| 0|} 430| | 431| |- (NSString *)unsignedShortDescriptionAtIndex:(NSInteger)anInt 432| 0|{ 433| 0| unsigned short shortValue; 434| | 435| 0| [self getArgument:&shortValue atIndex:anInt]; 436| 0| return [NSString stringWithFormat:@"%hu", shortValue]; 437| 0|} 438| | 439| |- (NSString *)longDescriptionAtIndex:(NSInteger)anInt 440| 0|{ 441| 0| long longValue; 442| | 443| 0| [self getArgument:&longValue atIndex:anInt]; 444| 0| return [NSString stringWithFormat:@"%ld", longValue]; 445| 0|} 446| | 447| |- (NSString *)unsignedLongDescriptionAtIndex:(NSInteger)anInt 448| 0|{ 449| 0| unsigned long longValue; 450| | 451| 0| [self getArgument:&longValue atIndex:anInt]; 452| 0| return [NSString stringWithFormat:@"%lu", longValue]; 453| 0|} 454| | 455| |- (NSString *)longLongDescriptionAtIndex:(NSInteger)anInt 456| 0|{ 457| 0| long long longLongValue; 458| | 459| 0| [self getArgument:&longLongValue atIndex:anInt]; 460| 0| return [NSString stringWithFormat:@"%qi", longLongValue]; 461| 0|} 462| | 463| |- (NSString *)unsignedLongLongDescriptionAtIndex:(NSInteger)anInt 464| 0|{ 465| 0| unsigned long long longLongValue; 466| | 467| 0| [self getArgument:&longLongValue atIndex:anInt]; 468| 0| return [NSString stringWithFormat:@"%qu", longLongValue]; 469| 0|} 470| | 471| |- (NSString *)doubleDescriptionAtIndex:(NSInteger)anInt 472| 0|{ 473| 0| double doubleValue; 474| | 475| 0| [self getArgument:&doubleValue atIndex:anInt]; 476| 0| return [NSString stringWithFormat:@"%f", doubleValue]; 477| 0|} 478| | 479| |- (NSString *)floatDescriptionAtIndex:(NSInteger)anInt 480| 0|{ 481| 0| float floatValue; 482| | 483| 0| [self getArgument:&floatValue atIndex:anInt]; 484| 0| return [NSString stringWithFormat:@"%f", floatValue]; 485| 0|} 486| | 487| |- (NSString *)longDoubleDescriptionAtIndex:(NSInteger)anInt 488| 0|{ 489| 0| long double longDoubleValue; 490| | 491| 0| [self getArgument:&longDoubleValue atIndex:anInt]; 492| 0| return [NSString stringWithFormat:@"%Lf", longDoubleValue]; 493| 0|} 494| | 495| |- (NSString *)structDescriptionAtIndex:(NSInteger)anInt 496| 0|{ 497| 0| return [NSString stringWithFormat:@"(%@)", [[self getArgumentAtIndexAsObject:anInt] description]]; 498| 0|} 499| | 500| |- (NSString *)pointerDescriptionAtIndex:(NSInteger)anInt 501| 0|{ 502| 0| void *buffer; 503| | 504| 0| [self getArgument:&buffer atIndex:anInt]; 505| | 506| 0| if(buffer == [OCMArg anyPointer]) 507| 0| return OCMArgAnyPointerDescription; 508| 0| else 509| 0| return [NSString stringWithFormat:@"%p", buffer]; 510| 0|} 511| | 512| |- (NSString *)cStringDescriptionAtIndex:(NSInteger)anInt 513| 0|{ 514| 0| char *cStringPtr; 515| | 516| 0| [self getArgument:&cStringPtr atIndex:anInt]; 517| | 518| 0| if(cStringPtr == [OCMArg anyPointer]) 519| 0| { 520| 0| return OCMArgAnyPointerDescription; 521| 0| } 522| 0| else 523| 0| { 524| 0| char buffer[104]; 525| 0| strlcpy(buffer, cStringPtr, sizeof(buffer)); 526| 0| strlcpy(buffer + 100, "...", (sizeof(buffer) - 100)); 527| 0| return [NSString stringWithFormat:@"\"%s\"", buffer]; 528| 0| } 529| 0|} 530| | 531| |- (NSString *)selectorDescriptionAtIndex:(NSInteger)anInt 532| 0|{ 533| 0| SEL selectorValue; 534| | 535| 0| [self getArgument:&selectorValue atIndex:anInt]; 536| 0| return [NSString stringWithFormat:@"@selector(%@)", NSStringFromSelector(selectorValue)]; 537| 0|} 538| | 539| | 540| |- (BOOL)isMethodFamily:(NSString *)family 541| 0|{ 542| | // Definitions here: https://clang.llvm.org/docs/AutomaticReferenceCounting.html#method-families 543| | 544| 0| NSMethodSignature *signature = [self methodSignature]; 545| 0| if(OCMIsObjectType(signature.methodReturnType) == NO) 546| 0| { 547| 0| return NO; 548| 0| } 549| | 550| 0| NSString *selString = NSStringFromSelector([self selector]); 551| 0| NSRange underscoreRange = [selString rangeOfString:@"^_*" options:NSRegularExpressionSearch]; 552| 0| selString = [selString substringFromIndex:NSMaxRange(underscoreRange)]; 553| | 554| 0| if([selString hasPrefix:family] == NO) 555| 0| { 556| 0| return NO; 557| 0| } 558| 0| NSUInteger familyLength = [family length]; 559| 0| if(([selString length] > familyLength) && 560| 0| ([[NSCharacterSet lowercaseLetterCharacterSet] characterIsMember:[selString characterAtIndex:familyLength]])) 561| 0| { 562| 0| return NO; 563| 0| } 564| 0| return YES; 565| 0|} 566| | 567| | 568| |- (BOOL)methodIsInInitFamily 569| 0|{ 570| 0| return [self isMethodFamily:@"init"]; 571| 0|} 572| | 573| |- (BOOL)methodIsInCreateFamily 574| 0|{ 575| 0| return [self isMethodFamily:@"alloc"] 576| 0| || [self isMethodFamily:@"copy"] 577| 0| || [self isMethodFamily:@"mutableCopy"] 578| 0| || [self isMethodFamily:@"new"]; 579| 0|} 580| | 581| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/NSMethodSignature+OCMAdditions.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#import "NSMethodSignature+OCMAdditions.h" 19| |#import "OCMFunctionsPrivate.h" 20| | 21| | 22| |@implementation NSMethodSignature(OCMAdditions) 23| | 24| |#pragma mark Signatures for dynamic properties 25| | 26| |+ (NSMethodSignature *)signatureForDynamicPropertyAccessedWithSelector:(SEL)selector inClass:(Class)aClass 27| 0|{ 28| 0| BOOL isGetter = YES; 29| 0| objc_property_t property = [self propertyMatchingSelector:selector inClass:aClass isGetter:&isGetter]; 30| 0| if(property == NULL) 31| 0| return nil; 32| | 33| 0| const char *propertyAttributesString = property_getAttributes(property); 34| 0| NSArray *propertyAttributes = [[NSString stringWithCString:propertyAttributesString 35| 0| encoding:NSASCIIStringEncoding] componentsSeparatedByString:@","]; 36| 0| NSString *typeStr = nil; 37| 0| BOOL isDynamic = NO; 38| 0| for(NSString *attribute in propertyAttributes) 39| 0| { 40| 0| if([attribute isEqualToString:@"D"]) 41| 0| isDynamic = YES; 42| 0| else if([attribute hasPrefix:@"T"]) 43| 0| typeStr = [attribute substringFromIndex:1]; 44| 0| } 45| | 46| 0| if(!isDynamic) 47| 0| return nil; 48| | 49| 0| NSRange r = [typeStr rangeOfString:@"\""]; // incomplete workaround to deal with structs 50| 0| if(r.location != NSNotFound) 51| 0| typeStr = [typeStr substringToIndex:r.location]; 52| | 53| 0| NSString *sigStringFormat = isGetter ? @"%@@:" : @"v@:%@"; 54| 0| const char *sigCString = [[NSString stringWithFormat:sigStringFormat, typeStr] cStringUsingEncoding:NSASCIIStringEncoding]; 55| 0| return [NSMethodSignature signatureWithObjCTypes:sigCString]; 56| 0|} 57| | 58| | 59| |+ (objc_property_t)propertyMatchingSelector:(SEL)selector inClass:(Class)aClass isGetter:(BOOL *)isGetterPtr 60| 0|{ 61| 0| NSString *propertyName = NSStringFromSelector(selector); 62| | 63| | // first try selector as is aassuming it's a getter 64| 0| objc_property_t property = class_getProperty(aClass, [propertyName cStringUsingEncoding:NSASCIIStringEncoding]); 65| 0| if(property != NULL) 66| 0| { 67| 0| *isGetterPtr = YES; 68| 0| return property; 69| 0| } 70| | 71| | // try setter next if selector starts with "set" 72| 0| if([propertyName hasPrefix:@"set"]) 73| 0| { 74| 0| propertyName = [propertyName substringFromIndex:@"set".length]; 75| 0| propertyName = [propertyName stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[propertyName substringToIndex:1] lowercaseString]]; 76| 0| if([propertyName hasSuffix:@":"]) 77| 0| propertyName = [propertyName substringToIndex:[propertyName length] - 1]; 78| | 79| 0| property = class_getProperty(aClass, [propertyName cStringUsingEncoding:NSASCIIStringEncoding]); 80| 0| if(property != NULL) 81| 0| { 82| 0| *isGetterPtr = NO; 83| 0| return property; 84| 0| } 85| 0| } 86| | 87| | // search through properties with custom getter/setter that corresponds to selector 88| 0| unsigned int propertiesCount = 0; 89| 0| objc_property_t *allProperties = class_copyPropertyList(aClass, &propertiesCount); 90| 0| for(unsigned int i = 0 ; i < propertiesCount; i++) 91| 0| { 92| 0| NSArray *propertyAttributes = [[NSString stringWithCString:property_getAttributes(allProperties[i]) 93| 0| encoding:NSASCIIStringEncoding] componentsSeparatedByString:@","]; 94| 0| for(NSString *attribute in propertyAttributes) 95| 0| { 96| 0| if(([attribute hasPrefix:@"G"] || [attribute hasPrefix:@"S"]) && 97| 0| [[attribute substringFromIndex:1] isEqualToString:propertyName]) 98| 0| { 99| 0| *isGetterPtr = ![attribute hasPrefix:@"S"]; 100| 0| property = allProperties[i]; 101| 0| i = propertiesCount; 102| 0| break; 103| 0| } 104| 0| } 105| 0| } 106| 0| free(allProperties); 107| | 108| 0| return property; 109| 0|} 110| | 111| | 112| |#pragma mark Signatures for blocks 113| | 114| |+ (NSMethodSignature *)signatureForBlock:(id)block 115| 0|{ 116| | /* For a more complete implementation of parsing the block data structure see: 117| | * 118| | * https://github.com/ebf/CTObjectiveCRuntimeAdditions/tree/master/CTObjectiveCRuntimeAdditions/CTObjectiveCRuntimeAdditions 119| | */ 120| | 121| 0| struct OCMBlockDef *blockRef = (__bridge struct OCMBlockDef *) block; 122| | 123| 0| if(!(blockRef->flags & OCMBlockDescriptionFlagsHasSignature)) 124| 0| return nil; 125| | 126| 0| void *signatureLocation = blockRef->descriptor; 127| 0| signatureLocation += sizeof(unsigned long int); 128| 0| signatureLocation += sizeof(unsigned long int); 129| 0| if(blockRef->flags & OCMBlockDescriptionFlagsHasCopyDispose) 130| 0| { 131| 0| signatureLocation += sizeof(void (*)(void *dst, void *src)); 132| 0| signatureLocation += sizeof(void (*)(void *src)); 133| 0| } 134| | 135| 0| const char *signature = (*(const char **) signatureLocation); 136| 0| return [NSMethodSignature signatureWithObjCTypes:signature]; 137| 0|} 138| | 139| | 140| |#pragma mark Extended attributes 141| | 142| |- (BOOL)usesSpecialStructureReturn 143| 0|{ 144| 0| const char *types = OCMTypeWithoutQualifiers([self methodReturnType]); 145| | 146| 0| if((types == NULL) || (types[0] != '{')) 147| 0| return NO; 148| | 149| | /* In some cases structures are returned by ref. The rules are complex and depend on the 150| | architecture, see: 151| | 152| | http://sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html 153| | http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/000-Introduction/introduction.html 154| | https://github.com/atgreen/libffi/blob/master/src/x86/ffi64.c 155| | http://www.uclibc.org/docs/psABI-x86_64.pdf 156| | http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf 157| | 158| | NSMethodSignature knows the details but has no API to return it, though it is in 159| | the debugDescription. Horribly kludgy. 160| | */ 161| 0| NSRange range = [[self debugDescription] rangeOfString:@"is special struct return? YES"]; 162| 0| return range.length > 0; 163| 0|} 164| | 165| | 166| |- (NSString *)fullTypeString 167| 0|{ 168| 0| NSMutableString *typeString = [NSMutableString string]; 169| 0| [typeString appendFormat:@"%s", [self methodReturnType]]; 170| 0| for (NSUInteger i=0; i<[self numberOfArguments]; i++) 171| 0| [typeString appendFormat:@"%s", [self getArgumentTypeAtIndex:i]]; 172| 0| return typeString; 173| 0|} 174| | 175| | 176| |- (const char *)fullObjCTypes 177| 0|{ 178| 0| return [[self fullTypeString] UTF8String]; 179| 0|} 180| | 181| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/NSNotificationCenter+OCMAdditions.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "NSNotificationCenter+OCMAdditions.h" 18| |#import "OCObserverMockObject.h" 19| | 20| | 21| |@implementation NSNotificationCenter(OCMAdditions) 22| | 23| |#pragma clang diagnostic push 24| |#pragma clang diagnostic ignored "-Wdeprecated-declarations" 25| | 26| |- (void)addMockObserver:(OCObserverMockObject *)notificationObserver name:(NSString *)notificationName object:(id)notificationSender 27| 0|{ 28| 0| [notificationObserver autoRemoveFromCenter:self]; 29| 0| [self addObserver:notificationObserver selector:@selector(handleNotification:) name:notificationName object:notificationSender]; 30| 0|} 31| | 32| |#pragma clang diagnostic pop 33| | 34| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/NSObject+OCMAdditions.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#import "NSObject+OCMAdditions.h" 19| |#import "NSMethodSignature+OCMAdditions.h" 20| | 21| | 22| |@implementation NSObject(OCMAdditions) 23| | 24| |+ (IMP)instanceMethodForwarderForSelector:(SEL)aSelector 25| 0|{ 26| | // use sel_registerName() and not @selector to avoid warning 27| 0| SEL selectorWithNoImplementation = sel_registerName("methodWhichMustNotExist::::"); 28| | 29| 0|#ifndef __arm64__ 30| 0| static NSMutableDictionary *_OCMReturnTypeCache; 31| | 32| 0| if(_OCMReturnTypeCache == nil) 33| 0| _OCMReturnTypeCache = [[NSMutableDictionary alloc] init]; 34| | 35| 0| BOOL needsStructureReturn; 36| 0| void *rawCacheKey[2] = { (void *)self, aSelector }; 37| 0| NSData *cacheKey = [NSData dataWithBytes:rawCacheKey length:sizeof(rawCacheKey)]; 38| 0| NSNumber *cachedValue = [_OCMReturnTypeCache objectForKey:cacheKey]; 39| | 40| 0| if(cachedValue == nil) 41| 0| { 42| 0| NSMethodSignature *sig = [self instanceMethodSignatureForSelector:aSelector]; 43| 0| needsStructureReturn = [sig usesSpecialStructureReturn]; 44| 0| [_OCMReturnTypeCache setObject:@(needsStructureReturn) forKey:cacheKey]; 45| 0| } 46| 0| else 47| 0| { 48| 0| needsStructureReturn = [cachedValue boolValue]; 49| 0| } 50| | 51| 0| if(needsStructureReturn) 52| 0| return class_getMethodImplementation_stret([NSObject class], selectorWithNoImplementation); 53| 0|#endif 54| | 55| 0| return class_getMethodImplementation([NSObject class], selectorWithNoImplementation); 56| 0|} 57| | 58| | 59| |+ (void)enumerateMethodsInClass:(Class)aClass usingBlock:(void (^)(Class cls, SEL sel))aBlock 60| 0|{ 61| 0| for(Class cls = aClass; cls != nil; cls = class_getSuperclass(cls)) 62| 0| { 63| 0| Method *methodList = class_copyMethodList(cls, NULL); 64| 0| if(methodList == NULL) 65| 0| continue; 66| | 67| 0| for(Method *mPtr = methodList; *mPtr != NULL; mPtr++) 68| 0| { 69| 0| SEL sel = method_getName(*mPtr); 70| 0| aBlock(cls, sel); 71| 0| } 72| 0| free(methodList); 73| 0| } 74| 0|} 75| | 76| | 77| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/NSValue+OCMAdditions.m: 1| |/* 2| | * Copyright (c) 2014-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "NSValue+OCMAdditions.h" 18| |#import "OCMFunctionsPrivate.h" 19| | 20| | 21| |@implementation NSValue(OCMAdditions) 22| | 23| |static NSNumber *OCMNumberForValue(NSValue *value) 24| 0|{ 25| 0|#define CREATE_NUM(_type) ({ _type _v; [value getValue:&_v]; @(_v); }) 26| 0| switch([value objCType][0]) 27| 0| { 28| 0| case 'c': return CREATE_NUM(char); 29| 0| case 'C': return CREATE_NUM(unsigned char); 30| 0| case 'B': return CREATE_NUM(bool); 31| 0| case 's': return CREATE_NUM(short); 32| 0| case 'S': return CREATE_NUM(unsigned short); 33| 0| case 'i': return CREATE_NUM(int); 34| 0| case 'I': return CREATE_NUM(unsigned int); 35| 0| case 'l': return CREATE_NUM(long); 36| 0| case 'L': return CREATE_NUM(unsigned long); 37| 0| case 'q': return CREATE_NUM(long long); 38| 0| case 'Q': return CREATE_NUM(unsigned long long); 39| 0| case 'f': return CREATE_NUM(float); 40| 0| case 'd': return CREATE_NUM(double); 41| 0| default: return nil; 42| 0| } 43| 0|} 44| | 45| | 46| |- (BOOL)getBytes:(void *)outputBuf objCType:(const char *)targetType 47| 0|{ 48| | /* 49| | * See if they are similar number types, and if we can convert losslessly between them. 50| | * For the most part, we set things up to use CFNumberGetValue, which returns false if 51| | * conversion will be lossy. 52| | */ 53| 0| CFNumberType inputType = OCMNumberTypeForObjCType([self objCType]); 54| 0| CFNumberType outputType = OCMNumberTypeForObjCType(targetType); 55| | 56| 0| if(inputType == 0 || outputType == 0) // one or both are non-number types 57| 0| return NO; 58| | 59| 0| NSNumber *inputNumber = [self isKindOfClass:[NSNumber class]] ? (NSNumber *)self : OCMNumberForValue(self); 60| | 61| | /* 62| | * Due to some legacy, back-compatible requirements in CFNumber.c, CFNumberGetValue can return true for 63| | * some conversions which should not be allowed (by reading source, conversions from integer types to 64| | * 8-bit or 16-bit integer types). So, check ourselves. 65| | */ 66| 0| long long min; 67| 0| long long max; 68| 0| long long val = [inputNumber longLongValue]; 69| 0| switch(targetType[0]) 70| 0| { 71| 0| case 'B': 72| 0| case 'c': min = CHAR_MIN; max = CHAR_MAX; break; 73| 0| case 'C': min = 0; max = UCHAR_MAX; break; 74| 0| case 's': min = SHRT_MIN; max = SHRT_MAX; break; 75| 0| case 'S': min = 0; max = USHRT_MAX; break; 76| 0| default: min = LLONG_MIN; max = LLONG_MAX; break; 77| 0| } 78| 0| if(val < min || val > max) 79| 0| return NO; 80| | 81| | /* Get the number, and return NO if the value was out of range or conversion was lossy */ 82| 0| return CFNumberGetValue((CFNumberRef)inputNumber, outputType, outputBuf); 83| 0|} 84| | 85| | 86| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCClassMockObject.m: 1| |/* 2| | * Copyright (c) 2005-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#import "OCClassMockObject.h" 19| |#import "OCMInvocationStub.h" 20| |#import "OCMFunctionsPrivate.h" 21| |#import "NSMethodSignature+OCMAdditions.h" 22| |#import "NSObject+OCMAdditions.h" 23| | 24| |@interface NSObject(OCMClassMockingSupport) 25| |+ (BOOL)supportsMocking:(NSString **)reason; 26| |@end 27| | 28| | 29| |@implementation OCClassMockObject 30| | 31| |#pragma mark Initialisers, description, accessors, etc. 32| | 33| |- (id)initWithClass:(Class)aClass 34| 0|{ 35| 0| [self assertClassIsSupported:aClass]; 36| 0| [super init]; 37| 0| mockedClass = aClass; 38| 0| [self prepareClassForClassMethodMocking]; 39| 0| return self; 40| 0|} 41| | 42| |- (void)dealloc 43| 0|{ 44| 0| [self stopMocking]; 45| 0| [super dealloc]; 46| 0|} 47| | 48| |- (NSString *)description 49| 0|{ 50| 0| return [NSString stringWithFormat:@"OCClassMockObject(%@)", NSStringFromClass(mockedClass)]; 51| 0|} 52| | 53| |- (Class)mockedClass 54| 0|{ 55| 0| return mockedClass; 56| 0|} 57| | 58| |- (void)assertClassIsSupported:(Class)aClass 59| 0|{ 60| 0| if(aClass == Nil) 61| 0| [NSException raise:NSInvalidArgumentException format:@"Class cannot be Nil."]; 62| | 63| 0| if([aClass respondsToSelector:@selector(supportsMocking:)]) 64| 0| { 65| 0| NSString *reason = nil; 66| 0| if(![aClass supportsMocking:&reason]) 67| 0| [NSException raise:NSInvalidArgumentException format:@"Class %@ does not support mocking: %@", aClass, reason]; 68| 0| } 69| 0|} 70| | 71| |#pragma mark Extending/overriding superclass behaviour 72| | 73| |- (void)stopMocking 74| 0|{ 75| 0| if(originalMetaClass != nil) 76| 0| { 77| 0| [self stopMockingClassMethods]; 78| 0| } 79| 0| if(classCreatedForNewMetaClass != nil) 80| 0| { 81| 0| OCMDisposeSubclass(classCreatedForNewMetaClass); 82| 0| classCreatedForNewMetaClass = nil; 83| 0| } 84| 0| [super stopMocking]; 85| 0|} 86| | 87| | 88| |- (void)stopMockingClassMethods 89| 0|{ 90| 0| OCMSetAssociatedMockForClass(nil, mockedClass); 91| 0| object_setClass(mockedClass, originalMetaClass); 92| 0| originalMetaClass = nil; 93| | /* created meta class will be disposed later because partial mocks create another subclass depending on it */ 94| 0|} 95| | 96| | 97| |- (void)addStub:(OCMInvocationStub *)aStub 98| 0|{ 99| 0| [super addStub:aStub]; 100| 0| if([aStub recordedAsClassMethod]) 101| 0| [self setupForwarderForClassMethodSelector:[[aStub recordedInvocation] selector]]; 102| 0|} 103| | 104| | 105| |#pragma mark Class method mocking 106| | 107| |- (void)prepareClassForClassMethodMocking 108| 0|{ 109| | /* the runtime and OCMock depend on string and array; we don't intercept methods on them to avoid endless loops */ 110| 0| if([[mockedClass class] isSubclassOfClass:[NSString class]] || [[mockedClass class] isSubclassOfClass:[NSArray class]]) 111| 0| return; 112| | 113| | /* trying to replace class methods on NSManagedObject and subclasses of it doesn't work; see #339 */ 114| 0| if([mockedClass isSubclassOfClass:objc_getClass("NSManagedObject")]) 115| 0| return; 116| | 117| | /* if there is another mock for this exact class, stop it */ 118| 0| id otherMock = OCMGetAssociatedMockForClass(mockedClass, NO); 119| 0| if(otherMock != nil) 120| 0| [otherMock stopMockingClassMethods]; 121| | 122| 0| OCMSetAssociatedMockForClass(self, mockedClass); 123| | 124| | /* dynamically create a subclass and use its meta class as the meta class for the mocked class */ 125| 0| classCreatedForNewMetaClass = OCMCreateSubclass(mockedClass, mockedClass); 126| 0| originalMetaClass = object_getClass(mockedClass); 127| 0| id newMetaClass = object_getClass(classCreatedForNewMetaClass); 128| | 129| | /* create a dummy initialize method */ 130| 0| Method myDummyInitializeMethod = class_getInstanceMethod([self mockObjectClass], @selector(initializeForClassObject)); 131| 0| const char *initializeTypes = method_getTypeEncoding(myDummyInitializeMethod); 132| 0| IMP myDummyInitializeIMP = method_getImplementation(myDummyInitializeMethod); 133| 0| class_addMethod(newMetaClass, @selector(initialize), myDummyInitializeIMP, initializeTypes); 134| | 135| 0| object_setClass(mockedClass, newMetaClass); // only after dummy initialize is installed (iOS9) 136| | 137| | /* point forwardInvocation: of the object to the implementation in the mock */ 138| 0| Method myForwardMethod = class_getInstanceMethod([self mockObjectClass], @selector(forwardInvocationForClassObject:)); 139| 0| IMP myForwardIMP = method_getImplementation(myForwardMethod); 140| 0| class_addMethod(newMetaClass, @selector(forwardInvocation:), myForwardIMP, method_getTypeEncoding(myForwardMethod)); 141| | 142| | /* adding forwarder for most class methods (instance methods on meta class) to allow for verify after run */ 143| 0| NSArray *methodBlackList = @[@"class", @"forwardingTargetForSelector:", @"methodSignatureForSelector:", @"forwardInvocation:", @"isBlock", 144| 0| @"instanceMethodForwarderForSelector:", @"instanceMethodSignatureForSelector:", @"resolveClassMethod:"]; 145| 0| [NSObject enumerateMethodsInClass:originalMetaClass usingBlock:^(Class cls, SEL sel) { 146| 0| if((cls == object_getClass([NSObject class])) || (cls == [NSObject class]) || (cls == object_getClass(cls))) 147| 0| return; 148| 0| if(OCMIsApplePrivateMethod(cls, sel)) 149| 0| return; 150| 0| if([methodBlackList containsObject:NSStringFromSelector(sel)]) 151| 0| return; 152| 0| @try 153| 0| { 154| 0| [self setupForwarderForClassMethodSelector:sel]; 155| 0| } 156| 0| @catch(NSException *e) 157| 0| { 158| | // ignore for now 159| 0| } 160| 0| }]; 161| 0|} 162| | 163| | 164| |- (void)setupForwarderForClassMethodSelector:(SEL)selector 165| 0|{ 166| 0| SEL aliasSelector = OCMAliasForOriginalSelector(selector); 167| 0| if(class_getClassMethod(mockedClass, aliasSelector) != NULL) 168| 0| return; 169| | 170| 0| Method originalMethod = class_getClassMethod(mockedClass, selector); 171| 0| IMP originalIMP = method_getImplementation(originalMethod); 172| 0| const char *types = method_getTypeEncoding(originalMethod); 173| | 174| 0| Class metaClass = object_getClass(mockedClass); 175| 0| IMP forwarderIMP = [originalMetaClass instanceMethodForwarderForSelector:selector]; 176| 0| class_addMethod(metaClass, aliasSelector, originalIMP, types); 177| 0| class_replaceMethod(metaClass, selector, forwarderIMP, types); 178| 0|} 179| | 180| | 181| |- (void)forwardInvocationForClassObject:(NSInvocation *)anInvocation 182| 0|{ 183| | // in here "self" is a reference to the real class, not the mock 184| 0| OCClassMockObject *mock = OCMGetAssociatedMockForClass((Class) self, YES); 185| 0| if(mock == nil) 186| 0| { 187| 0| [NSException raise:NSInternalInconsistencyException format:@"No mock for class %@", NSStringFromClass((Class)self)]; 188| 0| } 189| 0| if([mock handleInvocation:anInvocation] == NO) 190| 0| { 191| 0| [anInvocation setSelector:OCMAliasForOriginalSelector([anInvocation selector])]; 192| 0| [anInvocation invoke]; 193| 0| } 194| 0|} 195| | 196| |- (void)initializeForClassObject 197| 0|{ 198| | // we really just want to have an implementation so that the superclass's is not called 199| 0|} 200| | 201| | 202| |#pragma mark Proxy API 203| | 204| |- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 205| 0|{ 206| 0| NSMethodSignature *signature = [mockedClass instanceMethodSignatureForSelector:aSelector]; 207| 0| if(signature == nil) 208| 0| { 209| 0| signature = [NSMethodSignature signatureForDynamicPropertyAccessedWithSelector:aSelector inClass:mockedClass]; 210| 0| } 211| 0| return signature; 212| 0|} 213| | 214| |- (Class)mockObjectClass 215| 0|{ 216| 0| return [super class]; 217| 0|} 218| | 219| |- (Class)class 220| 0|{ 221| 0| return mockedClass; 222| 0|} 223| | 224| |- (BOOL)respondsToSelector:(SEL)selector 225| 0|{ 226| 0| return [mockedClass instancesRespondToSelector:selector]; 227| 0|} 228| | 229| |- (BOOL)isKindOfClass:(Class)aClass 230| 0|{ 231| 0| return [mockedClass isSubclassOfClass:aClass]; 232| 0|} 233| | 234| |- (BOOL)conformsToProtocol:(Protocol *)aProtocol 235| 0|{ 236| 0| Class clazz = mockedClass; 237| 0| while (clazz != nil) { 238| 0| if (class_conformsToProtocol(clazz, aProtocol)) { 239| 0| return YES; 240| 0| } 241| 0| clazz = class_getSuperclass(clazz); 242| 0| } 243| 0| return NO; 244| 0|} 245| | 246| |@end 247| | 248| | 249| |#pragma mark - 250| | 251| |/* 252| | taken from: 253| | `class-dump -f isNS /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/System/Library/Frameworks/CoreFoundation.framework` 254| | 255| | @ interface NSObject (__NSIsKinds) 256| | - (_Bool)isNSValue__; 257| | - (_Bool)isNSTimeZone__; 258| | - (_Bool)isNSString__; 259| | - (_Bool)isNSSet__; 260| | - (_Bool)isNSOrderedSet__; 261| | - (_Bool)isNSNumber__; 262| | - (_Bool)isNSDictionary__; 263| | - (_Bool)isNSDate__; 264| | - (_Bool)isNSData__; 265| | - (_Bool)isNSArray__; 266| | */ 267| | 268| |@implementation OCClassMockObject(NSIsKindsImplementation) 269| | 270| |- (BOOL)isNSValue__ 271| 0|{ 272| 0| return [mockedClass isSubclassOfClass:[NSValue class]]; 273| 0|} 274| | 275| |- (BOOL)isNSTimeZone__ 276| 0|{ 277| 0| return [mockedClass isSubclassOfClass:[NSTimeZone class]]; 278| 0|} 279| | 280| |- (BOOL)isNSSet__ 281| 0|{ 282| 0| return [mockedClass isSubclassOfClass:[NSSet class]]; 283| 0|} 284| | 285| |- (BOOL)isNSOrderedSet__ 286| 0|{ 287| 0| return [mockedClass isSubclassOfClass:[NSOrderedSet class]]; 288| 0|} 289| | 290| |- (BOOL)isNSNumber__ 291| 0|{ 292| 0| return [mockedClass isSubclassOfClass:[NSNumber class]]; 293| 0|} 294| | 295| |- (BOOL)isNSDate__ 296| 0|{ 297| 0| return [mockedClass isSubclassOfClass:[NSDate class]]; 298| 0|} 299| | 300| |- (BOOL)isNSString__ 301| 0|{ 302| 0| return [mockedClass isSubclassOfClass:[NSString class]]; 303| 0|} 304| | 305| |- (BOOL)isNSDictionary__ 306| 0|{ 307| 0| return [mockedClass isSubclassOfClass:[NSDictionary class]]; 308| 0|} 309| | 310| |- (BOOL)isNSData__ 311| 0|{ 312| 0| return [mockedClass isSubclassOfClass:[NSData class]]; 313| 0|} 314| | 315| |- (BOOL)isNSArray__ 316| 0|{ 317| 0| return [mockedClass isSubclassOfClass:[NSArray class]]; 318| 0|} 319| | 320| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMArg.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#import "OCMArg.h" 19| |#import "OCMBlockArgCaller.h" 20| |#import "OCMConstraint.h" 21| |#import "OCMPassByRefSetter.h" 22| | 23| | 24| |@implementation OCMArg 25| | 26| |+ (id)any 27| 0|{ 28| 0| return [OCMAnyConstraint constraint]; 29| 0|} 30| | 31| |+ (void *)anyPointer 32| 0|{ 33| 0| return (void *)0x01234567; 34| 0|} 35| | 36| |+ (id __autoreleasing *)anyObjectRef 37| 0|{ 38| 0| return (id *)0x01234567; 39| 0|} 40| | 41| |+ (SEL)anySelector 42| 0|{ 43| 0| return NSSelectorFromString(@"aSelectorThatMatchesAnySelector"); 44| 0|} 45| | 46| |+ (id)isNil 47| 0|{ 48| 0| return [OCMIsNilConstraint constraint]; 49| 0|} 50| | 51| |+ (id)isNotNil 52| 0|{ 53| 0| return [OCMIsNotNilConstraint constraint]; 54| 0|} 55| | 56| |+ (id)isEqual:(id)value 57| 0|{ 58| 0| return value; 59| 0|} 60| | 61| |+ (id)isNotEqual:(id)value 62| 0|{ 63| 0| OCMIsNotEqualConstraint *constraint = [OCMIsNotEqualConstraint constraint]; 64| 0| constraint->testValue = value; 65| 0| return constraint; 66| 0|} 67| | 68| |+ (id)isKindOfClass:(Class)cls 69| 0|{ 70| 0| return [[[OCMBlockConstraint alloc] initWithConstraintBlock:^BOOL(id obj) { 71| 0| return [obj isKindOfClass:cls]; 72| 0| }] autorelease]; 73| 0|} 74| | 75| |+ (id)checkWithSelector:(SEL)selector onObject:(id)anObject 76| 0|{ 77| 0| return [OCMConstraint constraintWithSelector:selector onObject:anObject]; 78| 0|} 79| | 80| |+ (id)checkWithBlock:(BOOL (^)(id))block 81| 0|{ 82| 0| return [[[OCMBlockConstraint alloc] initWithConstraintBlock:block] autorelease]; 83| 0|} 84| | 85| |+ (id *)setTo:(id)value 86| 0|{ 87| 0| return (id *)[[[OCMPassByRefSetter alloc] initWithValue:value] autorelease]; 88| 0|} 89| | 90| |+ (void *)setToValue:(NSValue *)value 91| 0|{ 92| 0| return (id *)[[[OCMPassByRefSetter alloc] initWithValue:value] autorelease]; 93| 0|} 94| | 95| |+ (id)invokeBlock 96| 0|{ 97| 0| return [[[OCMBlockArgCaller alloc] init] autorelease]; 98| 0|} 99| | 100| |+ (id)invokeBlockWithArgs:(id)first,... NS_REQUIRES_NIL_TERMINATION 101| 0|{ 102| | 103| 0| NSMutableArray *params = [NSMutableArray array]; 104| 0| va_list args; 105| 0| if(first) 106| 0| { 107| 0| [params addObject:first]; 108| 0| va_start(args, first); 109| 0| id obj; 110| 0| while((obj = va_arg(args, id))) 111| 0| { 112| 0| [params addObject:obj]; 113| 0| } 114| 0| va_end(args); 115| 0| } 116| 0| return [[[OCMBlockArgCaller alloc] initWithBlockArguments:params] autorelease]; 117| | 118| 0|} 119| | 120| |+ (id)defaultValue 121| 0|{ 122| 0| return [NSNull null]; 123| 0|} 124| | 125| | 126| |+ (id)resolveSpecialValues:(NSValue *)value 127| 0|{ 128| 0| const char *type = [value objCType]; 129| 0| if(type[0] == '^') 130| 0| { 131| 0| void *pointer = [value pointerValue]; 132| 0| if(pointer == (void *)0x01234567) 133| 0| return [OCMArg any]; 134| 0| if((pointer != NULL) && (object_getClass((id)pointer) == [OCMPassByRefSetter class])) 135| 0| return (id)pointer; 136| 0| } 137| 0| else if(type[0] == ':') 138| 0| { 139| 0| SEL selector; 140| 0| [value getValue:&selector]; 141| 0| if(selector == NSSelectorFromString(@"aSelectorThatMatchesAnySelector")) 142| 0| return [OCMArg any]; 143| 0| } 144| 0| return value; 145| 0|} 146| | 147| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMArgAction.m: 1| |/* 2| | * Copyright (c) 2015-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMArgAction.h" 18| | 19| | 20| |@implementation OCMArgAction 21| | 22| |- (void)handleArgument:(id)argument 23| 0|{ 24| | 25| 0|} 26| | 27| | 28| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMBlockArgCaller.m: 1| |/* 2| | * Copyright (c) 2015-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMBlockArgCaller.h" 18| |#import "NSInvocation+OCMAdditions.h" 19| | 20| | 21| |@implementation OCMBlockArgCaller 22| | 23| |- (instancetype)initWithBlockArguments:(NSArray *)someArgs 24| 0|{ 25| 0| self = [super init]; 26| 0| if(self) 27| 0| { 28| 0| arguments = [someArgs copy]; 29| 0| } 30| 0| return self; 31| 0|} 32| | 33| |- (void)dealloc 34| 0|{ 35| 0| [arguments release]; 36| 0| [super dealloc]; 37| 0|} 38| | 39| |- (id)copyWithZone:(NSZone *)zone 40| 0|{ 41| 0| return [self retain]; 42| 0|} 43| | 44| |- (void)handleArgument:(id)aBlock 45| 0|{ 46| 0| if(aBlock) 47| 0| { 48| 0| NSInvocation *inv = [NSInvocation invocationForBlock:aBlock withArguments:arguments]; 49| 0| [inv invokeWithTarget:aBlock]; 50| 0| } 51| 0|} 52| | 53| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMBlockCaller.m: 1| |/* 2| | * Copyright (c) 2010-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMBlockCaller.h" 18| | 19| | 20| |@implementation OCMBlockCaller 21| | 22| |-(id)initWithCallBlock:(void (^)(NSInvocation *))theBlock 23| 0|{ 24| 0| if ((self = [super init])) 25| 0| { 26| 0| block = [theBlock copy]; 27| 0| } 28| | 29| 0| return self; 30| 0|} 31| | 32| |-(void)dealloc 33| 0|{ 34| 0| [block release]; 35| 0| [super dealloc]; 36| 0|} 37| | 38| |- (void)handleInvocation:(NSInvocation *)anInvocation 39| 0|{ 40| 0| if (block != nil) 41| 0| { 42| 0| block(anInvocation); 43| 0| } 44| 0|} 45| | 46| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMBoxedReturnValueProvider.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMBoxedReturnValueProvider.h" 18| |#import "OCMFunctionsPrivate.h" 19| |#import "NSValue+OCMAdditions.h" 20| | 21| | 22| |@implementation OCMBoxedReturnValueProvider 23| | 24| |- (void)handleInvocation:(NSInvocation *)anInvocation 25| 0|{ 26| 0| NSUInteger valueSize = 0; 27| 0| NSValue *returnValueAsNSValue = (NSValue *)returnValue; 28| 0| NSGetSizeAndAlignment([returnValueAsNSValue objCType], &valueSize, NULL); 29| 0| char valueBuffer[valueSize]; 30| 0| [returnValueAsNSValue getValue:valueBuffer]; 31| | 32| 0| const char *returnType = [[anInvocation methodSignature] methodReturnType]; 33| | 34| 0| if([self isMethodReturnType:returnType compatibleWithValueType:[returnValueAsNSValue objCType] 35| 0| value:valueBuffer valueSize:valueSize]) 36| 0| { 37| 0| [anInvocation setReturnValue:valueBuffer]; 38| 0| } 39| 0| else if([returnValueAsNSValue getBytes:valueBuffer objCType:returnType]) 40| 0| { 41| 0| [anInvocation setReturnValue:valueBuffer]; 42| 0| } 43| 0| else 44| 0| { 45| 0| [NSException raise:NSInvalidArgumentException 46| 0| format:@"Return value cannot be used for method; method signature declares '%s' but value is '%s'.", returnType, [returnValueAsNSValue objCType]]; 47| 0| } 48| 0|} 49| | 50| |- (BOOL)isMethodReturnType:(const char *)returnType compatibleWithValueType:(const char *)valueType value:(const void *)value valueSize:(size_t)valueSize 51| 0|{ 52| | /* Same types are obviously compatible */ 53| 0| if(strcmp(returnType, valueType) == 0) 54| 0| return YES; 55| | 56| | /* Special treatment for nil and Nil */ 57| 0| if(strcmp(returnType, @encode(id)) == 0 || strcmp(returnType, @encode(Class)) == 0) 58| 0| return OCMIsNilValue(valueType, value, valueSize); 59| | 60| 0| return OCMEqualTypesAllowingOpaqueStructs(returnType, valueType); 61| 0|} 62| | 63| | 64| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMConstraint.m: 1| |#import 2| |/* 3| | * Copyright (c) 2007-2020 Erik Doernenburg and contributors 4| | * 5| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 6| | * not use these files except in compliance with the License. You may obtain 7| | * a copy of the License at 8| | * 9| | * http://www.apache.org/licenses/LICENSE-2.0 10| | * 11| | * Unless required by applicable law or agreed to in writing, software 12| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14| | * License for the specific language governing permissions and limitations 15| | * under the License. 16| | */ 17| | 18| |#import "OCMConstraint.h" 19| | 20| | 21| |@implementation OCMConstraint 22| | 23| |+ (instancetype)constraint 24| 0|{ 25| 0| return [[[self alloc] init] autorelease]; 26| 0|} 27| | 28| |- (BOOL)evaluate:(id)value 29| 0|{ 30| 0| return NO; 31| 0|} 32| | 33| |- (id)copyWithZone:(struct _NSZone *)zone __unused 34| 0|{ 35| 0| return [self retain]; 36| 0|} 37| | 38| |+ (instancetype)constraintWithSelector:(SEL)aSelector onObject:(id)anObject 39| 0|{ 40| 0| OCMInvocationConstraint *constraint = [OCMInvocationConstraint constraint]; 41| 0| NSMethodSignature *signature = [anObject methodSignatureForSelector:aSelector]; 42| 0| if(signature == nil) 43| 0| [NSException raise:NSInvalidArgumentException format:@"Unkown selector %@ used in constraint.", NSStringFromSelector(aSelector)]; 44| 0| NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 45| 0| [invocation setTarget:anObject]; 46| 0| [invocation setSelector:aSelector]; 47| 0| constraint->invocation = invocation; 48| 0| return constraint; 49| 0|} 50| | 51| |+ (instancetype)constraintWithSelector:(SEL)aSelector onObject:(id)anObject withValue:(id)aValue 52| 0|{ 53| 0| OCMInvocationConstraint *constraint = (OCMInvocationConstraint *)[self constraintWithSelector:aSelector onObject:anObject]; 54| 0| if([[constraint->invocation methodSignature] numberOfArguments] < 4) 55| 0| [NSException raise:NSInvalidArgumentException format:@"Constraint with value requires selector with two arguments."]; 56| 0| [constraint->invocation setArgument:&aValue atIndex:3]; 57| 0| return constraint; 58| 0|} 59| | 60| | 61| |@end 62| | 63| | 64| | 65| |#pragma mark - 66| | 67| |@implementation OCMAnyConstraint 68| | 69| |- (BOOL)evaluate:(id)value 70| 0|{ 71| 0| return YES; 72| 0|} 73| | 74| |@end 75| | 76| | 77| | 78| |#pragma mark - 79| | 80| |@implementation OCMIsNilConstraint 81| | 82| |- (BOOL)evaluate:(id)value 83| 0|{ 84| 0| return value == nil; 85| 0|} 86| | 87| |@end 88| | 89| | 90| | 91| |#pragma mark - 92| | 93| |@implementation OCMIsNotNilConstraint 94| | 95| |- (BOOL)evaluate:(id)value 96| 0|{ 97| 0| return value != nil; 98| 0|} 99| | 100| |@end 101| | 102| | 103| | 104| |#pragma mark - 105| | 106| |@implementation OCMIsNotEqualConstraint 107| | 108| |- (BOOL)evaluate:(id)value 109| 0|{ 110| 0| return ![value isEqual:testValue]; 111| 0|} 112| | 113| |@end 114| | 115| | 116| | 117| |#pragma mark - 118| | 119| |@implementation OCMInvocationConstraint 120| | 121| |- (BOOL)evaluate:(id)value 122| 0|{ 123| 0| [invocation setArgument:&value atIndex:2]; // should test if constraint takes arg 124| 0| [invocation invoke]; 125| 0| BOOL returnValue; 126| 0| [invocation getReturnValue:&returnValue]; 127| 0| return returnValue; 128| 0|} 129| | 130| |@end 131| | 132| |#pragma mark - 133| | 134| |@implementation OCMBlockConstraint 135| | 136| |- (instancetype)initWithConstraintBlock:(BOOL (^)(id))aBlock 137| 0|{ 138| 0| if ((self = [super init])) 139| 0| { 140| 0| block = [aBlock copy]; 141| 0| } 142| | 143| 0| return self; 144| 0|} 145| | 146| 0|- (void)dealloc { 147| 0| [block release]; 148| 0| [super dealloc]; 149| 0|} 150| | 151| |- (BOOL)evaluate:(id)value 152| 0|{ 153| 0| return block ? block(value) : NO; 154| 0|} 155| | 156| | 157| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMExceptionReturnValueProvider.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMExceptionReturnValueProvider.h" 18| | 19| | 20| |@implementation OCMExceptionReturnValueProvider 21| | 22| |NSString *OCMStubbedException = @"OCMStubbedException"; 23| | 24| | 25| |- (void)handleInvocation:(NSInvocation *)anInvocation 26| 0|{ 27| 0| [[NSException exceptionWithName:OCMStubbedException reason:@"Exception stubbed in test." userInfo:@{ @"exception": returnValue }] raise]; 28| 0|} 29| | 30| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMExpectationRecorder.m: 1| |/* 2| | * Copyright (c) 2004-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMExpectationRecorder.h" 18| |#import "OCMockObject.h" 19| |#import "OCMInvocationExpectation.h" 20| | 21| | 22| |@implementation OCMExpectationRecorder 23| | 24| |#pragma mark Initialisers, description, accessors, etc. 25| | 26| |- (id)init 27| 0|{ 28| 0| self = [super init]; 29| 0| [invocationMatcher release]; 30| 0| invocationMatcher = [[OCMInvocationExpectation alloc] init]; 31| 0| return self; 32| 0|} 33| | 34| |- (OCMInvocationExpectation *)expectation 35| 0|{ 36| 0| return (OCMInvocationExpectation *)invocationMatcher; 37| 0|} 38| | 39| | 40| |#pragma mark Modifying the expectation 41| | 42| |- (id)never 43| 0|{ 44| 0| [[self expectation] setMatchAndReject:YES]; 45| 0| return self; 46| 0|} 47| | 48| | 49| |#pragma mark Finishing recording 50| | 51| |- (void)forwardInvocation:(NSInvocation *)anInvocation 52| 0|{ 53| 0| [super forwardInvocation:anInvocation]; 54| 0| [mockObject addExpectation:[self expectation]]; 55| 0|} 56| | 57| | 58| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMFunctions.m: 1| |/* 2| | * Copyright (c) 2014-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#if !TARGET_OS_WATCH 19| |#import 20| |#endif 21| |#import "OCMFunctionsPrivate.h" 22| |#import "OCClassMockObject.h" 23| |#import "OCPartialMockObject.h" 24| |#import "OCMLocation.h" 25| | 26| | 27| |#pragma mark Known private API 28| | 29| |@interface NSException(OCMKnownExceptionMethods) 30| |+ (NSException *)failureInFile:(NSString *)file atLine:(int)line withDescription:(NSString *)formatString, ...; 31| |@end 32| | 33| |@interface NSObject(OCMKnownTestCaseMethods) 34| |- (void)recordFailureWithDescription:(NSString *)description inFile:(NSString *)file atLine:(NSUInteger)line expected:(BOOL)expected; 35| |- (void)failWithException:(NSException *)exception; 36| |@end 37| | 38| | 39| |#pragma mark Functions related to ObjC type system 40| | 41| |const char *OCMTypeWithoutQualifiers(const char *objCType) 42| 0|{ 43| 0| while(strchr("rnNoORV", objCType[0]) != NULL) 44| 0| objCType += 1; 45| 0| return objCType; 46| 0|} 47| | 48| | 49| |static BOOL OCMIsUnqualifiedClassType(const char *unqualifiedObjCType) 50| 0|{ 51| 0| return (strcmp(unqualifiedObjCType, @encode(Class)) == 0); 52| 0|} 53| | 54| | 55| |static BOOL OCMIsUnqualifiedBlockType(const char *unqualifiedObjCType) 56| 0|{ 57| 0| char blockType[] = @encode(void(^)(void)); 58| 0| if(strcmp(unqualifiedObjCType, blockType) == 0) 59| 0| return YES; 60| | 61| | // sometimes block argument/return types are tacked onto the type, in angle brackets 62| 0| if(strncmp(unqualifiedObjCType, blockType, sizeof(blockType) - 1) == 0 && unqualifiedObjCType[sizeof(blockType) - 1] == '<') 63| 0| return YES; 64| | 65| 0| return NO; 66| 0|} 67| | 68| |BOOL OCMIsClassType(const char *objCType) 69| 0|{ 70| 0| return OCMIsUnqualifiedClassType(OCMTypeWithoutQualifiers(objCType)); 71| 0|} 72| | 73| |BOOL OCMIsBlockType(const char *objCType) 74| 0|{ 75| 0| return OCMIsUnqualifiedBlockType(OCMTypeWithoutQualifiers(objCType)); 76| 0|} 77| | 78| | 79| |BOOL OCMIsObjectType(const char *objCType) 80| 0|{ 81| 0| const char *unqualifiedObjCType = OCMTypeWithoutQualifiers(objCType); 82| | 83| 0| char objectType[] = @encode(id); 84| 0| if(strcmp(unqualifiedObjCType, objectType) == 0 || OCMIsUnqualifiedClassType(unqualifiedObjCType)) 85| 0| return YES; 86| | 87| | // sometimes the name of an object's class is tacked onto the type, in double quotes 88| 0| if(strncmp(unqualifiedObjCType, objectType, sizeof(objectType) - 1) == 0 && unqualifiedObjCType[sizeof(objectType) - 1] == '"') 89| 0| return YES; 90| | 91| | // if the returnType is a typedef to an object, it has the form ^{OriginClass=#} 92| 0| NSString *regexString = @"^\\^\\{(.*)=#.*\\}"; 93| 0| NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:0 error:NULL]; 94| 0| NSString *type = [NSString stringWithCString:unqualifiedObjCType encoding:NSASCIIStringEncoding]; 95| 0| if([regex numberOfMatchesInString:type options:0 range:NSMakeRange(0, type.length)] > 0) 96| 0| return YES; 97| | 98| | // if the return type is a block we treat it like an object 99| 0| return OCMIsUnqualifiedBlockType(unqualifiedObjCType); 100| 0|} 101| | 102| | 103| |CFNumberType OCMNumberTypeForObjCType(const char *objcType) 104| 0|{ 105| 0| switch (objcType[0]) 106| 0| { 107| 0| case 'c': return kCFNumberCharType; 108| 0| case 'C': return kCFNumberCharType; 109| 0| case 'B': return kCFNumberCharType; 110| 0| case 's': return kCFNumberShortType; 111| 0| case 'S': return kCFNumberShortType; 112| 0| case 'i': return kCFNumberIntType; 113| 0| case 'I': return kCFNumberIntType; 114| 0| case 'l': return kCFNumberLongType; 115| 0| case 'L': return kCFNumberLongType; 116| 0| case 'q': return kCFNumberLongLongType; 117| 0| case 'Q': return kCFNumberLongLongType; 118| 0| case 'f': return kCFNumberFloatType; 119| 0| case 'd': return kCFNumberDoubleType; 120| 0| default: return 0; 121| 0| } 122| 0|} 123| | 124| | 125| |static BOOL ParseStructType(const char *type, const char **typeEnd, const char **typeNameEnd, const char **typeEqualSign) 126| 0|{ 127| 0| if (type[0] != '{' && type[0] != '(') 128| 0| return NO; 129| | 130| 0| *typeNameEnd = NULL; 131| 0| *typeEqualSign = NULL; 132| | 133| 0| const char endChar = type[0] == '{' ? '}' : ')'; 134| 0| for (const char* ptr = type + 1; *ptr; ++ptr) { 135| 0| switch (*ptr) { 136| 0| case '(': 137| 0| case '{': 138| 0| { 139| 0| const char *subTypeEnd; 140| 0| const char *subTypeNameEnd; 141| 0| const char *subTypeEqualSign; 142| 0| if (!ParseStructType(ptr, &subTypeEnd, &subTypeNameEnd, &subTypeEqualSign)) 143| 0| return NO; 144| 0| ptr = subTypeEnd; 145| 0| break; 146| 0| } 147| 0| case '=': 148| 0| { 149| 0| if (!*typeEqualSign) { 150| 0| *typeNameEnd = ptr; 151| 0| *typeEqualSign = ptr; 152| 0| } 153| 0| break; 154| 0| } 155| 0| case ')': 156| 0| case '}': 157| 0| { 158| 0| if (*ptr == endChar) { 159| 0| *typeEnd = ptr; 160| 0| if (!*typeNameEnd) 161| 0| *typeNameEnd = ptr; 162| 0| return YES; 163| 0| } 164| 0| break; 165| 0| } 166| 0| default: 167| 0| break; 168| 0| } 169| 0| } 170| | 171| 0| return NO; 172| 0|} 173| | 174| | 175| |/* 176| | * Sometimes an external type is an opaque struct (which will have an @encode of "{structName}" 177| | * or "{structName=}") but the actual method return type, or property type, will know the contents 178| | * of the struct (so will have an objcType of say "{structName=iiSS}". This function will determine 179| | * those are equal provided they have the same structure name, otherwise everything else will be 180| | * compared textually. This can happen particularly for pointers to such structures, which still 181| | * encode what is being pointed to. 182| | * 183| | * In addition, this funtion will consider structures with unknown names, encoded as "{?=}, equal to 184| | * structures with any name. This means that "{?=dd}" and "{foo=dd}", and even "{?=}" and "{foo=dd}", 185| | * are considered equal. 186| | * 187| | * For some types some runtime functions throw exceptions, which is why we wrap this in an 188| | * exception handler just below. 189| | */ 190| |static BOOL OCMEqualTypesAllowingOpaqueStructsInternal(const char *type1, const char *type2) 191| 0|{ 192| 0| type1 = OCMTypeWithoutQualifiers(type1); 193| 0| type2 = OCMTypeWithoutQualifiers(type2); 194| | 195| 0| switch (type1[0]) 196| 0| { 197| 0| case '{': 198| 0| case '(': 199| 0| { 200| 0| if (type2[0] != type1[0]) 201| 0| return NO; 202| | 203| 0| const char *type1End; 204| 0| const char *type1NameEnd; 205| 0| const char *type1EqualSign; 206| 0| if (!ParseStructType(type1, &type1End, &type1NameEnd, &type1EqualSign)) 207| 0| return NO; 208| | 209| 0| const char *type2End; 210| 0| const char *type2NameEnd; 211| 0| const char *type2EqualSign; 212| 0| if (!ParseStructType(type2, &type2End, &type2NameEnd, &type2EqualSign)) 213| 0| return NO; 214| | 215| | /* Opaque types either don't have an equals sign (just the name and the end brace), or 216| | * empty content after the equals sign. 217| | * We want that to compare the same as a type of the same name but with the content. 218| | */ 219| 0| BOOL type1Opaque = (type1EqualSign == NULL || type1EqualSign + 1 == type1End); 220| 0| BOOL type2Opaque = (type2EqualSign == NULL || type2EqualSign + 2 == type2End); 221| 0| intptr_t type1NameLen = type1NameEnd - type1; 222| 0| intptr_t type2NameLen = type2NameEnd - type2; 223| | 224| | /* If the names are not equal and neither of the names is a question mark, return NO */ 225| 0| if ((type1NameLen != type2NameLen || strncmp(type1, type2, type1NameLen)) && 226| 0| !((type1NameLen == 2) && (type1[1] == '?')) && !((type2NameLen == 2) && (type2[1] == '?')) && 227| 0| !(type1NameLen == 1 || type2NameLen == 1)) 228| 0| return NO; 229| | 230| | /* If the same name, and at least one is opaque, that is close enough. */ 231| 0| if (type1Opaque || type2Opaque) 232| 0| return YES; 233| | 234| | /* Otherwise, compare all the elements. Use NSGetSizeAndAlignment to walk through the struct elements. */ 235| 0| type1 = type1EqualSign + 1; 236| 0| type2 = type2EqualSign + 1; 237| 0| while (type1 != type1End && *type1) 238| 0| { 239| 0| if (!OCMEqualTypesAllowingOpaqueStructs(type1, type2)) 240| 0| return NO; 241| | 242| 0| if (*type1 != '{' && *type1 != '(') { 243| 0| type1 = NSGetSizeAndAlignment(type1, NULL, NULL); 244| 0| type2 = NSGetSizeAndAlignment(type2, NULL, NULL); 245| 0| } else { 246| 0| const char *subType1End; 247| 0| const char *subType1NameEnd; 248| 0| const char *subType1EqualSign; 249| 0| if (!ParseStructType(type1, &subType1End, &subType1NameEnd, &subType1EqualSign)) 250| 0| return NO; 251| | 252| 0| const char *subType2End; 253| 0| const char *subType2NameEnd; 254| 0| const char *subType2EqualSign; 255| 0| if (!ParseStructType(type2, &subType2End, &subType2NameEnd, &subType2EqualSign)) 256| 0| return NO; 257| | 258| 0| type1 = subType1End + 1; 259| 0| type2 = subType2End + 1; 260| 0| } 261| 0| } 262| 0| return YES; 263| 0| } 264| 0| case '^': 265| | /* for a pointer, make sure the other is a pointer, then recursively compare the rest */ 266| 0| if (type2[0] != type1[0]) 267| 0| return NO; 268| 0| return OCMEqualTypesAllowingOpaqueStructs(type1 + 1, type2 + 1); 269| | 270| 0| case '?': 271| 0| return type2[0] == '?'; 272| | 273| 0| case '\0': 274| 0| return type2[0] == '\0'; 275| | 276| 0| default: 277| 0| { 278| | // Move the type pointers past the current types, then compare that region 279| 0| const char *afterType1 = NSGetSizeAndAlignment(type1, NULL, NULL); 280| 0| const char *afterType2 = NSGetSizeAndAlignment(type2, NULL, NULL); 281| 0| intptr_t type1Len = afterType1 - type1; 282| 0| intptr_t type2Len = afterType2 - type2; 283| | 284| 0| return (type1Len == type2Len && (strncmp(type1, type2, type1Len) == 0)); 285| 0| } 286| 0| } 287| 0|} 288| | 289| |BOOL OCMEqualTypesAllowingOpaqueStructs(const char *type1, const char *type2) 290| 0|{ 291| 0| @try 292| 0| { 293| 0| return OCMEqualTypesAllowingOpaqueStructsInternal(type1, type2); 294| 0| } 295| 0| @catch (NSException *e) 296| 0| { 297| | /* Probably a bitfield or something that NSGetSizeAndAlignment chokes on, oh well */ 298| 0| return NO; 299| 0| } 300| 0|} 301| | 302| |BOOL OCMIsNilValue(const char *objectCType, const void *value, size_t valueSize) 303| 0|{ 304| | // First, check value itself 305| 0| for(size_t i = 0; i < valueSize; i++) 306| 0| if(((const char *)value)[i] != 0) 307| 0| return NO; 308| | 309| | // Depending on the compilation settings of the file where the return value gets recorded, 310| | // nil and Nil get potentially different encodings. Check all known encodings. 311| 0| if((strcmp(objectCType, @encode(void *)) == 0) || // Standard Objective-C 312| 0| (strcmp(objectCType, @encode(int)) == 0) || // 32 bit C++ (before nullptr) 313| 0| (strcmp(objectCType, @encode(long long)) == 0) || // 64 bit C++ (before nullptr) 314| 0| (strcmp(objectCType, @encode(char *)) == 0)) // C++ with nullptr 315| 0| return YES; 316| | 317| 0| return NO; 318| 0|} 319| | 320| | 321| |BOOL OCMIsAppleBaseClass(Class cls) 322| 0|{ 323| 0| return (cls == [NSObject class]) || (cls == [NSProxy class]); 324| 0|} 325| | 326| |BOOL OCMIsApplePrivateMethod(Class cls, SEL sel) 327| 0|{ 328| 0| NSString *className = NSStringFromClass(cls); 329| 0| NSString *selName = NSStringFromSelector(sel); 330| 0| return ([className hasPrefix:@"NS"] || [className hasPrefix:@"UI"]) && 331| 0| ([selName hasPrefix:@"_"] || [selName hasSuffix:@"_"]); 332| 0|} 333| | 334| |BOOL OCMIsBlock(id potentialBlock) 335| 0|{ 336| 0| static Class blockClass; 337| 0| static dispatch_once_t onceToken; 338| 0| dispatch_once(&onceToken, ^ 339| 0| { 340| 0| blockClass = [^{} class]; 341| 0| Class nsObjectClass = [NSObject class]; 342| 0| while([blockClass superclass] != nsObjectClass) 343| 0| { 344| 0| blockClass = [blockClass superclass]; 345| 0| NSCAssert(blockClass != nil, @"Blocks are expected to inherit from NSObject."); 346| 0| } 347| 0| }); 348| 0| return [potentialBlock isKindOfClass:blockClass]; 349| 0|} 350| | 351| |BOOL OCMIsNonEscapingBlock(id block) 352| 0|{ 353| 0| struct OCMBlockDef *blockRef = (__bridge struct OCMBlockDef *)block; 354| 0| return OCMIsBlock(block) && (blockRef->flags & OCMBlockIsNoEscape) != 0; 355| 0|} 356| | 357| | 358| |#pragma mark Creating and disposing classes 359| | 360| |static NSString *const OCMSubclassPrefix = @"OCMock_"; 361| | 362| |Class OCMCreateSubclass(Class class, void *ref) 363| 0|{ 364| 0| const char *className = [[NSString stringWithFormat:@"%@%@-%p-%u", OCMSubclassPrefix, NSStringFromClass(class), ref, arc4random()] UTF8String]; 365| 0| Class subclass = objc_allocateClassPair(class, className, 0); 366| 0| objc_registerClassPair(subclass); 367| 0| return subclass; 368| 0|} 369| | 370| |void OCMDisposeSubclass(Class cls) 371| 0|{ 372| 0| if(!OCMIsMockSubclass(cls)) 373| 0| { 374| 0| [NSException raise:NSInvalidArgumentException format:@"Not a mock subclass; found %@\nThe subclass dynamically created by OCMock has been replaced by another class. This can happen when KVO or CoreData create their own dynamic subclass after OCMock created its subclass.\nYou will need to reorder initialization and/or teardown so that classes are created and disposed of in the right order.", NSStringFromClass(cls)]; 375| 0| } 376| 0| objc_disposeClassPair(cls); 377| 0|} 378| | 379| |BOOL OCMIsMockSubclass(Class cls) 380| 0|{ 381| 0| return [NSStringFromClass(cls) hasPrefix:OCMSubclassPrefix]; 382| 0|} 383| | 384| |BOOL OCMIsSubclassOfMockClass(Class cls) 385| 0|{ 386| 0| for(; cls != nil; cls = class_getSuperclass(cls)) 387| 0| { 388| 0| if(OCMIsMockSubclass(cls)) 389| 0| return YES; 390| 0| } 391| 0| return NO; 392| 0|} 393| | 394| | 395| |#pragma mark Alias for renaming real methods 396| | 397| |static NSString *const OCMRealMethodAliasPrefix = @"ocmock_replaced_"; 398| |static const char *const OCMRealMethodAliasPrefixCString = "ocmock_replaced_"; 399| | 400| |BOOL OCMIsAliasSelector(SEL selector) 401| 0|{ 402| 0| return [NSStringFromSelector(selector) hasPrefix:OCMRealMethodAliasPrefix]; 403| 0|} 404| | 405| |SEL OCMAliasForOriginalSelector(SEL selector) 406| 0|{ 407| 0| char aliasName[2048]; 408| 0| const char *originalName = sel_getName(selector); 409| 0| strlcpy(aliasName, OCMRealMethodAliasPrefixCString, sizeof(aliasName)); 410| 0| strlcat(aliasName, originalName, sizeof(aliasName)); 411| 0| return sel_registerName(aliasName); 412| 0|} 413| | 414| |SEL OCMOriginalSelectorForAlias(SEL selector) 415| 0|{ 416| 0| if(!OCMIsAliasSelector(selector)) 417| 0| [NSException raise:NSInvalidArgumentException format:@"Not an alias selector; found %@", NSStringFromSelector(selector)]; 418| 0| NSString *string = NSStringFromSelector(selector); 419| 0| return NSSelectorFromString([string substringFromIndex:[OCMRealMethodAliasPrefix length]]); 420| 0|} 421| | 422| | 423| |#pragma mark Wrappers around associative references 424| | 425| |static NSString *const OCMClassMethodMockObjectKey = @"OCMClassMethodMockObjectKey"; 426| | 427| |void OCMSetAssociatedMockForClass(OCClassMockObject *mock, Class aClass) 428| 0|{ 429| 0| if((mock != nil) && (objc_getAssociatedObject(aClass, OCMClassMethodMockObjectKey) != nil)) 430| 0| [NSException raise:NSInternalInconsistencyException format:@"Another mock is already associated with class %@", NSStringFromClass(aClass)]; 431| 0| objc_setAssociatedObject(aClass, OCMClassMethodMockObjectKey, mock, OBJC_ASSOCIATION_ASSIGN); 432| 0|} 433| | 434| |OCClassMockObject *OCMGetAssociatedMockForClass(Class aClass, BOOL includeSuperclasses) 435| 0|{ 436| 0| OCClassMockObject *mock = nil; 437| 0| do 438| 0| { 439| 0| mock = objc_getAssociatedObject(aClass, OCMClassMethodMockObjectKey); 440| 0| aClass = class_getSuperclass(aClass); 441| 0| } 442| 0| while((mock == nil) && (aClass != nil) && includeSuperclasses); 443| 0| return mock; 444| 0|} 445| | 446| |static NSString *const OCMPartialMockObjectKey = @"OCMPartialMockObjectKey"; 447| | 448| |void OCMSetAssociatedMockForObject(OCClassMockObject *mock, id anObject) 449| 0|{ 450| 0| if((mock != nil) && (objc_getAssociatedObject(anObject, OCMPartialMockObjectKey) != nil)) 451| 0| [NSException raise:NSInternalInconsistencyException format:@"Another mock is already associated with object %@", anObject]; 452| 0| objc_setAssociatedObject(anObject, OCMPartialMockObjectKey, mock, OBJC_ASSOCIATION_ASSIGN); 453| 0|} 454| | 455| |OCPartialMockObject *OCMGetAssociatedMockForObject(id anObject) 456| 0|{ 457| 0| return objc_getAssociatedObject(anObject, OCMPartialMockObjectKey); 458| 0|} 459| | 460| | 461| |#pragma mark Functions related to IDE error reporting 462| | 463| |void OCMReportFailure(OCMLocation *loc, NSString *description) 464| 0|{ 465| 0| id testCase = [loc testCase]; 466| 0|#ifdef __IPHONE_14_0 // this is actually a test for Xcode 12; see issue #472 467| 0|#if !TARGET_OS_WATCH 468| 0| if((testCase != nil) && [testCase respondsToSelector:@selector(recordIssue:)]) 469| 0| { 470| 0| XCTSourceCodeLocation *xctloc = [[[XCTSourceCodeLocation alloc] initWithFilePath:[loc file] lineNumber:[loc line]] autorelease]; 471| 0| XCTSourceCodeContext *xctctx = [[[XCTSourceCodeContext alloc] initWithLocation:xctloc] autorelease]; 472| 0| XCTIssue *issue = [[[XCTIssue alloc] initWithType:XCTIssueTypeAssertionFailure compactDescription:description 473| 0| detailedDescription:nil sourceCodeContext:xctctx associatedError:nil attachments:[NSArray array]] autorelease]; 474| 0| [testCase recordIssue:issue]; 475| 0| } 476| 0| else 477| 0|#endif 478| 0|#endif 479| 0| if((testCase != nil) && [testCase respondsToSelector:@selector(recordFailureWithDescription:inFile:atLine:expected:)]) 480| 0| { 481| 0| [testCase recordFailureWithDescription:description inFile:[loc file] atLine:[loc line] expected:NO]; 482| 0| } 483| 0| else if((testCase != nil) && [testCase respondsToSelector:@selector(failWithException:)]) 484| 0| { 485| 0| NSException *exception = nil; 486| 0| if([NSException instancesRespondToSelector:@selector(failureInFile:atLine:withDescription:)]) 487| 0| { 488| 0| exception = [NSException failureInFile:[loc file] atLine:(int)[loc line] withDescription:description]; 489| 0| } 490| 0| else 491| 0| { 492| 0| NSString *reason = [NSString stringWithFormat:@"%@:%lu %@", [loc file], (unsigned long)[loc line], description]; 493| 0| exception = [NSException exceptionWithName:@"OCMockTestFailure" reason:reason userInfo:nil]; 494| 0| } 495| 0| [testCase failWithException:exception]; 496| 0| } 497| 0| else if(loc != nil) 498| 0| { 499| 0| NSLog(@"%@:%lu %@", [loc file], (unsigned long)[loc line], description); 500| 0| NSString *reason = [NSString stringWithFormat:@"%@:%lu %@", [loc file], (unsigned long)[loc line], description]; 501| 0| [[NSException exceptionWithName:@"OCMockTestFailure" reason:reason userInfo:nil] raise]; 502| | 503| 0| } 504| 0| else 505| 0| { 506| 0| NSLog(@"%@", description); 507| 0| [[NSException exceptionWithName:@"OCMockTestFailure" reason:description userInfo:nil] raise]; 508| 0| } 509| | 510| 0|} /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMIndirectReturnValueProvider.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMIndirectReturnValueProvider.h" 18| | 19| | 20| |@implementation OCMIndirectReturnValueProvider 21| | 22| |- (id)initWithProvider:(id)aProvider andSelector:(SEL)aSelector 23| 0|{ 24| 0| if ((self = [super init])) 25| 0| { 26| 0| provider = [aProvider retain]; 27| 0| selector = aSelector; 28| 0| } 29| | 30| 0| return self; 31| 0|} 32| | 33| |- (void)dealloc 34| 0|{ 35| 0| [provider release]; 36| 0| [super dealloc]; 37| 0|} 38| | 39| |- (void)handleInvocation:(NSInvocation *)anInvocation 40| 0|{ 41| 0| id originalTarget = [anInvocation target]; 42| 0| SEL originalSelector = [anInvocation selector]; 43| | 44| 0| [anInvocation setTarget:provider]; 45| 0| [anInvocation setSelector:selector]; 46| 0| [anInvocation invoke]; 47| | 48| 0| [anInvocation setTarget:originalTarget]; 49| 0| [anInvocation setSelector:originalSelector]; 50| 0|} 51| | 52| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMInvocationExpectation.m: 1| |/* 2| | * Copyright (c) 2014-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMInvocationExpectation.h" 18| |#import "NSInvocation+OCMAdditions.h" 19| | 20| | 21| |@implementation OCMInvocationExpectation 22| | 23| |- (void)setMatchAndReject:(BOOL)flag 24| 0|{ 25| 0| matchAndReject = flag; 26| 0| if(matchAndReject) 27| 0| isSatisfied = YES; 28| 0|} 29| | 30| |- (BOOL)isMatchAndReject 31| 0|{ 32| 0| return matchAndReject; 33| 0|} 34| | 35| |- (BOOL)isSatisfied 36| 0|{ 37| 0| return isSatisfied; 38| 0|} 39| | 40| |- (void)addInvocationAction:(id)anAction 41| 0|{ 42| 0| if(matchAndReject) 43| 0| { 44| 0| [NSException raise:NSInternalInconsistencyException format:@"%@: cannot add action to a reject stub; got %@", 45| 0| [self description], anAction]; 46| 0| } 47| 0| [super addInvocationAction:anAction]; 48| 0|} 49| | 50| |- (void)handleInvocation:(NSInvocation *)anInvocation 51| 0|{ 52| 0| if(matchAndReject) 53| 0| { 54| 0| isSatisfied = NO; 55| 0| [NSException raise:NSInternalInconsistencyException format:@"%@: explicitly disallowed method invoked: %@", 56| 0| [self description], [anInvocation invocationDescription]]; 57| 0| } 58| 0| else 59| 0| { 60| 0| [super handleInvocation:anInvocation]; 61| 0| isSatisfied = YES; 62| 0| } 63| 0|} 64| | 65| | 66| | 67| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMInvocationMatcher.m: 1| |/* 2| | * Copyright (c) 2014-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#import "OCMInvocationMatcher.h" 19| |#import "OCMArg.h" 20| |#import "OCMConstraint.h" 21| |#import "OCMPassByRefSetter.h" 22| |#import "OCMFunctionsPrivate.h" 23| |#import "NSInvocation+OCMAdditions.h" 24| | 25| | 26| |@interface NSObject(HCMatcherDummy) 27| |- (BOOL)matches:(id)item; 28| |@end 29| | 30| | 31| |@implementation OCMInvocationMatcher 32| | 33| |- (void)dealloc 34| 0|{ 35| 0| [recordedInvocation release]; 36| 0| [super dealloc]; 37| 0|} 38| | 39| |- (void)setInvocation:(NSInvocation *)anInvocation 40| 0|{ 41| 0| [recordedInvocation release]; 42| | // Don't do a regular -retainArguments on the invocation that we use for matching. NSInvocation 43| | // effectively does an strcpy on char* arguments which messes up matching them literally and blows 44| | // up with anyPointer (in strlen since it's not actually a C string). Also on the off-chance that 45| | // anInvocation contains self as an argument, -retainArguments would create a retain cycle. 46| 0| [anInvocation retainObjectArgumentsExcludingObject:self]; 47| 0| recordedInvocation = [anInvocation retain]; 48| 0|} 49| | 50| |- (void)setRecordedAsClassMethod:(BOOL)flag 51| 0|{ 52| 0| recordedAsClassMethod = flag; 53| 0|} 54| | 55| |- (BOOL)recordedAsClassMethod 56| 0|{ 57| 0| return recordedAsClassMethod; 58| 0|} 59| | 60| |- (void)setIgnoreNonObjectArgs:(BOOL)flag 61| 0|{ 62| 0| ignoreNonObjectArgs = flag; 63| 0|} 64| | 65| |- (NSString *)description 66| 0|{ 67| 0| return [recordedInvocation invocationDescription]; 68| 0|} 69| | 70| |- (NSInvocation *)recordedInvocation 71| 0|{ 72| 0| return recordedInvocation; 73| 0|} 74| | 75| |- (BOOL)matchesSelector:(SEL)sel 76| 0|{ 77| 0| if(sel == [recordedInvocation selector]) 78| 0| return YES; 79| 0| if(OCMIsAliasSelector(sel) && 80| 0| OCMOriginalSelectorForAlias(sel) == [recordedInvocation selector]) 81| 0| return YES; 82| | 83| 0| return NO; 84| 0|} 85| | 86| |- (BOOL)matchesInvocation:(NSInvocation *)anInvocation 87| 0|{ 88| 0| id target = [anInvocation target]; 89| 0| BOOL isClassMethodInvocation = (target != nil) && (target == [target class]); 90| 0| if(isClassMethodInvocation != recordedAsClassMethod) 91| 0| return NO; 92| | 93| 0| if(![self matchesSelector:[anInvocation selector]]) 94| 0| return NO; 95| | 96| 0| NSMethodSignature *signature = [recordedInvocation methodSignature]; 97| 0| NSUInteger n = [signature numberOfArguments]; 98| 0| for(NSUInteger i = 2; i < n; i++) 99| 0| { 100| 0| if(ignoreNonObjectArgs && !OCMIsObjectType([signature getArgumentTypeAtIndex:i])) 101| 0| { 102| 0| continue; 103| 0| } 104| | 105| 0| id recordedArg = [recordedInvocation getArgumentAtIndexAsObject:i]; 106| 0| id passedArg = [anInvocation getArgumentAtIndexAsObject:i]; 107| | 108| 0| if([recordedArg isProxy]) 109| 0| { 110| 0| if(![recordedArg isEqual:passedArg]) 111| 0| return NO; 112| 0| continue; 113| 0| } 114| | 115| 0| if([recordedArg isKindOfClass:[NSValue class]]) 116| 0| recordedArg = [OCMArg resolveSpecialValues:recordedArg]; 117| | 118| 0| if([recordedArg isKindOfClass:[OCMConstraint class]]) 119| 0| { 120| 0| if([recordedArg evaluate:passedArg] == NO) 121| 0| return NO; 122| 0| } 123| 0| else if([recordedArg isKindOfClass:[OCMArgAction class]]) 124| 0| { 125| | // ignore, will be dealt with in handleInvocation: where applicable 126| 0| } 127| 0| else if([recordedArg conformsToProtocol:objc_getProtocol("HCMatcher")]) 128| 0| { 129| 0| if([recordedArg matches:passedArg] == NO) 130| 0| return NO; 131| 0| } 132| 0| else 133| 0| { 134| 0| if(([recordedArg class] == [NSNumber class]) && 135| 0| ([(NSNumber*)recordedArg compare:(NSNumber*)passedArg] != NSOrderedSame)) 136| 0| return NO; 137| 0| if(([recordedArg isEqual:passedArg] == NO) && 138| 0| !((recordedArg == nil) && (passedArg == nil))) 139| 0| return NO; 140| 0| } 141| 0| } 142| 0| return YES; 143| 0|} 144| | 145| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMInvocationStub.m: 1| |/* 2| | * Copyright (c) 2014-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMInvocationStub.h" 18| |#import "OCMArg.h" 19| |#import "OCMArgAction.h" 20| |#import "NSInvocation+OCMAdditions.h" 21| | 22| 0|#define UNSET_RETURN_VALUE_MARKER ((id)0x01234567) 23| | 24| | 25| |@implementation OCMInvocationStub 26| | 27| |- (id)init 28| 0|{ 29| 0| self = [super init]; 30| 0| invocationActions = [[NSMutableArray alloc] init]; 31| 0| return self; 32| 0|} 33| | 34| |- (void)dealloc 35| 0|{ 36| 0| [invocationActions release]; 37| 0| [super dealloc]; 38| 0|} 39| | 40| | 41| |- (void)addInvocationAction:(id)anAction 42| 0|{ 43| 0| [invocationActions addObject:anAction]; 44| 0|} 45| | 46| |- (NSArray *)invocationActions 47| 0|{ 48| 0| return invocationActions; 49| 0|} 50| | 51| | 52| |- (void)handleInvocation:(NSInvocation *)anInvocation 53| 0|{ 54| 0| [self invokeArgActionsForInvocation:anInvocation]; 55| 0| id target = [anInvocation target]; 56| | 57| 0| BOOL isInInitFamily = [anInvocation methodIsInInitFamily]; 58| 0| BOOL isInCreateFamily = isInInitFamily ? NO : [anInvocation methodIsInCreateFamily]; 59| 0| if(isInInitFamily || isInCreateFamily) 60| 0| { 61| 0| id returnVal = UNSET_RETURN_VALUE_MARKER; 62| 0| [anInvocation setReturnValue:&returnVal]; 63| | 64| 0| [self invokeActionsForInvocation:anInvocation]; 65| | 66| 0| [anInvocation getReturnValue:&returnVal]; 67| 0| if(returnVal == UNSET_RETURN_VALUE_MARKER) 68| 0| [NSException raise:NSInvalidArgumentException format:@"%@ was stubbed but no return value set. A return value is required for all alloc/copy/new/mutablecopy/init methods. If you intended to return nil, make this explicit with .andReturn(nil)", NSStringFromSelector([anInvocation selector])]; 69| | 70| 0| if(isInCreateFamily) 71| 0| { 72| | // methods that "create" an object return it with an extra retain count 73| 0| [returnVal retain]; 74| 0| } 75| 0| if(isInInitFamily) 76| 0| { 77| | // init family methods "consume" self and retain their return value. Do the retain 78| | // first in case the return value and self are the same. 79| 0| [returnVal retain]; 80| 0| [target release]; 81| 0| } 82| 0| } 83| 0| else 84| 0| { 85| 0| [self invokeActionsForInvocation:anInvocation]; 86| 0| } 87| 0|} 88| | 89| |- (void)invokeArgActionsForInvocation:(NSInvocation *)anInvocation 90| 0|{ 91| 0| NSMethodSignature *signature = [recordedInvocation methodSignature]; 92| 0| NSUInteger n = [signature numberOfArguments]; 93| 0| for(NSUInteger i = 2; i < n; i++) 94| 0| { 95| 0| id recordedArg = [recordedInvocation getArgumentAtIndexAsObject:i]; 96| 0| id passedArg = [anInvocation getArgumentAtIndexAsObject:i]; 97| | 98| 0| if([recordedArg isProxy]) 99| 0| continue; 100| | 101| 0| if([recordedArg isKindOfClass:[NSValue class]]) 102| 0| recordedArg = [OCMArg resolveSpecialValues:recordedArg]; 103| | 104| 0| if([recordedArg isKindOfClass:[OCMArgAction class]]) 105| 0| [recordedArg handleArgument:passedArg]; 106| 0| } 107| 0|} 108| | 109| |- (void)invokeActionsForInvocation:(NSInvocation *)anInvocation 110| 0|{ 111| 0| [invocationActions makeObjectsPerformSelector:@selector(handleInvocation:) withObject:anInvocation]; 112| 0|} 113| | 114| | 115| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMLocation.m: 1| |/* 2| | * Copyright (c) 2014-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMLocation.h" 18| | 19| | 20| |@implementation OCMLocation 21| | 22| |+ (instancetype)locationWithTestCase:(id)aTestCase file:(NSString *)aFile line:(NSUInteger)aLine 23| 0|{ 24| 0| return [[[OCMLocation alloc] initWithTestCase:aTestCase file:aFile line:aLine] autorelease]; 25| 0|} 26| | 27| |- (instancetype)initWithTestCase:(id)aTestCase file:(NSString *)aFile line:(NSUInteger)aLine 28| 0|{ 29| 0| if ((self = [super init])) 30| 0| { 31| 0| testCase = aTestCase; 32| 0| file = [aFile retain]; 33| 0| line = aLine; 34| 0| } 35| | 36| 0| return self; 37| 0|} 38| | 39| |- (void)dealloc 40| 0|{ 41| 0| [file release]; 42| 0| [super dealloc]; 43| 0|} 44| | 45| |- (id)testCase 46| 0|{ 47| 0| return testCase; 48| 0|} 49| | 50| |- (NSString *)file 51| 0|{ 52| 0| return file; 53| 0|} 54| | 55| |- (NSUInteger)line 56| 0|{ 57| 0| return line; 58| 0|} 59| | 60| |@end 61| | 62| | 63| |OCMLocation *OCMMakeLocation(id testCase, const char *fileCString, int line) 64| 0|{ 65| 0| return [OCMLocation locationWithTestCase:testCase file:[NSString stringWithUTF8String:fileCString] line:line]; 66| 0|} 67| | /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMMacroState.m: 1| |/* 2| | * Copyright (c) 2014-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMMacroState.h" 18| |#import "OCMExpectationRecorder.h" 19| |#import "OCMVerifier.h" 20| | 21| | 22| |@implementation OCMMacroState 23| | 24| |static NSString *const OCMGlobalStateKey = @"OCMGlobalStateKey"; 25| | 26| |#pragma mark Methods to begin/end macros 27| | 28| |+ (void)beginStubMacro 29| 0|{ 30| 0| OCMStubRecorder *recorder = [[[OCMStubRecorder alloc] init] autorelease]; 31| 0| OCMMacroState *macroState = [[OCMMacroState alloc] initWithRecorder:recorder]; 32| 0| [NSThread currentThread].threadDictionary[OCMGlobalStateKey] = macroState; 33| 0| [macroState release]; 34| 0|} 35| | 36| |+ (OCMStubRecorder *)endStubMacro 37| 0|{ 38| 0| NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary; 39| 0| OCMMacroState *globalState = threadDictionary[OCMGlobalStateKey]; 40| 0| OCMStubRecorder *recorder = [[(OCMStubRecorder *)[globalState recorder] retain] autorelease]; 41| 0| BOOL didThrow = [globalState invocationDidThrow]; 42| 0| [threadDictionary removeObjectForKey:OCMGlobalStateKey]; 43| 0| if(didThrow == NO && [recorder didRecordInvocation] == NO) 44| 0| { 45| 0| [NSException raise:NSInternalInconsistencyException 46| 0| format:@"Did not record an invocation in OCMStub/OCMExpect/OCMReject.\n" 47| 0| @"Possible causes are:\n" 48| 0| @"- The receiver is not a mock object.\n" 49| 0| @"- The selector conflicts with a selector implemented by OCMStubRecorder/OCMExpectationRecorder."]; 50| 0| } 51| 0| return recorder; 52| 0|} 53| | 54| | 55| |+ (void)beginExpectMacro 56| 0|{ 57| 0| OCMExpectationRecorder *recorder = [[[OCMExpectationRecorder alloc] init] autorelease]; 58| 0| OCMMacroState *macroState = [[OCMMacroState alloc] initWithRecorder:recorder]; 59| 0| [NSThread currentThread].threadDictionary[OCMGlobalStateKey] = macroState; 60| 0| [macroState release]; 61| 0|} 62| | 63| |+ (OCMStubRecorder *)endExpectMacro 64| 0|{ 65| 0| return [self endStubMacro]; 66| 0|} 67| | 68| | 69| |+ (void)beginRejectMacro 70| 0|{ 71| 0| OCMExpectationRecorder *recorder = [[[OCMExpectationRecorder alloc] init] autorelease]; 72| 0| OCMMacroState *macroState = [[OCMMacroState alloc] initWithRecorder:recorder]; 73| 0| [NSThread currentThread].threadDictionary[OCMGlobalStateKey] = macroState; 74| 0| [macroState release]; 75| 0|} 76| | 77| |+ (OCMStubRecorder *)endRejectMacro 78| 0|{ 79| 0| OCMMacroState *globalState = [NSThread currentThread].threadDictionary[OCMGlobalStateKey]; 80| | // Calling never after the invocation to avoid running afoul of ARC's expectations on 81| | // return values from init methods. 82| 0| [(OCMExpectationRecorder *)[globalState recorder] never]; 83| 0| return [self endStubMacro]; 84| 0|} 85| | 86| | 87| |+ (void)beginVerifyMacroAtLocation:(OCMLocation *)aLocation 88| 0|{ 89| 0| return [self beginVerifyMacroAtLocation:aLocation withQuantifier:nil]; 90| 0|} 91| | 92| |+ (void)beginVerifyMacroAtLocation:(OCMLocation *)aLocation withQuantifier:(OCMQuantifier *)quantifier 93| 0|{ 94| 0| OCMVerifier *recorder = [[[OCMVerifier alloc] init] autorelease]; 95| 0| [recorder setLocation:aLocation]; 96| 0| [recorder setQuantifier:quantifier]; 97| 0| OCMMacroState *macroState = [[OCMMacroState alloc] initWithRecorder:recorder]; 98| 0| [NSThread currentThread].threadDictionary[OCMGlobalStateKey] = macroState; 99| 0| [macroState release]; 100| 0|} 101| | 102| |+ (void)endVerifyMacro 103| 0|{ 104| 0| NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary; 105| 0| OCMMacroState *globalState = threadDictionary[OCMGlobalStateKey]; 106| 0| OCMVerifier *verifier = [[(OCMVerifier *)[globalState recorder] retain] autorelease]; 107| 0| BOOL didThrow = [globalState invocationDidThrow]; 108| 0| [threadDictionary removeObjectForKey:OCMGlobalStateKey]; 109| 0| if(didThrow == NO && [verifier didRecordInvocation] == NO) 110| 0| { 111| 0| [NSException raise:NSInternalInconsistencyException 112| 0| format:@"Did not record an invocation in OCMVerify.\n" 113| 0| @"Possible causes are:\n" 114| 0| @"- The receiver is not a mock object.\n" 115| 0| @"- The selector conflicts with a selector implemented by OCMVerifier."]; 116| 0| } 117| 0|} 118| | 119| | 120| |#pragma mark Accessing global state 121| | 122| |+ (OCMMacroState *)globalState 123| 0|{ 124| 0| return [NSThread currentThread].threadDictionary[OCMGlobalStateKey]; 125| 0|} 126| | 127| | 128| |#pragma mark Init, dealloc, accessors 129| | 130| |- (id)initWithRecorder:(OCMRecorder *)aRecorder 131| 0|{ 132| 0| if((self = [super init])) 133| 0| { 134| 0| recorder = [aRecorder retain]; 135| 0| } 136| | 137| 0| return self; 138| 0|} 139| | 140| |- (void)dealloc 141| 0|{ 142| 0| [recorder release]; 143| 0| if([NSThread currentThread].threadDictionary[OCMGlobalStateKey] == self) 144| 0| [NSException raise:NSInternalInconsistencyException format:@"Unexpected dealloc while set as the global state"]; 145| 0| [super dealloc]; 146| 0|} 147| | 148| |- (void)setRecorder:(OCMRecorder *)aRecorder 149| 0|{ 150| 0| [recorder autorelease]; 151| 0| recorder = [aRecorder retain]; 152| 0|} 153| | 154| |- (OCMRecorder *)recorder 155| 0|{ 156| 0| return recorder; 157| 0|} 158| | 159| |- (void)setInvocationDidThrow:(BOOL)flag 160| 0|{ 161| 0| invocationDidThrow = flag; 162| 0|} 163| | 164| |- (BOOL)invocationDidThrow 165| 0|{ 166| 0| return invocationDidThrow; 167| 0|} 168| | 169| | 170| |#pragma mark Changing the recorder 171| | 172| |- (void)switchToClassMethod 173| 0|{ 174| 0| [recorder classMethod]; 175| 0|} 176| | 177| | 178| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMNonRetainingObjectReturnValueProvider.m: 1| |/* 2| | * Copyright (c) 2019-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMNonRetainingObjectReturnValueProvider.h" 18| |#import "OCMFunctions.h" 19| |#import "NSInvocation+OCMAdditions.h" 20| | 21| | 22| |@implementation OCMNonRetainingObjectReturnValueProvider 23| | 24| |- (instancetype)initWithValue:(id)aValue 25| 0|{ 26| 0| if ((self = [super init])) 27| 0| returnValue = aValue; 28| 0| return self; 29| 0|} 30| | 31| |- (void)handleInvocation:(NSInvocation *)anInvocation 32| 0|{ 33| 0| if(!OCMIsObjectType([[anInvocation methodSignature] methodReturnType])) 34| 0| { 35| 0| @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Expected invocation with object return type. Did you mean to use andReturnValue: instead?" userInfo:nil]; 36| 0| } 37| 0| [anInvocation setReturnValue:&returnValue]; 38| 0|} 39| |@end 40| | /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMNotificationPoster.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMNotificationPoster.h" 18| | 19| | 20| |@implementation OCMNotificationPoster 21| | 22| |- (id)initWithNotification:(id)aNotification 23| 0|{ 24| 0| if ((self = [super init])) 25| 0| { 26| 0| notification = [aNotification retain]; 27| 0| } 28| | 29| 0| return self; 30| 0|} 31| | 32| |- (void)dealloc 33| 0|{ 34| 0| [notification release]; 35| 0| [super dealloc]; 36| 0|} 37| | 38| |- (void)handleInvocation:(NSInvocation *)anInvocation 39| 0|{ 40| 0| [[NSNotificationCenter defaultCenter] postNotification:notification]; 41| 0|} 42| | 43| | 44| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMObjectReturnValueProvider.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMObjectReturnValueProvider.h" 18| | 19| | 20| |@implementation OCMObjectReturnValueProvider 21| | 22| |- (instancetype)initWithValue:(id)aValue 23| 0|{ 24| 0| if((self = [super initWithValue:aValue])) 25| 0| [returnValue retain]; 26| 0| return self; 27| 0|} 28| | 29| |- (void)dealloc 30| 0|{ 31| 0| [returnValue release]; 32| 0| [super dealloc]; 33| 0|} 34| | 35| | 36| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMObserverRecorder.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#import "OCMObserverRecorder.h" 19| |#import "OCMConstraint.h" 20| | 21| | 22| |@interface NSObject(HCMatcherDummy) 23| |- (BOOL)matches:(id)item; 24| |@end 25| | 26| |#pragma mark - 27| | 28| | 29| |@implementation OCMObserverRecorder 30| | 31| |#pragma mark Initialisers, description, accessors, etc. 32| | 33| |- (void)dealloc 34| 0|{ 35| 0| [recordedNotification release]; 36| 0| [super dealloc]; 37| 0|} 38| | 39| |- (BOOL)didRecordInvocation 40| 0|{ 41| 0| return YES; // Needed for macro use, and recorder can only end up in macro state if it was used. 42| 0|} 43| | 44| | 45| |#pragma mark Recording 46| | 47| |- (NSNotification *)notificationWithName:(NSString *)name object:(id)sender 48| 0|{ 49| 0| recordedNotification = [[NSNotification notificationWithName:name object:sender] retain]; 50| 0| return nil; 51| 0|} 52| | 53| |- (NSNotification *)notificationWithName:(NSString *)name object:(id)sender userInfo:(NSDictionary *)userInfo 54| 0|{ 55| 0| recordedNotification = [[NSNotification notificationWithName:name object:sender userInfo:userInfo] retain]; 56| 0| return nil; 57| 0|} 58| | 59| | 60| |#pragma mark Verification 61| | 62| |- (BOOL)matchesNotification:(NSNotification *)aNotification 63| 0|{ 64| 0| return [self argument:[recordedNotification name] matchesArgument:[aNotification name]] && 65| 0| [self argument:[recordedNotification object] matchesArgument:[aNotification object]] && 66| 0| [self argument:[recordedNotification userInfo] matchesArgument:[aNotification userInfo]]; 67| 0|} 68| | 69| |- (BOOL)argument:(id)expectedArg matchesArgument:(id)observedArg 70| 0|{ 71| 0| if([expectedArg isKindOfClass:[OCMConstraint class]]) 72| 0| { 73| 0| return [expectedArg evaluate:observedArg]; 74| 0| } 75| 0| else if([expectedArg conformsToProtocol:objc_getProtocol("HCMatcher")]) 76| 0| { 77| 0| return [expectedArg matches:observedArg]; 78| 0| } 79| 0| else if (expectedArg == observedArg) 80| 0| { 81| 0| return YES; 82| 0| } 83| 0| else if (expectedArg == nil || observedArg == nil) 84| 0| { 85| 0| return NO; 86| 0| } 87| 0| else 88| 0| { 89| 0| return [expectedArg isEqual:observedArg]; 90| 0| } 91| 0|} 92| | 93| | 94| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMPassByRefSetter.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMPassByRefSetter.h" 18| | 19| | 20| |@implementation OCMPassByRefSetter 21| | 22| |- (id)initWithValue:(id)aValue 23| 0|{ 24| 0| if ((self = [super init])) 25| 0| { 26| 0| value = [aValue retain]; 27| 0| } 28| | 29| 0| return self; 30| 0|} 31| | 32| |- (void)dealloc 33| 0|{ 34| 0| [value release]; 35| 0| [super dealloc]; 36| 0|} 37| | 38| |- (void)handleArgument:(id)arg 39| 0|{ 40| 0| void *pointerValue = [arg pointerValue]; 41| 0| if(pointerValue != NULL) 42| 0| { 43| 0| if([value isKindOfClass:[NSValue class]]) 44| 0| [(NSValue *)value getValue:pointerValue]; 45| 0| else 46| 0| *(id *)pointerValue = value; 47| 0| } 48| 0|} 49| | 50| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMQuantifier.m: 1| |/* 2| | * Copyright (c) 2016-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMQuantifier.h" 18| |#import "OCMMacroState.h" 19| |#import "OCMVerifier.h" 20| | 21| | 22| |@interface OCMExactCountQuantifier : OCMQuantifier 23| | 24| |@end 25| | 26| |@interface OCMAtLeastQuantifier : OCMQuantifier 27| | 28| |@end 29| | 30| |@interface OCMAtMostQuantifier : OCMQuantifier 31| | 32| |@end 33| | 34| | 35| | 36| |@implementation OCMQuantifier 37| | 38| |+ (instancetype)exactly:(NSUInteger)count 39| 0|{ 40| 0| return [[[OCMExactCountQuantifier alloc] initWithCount:count] autorelease]; 41| 0|} 42| | 43| |+ (instancetype)never 44| 0|{ 45| 0| return [self exactly:0]; 46| 0|} 47| | 48| |+ (instancetype)atLeast:(NSUInteger)count 49| 0|{ 50| 0| return [[[OCMAtLeastQuantifier alloc] initWithCount:count] autorelease]; 51| 0|} 52| | 53| |+ (instancetype)atMost:(NSUInteger)count 54| 0|{ 55| 0| return [[[OCMAtMostQuantifier alloc] initWithCount:count] autorelease]; 56| 0|} 57| | 58| | 59| |- (instancetype)initWithCount:(NSUInteger)count 60| 0|{ 61| 0| if((self = [super init]) != nil) 62| 0| { 63| 0| expectedCount = count; 64| 0| [(OCMVerifier *)[[OCMMacroState globalState] recorder] setQuantifier:self]; 65| 0| } 66| 0| return self; 67| 0|} 68| | 69| | 70| |- (BOOL)isValidCount:(NSUInteger)count 71| 0|{ 72| 0| return NO; 73| 0|} 74| | 75| |- (NSString *)description 76| 0|{ 77| 0| switch(expectedCount) 78| 0| { 79| 0| case 0: return @"never"; 80| 0| case 1: return @"once"; 81| 0| default: return [NSString stringWithFormat:@"%lu times", (unsigned long)expectedCount]; 82| 0| } 83| 0|} 84| | 85| |@end 86| | 87| | 88| |@implementation OCMExactCountQuantifier 89| | 90| |- (BOOL)isValidCount:(NSUInteger)count 91| 0|{ 92| 0| return count == expectedCount; 93| 0|} 94| | 95| |@end 96| | 97| | 98| |@implementation OCMAtLeastQuantifier 99| | 100| |- (instancetype)initWithCount:(NSUInteger)count 101| 0|{ 102| 0| if(count == 0) 103| 0| @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Count for an at-least quantifier cannot be zero." userInfo:nil]; 104| 0| return [super initWithCount:count]; 105| 0|} 106| | 107| |- (BOOL)isValidCount:(NSUInteger)count 108| 0|{ 109| 0| return count >= expectedCount; 110| 0|} 111| | 112| |- (NSString *)description 113| 0|{ 114| 0| return [@"at least " stringByAppendingString:[super description]]; 115| 0|} 116| | 117| |@end 118| | 119| | 120| |@implementation OCMAtMostQuantifier 121| | 122| |- (instancetype)initWithCount:(NSUInteger)count 123| 0|{ 124| 0| if(count == 0) 125| 0| @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Count for an at-most quantifier cannot be zero. Use never or exactly-zero quantifier instead." userInfo:nil]; 126| 0| return [super initWithCount:count]; 127| 0|} 128| | 129| |- (BOOL)isValidCount:(NSUInteger)count 130| 0|{ 131| 0| return count <= expectedCount; 132| 0|} 133| | 134| |- (NSString *)description 135| 0|{ 136| 0| return [@"at most " stringByAppendingString:[super description]]; 137| 0|} 138| | 139| |@end 140| | /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMRealObjectForwarder.m: 1| |/* 2| | * Copyright (c) 2010-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#import "OCMRealObjectForwarder.h" 19| |#import "OCPartialMockObject.h" 20| |#import "OCMFunctionsPrivate.h" 21| |#import "NSInvocation+OCMAdditions.h" 22| | 23| | 24| |@implementation OCMRealObjectForwarder 25| | 26| |- (void)handleInvocation:(NSInvocation *)anInvocation 27| 0|{ 28| 0| id invocationTarget = [anInvocation target]; 29| | 30| 0| BOOL isInInitFamily = [anInvocation methodIsInInitFamily]; 31| 0| BOOL isInCreateFamily = isInInitFamily ? NO : [anInvocation methodIsInCreateFamily]; 32| | 33| 0| [anInvocation setSelector:OCMAliasForOriginalSelector([anInvocation selector])]; 34| 0| if([invocationTarget isProxy]) 35| 0| { 36| 0| if(!class_getInstanceMethod([invocationTarget mockObjectClass], @selector(realObject))) 37| 0| [NSException raise:NSInternalInconsistencyException format:@"Method andForwardToRealObject can only be used with partial mocks and class methods."]; 38| | 39| 0| NSObject *realObject = [(OCPartialMockObject *) invocationTarget realObject]; 40| 0| [anInvocation setTarget:realObject]; 41| 0| if(isInInitFamily) 42| 0| { 43| | // The init method of the real object will "consume" self, but because the method was 44| | // invoked on the mock and not the real object a corresponding retain is missing; so 45| | // we do this here. 46| 0| [realObject retain]; 47| 0| } 48| 0| } 49| | 50| 0| [anInvocation invoke]; 51| | 52| 0| if(isInInitFamily || isInCreateFamily) 53| 0| { 54| | // After invoking the method on the real object the return value's retain count is correct, 55| | // but because we have a chain of handlers for an invocation and we handle the retain count 56| | // adjustments at the end in the stub, we undo the additional retains here. 57| 0| id returnVal; 58| 0| [anInvocation getReturnValue:&returnVal]; 59| 0| [returnVal autorelease]; 60| 0| } 61| 0|} 62| | 63| | 64| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMRecorder.m: 1| |#import 2| |/* 3| | * Copyright (c) 2014-2020 Erik Doernenburg and contributors 4| | * 5| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 6| | * not use these files except in compliance with the License. You may obtain 7| | * a copy of the License at 8| | * 9| | * http://www.apache.org/licenses/LICENSE-2.0 10| | * 11| | * Unless required by applicable law or agreed to in writing, software 12| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14| | * License for the specific language governing permissions and limitations 15| | * under the License. 16| | */ 17| | 18| |#import 19| |#import "OCMRecorder.h" 20| |#import "OCClassMockObject.h" 21| |#import "OCMInvocationMatcher.h" 22| |#import "NSInvocation+OCMAdditions.h" 23| | 24| | 25| |@implementation OCMRecorder 26| | 27| |- (instancetype)init 28| 0|{ 29| | // no super, we're inheriting from NSProxy 30| 0| didRecordInvocation = NO; 31| 0| shouldReturnMockFromInit = NO; 32| 0| return self; 33| 0|} 34| | 35| |- (instancetype)initWithMockObject:(OCMockObject *)aMockObject 36| 0|{ 37| 0| [self init]; 38| 0| [self setMockObject:aMockObject]; 39| 0| return self; 40| 0|} 41| | 42| |- (void)setMockObject:(OCMockObject *)aMockObject 43| 0|{ 44| 0| mockObject = aMockObject; 45| 0|} 46| | 47| |- (void)setShouldReturnMockFromInit:(BOOL)flag 48| 0|{ 49| 0| shouldReturnMockFromInit = flag; 50| 0|} 51| | 52| |- (void)dealloc 53| 0|{ 54| 0| [invocationMatcher release]; 55| 0| [super dealloc]; 56| 0|} 57| | 58| |- (NSString *)description 59| 0|{ 60| 0| return [invocationMatcher description]; 61| 0|} 62| | 63| |- (OCMInvocationMatcher *)invocationMatcher 64| 0|{ 65| 0| return invocationMatcher; 66| 0|} 67| | 68| |- (BOOL)didRecordInvocation 69| 0|{ 70| 0| return didRecordInvocation; 71| 0|} 72| | 73| | 74| |#pragma mark Modifying the matcher 75| | 76| |- (id)classMethod 77| 0|{ 78| | // should we handle the case where this is called with a mock that isn't a class mock? 79| 0| [invocationMatcher setRecordedAsClassMethod:YES]; 80| 0| return self; 81| 0|} 82| | 83| |- (id)ignoringNonObjectArgs 84| 0|{ 85| 0| [invocationMatcher setIgnoreNonObjectArgs:YES]; 86| 0| return self; 87| 0|} 88| | 89| | 90| |#pragma mark Recording the actual invocation 91| | 92| |- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 93| 0|{ 94| 0| if([invocationMatcher recordedAsClassMethod]) 95| 0| return [[(OCClassMockObject *)mockObject mockedClass] methodSignatureForSelector:aSelector]; 96| | 97| 0| NSMethodSignature *signature = [mockObject methodSignatureForSelector:aSelector]; 98| 0| if(signature == nil) 99| 0| { 100| | // if we're a working with a class mock and there is a class method, auto-switch 101| 0| if(([object_getClass(mockObject) isSubclassOfClass:[OCClassMockObject class]]) && 102| 0| ([[(OCClassMockObject *)mockObject mockedClass] respondsToSelector:aSelector])) 103| 0| { 104| 0| [self classMethod]; 105| 0| signature = [self methodSignatureForSelector:aSelector]; 106| 0| } 107| 0| } 108| 0| return signature; 109| 0|} 110| | 111| |- (void)forwardInvocation:(NSInvocation *)anInvocation 112| 0|{ 113| 0| [anInvocation setTarget:nil]; 114| 0| didRecordInvocation = YES; 115| 0| [invocationMatcher setInvocation:anInvocation]; 116| | 117| | // Code with ARC may retain the receiver of an init method before invoking it. In that case it 118| | // relies on the init method returning an object it can release. So, we must set the correct 119| | // return value here. Normally, the correct return value is the recorder but sometimes it's the 120| | // mock. The decision is easier to make in the mock, which is why the mock sets a flag in the 121| | // recorder and we simply use the flag here. 122| 0| if([anInvocation methodIsInInitFamily]) 123| 0| { 124| 0| id returnValue = shouldReturnMockFromInit ? (id)mockObject : (id)self; 125| 0| [anInvocation setReturnValue:&returnValue]; 126| 0| } 127| 0|} 128| | 129| |- (void)doesNotRecognizeSelector:(SEL)aSelector __used 130| 0|{ 131| 0| [NSException raise:NSInvalidArgumentException format:@"%@: cannot stub/expect/verify method '%@' because no such method exists in the mocked class.", mockObject, NSStringFromSelector(aSelector)]; 132| 0|} 133| | 134| | 135| |@end 136| | 137| | 138| |@implementation OCMRecorder (Properties) 139| | 140| |@dynamic _ignoringNonObjectArgs; 141| | 142| |- (OCMRecorder *(^)(void))_ignoringNonObjectArgs 143| 0|{ 144| 0| id (^theBlock)(void) = ^ (void) 145| 0| { 146| 0| return [self ignoringNonObjectArgs]; 147| 0| }; 148| 0| return [[theBlock copy] autorelease]; 149| 0|} 150| | 151| | 152| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMStubRecorder.m: 1| |/* 2| | * Copyright (c) 2004-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMStubRecorder.h" 18| |#import "OCClassMockObject.h" 19| |#import "OCMInvocationStub.h" 20| |#import "OCMBlockCaller.h" 21| |#import "OCMBoxedReturnValueProvider.h" 22| |#import "OCMExceptionReturnValueProvider.h" 23| |#import "OCMIndirectReturnValueProvider.h" 24| |#import "OCMNotificationPoster.h" 25| |#import "OCMRealObjectForwarder.h" 26| | 27| |#if !TARGET_OS_WATCH 28| |#import 29| |#endif 30| | 31| |@implementation OCMStubRecorder 32| | 33| |#pragma mark Initialisers, description, accessors, etc. 34| | 35| |- (id)init 36| 0|{ 37| 0| if(invocationMatcher != nil) 38| 0| [NSException raise:NSInternalInconsistencyException format:@"** Method init invoked twice on stub recorder. Are you trying to mock the init method? This is currently not supported."]; 39| | 40| 0| self = [super init]; 41| 0| invocationMatcher = [[OCMInvocationStub alloc] init]; 42| 0| return self; 43| 0|} 44| | 45| |- (OCMInvocationStub *)stub 46| 0|{ 47| 0| return (OCMInvocationStub *)invocationMatcher; 48| 0|} 49| | 50| | 51| |#pragma mark Recording invocation actions 52| | 53| |- (id)andReturn:(id)anObject 54| 0|{ 55| 0| id action; 56| 0| if(anObject == mockObject) 57| 0| { 58| 0| action = [[[OCMNonRetainingObjectReturnValueProvider alloc] initWithValue:anObject] autorelease]; 59| 0| } 60| 0| else 61| 0| { 62| 0| action = [[[OCMObjectReturnValueProvider alloc] initWithValue:anObject] autorelease]; 63| 0| } 64| 0| [[self stub] addInvocationAction:action]; 65| 0| return self; 66| 0|} 67| | 68| |- (id)andReturnValue:(NSValue *)aValue 69| 0|{ 70| 0| [[self stub] addInvocationAction:[[[OCMBoxedReturnValueProvider alloc] initWithValue:aValue] autorelease]]; 71| 0| return self; 72| 0|} 73| | 74| |- (id)andThrow:(NSException *)anException 75| 0|{ 76| 0| [[self stub] addInvocationAction:[[[OCMExceptionReturnValueProvider alloc] initWithValue:anException] autorelease]]; 77| 0| return self; 78| 0|} 79| | 80| |- (id)andPost:(NSNotification *)aNotification 81| 0|{ 82| 0| [[self stub] addInvocationAction:[[[OCMNotificationPoster alloc] initWithNotification:aNotification] autorelease]]; 83| 0| return self; 84| 0|} 85| | 86| |- (id)andCall:(SEL)selector onObject:(id)anObject 87| 0|{ 88| 0| [[self stub] addInvocationAction:[[[OCMIndirectReturnValueProvider alloc] initWithProvider:anObject andSelector:selector] autorelease]]; 89| 0| return self; 90| 0|} 91| | 92| |- (id)andDo:(void (^)(NSInvocation *))aBlock 93| 0|{ 94| 0| [[self stub] addInvocationAction:[[[OCMBlockCaller alloc] initWithCallBlock:aBlock] autorelease]]; 95| 0| return self; 96| 0|} 97| | 98| |- (id)andForwardToRealObject 99| 0|{ 100| 0| [[self stub] addInvocationAction:[[[OCMRealObjectForwarder alloc] init] autorelease]]; 101| 0| return self; 102| 0|} 103| | 104| |#if !TARGET_OS_WATCH 105| |- (id)andFulfill:(XCTestExpectation *)expectation 106| 0|{ 107| 0| return [self andDo:^(NSInvocation *invocation) 108| 0| { 109| 0| [expectation fulfill]; 110| 0| }]; 111| 0|} 112| |#endif 113| | 114| |#pragma mark Finishing recording 115| | 116| |- (void)forwardInvocation:(NSInvocation *)anInvocation 117| 0|{ 118| 0| [super forwardInvocation:anInvocation]; 119| 0| [mockObject addStub:[self stub]]; 120| 0|} 121| | 122| | 123| |@end 124| | 125| | 126| |@implementation OCMStubRecorder (Properties) 127| | 128| |@dynamic _andReturn; 129| | 130| |- (OCMStubRecorder *(^)(NSValue *))_andReturn 131| 0|{ 132| 0| id (^theBlock)(id) = ^ (NSValue *aValue) 133| 0| { 134| 0| if(OCMIsObjectType([aValue objCType])) 135| 0| { 136| 0| id objValue = nil; 137| 0| [aValue getValue:&objValue]; // TODO: deprecated but replacement available in 10.13 only 138| 0| return [self andReturn:objValue]; 139| 0| } 140| 0| else 141| 0| { 142| 0| return [self andReturnValue:aValue]; 143| 0| } 144| 0| }; 145| 0| return (id)[[theBlock copy] autorelease]; 146| 0|} 147| | 148| | 149| |@dynamic _andThrow; 150| | 151| |- (OCMStubRecorder *(^)(NSException *))_andThrow 152| 0|{ 153| 0| id (^theBlock)(id) = ^ (NSException * anException) 154| 0| { 155| 0| return [self andThrow:anException]; 156| 0| }; 157| 0| return (id)[[theBlock copy] autorelease]; 158| 0|} 159| | 160| | 161| |@dynamic _andPost; 162| | 163| |- (OCMStubRecorder *(^)(NSNotification *))_andPost 164| 0|{ 165| 0| id (^theBlock)(id) = ^ (NSNotification * aNotification) 166| 0| { 167| 0| return [self andPost:aNotification]; 168| 0| }; 169| 0| return (id)[[theBlock copy] autorelease]; 170| 0|} 171| | 172| | 173| |@dynamic _andCall; 174| | 175| |- (OCMStubRecorder *(^)(id, SEL))_andCall 176| 0|{ 177| 0| id (^theBlock)(id, SEL) = ^ (id anObject, SEL aSelector) 178| 0| { 179| 0| return [self andCall:aSelector onObject:anObject]; 180| 0| }; 181| 0| return (id)[[theBlock copy] autorelease]; 182| 0|} 183| | 184| | 185| |@dynamic _andDo; 186| | 187| |- (OCMStubRecorder *(^)(void (^)(NSInvocation *)))_andDo 188| 0|{ 189| 0| id (^theBlock)(void (^)(NSInvocation *)) = ^ (void (^ blockToCall)(NSInvocation *)) 190| 0| { 191| 0| return [self andDo:blockToCall]; 192| 0| }; 193| 0| return (id)[[theBlock copy] autorelease]; 194| 0|} 195| | 196| | 197| |@dynamic _andForwardToRealObject; 198| | 199| |- (OCMStubRecorder *(^)(void))_andForwardToRealObject 200| 0|{ 201| 0| id (^theBlock)(void) = ^ (void) 202| 0| { 203| 0| return [self andForwardToRealObject]; 204| 0| }; 205| 0| return (id)[[theBlock copy] autorelease]; 206| 0|} 207| | 208| |#if !TARGET_OS_WATCH 209| | 210| |@dynamic _andFulfill; 211| | 212| |- (OCMStubRecorder * (^)(XCTestExpectation *))_andFulfill 213| 0|{ 214| 0| id (^theBlock)(XCTestExpectation *) = ^ (XCTestExpectation *expectation) 215| 0| { 216| 0| return [self andFulfill:expectation]; 217| 0| }; 218| 0| return (id)[[theBlock copy] autorelease]; 219| 0|} 220| |#endif 221| | 222| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMVerifier.m: 1| |/* 2| | * Copyright (c) 2014-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMVerifier.h" 18| |#import "OCMockObject.h" 19| |#import "OCMInvocationMatcher.h" 20| |#import "OCMLocation.h" 21| |#import "OCMQuantifier.h" 22| | 23| | 24| |@implementation OCMVerifier 25| | 26| |- (id)init 27| 0|{ 28| 0| if(invocationMatcher != nil) 29| 0| [NSException raise:NSInternalInconsistencyException format:@"** Method init invoked twice on verifier. Are you trying to verify the init method? This is currently not supported."]; 30| 0| if ((self = [super init])) 31| 0| { 32| 0| invocationMatcher = [[OCMInvocationMatcher alloc] init]; 33| 0| } 34| | 35| 0| return self; 36| 0|} 37| | 38| |- (id)withQuantifier:(OCMQuantifier *)quantifier 39| 0|{ 40| 0| [self setQuantifier:quantifier]; 41| 0| return self; 42| 0|} 43| | 44| |- (void)forwardInvocation:(NSInvocation *)anInvocation 45| 0|{ 46| 0| [super forwardInvocation:anInvocation]; 47| 0| [mockObject verifyInvocation:invocationMatcher withQuantifier:self.quantifier atLocation:self.location]; 48| 0|} 49| | 50| |- (void)dealloc 51| 0|{ 52| 0| [_location release]; 53| 0| [_quantifier release]; 54| 0| [super dealloc]; 55| 0|} 56| | 57| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCMockObject.m: 1| |/* 2| | * Copyright (c) 2004-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCMockObject.h" 18| |#import "OCClassMockObject.h" 19| |#import "OCProtocolMockObject.h" 20| |#import "OCPartialMockObject.h" 21| |#import "OCObserverMockObject.h" 22| |#import "OCMExceptionReturnValueProvider.h" 23| |#import "OCMExpectationRecorder.h" 24| |#import "OCMInvocationExpectation.h" 25| |#import "OCMLocation.h" 26| |#import "OCMMacroState.h" 27| |#import "OCMQuantifier.h" 28| |#import "OCMVerifier.h" 29| |#import "OCMFunctionsPrivate.h" 30| |#import "NSInvocation+OCMAdditions.h" 31| | 32| | 33| |@implementation OCMockObject 34| | 35| |#pragma mark Class initialisation 36| | 37| |+ (void)initialize 38| 0|{ 39| 0| if([[NSInvocation class] instanceMethodSignatureForSelector:@selector(getArgumentAtIndexAsObject:)] == NULL) 40| 0| [NSException raise:NSInternalInconsistencyException format:@"** Expected method not present; the method getArgumentAtIndexAsObject: is not implemented by NSInvocation. If you see this exception it is likely that you are using the static library version of OCMock and your project is not configured correctly to load categories from static libraries. Did you forget to add the -ObjC linker flag?"]; 41| 0|} 42| | 43| | 44| |#pragma mark Factory methods 45| | 46| |+ (id)mockForClass:(Class)aClass 47| 0|{ 48| 0| return [[[OCClassMockObject alloc] initWithClass:aClass] autorelease]; 49| 0|} 50| | 51| |+ (id)mockForProtocol:(Protocol *)aProtocol 52| 0|{ 53| 0| return [[[OCProtocolMockObject alloc] initWithProtocol:aProtocol] autorelease]; 54| 0|} 55| | 56| |+ (id)partialMockForObject:(NSObject *)anObject 57| 0|{ 58| 0| return [[[OCPartialMockObject alloc] initWithObject:anObject] autorelease]; 59| 0|} 60| | 61| | 62| |+ (id)niceMockForClass:(Class)aClass 63| 0|{ 64| 0| return [self _makeNice:[self mockForClass:aClass]]; 65| 0|} 66| | 67| |+ (id)niceMockForProtocol:(Protocol *)aProtocol 68| 0|{ 69| 0| return [self _makeNice:[self mockForProtocol:aProtocol]]; 70| 0|} 71| | 72| | 73| |+ (id)_makeNice:(OCMockObject *)mock 74| 0|{ 75| 0| mock->isNice = YES; 76| 0| return mock; 77| 0|} 78| | 79| | 80| |+ (id)observerMock 81| 0|{ 82| 0| return [[[OCObserverMockObject alloc] init] autorelease]; 83| 0|} 84| | 85| | 86| |#pragma mark Initialisers, description, accessors, etc. 87| | 88| |- (instancetype)init 89| 0|{ 90| | // check if we are called from inside a macro 91| 0| OCMRecorder *recorder = [[OCMMacroState globalState] recorder]; 92| 0| if(recorder != nil) 93| 0| { 94| 0| [recorder setMockObject:self]; 95| 0| return (id)[recorder init]; 96| 0| } 97| | 98| | // skip initialisation when init is called again, which can happen when stubbing alloc/init 99| 0| if(stubs != nil) 100| 0| { 101| 0| return self; 102| 0| } 103| | 104| 0| if([self class] == [OCMockObject class]) 105| 0| { 106| 0| [NSException raise:NSInternalInconsistencyException format:@"*** Cannot create instances of OCMockObject. Please use one of the subclasses."]; 107| 0| } 108| | 109| | // no [super init], we're inheriting from NSProxy 110| 0| expectationOrderMatters = NO; 111| 0| stubs = [[NSMutableArray alloc] init]; 112| 0| expectations = [[NSMutableArray alloc] init]; 113| 0| exceptions = [[NSMutableArray alloc] init]; 114| 0| invocations = [[NSMutableArray alloc] init]; 115| 0| return self; 116| 0|} 117| | 118| |- (void)dealloc 119| 0|{ 120| 0| [stubs release]; 121| 0| [expectations release]; 122| 0| [exceptions release]; 123| 0| [invocations release]; 124| 0| [super dealloc]; 125| 0|} 126| | 127| |- (NSString *)description 128| 0|{ 129| 0| return @"OCMockObject"; 130| 0|} 131| | 132| |- (void)addStub:(OCMInvocationStub *)aStub 133| 0|{ 134| 0| [self assertInvocationsArrayIsPresent]; 135| 0| @synchronized(stubs) 136| 0| { 137| 0| [stubs addObject:aStub]; 138| 0| } 139| 0|} 140| | 141| |- (OCMInvocationStub *)stubForInvocation:(NSInvocation *)anInvocation 142| 0|{ 143| 0| @synchronized(stubs) 144| 0| { 145| 0| for(OCMInvocationStub *stub in stubs) 146| 0| if([stub matchesInvocation:anInvocation]) 147| 0| return stub; 148| 0| return nil; 149| 0| } 150| 0|} 151| | 152| |- (void)addExpectation:(OCMInvocationExpectation *)anExpectation 153| 0|{ 154| 0| @synchronized(expectations) 155| 0| { 156| 0| [expectations addObject:anExpectation]; 157| 0| } 158| 0|} 159| | 160| |- (void)assertInvocationsArrayIsPresent 161| 0|{ 162| 0| if(invocations == nil) 163| 0| { 164| 0| [NSException raise:NSInternalInconsistencyException format:@"** Cannot use mock object %@ at %p. This error usually occurs when a mock object is used after stopMocking has been called on it. In most cases it is not necessary to call stopMocking. If you know you have to, please make sure that the mock object is not used afterwards.", [self description], (void *)self]; 165| 0| } 166| 0|} 167| | 168| |- (void)addInvocation:(NSInvocation *)anInvocation 169| 0|{ 170| 0| @synchronized(invocations) 171| 0| { 172| | // We can't do a normal retain arguments on anInvocation because its target/arguments/return 173| | // value could be self. That would produce a retain cycle self->invocations->anInvocation->self. 174| | // However we need to retain everything on anInvocation that isn't self because we expect them to 175| | // stick around after this method returns. Use our special method to retain just what's needed. 176| | // This still doesn't completely prevent retain cycles since any of the arguments could have a 177| | // strong reference to self. Those will have to be broken with manual calls to -stopMocking. 178| 0| [anInvocation retainObjectArgumentsExcludingObject:self]; 179| 0| [invocations addObject:anInvocation]; 180| 0| } 181| 0|} 182| | 183| | 184| |#pragma mark Public API 185| | 186| |- (void)setExpectationOrderMatters:(BOOL)flag 187| 0|{ 188| 0| expectationOrderMatters = flag; 189| 0|} 190| | 191| |- (void)stopMocking 192| 0|{ 193| | // invocations can contain objects that clients expect to be deallocated by now, 194| | // and they can also have a strong reference to self, creating a retain cycle. Get 195| | // rid of all of the invocations to hopefully let their objects deallocate, and to 196| | // break any retain cycles involving self. 197| 0| @synchronized(invocations) 198| 0| { 199| 0| [invocations removeAllObjects]; 200| 0| [invocations autorelease]; 201| 0| invocations = nil; 202| 0| } 203| 0|} 204| | 205| | 206| |- (id)stub 207| 0|{ 208| 0| return [[[OCMStubRecorder alloc] initWithMockObject:self] autorelease]; 209| 0|} 210| | 211| |- (id)expect 212| 0|{ 213| 0| return [[[OCMExpectationRecorder alloc] initWithMockObject:self] autorelease]; 214| 0|} 215| | 216| |- (id)reject 217| 0|{ 218| 0| return [[self expect] never]; 219| 0|} 220| | 221| | 222| |- (id)verify 223| 0|{ 224| 0| return [self verifyAtLocation:nil]; 225| 0|} 226| | 227| |- (id)verifyAtLocation:(OCMLocation *)location 228| 0|{ 229| 0| NSMutableArray *unsatisfiedExpectations = [NSMutableArray array]; 230| 0| @synchronized(expectations) 231| 0| { 232| 0| for(OCMInvocationExpectation *e in expectations) 233| 0| { 234| 0| if(![e isSatisfied]) 235| 0| [unsatisfiedExpectations addObject:e]; 236| 0| } 237| 0| } 238| | 239| 0| if([unsatisfiedExpectations count] == 1) 240| 0| { 241| 0| NSString *description = [NSString stringWithFormat:@"%@: expected method was not invoked: %@", 242| 0| [self description], [[unsatisfiedExpectations objectAtIndex:0] description]]; 243| 0| OCMReportFailure(location, description); 244| 0| } 245| 0| else if([unsatisfiedExpectations count] > 0) 246| 0| { 247| 0| NSString *description = [NSString stringWithFormat:@"%@: %@ expected methods were not invoked: %@", 248| 0| [self description], @([unsatisfiedExpectations count]), [self _stubDescriptions:YES]]; 249| 0| OCMReportFailure(location, description); 250| 0| } 251| | 252| 0| OCMInvocationExpectation *firstException = nil; 253| 0| @synchronized(exceptions) 254| 0| { 255| 0| firstException = [exceptions.firstObject retain]; 256| 0| } 257| 0| if(firstException) 258| 0| { 259| 0| NSString *description = [NSString stringWithFormat:@"%@: %@ (This is a strict mock failure that was ignored when it actually occurred.)", 260| 0| [self description], [firstException description]]; 261| 0| OCMReportFailure(location, description); 262| 0| } 263| 0| [firstException release]; 264| | 265| 0| return [[[OCMVerifier alloc] initWithMockObject:self] autorelease]; 266| 0|} 267| | 268| | 269| |- (void)verifyWithDelay:(NSTimeInterval)delay 270| 0|{ 271| 0| [self verifyWithDelay:delay atLocation:nil]; 272| 0|} 273| | 274| |- (void)verifyWithDelay:(NSTimeInterval)delay atLocation:(OCMLocation *)location 275| 0|{ 276| 0| NSTimeInterval step = 0.01; 277| 0| while(delay > 0) 278| 0| { 279| 0| @synchronized(expectations) 280| 0| { 281| 0| BOOL allExpectationsAreMatchAndReject = YES; 282| 0| for(OCMInvocationExpectation *expectation in expectations) 283| 0| { 284| 0| if(![expectation isMatchAndReject]) 285| 0| { 286| 0| allExpectationsAreMatchAndReject = NO; 287| 0| break; 288| 0| } 289| 0| } 290| 0| if(allExpectationsAreMatchAndReject) 291| 0| break; 292| 0| } 293| 0| [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:MIN(step, delay)]]; 294| 0| delay -= step; 295| 0| step *= 2; 296| 0| } 297| 0| [self verifyAtLocation:location]; 298| 0|} 299| | 300| | 301| |#pragma mark Verify after running 302| | 303| |- (void)verifyInvocation:(OCMInvocationMatcher *)matcher 304| 0|{ 305| 0| [self verifyInvocation:matcher atLocation:nil]; 306| 0|} 307| | 308| |- (void)verifyInvocation:(OCMInvocationMatcher *)matcher atLocation:(OCMLocation *)location 309| 0|{ 310| 0| [self verifyInvocation:matcher withQuantifier:nil atLocation:location]; 311| 0|} 312| | 313| |- (void)verifyInvocation:(OCMInvocationMatcher *)matcher withQuantifier:(OCMQuantifier *)quantifier atLocation:(OCMLocation *)location 314| 0|{ 315| 0| NSUInteger count = 0; 316| 0| [self assertInvocationsArrayIsPresent]; 317| 0| @synchronized(invocations) 318| 0| { 319| 0| for(NSInvocation *invocation in invocations) 320| 0| { 321| 0| if([matcher matchesInvocation:invocation]) 322| 0| count += 1; 323| 0| } 324| 0| } 325| 0| if(quantifier == nil) 326| 0| quantifier = [OCMQuantifier atLeast:1]; 327| 0| if(![quantifier isValidCount:count]) 328| 0| { 329| 0| NSString *description = [self descriptionForVerificationFailureWithMatcher:matcher quantifier:quantifier invocationCount:count]; 330| 0| OCMReportFailure(location, description); 331| 0| } 332| 0|} 333| | 334| |- (NSString *)descriptionForVerificationFailureWithMatcher:(OCMInvocationMatcher *)matcher quantifier:(OCMQuantifier *)quantifier invocationCount:(NSUInteger)count 335| 0|{ 336| 0| NSString *actualDescription = nil; 337| 0| switch(count) 338| 0| { 339| 0| case 0: actualDescription = @"not invoked"; break; 340| 0| case 1: actualDescription = @"invoked once"; break; 341| 0| default: actualDescription = [NSString stringWithFormat:@"invoked %lu times", (unsigned long)count]; break; 342| 0| } 343| | 344| 0| return [NSString stringWithFormat:@"%@: Method `%@` was %@; but was expected %@.", 345| 0| [self description], [matcher description], actualDescription, [quantifier description]]; 346| 0|} 347| | 348| | 349| |#pragma mark Handling invocations 350| | 351| |- (id)forwardingTargetForSelector:(SEL)aSelector 352| 0|{ 353| 0| if([OCMMacroState globalState] != nil) 354| 0| { 355| 0| OCMRecorder *recorder = [[OCMMacroState globalState] recorder]; 356| 0| [recorder setMockObject:self]; 357| | // In order for ARC to work correctly, the recorder has to set up return values for 358| | // methods in the init family of methods. If the mock forwards a method to the recorder 359| | // that it will record, i.e. a method that the recorder does not implement, then the 360| | // recorder must set the mock as the return value. Otherwise it must use itself. 361| 0| [recorder setShouldReturnMockFromInit:(class_getInstanceMethod(object_getClass(recorder), aSelector) == NO)]; 362| 0| return recorder; 363| 0| } 364| 0| return nil; 365| 0|} 366| | 367| | 368| |- (BOOL)handleSelector:(SEL)sel 369| 0|{ 370| 0| @synchronized(stubs) 371| 0| { 372| 0| for(OCMInvocationStub *recorder in stubs) 373| 0| if([recorder matchesSelector:sel]) 374| 0| return YES; 375| 0| } 376| 0| return NO; 377| 0|} 378| | 379| |- (void)forwardInvocation:(NSInvocation *)anInvocation 380| 0|{ 381| 0| @try 382| 0| { 383| 0| if([self handleInvocation:anInvocation] == NO) 384| 0| [self handleUnRecordedInvocation:anInvocation]; 385| 0| } 386| 0| @catch(NSException *e) 387| 0| { 388| 0| if([[e name] isEqualToString:OCMStubbedException]) 389| 0| { 390| 0| e = [[e userInfo] objectForKey:@"exception"]; 391| 0| } 392| 0| else 393| 0| { 394| | // add non-stubbed method to list of exceptions to be re-raised in verify 395| 0| @synchronized(exceptions) 396| 0| { 397| 0| [exceptions addObject:e]; 398| 0| } 399| 0| } 400| 0| [e raise]; 401| 0| } 402| 0|} 403| | 404| |- (BOOL)handleInvocation:(NSInvocation *)anInvocation 405| 0|{ 406| 0| [self assertInvocationsArrayIsPresent]; 407| 0| [self addInvocation:anInvocation]; 408| | 409| 0| OCMInvocationStub *stub = [self stubForInvocation:anInvocation]; 410| 0| if(stub == nil) 411| 0| return NO; 412| | 413| | // Retain the stub in case it ends up being removed because we still need it at the end for handleInvocation: 414| 0| [stub retain]; 415| | 416| 0| BOOL removeStub = NO; 417| 0| @synchronized(expectations) 418| 0| { 419| 0| if([expectations containsObject:stub]) 420| 0| { 421| 0| OCMInvocationExpectation *expectation = [self _nextExpectedInvocation]; 422| 0| if(expectationOrderMatters && (expectation != stub)) 423| 0| { 424| 0| [NSException raise:NSInternalInconsistencyException format:@"%@: unexpected method invoked: %@\n\texpected:\t%@", 425| 0| [self description], [stub description], [[expectations objectAtIndex:0] description]]; 426| 0| } 427| | 428| | // We can't check isSatisfied yet, since the stub won't be satisfied until we call 429| | // handleInvocation: since we'll still have the current expectation in the expectations array, which 430| | // will cause an exception if expectationOrderMatters is YES and we're not ready for any future 431| | // expected methods to be called yet 432| 0| if(![(OCMInvocationExpectation *)stub isMatchAndReject]) 433| 0| { 434| 0| [expectations removeObject:stub]; 435| 0| removeStub = YES; 436| 0| } 437| 0| } 438| 0| } 439| 0| if(removeStub) 440| 0| { 441| 0| @synchronized(stubs) 442| 0| { 443| 0| [stubs removeObject:stub]; 444| 0| } 445| 0| } 446| | 447| 0| @try 448| 0| { 449| 0| [stub handleInvocation:anInvocation]; 450| 0| } 451| 0| @finally 452| 0| { 453| 0| [stub release]; 454| 0| } 455| | 456| 0| return YES; 457| 0|} 458| | 459| |// Must be synchronized on expectations when calling this method. 460| |- (OCMInvocationExpectation *)_nextExpectedInvocation 461| 0|{ 462| 0| for(OCMInvocationExpectation *expectation in expectations) 463| 0| if(![expectation isMatchAndReject]) 464| 0| return expectation; 465| 0| return nil; 466| 0|} 467| | 468| |- (void)handleUnRecordedInvocation:(NSInvocation *)anInvocation 469| 0|{ 470| 0| if(isNice == NO) 471| 0| { 472| 0| [NSException raise:NSInternalInconsistencyException format:@"%@: unexpected method invoked: %@ %@", 473| 0| [self description], [anInvocation invocationDescription], [self _stubDescriptions:NO]]; 474| 0| } 475| 0|} 476| | 477| |- (void)doesNotRecognizeSelector:(SEL)aSelector __unused 478| 0|{ 479| 0| if([OCMMacroState globalState] != nil) 480| 0| { 481| | // we can't do anything clever with the macro state because we must raise an exception here 482| 0| [NSException raise:NSInvalidArgumentException format:@"%@: Cannot stub/expect/verify method '%@' because no such method exists in the mocked class.", 483| 0| [self description], NSStringFromSelector(aSelector)]; 484| 0| } 485| 0| else 486| 0| { 487| 0| [NSException raise:NSInvalidArgumentException format:@"-[%@ %@]: unrecognized selector sent to instance %p", 488| 0| [self description], NSStringFromSelector(aSelector), (void *)self]; 489| 0| } 490| 0|} 491| | 492| | 493| |#pragma mark Helper methods 494| | 495| |- (NSString *)_stubDescriptions:(BOOL)onlyExpectations 496| 0|{ 497| 0| NSMutableString *outputString = [NSMutableString string]; 498| 0| NSArray *stubsCopy = nil; 499| 0| @synchronized(stubs) 500| 0| { 501| 0| stubsCopy = [stubs copy]; 502| 0| } 503| 0| for(OCMStubRecorder *stub in stubsCopy) 504| 0| { 505| 0| BOOL expectationsContainStub = NO; 506| 0| @synchronized(expectations) 507| 0| { 508| 0| expectationsContainStub = [expectations containsObject:stub]; 509| 0| } 510| | 511| 0| NSString *prefix = @""; 512| | 513| 0| if(onlyExpectations) 514| 0| { 515| 0| if(expectationsContainStub == NO) 516| 0| continue; 517| 0| } 518| 0| else 519| 0| { 520| 0| if(expectationsContainStub) 521| 0| prefix = @"expected:\t"; 522| 0| else 523| 0| prefix = @"stubbed:\t"; 524| 0| } 525| 0| [outputString appendFormat:@"\n\t%@%@", prefix, [stub description]]; 526| 0| } 527| 0| [stubsCopy release]; 528| 0| return outputString; 529| 0|} 530| | 531| | 532| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCObserverMockObject.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import "OCObserverMockObject.h" 18| |#import "OCMLocation.h" 19| |#import "OCMMacroState.h" 20| |#import "OCMObserverRecorder.h" 21| |#import "OCMFunctionsPrivate.h" 22| | 23| |#pragma clang diagnostic push 24| |#pragma clang diagnostic ignored "-Wdeprecated-implementations" 25| |@implementation OCObserverMockObject 26| |#pragma clang diagnostic pop 27| | 28| |#pragma mark Initialisers, description, accessors, etc. 29| | 30| |- (id)init 31| 0|{ 32| 0| if ((self = [super init])) 33| 0| { 34| 0| recorders = [[NSMutableArray alloc] init]; 35| 0| centers = [[NSMutableArray alloc] init]; 36| 0| } 37| | 38| 0| return self; 39| 0|} 40| | 41| |- (id)retain 42| 0|{ 43| 0| return [super retain]; 44| 0|} 45| | 46| |- (void)dealloc 47| 0|{ 48| 0| for(NSNotificationCenter *c in centers) 49| 0| [c removeObserver:self]; 50| 0| [centers release]; 51| 0| [recorders release]; 52| 0| [super dealloc]; 53| 0|} 54| | 55| |- (NSString *)description 56| 0|{ 57| 0| return @"OCObserverMockObject"; 58| 0|} 59| | 60| |- (void)setExpectationOrderMatters:(BOOL)flag 61| 0|{ 62| 0| expectationOrderMatters = flag; 63| 0|} 64| | 65| |- (void)autoRemoveFromCenter:(NSNotificationCenter *)aCenter 66| 0|{ 67| 0| @synchronized(centers) 68| 0| { 69| 0| [centers addObject:aCenter]; 70| 0| } 71| 0|} 72| | 73| | 74| |#pragma mark Public API 75| | 76| |- (id)expect 77| 0|{ 78| 0| OCMObserverRecorder *recorder = [[[OCMObserverRecorder alloc] init] autorelease]; 79| 0| @synchronized(recorders) 80| 0| { 81| 0| [recorders addObject:recorder]; 82| 0| } 83| 0| return recorder; 84| 0|} 85| | 86| |- (void)verify 87| 0|{ 88| 0| [self verifyAtLocation:nil]; 89| 0|} 90| | 91| |- (void)verifyAtLocation:(OCMLocation *)location 92| 0|{ 93| 0| @synchronized(recorders) 94| 0| { 95| 0| if([recorders count] == 1) 96| 0| { 97| 0| NSString *description = [NSString stringWithFormat:@"%@: expected notification was not observed: %@", 98| 0| [self description], [[recorders lastObject] description]]; 99| 0| OCMReportFailure(location, description); 100| 0| } 101| 0| else if([recorders count] > 0) 102| 0| { 103| 0| NSString *description = [NSString stringWithFormat:@"%@ : %@ expected notifications were not observed.", 104| 0| [self description], @([recorders count])]; 105| 0| OCMReportFailure(location, description); 106| 0| } 107| 0| } 108| 0|} 109| | 110| | 111| |#pragma mark Receiving recording requests via macro 112| | 113| |// This is a bit of a hack. The methods simply assume that when they are called from within a macro that it's 114| |// the OCMExpect macro. That creates a recorder for mock objects, which we cannot use here. So, we overwrite 115| |// it with a newly allocated recorder. 116| | 117| |- (NSNotification *)notificationWithName:(NSString *)name object:(id)sender 118| 0|{ 119| 0| if([OCMMacroState globalState] != nil) 120| 0| { 121| 0| id recorder = [self expect]; 122| 0| [[OCMMacroState globalState] setRecorder:recorder]; 123| 0| return [recorder notificationWithName:name object:sender]; 124| 0| } 125| 0| return nil; 126| 0|} 127| | 128| |- (NSNotification *)notificationWithName:(NSString *)name object:(id)sender userInfo:(NSDictionary *)userInfo 129| 0|{ 130| 0| if([OCMMacroState globalState] != nil) 131| 0| { 132| 0| id recorder = [self expect]; 133| 0| [[OCMMacroState globalState] setRecorder:recorder]; 134| 0| return [recorder notificationWithName:name object:sender userInfo:userInfo]; 135| 0| } 136| 0| return nil; 137| 0|} 138| | 139| | 140| |#pragma mark Receiving notifications 141| | 142| |- (void)handleNotification:(NSNotification *)aNotification 143| 0|{ 144| 0| @synchronized(recorders) 145| 0| { 146| 0| NSUInteger i, limit; 147| | 148| 0| limit = expectationOrderMatters ? 1 : [recorders count]; 149| 0| for(i = 0; i < limit; i++) 150| 0| { 151| 0| if([[recorders objectAtIndex:i] matchesNotification:aNotification]) 152| 0| { 153| 0| [recorders removeObjectAtIndex:i]; 154| 0| return; 155| 0| } 156| 0| } 157| 0| } 158| 0| [NSException raise:NSInternalInconsistencyException format:@"%@: unexpected notification observed: %@", [self description], 159| 0| [aNotification description]]; 160| 0|} 161| | 162| | 163| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCPartialMockObject.m: 1| |/* 2| | * Copyright (c) 2009-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#import "OCPartialMockObject.h" 19| |#import "NSObject+OCMAdditions.h" 20| |#import "OCMFunctionsPrivate.h" 21| |#import "OCMInvocationStub.h" 22| |#import "NSInvocation+OCMAdditions.h" 23| |#import "NSMethodSignature+OCMAdditions.h" 24| | 25| | 26| |@implementation OCPartialMockObject 27| | 28| |#pragma mark Initialisers, description, accessors, etc. 29| | 30| |- (id)initWithObject:(NSObject *)anObject 31| 0|{ 32| 0| if(anObject == nil) 33| 0| [NSException raise:NSInvalidArgumentException format:@"Object cannot be nil."]; 34| 0| Class const class = [self classToSubclassForObject:anObject]; 35| 0| [super initWithClass:class]; 36| 0| realObject = [anObject retain]; 37| 0| [self prepareObjectForInstanceMethodMocking]; 38| 0| return self; 39| 0|} 40| | 41| |- (NSString *)description 42| 0|{ 43| 0| return [NSString stringWithFormat:@"OCPartialMockObject(%@)", NSStringFromClass(mockedClass)]; 44| 0|} 45| | 46| |- (NSObject *)realObject 47| 0|{ 48| 0| return realObject; 49| 0|} 50| | 51| |#pragma mark Helper methods 52| | 53| |- (void)assertClassIsSupported:(Class)class 54| 0|{ 55| 0| [super assertClassIsSupported:class]; 56| 0| NSString *classname = NSStringFromClass(class); 57| 0| NSString *reason = nil; 58| 0| if([classname hasPrefix:@"__NSTagged"] || [classname hasPrefix:@"NSTagged"]) 59| 0| reason = [NSString stringWithFormat:@"OCMock does not support partially mocking tagged classes; got %@", classname]; 60| 0| else if([classname hasPrefix:@"__NSCF"]) 61| 0| reason = [NSString stringWithFormat:@"OCMock does not support partially mocking toll-free bridged classes; got %@", classname]; 62| | 63| 0| if(reason != nil) 64| 0| [[NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil] raise]; 65| 0|} 66| | 67| |- (Class)classToSubclassForObject:(id)object 68| 0|{ 69| 0| if([object observationInfo] != NULL) 70| 0| { 71| | // Special treatment for objects that are observed with KVO. The KVO implementation sets 72| | // a subclass for such objects and it overrides the -class method to return the original 73| | // class. If we base our subclass on the KVO subclass, as returned by object_getClass(), 74| | // crashes will occur. So, we take the real class instead. Unfortunately, this removes 75| | // any observers set up before. 76| 0| NSLog(@"Warning: Creating a partial mock for %@. This object has observers, which will now stop receiving KVO notifications. If you want to receive KVO notifications, create the partial mock first, and then register the observer.", object); 77| 0| return [object class]; 78| 0| } 79| | 80| 0| return object_getClass(object); 81| 0|} 82| | 83| |#pragma mark Extending/overriding superclass behaviour 84| | 85| |- (void)stopMocking 86| 0|{ 87| 0| if(realObject != nil) 88| 0| { 89| 0| Class partialMockClass = object_getClass(realObject); 90| 0| OCMSetAssociatedMockForObject(nil, realObject); 91| 0| object_setClass(realObject, [self mockedClass]); 92| 0| [realObject release]; 93| 0| realObject = nil; 94| 0| OCMDisposeSubclass(partialMockClass); 95| 0| } 96| 0| [super stopMocking]; 97| 0|} 98| | 99| |- (void)addStub:(OCMInvocationStub *)aStub 100| 0|{ 101| 0| [super addStub:aStub]; 102| 0| if(![aStub recordedAsClassMethod]) 103| 0| [self setupForwarderForSelector:[[aStub recordedInvocation] selector]]; 104| 0|} 105| | 106| |- (void)addInvocation:(NSInvocation *)anInvocation 107| 0|{ 108| | // If the mock invokes a method on the real object we end up here a second time, but because 109| | // the mock has added the invocation already we do not want to add it again. 110| 0| if((invocationFromMock == nil) || ([anInvocation selector] != [invocationFromMock selector])) 111| 0| [super addInvocation:anInvocation]; 112| 0|} 113| | 114| |- (void)handleUnRecordedInvocation:(NSInvocation *)anInvocation 115| 0|{ 116| | // In the case of an init that is called on a mock we must return the mock instance and 117| | // not the realObject if the underlying init returns the realObject because at the call site 118| | // ARC will have retained the target and the release/retain count must balance. If we return 119| | // the realObject, then realObject will be over released and the mock will leak. Equally if 120| | // we are called on the realObject we need to make sure not to return the mock. 121| 0| id targetReceivingInit = nil; 122| 0| if([anInvocation methodIsInInitFamily]) 123| 0| { 124| 0| targetReceivingInit = [anInvocation target]; 125| 0| [realObject retain]; 126| 0| } 127| | 128| 0| invocationFromMock = anInvocation; 129| 0| [anInvocation invokeWithTarget:realObject]; 130| 0| invocationFromMock = nil; 131| | 132| 0| if(targetReceivingInit) 133| 0| { 134| 0| id returnVal; 135| 0| [anInvocation getReturnValue:&returnVal]; 136| 0| if(returnVal == realObject) 137| 0| { 138| 0| [anInvocation setReturnValue:&self]; 139| 0| [realObject release]; 140| 0| [self retain]; 141| 0| } 142| 0| [targetReceivingInit release]; 143| 0| } 144| 0|} 145| | 146| | 147| |#pragma mark Subclass management 148| | 149| |- (void)prepareObjectForInstanceMethodMocking 150| 0|{ 151| 0| OCMSetAssociatedMockForObject(self, realObject); 152| | 153| | /* dynamically create a subclass and set it as the class of the object */ 154| 0| Class subclass = OCMCreateSubclass(mockedClass, realObject); 155| 0| object_setClass(realObject, subclass); 156| | 157| | /* point forwardInvocation: of the object to the implementation in the mock */ 158| 0| Method myForwardMethod = class_getInstanceMethod([self mockObjectClass], @selector(forwardInvocationForRealObject:)); 159| 0| IMP myForwardIMP = method_getImplementation(myForwardMethod); 160| 0| class_addMethod(subclass, @selector(forwardInvocation:), myForwardIMP, method_getTypeEncoding(myForwardMethod)); 161| | 162| | /* do the same for forwardingTargetForSelector, remember existing imp with alias selector */ 163| 0| Method myForwardingTargetMethod = class_getInstanceMethod([self mockObjectClass], @selector(forwardingTargetForSelectorForRealObject:)); 164| 0| IMP myForwardingTargetIMP = method_getImplementation(myForwardingTargetMethod); 165| 0| IMP originalForwardingTargetIMP = [mockedClass instanceMethodForSelector:@selector(forwardingTargetForSelector:)]; 166| 0| class_addMethod(subclass, @selector(forwardingTargetForSelector:), myForwardingTargetIMP, method_getTypeEncoding(myForwardingTargetMethod)); 167| 0| class_addMethod(subclass, @selector(ocmock_replaced_forwardingTargetForSelector:), originalForwardingTargetIMP, method_getTypeEncoding(myForwardingTargetMethod)); 168| | 169| | /* We also override the -class method to return the original class */ 170| 0| Method myObjectClassMethod = class_getInstanceMethod([self mockObjectClass], @selector(classForRealObject)); 171| 0| const char *objectClassTypes = method_getTypeEncoding(myObjectClassMethod); 172| 0| IMP myObjectClassImp = method_getImplementation(myObjectClassMethod); 173| 0| class_addMethod(subclass, @selector(class), myObjectClassImp, objectClassTypes); 174| | 175| | /* Adding forwarder for most instance methods to allow for verify after run */ 176| 0| NSArray *methodBlackList = @[@"class", @"forwardingTargetForSelector:", @"methodSignatureForSelector:", @"forwardInvocation:", 177| 0| @"allowsWeakReference", @"retainWeakReference", @"isBlock", @"retainCount", @"retain", @"release", @"autorelease"]; 178| 0| [NSObject enumerateMethodsInClass:mockedClass usingBlock:^(Class cls, SEL sel) { 179| 0| if(OCMIsAppleBaseClass(cls) || OCMIsApplePrivateMethod(cls, sel)) 180| 0| return; 181| 0| if([methodBlackList containsObject:NSStringFromSelector(sel)]) 182| 0| return; 183| 0| @try 184| 0| { 185| 0| [self setupForwarderForSelector:sel]; 186| 0| } 187| 0| @catch(NSException *e) 188| 0| { 189| | // ignore for now 190| 0| } 191| 0| }]; 192| 0|} 193| | 194| |- (void)setupForwarderForSelector:(SEL)sel 195| 0|{ 196| 0| SEL aliasSelector = OCMAliasForOriginalSelector(sel); 197| 0| if(class_getInstanceMethod(object_getClass(realObject), aliasSelector) != NULL) 198| 0| return; 199| | 200| 0| Method originalMethod = class_getInstanceMethod(mockedClass, sel); 201| | /* Might be NULL if the selector is forwarded to another class */ 202| 0| IMP originalIMP = (originalMethod != NULL) ? method_getImplementation(originalMethod) : NULL; 203| 0| const char *types = (originalMethod != NULL) ? method_getTypeEncoding(originalMethod) : NULL; 204| | // TODO: check the fallback implementation is actually sufficient 205| 0| if(types == NULL) 206| 0| types = ([[mockedClass instanceMethodSignatureForSelector:sel] fullObjCTypes]); 207| | 208| 0| Class subclass = object_getClass([self realObject]); 209| 0| IMP forwarderIMP = [mockedClass instanceMethodForwarderForSelector:sel]; 210| 0| class_replaceMethod(subclass, sel, forwarderIMP, types); 211| 0| class_addMethod(subclass, aliasSelector, originalIMP, types); 212| 0|} 213| | 214| | 215| |// Implementation of the -class method; return the Class that was reported with [realObject class] prior to mocking 216| |- (Class)classForRealObject 217| 0|{ 218| | // in here "self" is a reference to the real object, not the mock 219| 0| OCPartialMockObject *mock = OCMGetAssociatedMockForObject(self); 220| 0| if(mock == nil) 221| 0| [NSException raise:NSInternalInconsistencyException format:@"No partial mock for object %p", self]; 222| 0| return [mock mockedClass]; 223| 0|} 224| | 225| | 226| |- (id)forwardingTargetForSelectorForRealObject:(SEL)sel 227| 0|{ 228| | // in here "self" is a reference to the real object, not the mock 229| 0| OCPartialMockObject *mock = OCMGetAssociatedMockForObject(self); 230| 0| if(mock == nil) 231| 0| [NSException raise:NSInternalInconsistencyException format:@"No partial mock for object %p", self]; 232| 0| if([mock handleSelector:sel]) 233| 0| return self; 234| | 235| 0| return [self ocmock_replaced_forwardingTargetForSelector:sel]; 236| 0|} 237| | 238| |// Make the compiler happy in -forwardingTargetForSelectorForRealObject: because it can't find the message… 239| |- (id)ocmock_replaced_forwardingTargetForSelector:(SEL)sel 240| 0|{ 241| 0| return nil; 242| 0|} 243| | 244| | 245| |- (void)forwardInvocationForRealObject:(NSInvocation *)anInvocation 246| 0|{ 247| | // in here "self" is a reference to the real object, not the mock 248| 0| OCPartialMockObject *mock = OCMGetAssociatedMockForObject(self); 249| 0| if(mock == nil) 250| 0| [NSException raise:NSInternalInconsistencyException format:@"No partial mock for object %p", self]; 251| | 252| 0| if([mock handleInvocation:anInvocation] == NO) 253| 0| { 254| 0| [anInvocation setSelector:OCMAliasForOriginalSelector([anInvocation selector])]; 255| 0| [anInvocation invoke]; 256| 0| } 257| 0|} 258| | 259| | 260| |#pragma mark Verification handling 261| | 262| |- (NSString *)descriptionForVerificationFailureWithMatcher:(OCMInvocationMatcher *)matcher quantifier:(OCMQuantifier *)quantifier invocationCount:(NSUInteger)count 263| 0|{ 264| 0| SEL matcherSel = [[matcher recordedInvocation] selector]; 265| 0| __block BOOL stubbingMightHelp = NO; 266| 0| [NSObject enumerateMethodsInClass:mockedClass usingBlock:^(Class cls, SEL sel) { 267| 0| if(sel == matcherSel) 268| 0| stubbingMightHelp = OCMIsAppleBaseClass(cls) || OCMIsApplePrivateMethod(cls, sel); 269| 0| }]; 270| | 271| 0| NSString *description = [super descriptionForVerificationFailureWithMatcher:matcher quantifier:quantifier invocationCount:count]; 272| 0| if(stubbingMightHelp) 273| 0| { 274| 0| description = [description stringByAppendingFormat:@" Adding a stub for the method may resolve the issue, e.g. `OCMStub([mockObject %@]).andForwardToRealObject()`", [matcher description]]; 275| 0| } 276| 0| return description; 277| 0|} 278| | 279| | 280| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/OCMock/Source/OCMock/OCProtocolMockObject.m: 1| |/* 2| | * Copyright (c) 2005-2020 Erik Doernenburg and contributors 3| | * 4| | * Licensed under the Apache License, Version 2.0 (the "License"); you may 5| | * not use these files except in compliance with the License. You may obtain 6| | * a copy of the License at 7| | * 8| | * http://www.apache.org/licenses/LICENSE-2.0 9| | * 10| | * Unless required by applicable law or agreed to in writing, software 11| | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12| | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13| | * License for the specific language governing permissions and limitations 14| | * under the License. 15| | */ 16| | 17| |#import 18| |#import "OCProtocolMockObject.h" 19| | 20| | 21| |@implementation OCProtocolMockObject 22| | 23| |#pragma mark Initialisers, description, accessors, etc. 24| | 25| |- (id)initWithProtocol:(Protocol *)aProtocol 26| 0|{ 27| 0| if(aProtocol == nil) 28| 0| [NSException raise:NSInvalidArgumentException format:@"Protocol cannot be nil."]; 29| | 30| 0| [super init]; 31| 0| mockedProtocol = aProtocol; 32| 0| return self; 33| 0|} 34| | 35| |- (NSString *)description 36| 0|{ 37| 0| const char* name = protocol_getName(mockedProtocol); 38| 0| return [NSString stringWithFormat:@"OCProtocolMockObject(%s)", name]; 39| 0|} 40| | 41| |#pragma mark Proxy API 42| | 43| |- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 44| 0|{ 45| 0| struct { BOOL isRequired; BOOL isInstance; } opts[4] = { {YES, YES}, {NO, YES}, {YES, NO}, {NO, NO} }; 46| 0| for(int i = 0; i < 4; i++) 47| 0| { 48| 0| struct objc_method_description methodDescription = protocol_getMethodDescription(mockedProtocol, aSelector, opts[i].isRequired, opts[i].isInstance); 49| 0| if(methodDescription.name != NULL) 50| 0| return [NSMethodSignature signatureWithObjCTypes:methodDescription.types]; 51| 0| } 52| 0| return nil; 53| 0|} 54| | 55| |- (BOOL)conformsToProtocol:(Protocol *)aProtocol 56| 0|{ 57| 0| return protocol_conformsToProtocol(mockedProtocol, aProtocol); 58| 0|} 59| | 60| |- (BOOL)respondsToSelector:(SEL)selector 61| 0|{ 62| 0| return ([self methodSignatureForSelector:selector] != nil); 63| 0|} 64| | 65| |@end <<<<<< EOF # path=OCMock#OCMQuantifier.m.gcov.reduced -: 0:Source:OCMock/OCMQuantifier.m <<<<<< EOF # path=Parse#Internal#ThreadSafety#PFThreadsafety.m.gcov.reduced -: 0:Source:Parse/Internal/ThreadSafety/PFThreadsafety.m <<<<<< EOF # path=Parse#PFEncoder.m.gcov.reduced -: 0:Source:Parse/PFEncoder.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKAppEventsConfigurationManager.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsConfigurationManager.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#dispatch#once.h.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/dispatch/once.h 18:80: 18:82: 18:83: 1:84: 1:85: 17:86: 18:88: 18:89: <<<<<< EOF # path=FBSDKCoreKit#Internal#TokenCaching#FBSDKKeychainStore.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#functional.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/functional #####:691: #####:692: <<<<<< EOF # path=FBSDKCoreKit#AppLink#FBSDKAppLinkTarget.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppLink/FBSDKAppLinkTarget.m <<<<<< EOF # path=Parse#Internal#Relation#State#PFRelationState.m.gcov.reduced -: 0:Source:Parse/Internal/Relation/State/PFRelationState.m <<<<<< EOF # path=Parse#Internal#File#Controller#PFFileStagingController.h.gcov.reduced -: 0:Source:Parse/Internal/File/Controller/PFFileStagingController.h <<<<<< EOF # path=FBSDKCoreKit#Internal#Network#FBSDKGraphRequestConnectionFactory.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Network/FBSDKGraphRequestConnectionFactory.m <<<<<< EOF # path=FBSDKCoreKit#Internal#ServerConfiguration#FBSDKServerConfiguration.h.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.h <<<<<< EOF # path=Parse#Internal#Query#Utilities#PFQueryUtilities.m.gcov.reduced -: 0:Source:Parse/Internal/Query/Utilities/PFQueryUtilities.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKTimeSpentRecordingFactory.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKTimeSpentRecordingFactory.m <<<<<< EOF # path=Parse#PFGeoPoint.m.gcov.reduced -: 0:Source:Parse/PFGeoPoint.m <<<<<< EOF # path=Parse#Internal#Installation#Controller#PFInstallationController.m.gcov.reduced -: 0:Source:Parse/Internal/Installation/Controller/PFInstallationController.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#LocalDataStore#OfflineQueryLogic#PFOfflineQueryLogic.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.m #####:826: <<<<<< EOF # path=FBSDKCoreKit#FBSDKRandom.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKRandom.m <<<<<< EOF # path=Parse#Internal#Push#Manager#PFPushManager.m.gcov.reduced -: 0:Source:Parse/Internal/Push/Manager/PFPushManager.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Object#OperationSet#PFOperationSet.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Object/OperationSet/PFOperationSet.m #####:79: <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#PFAnonymousUtils.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/PFAnonymousUtils.m #####:57: <<<<<< EOF # path=OCMock#OCMMacroState.m.gcov.reduced -: 0:Source:OCMock/OCMMacroState.m <<<<<< EOF # path=FBSDKCoreKit#Internal#ServerConfiguration#FBSDKErrorRecoveryConfiguration.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.m <<<<<< EOF # path=OCMock#OCMExpectationRecorder.m.gcov.reduced -: 0:Source:OCMock/OCMExpectationRecorder.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#FBSDKCoreKit#FBSDKCoreKit#Internal#Network#FBSDKGraphRequestPiggybackManager.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.m #####:98: <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKBackgroundEventLogger.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKBackgroundEventLogger.m <<<<<< EOF # path=OCMock#NSObject+OCMAdditions.m.gcov.reduced -: 0:Source:OCMock/NSObject+OCMAdditions.m <<<<<< EOF # path=Parse#Internal#User#State#PFUserState_Private.h.gcov.reduced -: 0:Source:Parse/Internal/User/State/PFUserState_Private.h <<<<<< EOF # path=Parse#Internal#Product#ProductsRequestHandler#PFProductsRequestHandler.h.gcov.reduced -: 0:Source:Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.h <<<<<< EOF # path=Parse#Internal#Commands#CommandRunner#URLSession#Session#TaskDelegate#PFURLSessionDataTaskDelegate_Private.h.gcov.reduced -: 0:Source:Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate_Private.h <<<<<< EOF # path=Parse#Internal#Query#State#PFQueryState_Private.h.gcov.reduced -: 0:Source:Parse/Internal/Query/State/PFQueryState_Private.h <<<<<< EOF # path=Parse#Internal#Commands#PFRESTPushCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTPushCommand.m <<<<<< EOF # path=Parse#Internal#PropertyInfo#PFPropertyInfo.m.gcov.reduced -: 0:Source:Parse/Internal/PropertyInfo/PFPropertyInfo.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#ML#FBSDKModelUtility.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/ML/FBSDKModelUtility.m <<<<<< EOF # path=Parse#Internal#File#Controller#PFFileController.h.gcov.reduced -: 0:Source:Parse/Internal/File/Controller/PFFileController.h <<<<<< EOF # path=Tests#Other#TestCase#PFFacebookTestCase.m.gcov.reduced -: 0:Source:Tests/Other/TestCase/PFFacebookTestCase.m <<<<<< EOF # path=Parse#Internal#Push#State#PFPushState.m.gcov.reduced -: 0:Source:Parse/Internal/Push/State/PFPushState.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKLocation.h.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKLocation.h <<<<<< EOF # path=Parse#Internal#Commands#PFRESTAnalyticsCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTAnalyticsCommand.m <<<<<< EOF # path=Parse#Internal#Object#Controller#PFObjectController.h.gcov.reduced -: 0:Source:Parse/Internal/Object/Controller/PFObjectController.h <<<<<< EOF # path=Parse#Internal#Object#Subclassing#PFObjectSubclassInfo.m.gcov.reduced -: 0:Source:Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#FBSDKCoreKit#FBSDKCoreKit#FBSDKBridgeAPI.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/FBSDKBridgeAPI.m #####:295: <<<<<< EOF # path=FBSDKCoreKit#Internal#Network#FBSDKGraphRequestMetadata.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKAuthenticationToken.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKAuthenticationToken.m <<<<<< EOF # path=Parse#Internal#File#FileDataStream#PFFileDataStream.m.gcov.reduced -: 0:Source:Parse/Internal/File/FileDataStream/PFFileDataStream.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#limits.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/limits #####:214: #####:451: <<<<<< EOF # path=Bolts#Common#BFTask.m.gcov.reduced -: 0:Source:Bolts/Common/BFTask.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKAuthenticationTokenClaims.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKAuthenticationTokenClaims.m <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKLoginCompletion.m.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKLoginCompletion.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#SKAdNetwork#FBSDKSKAdNetworkConversionConfiguration.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/SKAdNetwork/FBSDKSKAdNetworkConversionConfiguration.m <<<<<< EOF # path=Bolts#Common#BFExecutor.m.gcov.reduced -: 0:Source:Bolts/Common/BFExecutor.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#FBSDKLoginKit#FBSDKLoginKit#Internal#FBSDKLoginCompletion.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion.m #####:236: <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#memory.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/memory #####:749: #####:750: #####:752: 2:836: 2:856: #####:860: #####:863: #####:864: #####:865: #####:870: #####:875: #####:879: #####:881: #####:909: #####:910: #####:915: #####:916: #####:917: #####:920: #####:921: #####:922: #####:1061: #####:1062: #####:1063: #####:1064: #####:1065: #####:1066: #####:1067: #####:1092: #####:1093: #####:1094: #####:1095: #####:1096: #####:1097: 1:1250: 1:1252: 4:1259: 4:1260: 4:1261: 4:1262: 3:1274: #####:1276: 3:1291: 1:1293: #####:1300: #####:1301: #####:1302: 1:1312: #####:1314: 2:1340: 8:1344: 8:1345: 3:1359: 3:1360: #####:1364: #####:1365: 1:1369: 1:1370: #####:1374: #####:1375: #####:1572: #####:1573: #####:1576: #####:1643: #####:1657: #####:1658: #####:1661: #####:1662: #####:1665: #####:1666: #####:1678: #####:1679: #####:1680: #####:1681: #####:1685: #####:1686: #####:1687: #####:1688: #####:1689: #####:1690: 2:1774: #####:1814: #####:1815: #####:1818: 2:1866: #####:1876: #####:1877: #####:1885: #####:1886: #####:1890: #####:1891: #####:1899: #####:1900: #####:1901: #####:1902: #####:1910: #####:1911: #####:1912: #####:1913: #####:1914: #####:1915: 1:1918: 1:1919: 1:1920: 1:1921: #####:1922: 1:1923: #####:2436: #####:2437: #####:2439: #####:2447: #####:2448: #####:2450: #####:2491: #####:2492: #####:2500: #####:2501: #####:2502: #####:2504: #####:2505: #####:2506: #####:2507: #####:2509: #####:2510: #####:2525: #####:2526: #####:2527: #####:2539: #####:2540: #####:2541: #####:2547: #####:2548: #####:2549: #####:2550: #####:2569: #####:2570: #####:2585: #####:2586: #####:2587: #####:2594: #####:2595: #####:2596: #####:2597: #####:2598: #####:2602: #####:2603: #####:2608: #####:2609: #####:2610: #####:2611: #####:2863: #####:2954: #####:2982: #####:2983: #####:2984: #####:2985: #####:2986: #####:3013: #####:3015: #####:3016: #####:3023: #####:3024: #####:3026: #####:3029: #####:3030: #####:3031: #####:3033: #####:3124: #####:3125: #####:3126: #####:3127: #####:3128: #####:3129: #####:3130: #####:3147: #####:3148: #####:3149: #####:3150: #####:3151: #####:3152: #####:3153: #####:3235: #####:3236: #####:3237: #####:3238: #####:3239: #####:3267: #####:3268: #####:3269: #####:3270: #####:3322: #####:3323: #####:3324: #####:3325: #####:3326: #####:3357: #####:3358: #####:3359: #####:3360: <<<<<< EOF # path=Parse#Internal#Analytics#Controller#PFAnalyticsController.h.gcov.reduced -: 0:Source:Parse/Internal/Analytics/Controller/PFAnalyticsController.h <<<<<< EOF # path=Parse#Internal#FieldOperation#PFFieldOperation.m.gcov.reduced -: 0:Source:Parse/Internal/FieldOperation/PFFieldOperation.m <<<<<< EOF # path=OCMock#OCMFunctions.m.gcov.reduced -: 0:Source:OCMock/OCMFunctions.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#Integrity#FBSDKRestrictiveDataFilterManager.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/Integrity/FBSDKRestrictiveDataFilterManager.m <<<<<< EOF # path=Parse#Internal#ParseModule.m.gcov.reduced -: 0:Source:Parse/Internal/ParseModule.m <<<<<< EOF # path=Parse#Internal#Object#LocalIdStore#PFObjectLocalIdStore.h.gcov.reduced -: 0:Source:Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.h <<<<<< EOF # path=FBSDKCoreKit#GraphAPI#FBSDKGraphErrorRecoveryProcessor.m.gcov.reduced -: 0:Source:FBSDKCoreKit/GraphAPI/FBSDKGraphErrorRecoveryProcessor.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AAM#FBSDKMetadataIndexer.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AAM/FBSDKMetadataIndexer.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMReporter.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMReporter.m <<<<<< EOF # path=OCMock#OCMBlockArgCaller.m.gcov.reduced -: 0:Source:OCMock/OCMBlockArgCaller.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#SKAdNetwork#FBSDKSKAdNetworkRule.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/SKAdNetwork/FBSDKSKAdNetworkRule.h <<<<<< EOF # path=Parse#Internal#User#Coder#File#PFUserFileCodingLogic.m.gcov.reduced -: 0:Source:Parse/Internal/User/Coder/File/PFUserFileCodingLogic.m <<<<<< EOF # path=Parse#Internal#PFFileManager.m.gcov.reduced -: 0:Source:Parse/Internal/PFFileManager.m <<<<<< EOF # path=Parse#PFPush.m.gcov.reduced -: 0:Source:Parse/PFPush.m <<<<<< EOF # path=Parse#PFInstallation.m.gcov.reduced -: 0:Source:Parse/PFInstallation.m <<<<<< EOF # path=Parse#Internal#PFCoreManager.h.gcov.reduced -: 0:Source:Parse/Internal/PFCoreManager.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Commands#CommandRunner#URLSession#Session#PFURLSession.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.m #####:101: <<<<<< EOF # path=Parse#Internal#PFEventuallyQueue.h.gcov.reduced -: 0:Source:Parse/Internal/PFEventuallyQueue.h <<<<<< EOF # path=FBSDKCoreKit#FBSDKBridgeAPI.h.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKBridgeAPI.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMAdvertiserSingleEntryRule.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMAdvertiserSingleEntryRule.m <<<<<< EOF # path=Parse#Internal#Push#Controller#PFPushController.m.gcov.reduced -: 0:Source:Parse/Internal/Push/Controller/PFPushController.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#__string.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/__string #####:372: #####:412: #####:413: #####:414: #####:415: #####:417: #####:430: #####:1157: #####:1158: #####:1160: <<<<<< EOF # path=FBSDKCoreKit#FBSDKUserAgeRange.h.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKUserAgeRange.h <<<<<< EOF # path=Parse#Internal#Push#Utilites#PFPushUtilities.m.gcov.reduced -: 0:Source:Parse/Internal/Push/Utilites/PFPushUtilities.m <<<<<< EOF # path=Parse#Internal#LocalDataStore#SQLite#PFSQLiteDatabase.m.gcov.reduced -: 0:Source:Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.m <<<<<< EOF # path=Parse#ParseClientConfiguration.h.gcov.reduced -: 0:Source:Parse/ParseClientConfiguration.h <<<<<< EOF # path=Parse#PFACL.m.gcov.reduced -: 0:Source:Parse/PFACL.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#PFAlertView.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/PFAlertView.m #####:30: <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#ParseManager.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/ParseManager.m #####:145: <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#Sources#FBSDKCoreKit_Basics#FBSDKURLSession.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKURLSession.m 2:33: 2:36: 2:37: 2:38: 2:39: 2:40: 2:41: 1:43: 1:46: 2:47: 1:48: 1:49: 1:50: 1:51: #####:52: #####:53: #####:54: 1:55: 1:57: 1:59: 2:60: 1:61: 1:62: 1:63: 1:64: 1:65: 2:67: 2:69: 2:70: 2:71: 2:73: 2:75: <<<<<< EOF # path=Parse#Internal#Commands#PFRESTCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTCommand.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKURL.h.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKURL.h <<<<<< EOF # path=Parse#Internal#Commands#PFRESTUserCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTUserCommand.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKProfile.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKProfile.m <<<<<< EOF # path=Parse#Internal#Object#EstimatedData#PFObjectEstimatedData.m.gcov.reduced -: 0:Source:Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Installation#CurrentInstallationController#PFCurrentInstallationController.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.m #####:104: <<<<<< EOF # path=Parse#Internal#PFReachability.m.gcov.reduced -: 0:Source:Parse/Internal/PFReachability.m <<<<<< EOF # path=OCMock#OCMExceptionReturnValueProvider.m.gcov.reduced -: 0:Source:OCMock/OCMExceptionReturnValueProvider.m <<<<<< EOF # path=Parse#Internal#Push#ChannelsController#PFPushChannelsController.m.gcov.reduced -: 0:Source:Parse/Internal/Push/ChannelsController/PFPushChannelsController.m <<<<<< EOF # path=Parse#Internal#ACL#State#PFACLState.h.gcov.reduced -: 0:Source:Parse/Internal/ACL/State/PFACLState.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Object#Subclassing#PFObjectSubclassInfo.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.m #####:102: <<<<<< EOF # path=Parse#Internal#PFCommandResult.h.gcov.reduced -: 0:Source:Parse/Internal/PFCommandResult.h <<<<<< EOF # path=FBSDKCoreKit#Internal#Network#FBSDKGraphRequestPiggybackManager.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.m <<<<<< EOF # path=Parse#Internal#Persistence#PFPersistenceController.m.gcov.reduced -: 0:Source:Parse/Internal/Persistence/PFPersistenceController.m <<<<<< EOF # path=Parse#Internal#Commands#PFRESTFileCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTFileCommand.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#__memory#allocator_traits.h.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/__memory/allocator_traits.h #####:259: #####:260: #####:279: #####:280: #####:281: #####:286: #####:288: #####:290: #####:305: #####:307: #####:309: #####:313: #####:317: #####:319: #####:324: #####:326: #####:345: #####:346: <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKAppEventsStateManager.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsStateManager.m <<<<<< EOF # path=Bolts#Common#BFCancellationToken.m.gcov.reduced -: 0:Source:Bolts/Common/BFCancellationToken.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Commands#PFRESTCommand.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Commands/PFRESTCommand.m #####:192: <<<<<< EOF # path=Parse#Internal#Object#Subclassing#PFObjectSubclassingController.m.gcov.reduced -: 0:Source:Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m <<<<<< EOF # path=Parse#Internal#Config#Controller#PFCurrentConfigController.h.gcov.reduced -: 0:Source:Parse/Internal/Config/Controller/PFCurrentConfigController.h <<<<<< EOF # path=OCMock#OCMockObject.m.gcov.reduced -: 0:Source:OCMock/OCMockObject.m <<<<<< EOF # path=Parse#Internal#Object#PinningStore#PFPinningObjectStore.m.gcov.reduced -: 0:Source:Parse/Internal/Object/PinningStore/PFPinningObjectStore.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#System#Library#Frameworks#Foundation.framework#Headers#NSObject.h.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObject.h #####:109: #####:110: <<<<<< EOF # path=OCMock#OCMNotificationPoster.m.gcov.reduced -: 0:Source:OCMock/OCMNotificationPoster.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKAppEventsAtePublisher.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsAtePublisher.m <<<<<< EOF # path=Parse#Internal#ParseManager.h.gcov.reduced -: 0:Source:Parse/Internal/ParseManager.h <<<<<< EOF # path=Parse#Internal#Query#State#PFQueryState.h.gcov.reduced -: 0:Source:Parse/Internal/Query/State/PFQueryState.h <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#type_traits.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/type_traits #####:2567: #####:2568: #####:2570: 12:2576: 12:2577: 12:2578: #####:3948: #####:3950: #####:3951: #####:3952: #####:3953: #####:3954: <<<<<< EOF # path=ParseFacebookUtils#Internal#AuthenticationProvider#iOS#PFFacebookMobileAuthenticationProvider_Private.h.gcov.reduced -: 0:Source:ParseFacebookUtils/Internal/AuthenticationProvider/iOS/PFFacebookMobileAuthenticationProvider_Private.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Push#Manager#PFPushManager.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Push/Manager/PFPushManager.m #####:54: <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKInternalUtility.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKInternalUtility.m <<<<<< EOF # path=Parse#Parse.m.gcov.reduced -: 0:Source:Parse/Parse.m <<<<<< EOF # path=Parse#Internal#User#CurrentUserController#PFCurrentUserController.m.gcov.reduced -: 0:Source:Parse/Internal/User/CurrentUserController/PFCurrentUserController.m <<<<<< EOF # path=FBSDKCoreKit#GraphAPI#FBSDKGraphRequestConnection.h.gcov.reduced -: 0:Source:FBSDKCoreKit/GraphAPI/FBSDKGraphRequestConnection.h <<<<<< EOF # path=Parse#Internal#Session#Controller#PFSessionController.h.gcov.reduced -: 0:Source:Parse/Internal/Session/Controller/PFSessionController.h <<<<<< EOF # path=Parse#Internal#LocalDataStore#OfflineStore#PFOfflineStore.m.gcov.reduced -: 0:Source:Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKProductRequestFactory.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKProductRequestFactory.m <<<<<< EOF # path=Parse#Internal#FieldOperation#PFFieldOperationDecoder.m.gcov.reduced -: 0:Source:Parse/Internal/FieldOperation/PFFieldOperationDecoder.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#__hash_table.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/__hash_table #####:72: #####:73: #####:74: #####:78: #####:79: #####:80: #####:84: #####:85: 2:88: #####:106: #####:107: #####:108: #####:113: #####:114: #####:115: #####:116: #####:121: #####:122: #####:123: #####:172: #####:173: #####:193: #####:194: #####:371: #####:372: #####:373: #####:450: #####:453: #####:457: #####:460: #####:461: #####:473: #####:474: #####:475: #####:478: #####:479: #####:491: #####:492: #####:493: 2:782: 2:784: #####:787: #####:789: #####:792: #####:794: #####:795: #####:796: #####:797: #####:800: #####:802: #####:805: #####:807: #####:810: #####:811: #####:812: #####:813: #####:839: #####:841: #####:842: #####:843: #####:846: #####:847: #####:848: #####:849: #####:850: #####:851: #####:852: #####:966: #####:969: #####:972: #####:974: #####:977: #####:982: #####:984: 1:987: #####:989: #####:990: 1:999: #####:1153: #####:1154: #####:1193: #####:1194: #####:1195: #####:1367: #####:1372: #####:1373: #####:1375: #####:1379: #####:1380: #####:1381: #####:1382: #####:1383: 2:1396: 1:1403: 1:1404: 2:1405: 2:1406: #####:1440: #####:1441: #####:1442: #####:1444: #####:1445: #####:1446: #####:1447: #####:1448: #####:1449: #####:1450: 2:1510: 2:1511: 1:1519: 2:1523: 1:1557: 1:1559: 1:1560: 1:1561: #####:1563: #####:1579: #####:1580: #####:1581: #####:1582: 1:1584: #####:1601: #####:1607: #####:1608: #####:1609: #####:1610: #####:1611: #####:1612: #####:1613: #####:1614: #####:1615: #####:1616: #####:1617: #####:1618: #####:1620: #####:1621: #####:1622: #####:1623: #####:1624: #####:1628: #####:1681: #####:1687: #####:1688: #####:1690: #####:1799: #####:1800: #####:1804: #####:1811: #####:1812: #####:1816: #####:1822: #####:1823: #####:1824: #####:1826: #####:1827: #####:1828: #####:1829: #####:1830: #####:1831: #####:1832: #####:1833: #####:2069: #####:2070: #####:2072: #####:2073: #####:2074: #####:2077: #####:2079: #####:2080: #####:2081: #####:2083: #####:2084: #####:2085: #####:2087: #####:2088: #####:2089: #####:2090: #####:2091: #####:2093: #####:2094: #####:2096: #####:2097: #####:2098: #####:2099: #####:2100: #####:2102: #####:2103: #####:2105: #####:2106: #####:2107: #####:2109: #####:2110: #####:2111: #####:2112: #####:2113: #####:2116: #####:2117: #####:2119: #####:2121: #####:2122: #####:2123: #####:2128: #####:2130: #####:2306: #####:2308: #####:2309: #####:2310: #####:2311: #####:2312: #####:2313: #####:2314: #####:2315: #####:2316: #####:2318: #####:2321: #####:2322: #####:2324: #####:2325: #####:2326: #####:2327: #####:2331: #####:2332: #####:2336: #####:2337: #####:2338: #####:2339: #####:2340: #####:2342: #####:2343: #####:2344: #####:2345: #####:2346: #####:2348: #####:2349: #####:2350: #####:2351: #####:2352: #####:2354: #####:2355: #####:2356: #####:2359: #####:2361: #####:2362: #####:2363: #####:2364: #####:2367: #####:2368: #####:2369: #####:2370: #####:2371: #####:2373: #####:2374: #####:2375: #####:2379: #####:2380: #####:2381: #####:2382: #####:2418: #####:2419: #####:2420: #####:2421: #####:2422: #####:2424: #####:2425: #####:2426: #####:2428: #####:2429: #####:2430: #####:2431: #####:2433: #####:2434: #####:2438: #####:2440: #####:2441: #####:2443: #####:2444: #####:2445: #####:2466: #####:2468: #####:2471: #####:2472: #####:2473: #####:2474: #####:2476: #####:2477: #####:2478: #####:2479: #####:2480: <<<<<< EOF # path=Parse#Internal#ACL#DefaultACLController#PFDefaultACLController.h.gcov.reduced -: 0:Source:Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.h <<<<<< EOF # path=FBSDKLoginKit#FBSDKLoginConfiguration.m.gcov.reduced -: 0:Source:FBSDKLoginKit/FBSDKLoginConfiguration.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMEvent.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMEvent.m <<<<<< EOF # path=FBSDKCoreKit#Internal#Instrument#FBSDKInstrumentManager.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Instrument/FBSDKInstrumentManager.m <<<<<< EOF # path=Parse#Internal#PFSystemLogger.h.gcov.reduced -: 0:Source:Parse/Internal/PFSystemLogger.h <<<<<< EOF # path=FBSDKCoreKit#FBSDKAccessToken.h.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKAccessToken.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#SuggestedEvents#FBSDKFeatureExtractor.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/SuggestedEvents/FBSDKFeatureExtractor.m <<<<<< EOF # path=Parse#Internal#Persistence#Group#PFFilePersistenceGroup.m.gcov.reduced -: 0:Source:Parse/Internal/Persistence/Group/PFFilePersistenceGroup.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMConfiguration.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMConfiguration.m <<<<<< EOF # path=OCMock#NSValue+OCMAdditions.m.gcov.reduced -: 0:Source:OCMock/NSValue+OCMAdditions.m <<<<<< EOF # path=FBSDKLoginKit#FBSDKLoginManager.m.gcov.reduced -: 0:Source:FBSDKLoginKit/FBSDKLoginManager.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#Codeless#FBSDKEventBindingManager.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/Codeless/FBSDKEventBindingManager.m <<<<<< EOF # path=Parse#Internal#Commands#CommandRunner#URLSession#PFURLSessionCommandRunner.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.m <<<<<< EOF # path=ParseFacebookUtils#Internal#AuthenticationProvider#iOS#PFFacebookMobileAuthenticationProvider.m.gcov.reduced -: 0:Source:ParseFacebookUtils/Internal/AuthenticationProvider/iOS/PFFacebookMobileAuthenticationProvider.m <<<<<< EOF # path=FBSDKCoreKit#Internal#UI#FBSDKCloseIcon.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Config#Controller#PFConfigController.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Config/Controller/PFConfigController.m #####:78: <<<<<< EOF # path=Parse#Internal#PFAlertView.m.gcov.reduced -: 0:Source:Parse/Internal/PFAlertView.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#math.h.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/math.h #####:830: #####:1213: <<<<<< EOF # path=FBSDKCoreKit#Internal#WebDialog#FBSDKWebDialogView.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#SuggestedEvents#FBSDKSuggestedEventsIndexer.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/SuggestedEvents/FBSDKSuggestedEventsIndexer.m <<<<<< EOF # path=Parse#Internal#PFMulticastDelegate.m.gcov.reduced -: 0:Source:Parse/Internal/PFMulticastDelegate.m <<<<<< EOF # path=Parse#Internal#Analytics#Utilities#PFAnalyticsUtilities.m.gcov.reduced -: 0:Source:Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.m <<<<<< EOF # path=Parse#Internal#PFBase64Encoder.m.gcov.reduced -: 0:Source:Parse/Internal/PFBase64Encoder.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#FBSDKCoreKit#FBSDKCoreKit#AppEvents#Internal#ML#FBSDKModelManager.mm.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/ML/FBSDKModelManager.mm 1:53: <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#User#CurrentUserController#PFCurrentUserController.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/User/CurrentUserController/PFCurrentUserController.m #####:100: <<<<<< EOF # path=OCMock#OCMObjectReturnValueProvider.m.gcov.reduced -: 0:Source:OCMock/OCMObjectReturnValueProvider.m <<<<<< EOF # path=Parse#PFFileObject.m.gcov.reduced -: 0:Source:Parse/PFFileObject.m <<<<<< EOF # path=FBSDKCoreKit#Internal#Network#FBSDKGraphRequestPiggybackManagerProvider.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManagerProvider.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#Codeless#FBSDKCodelessPathComponent.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/Codeless/FBSDKCodelessPathComponent.h <<<<<< EOF # path=Parse#Internal#PFCommandCache.h.gcov.reduced -: 0:Source:Parse/Internal/PFCommandCache.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#Sources#FBSDKCoreKit_Basics#FBSDKUserDataStore.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKUserDataStore.m #####:51: #####:53: #####:54: #####:55: #####:56: #####:57: #####:59: #####:71: #####:72: #####:73: #####:74: #####:75: #####:76: #####:77: #####:78: #####:79: #####:80: #####:81: #####:82: #####:83: #####:84: #####:85: #####:86: #####:87: #####:88: #####:89: #####:90: #####:91: #####:92: #####:93: #####:94: #####:95: #####:96: #####:97: #####:98: #####:99: #####:100: #####:101: #####:102: #####:103: #####:104: #####:106: #####:107: #####:108: #####:110: #####:111: #####:113: #####:116: #####:117: #####:118: #####:120: #####:123: #####:124: #####:125: #####:126: #####:127: #####:129: #####:131: #####:132: #####:134: #####:137: #####:138: #####:139: #####:140: #####:141: #####:143: #####:145: #####:146: #####:148: #####:150: #####:151: #####:152: #####:153: #####:155: #####:157: #####:158: #####:160: #####:162: #####:165: #####:167: #####:168: #####:169: #####:170: #####:171: #####:172: #####:173: #####:174: #####:175: #####:176: #####:177: #####:178: #####:179: #####:181: #####:183: #####:194: #####:196: #####:198: #####:199: #####:200: #####:201: #####:202: #####:203: #####:207: #####:209: #####:210: #####:211: #####:212: #####:215: #####:216: #####:217: #####:218: #####:219: #####:220: #####:222: #####:224: #####:225: #####:228: #####:229: #####:232: #####:234: #####:236: #####:239: #####:240: #####:242: #####:243: #####:245: #####:248: #####:249: #####:250: #####:251: #####:252: #####:253: #####:254: #####:255: #####:256: #####:260: #####:262: #####:265: #####:266: #####:267: #####:268: #####:269: #####:270: #####:271: #####:272: #####:273: #####:275: #####:277: #####:278: #####:279: <<<<<< EOF # path=OCMock#OCMVerifier.h.gcov.reduced -: 0:Source:OCMock/OCMVerifier.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#PFPinningEventuallyQueue.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/PFPinningEventuallyQueue.m #####:273: <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#Codeless#FBSDKCodelessParameterComponent.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/Codeless/FBSDKCodelessParameterComponent.h <<<<<< EOF # path=Parse#Internal#User#State#PFUserState.h.gcov.reduced -: 0:Source:Parse/Internal/User/State/PFUserState.h <<<<<< EOF # path=Parse#Internal#PropertyInfo#PFPropertyInfo_Runtime.m.gcov.reduced -: 0:Source:Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.m <<<<<< EOF # path=Parse#Internal#CloudCode#PFCloudCodeController.h.gcov.reduced -: 0:Source:Parse/Internal/CloudCode/PFCloudCodeController.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#PFFileObject.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/PFFileObject.m #####:263: <<<<<< EOF # path=Parse#Internal#PFApplication.m.gcov.reduced -: 0:Source:Parse/Internal/PFApplication.m <<<<<< EOF # path=OCMock#OCProtocolMockObject.m.gcov.reduced -: 0:Source:OCMock/OCProtocolMockObject.m <<<<<< EOF # path=Parse#Internal#Commands#PFRESTSessionCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTSessionCommand.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKImpressionTrackingButton.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKImpressionTrackingButton.m <<<<<< EOF # path=Parse#Internal#Object#OperationSet#PFOperationSet.h.gcov.reduced -: 0:Source:Parse/Internal/Object/OperationSet/PFOperationSet.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKAppEventsState.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsState.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKAppEventsConfiguration.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsConfiguration.m <<<<<< EOF # path=Parse#Internal#Query#Controller#PFQueryController.m.gcov.reduced -: 0:Source:Parse/Internal/Query/Controller/PFQueryController.m <<<<<< EOF # path=Parse#Internal#PropertyInfo#PFPropertyInfo_Private.h.gcov.reduced -: 0:Source:Parse/Internal/PropertyInfo/PFPropertyInfo_Private.h <<<<<< EOF # path=FBSDKCoreKit#Internal#WebDialog#FBSDKWebViewFactory.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/WebDialog/FBSDKWebViewFactory.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKMeasurementEvent.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKMeasurementEvent.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#Integrity#FBSDKIntegrityManager.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/Integrity/FBSDKIntegrityManager.m <<<<<< EOF # path=OCMock#OCMNonRetainingObjectReturnValueProvider.m.gcov.reduced -: 0:Source:OCMock/OCMNonRetainingObjectReturnValueProvider.m <<<<<< EOF # path=Parse#Internal#LocalDataStore#Pin#PFPin.m.gcov.reduced -: 0:Source:Parse/Internal/LocalDataStore/Pin/PFPin.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#PFEventuallyQueue.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/PFEventuallyQueue.m #####:237: <<<<<< EOF # path=OCMock#NSInvocation+OCMAdditions.m.gcov.reduced -: 0:Source:OCMock/NSInvocation+OCMAdditions.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#Codeless#FBSDKEventBinding.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/Codeless/FBSDKEventBinding.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#Sources#FBSDKCoreKit_Basics#FBSDKTypeUtility.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKTypeUtility.m 11:25: 11:27: 11:28: 10:30: 10:32: 10:33: #####:36: 10:37: 11:39: 11:41: 8:42: 8:43: 11:44: #####:46: #####:48: #####:49: #####:50: #####:51: #####:52: #####:53: #####:54: #####:55: #####:57: #####:59: #####:61: #####:62: #####:64: #####:66: #####:68: 25:70: 25:72: 25:73: 20:75: 20:77: 20:79: 12:80: 8:82: 20:84: 29:86: 29:88: 23:89: 23:90: 29:91: 5:93: 5:95: 5:96: 5:97: 5:98: 5:99: #####:101: #####:103: #####:104: #####:106: #####:108: #####:109: #####:110: #####:111: #####:113: #####:115: 1:117: 1:119: 1:120: #####:122: #####:124: #####:125: 1:127: 1:129: #####:130: 1:131: #####:132: 1:133: #####:134: 1:136: 1:138: #####:140: #####:142: #####:143: #####:144: #####:145: #####:147: #####:149: #####:151: #####:153: #####:154: #####:158: #####:159: #####:160: #####:161: #####:162: #####:164: #####:166: #####:168: #####:169: #####:170: #####:171: #####:173: #####:175: 1:177: 1:179: 1:180: 1:182: 1:184: 1:187: #####:188: #####:189: 1:190: 1:191: 1:192: #####:194: #####:196: #####:197: #####:200: #####:202: #####:203: #####:204: #####:205: #####:206: #####:207: 37:211: 37:213: 37:214: <<<<<< EOF # path=Parse#Internal#LocalDataStore#SQLite#PFSQLiteDatabaseResult.m.gcov.reduced -: 0:Source:Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.m <<<<<< EOF # path=Parse#Internal#Persistence#Group#PFUserDefaultsPersistenceGroup.h.gcov.reduced -: 0:Source:Parse/Internal/Persistence/Group/PFUserDefaultsPersistenceGroup.h <<<<<< EOF # path=Parse#Internal#Object#State#PFObjectState.m.gcov.reduced -: 0:Source:Parse/Internal/Object/State/PFObjectState.m <<<<<< EOF # path=OCMock#OCMBlockCaller.m.gcov.reduced -: 0:Source:OCMock/OCMBlockCaller.m <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKLoginUtility.m.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKLoginUtility.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#LocalDataStore#SQLite#PFSQLiteDatabaseResult.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.m #####:96: <<<<<< EOF # path=Parse#Internal#Installation#CurrentInstallationController#PFCurrentInstallationController.m.gcov.reduced -: 0:Source:Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#ML#FBSDKModelRuntime.hpp.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/ML/FBSDKModelRuntime.hpp <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKLogger.h.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKLogger.h <<<<<< EOF # path=FBSDKCoreKit#AppLink#FBSDKAppLinkUtility.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppLink/FBSDKAppLinkUtility.m <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKContainerViewController.h.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKContainerViewController.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#SKAdNetwork#FBSDKSKAdNetworkEvent.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/SKAdNetwork/FBSDKSKAdNetworkEvent.h <<<<<< EOF # path=FBSDKCoreKit#AppLink#FBSDKAppLink.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppLink/FBSDKAppLink.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#FBSDKCoreKit#FBSDKCoreKit#AppEvents#FBSDKAppEvents.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEvents.m #####:1187: <<<<<< EOF # path=Parse#Internal#Commands#CommandRunner#URLSession#Session#PFURLSession.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#Sources#FBSDKCoreKit_Basics#FBSDKURLSessionTask.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKURLSessionTask.m 1:25: 1:27: 1:28: 1:29: 1:30: 1:31: 1:33: 1:37: 1:38: 1:39: 1:40: 1:41: 1:42: #####:44: #####:46: 1:51: 1:53: 1:54: #####:56: #####:58: #####:59: #####:60: <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#unordered_map.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/unordered_map 1:457: 1:459: #####:470: #####:471: 1:538: 1:540: #####:548: #####:549: #####:551: #####:552: #####:716: #####:717: #####:721: #####:726: #####:727: #####:731: #####:877: #####:885: #####:887: #####:890: #####:900: #####:901: #####:903: #####:904: 3:978: 2:980: 2:984: 2:1042: 2:1044: #####:1078: #####:1087: #####:1089: #####:1354: #####:1410: #####:1605: #####:1607: #####:1608: #####:1612: #####:1613: #####:1614: #####:1704: #####:1706: #####:1707: #####:1708: #####:1727: #####:1729: #####:1730: #####:1731: #####:1732: #####:1795: #####:1796: #####:1797: #####:1798: #####:1799: #####:1800: <<<<<< EOF # path=FBSDKCoreKit#Internal#UI#FBSDKViewImpressionTracker.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/UI/FBSDKViewImpressionTracker.m <<<<<< EOF # path=Parse#Internal#Commands#PFRESTCommand_Private.h.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTCommand_Private.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#Sources#FBSDKCoreKit_Basics#FBSDKLibAnalyzer.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKLibAnalyzer.m #####:29: #####:31: #####:32: #####:34: #####:37: #####:38: #####:39: #####:40: #####:41: #####:42: #####:43: #####:44: #####:45: #####:46: #####:47: #####:48: #####:50: #####:53: #####:54: #####:56: #####:57: #####:58: #####:60: #####:61: #####:62: #####:64: #####:65: #####:66: #####:67: #####:69: #####:70: #####:72: #####:73: #####:74: #####:75: #####:76: #####:79: #####:80: #####:82: #####:83: #####:84: #####:86: #####:87: #####:89: #####:90: #####:94: #####:97: #####:99: #####:100: #####:102: #####:103: #####:104: #####:105: #####:106: #####:107: #####:108: #####:109: #####:111: #####:112: #####:113: #####:114: #####:115: #####:117: #####:118: #####:120: #####:123: #####:124: #####:125: #####:126: #####:127: #####:128: #####:129: #####:130: #####:131: #####:132: #####:134: #####:135: #####:136: #####:138: #####:139: #####:140: #####:141: #####:143: #####:146: #####:147: #####:149: #####:151: #####:152: #####:154: #####:155: #####:157: #####:158: #####:159: #####:160: #####:161: #####:162: #####:164: #####:165: #####:166: #####:167: #####:168: #####:169: #####:170: #####:171: #####:172: #####:174: #####:176: #####:177: #####:178: #####:179: #####:180: #####:182: #####:183: #####:184: #####:185: #####:187: #####:190: #####:191: #####:192: #####:194: #####:195: #####:197: #####:198: #####:199: #####:201: #####:204: #####:205: #####:207: #####:208: #####:210: #####:211: #####:214: #####:215: #####:218: #####:219: #####:222: #####:223: #####:225: #####:226: #####:227: #####:228: #####:229: <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKPermission.h.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKPermission.h <<<<<< EOF # path=Parse#Internal#User#Controller#PFUserController.m.gcov.reduced -: 0:Source:Parse/Internal/User/Controller/PFUserController.m <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKFeatureManager.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKFeatureManager.m <<<<<< EOF # path=FBSDKLoginKit#FBSDKLoginManagerLoginResult.m.gcov.reduced -: 0:Source:FBSDKLoginKit/FBSDKLoginManagerLoginResult.m <<<<<< EOF # path=Parse#Internal#PFBaseState.h.gcov.reduced -: 0:Source:Parse/Internal/PFBaseState.h <<<<<< EOF # path=Parse#Internal#User#AuthenticationProviders#Providers#Anonymous#PFAnonymousAuthenticationProvider.m.gcov.reduced -: 0:Source:Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.m <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKAuthenticationStatusUtility.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKAuthenticationStatusUtility.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#stdexcept.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/stdexcept #####:153: #####:165: #####:253: #####:254: #####:256: #####:261: #####:264: #####:265: #####:267: #####:272: <<<<<< EOF # path=Parse#Internal#Installation#InstallationIdentifierStore#PFInstallationIdentifierStore.h.gcov.reduced -: 0:Source:Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.h <<<<<< EOF # path=FBSDKCoreKit#GraphAPI#FBSDKGraphRequestDataAttachment.m.gcov.reduced -: 0:Source:FBSDKCoreKit/GraphAPI/FBSDKGraphRequestDataAttachment.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKApplicationDelegate.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKApplicationDelegate.m <<<<<< EOF # path=FBSDKCoreKit#Internal#Network#FBSDKGraphRequestBody.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.m <<<<<< EOF # path=Parse#Internal#LocalDataStore#SQLite#PFSQLiteStatement.m.gcov.reduced -: 0:Source:Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.m <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKMonotonicTime.m.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKMonotonicTime.m <<<<<< EOF # path=Parse#PFAnonymousUtils.m.gcov.reduced -: 0:Source:Parse/PFAnonymousUtils.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Commands#PFRESTQueryCommand.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Commands/PFRESTQueryCommand.m #####:147: <<<<<< EOF # path=Parse#Internal#Query#Controller#PFOfflineQueryController.m.gcov.reduced -: 0:Source:Parse/Internal/Query/Controller/PFOfflineQueryController.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKAppEventsStateFactory.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsStateFactory.m <<<<<< EOF # path=OCMock#OCMInvocationExpectation.m.gcov.reduced -: 0:Source:OCMock/OCMInvocationExpectation.m <<<<<< EOF # path=Tests#TestApplication#Classes#main.m.gcov.reduced -: 0:Source:Tests/TestApplication/Classes/main.m <<<<<< EOF # path=Parse#Internal#Object#Controller#OfflineController#PFOfflineObjectController.m.gcov.reduced -: 0:Source:Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.m <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKLoginManager+Internal.h.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKLoginManager+Internal.h <<<<<< EOF # path=Parse#Internal#Commands#CommandRunner#URLSession#Session#TaskDelegate#PFURLSessionDataTaskDelegate.h.gcov.reduced -: 0:Source:Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.h <<<<<< EOF # path=OCMock#OCMPassByRefSetter.m.gcov.reduced -: 0:Source:OCMock/OCMPassByRefSetter.m <<<<<< EOF # path=Parse#Internal#Commands#CommandRunner#URLSession#Session#TaskDelegate#PFURLSessionFileDownloadTaskDelegate.h.gcov.reduced -: 0:Source:Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.h <<<<<< EOF # path=Parse#Internal#PFWeakValue.h.gcov.reduced -: 0:Source:Parse/Internal/PFWeakValue.h <<<<<< EOF # path=Bolts#Common#BFTaskCompletionSource.m.gcov.reduced -: 0:Source:Bolts/Common/BFTaskCompletionSource.m <<<<<< EOF # path=Parse#Internal#MultiProcessLock#PFMultiProcessFileLock.h.gcov.reduced -: 0:Source:Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMAdvertiserMultiEntryRule.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMAdvertiserMultiEntryRule.h <<<<<< EOF # path=Parse#Internal#Object#Utilities#PFObjectUtilities.m.gcov.reduced -: 0:Source:Parse/Internal/Object/Utilities/PFObjectUtilities.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#PFLocationManager.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/PFLocationManager.m #####:38: <<<<<< EOF # path=OCMock#OCMIndirectReturnValueProvider.m.gcov.reduced -: 0:Source:OCMock/OCMIndirectReturnValueProvider.m <<<<<< EOF # path=Parse#PFSession.m.gcov.reduced -: 0:Source:Parse/PFSession.m <<<<<< EOF # path=Parse#Internal#PFJSONSerialization.m.gcov.reduced -: 0:Source:Parse/Internal/PFJSONSerialization.m <<<<<< EOF # path=Parse#Internal#User#AuthenticationProviders#Controller#PFUserAuthenticationController.h.gcov.reduced -: 0:Source:Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.h <<<<<< EOF # path=Parse#PFObject.m.gcov.reduced -: 0:Source:Parse/PFObject.m <<<<<< EOF # path=Parse#Internal#Object#BatchController#PFObjectBatchController.m.gcov.reduced -: 0:Source:Parse/Internal/Object/BatchController/PFObjectBatchController.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMRule.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMRule.m <<<<<< EOF # path=Parse#Internal#Commands#PFRESTConfigCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTConfigCommand.m <<<<<< EOF # path=FBSDKCoreKit#Internal#Instrument#ErrorReport#FBSDKErrorReport.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Instrument/ErrorReport/FBSDKErrorReport.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#System#Library#Frameworks#Foundation.framework#Headers#NSRange.h.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSRange.h 102:19: 102:21: 102:22: 102:23: <<<<<< EOF # path=FBSDKCoreKit#GraphAPI#FBSDKGraphRequest.m.gcov.reduced -: 0:Source:FBSDKCoreKit/GraphAPI/FBSDKGraphRequest.m <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKAuthenticationTokenHeader.m.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKAuthenticationTokenHeader.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Object#State#PFObjectState.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Object/State/PFObjectState.m #####:121: <<<<<< EOF # path=FBSDKCoreKit#Internal#Instrument#CrashReport#FBSDKCrashObserver.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Instrument/CrashReport/FBSDKCrashObserver.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMInvocation.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMInvocation.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#LocalDataStore#OfflineStore#PFOfflineStore.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.m #####:122: <<<<<< EOF # path=Parse#Internal#Object#FilePersistence#PFObjectFilePersistenceController.m.gcov.reduced -: 0:Source:Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.m <<<<<< EOF # path=ParseFacebookUtils#PFFacebookUtils.m.gcov.reduced -: 0:Source:ParseFacebookUtils/PFFacebookUtils.m <<<<<< EOF # path=Parse#Internal#PFTaskQueue.m.gcov.reduced -: 0:Source:Parse/Internal/PFTaskQueue.m <<<<<< EOF # path=Parse#Internal#PFAsyncTaskQueue.m.gcov.reduced -: 0:Source:Parse/Internal/PFAsyncTaskQueue.m <<<<<< EOF # path=Parse#Internal#File#State#PFFileState.h.gcov.reduced -: 0:Source:Parse/Internal/File/State/PFFileState.h <<<<<< EOF # path=Parse#PFNetworkActivityIndicatorManager.m.gcov.reduced -: 0:Source:Parse/PFNetworkActivityIndicatorManager.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKBridgeAPIResponse.h.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKBridgeAPIResponse.h <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKMath.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKMath.m <<<<<< EOF # path=Parse#Internal#Commands#CommandRunner#URLRequestConstructor#PFCommandURLRequestConstructor.h.gcov.reduced -: 0:Source:Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.h <<<<<< EOF # path=Parse#Internal#Config#Controller#PFConfigController.m.gcov.reduced -: 0:Source:Parse/Internal/Config/Controller/PFConfigController.m <<<<<< EOF # path=./FBSDKCoreKit_Basics.framework.coverage.txt /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKBase64.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKBase64.h" 20| | 21| |@implementation FBSDKBase64 22| | 23| |static FBSDKBase64 *_decoder; 24| |static FBSDKBase64 *_encoder; 25| | 26| |#pragma mark - Class Methods 27| | 28| |+ (void)initialize 29| 0|{ 30| 0| if (self == [FBSDKBase64 class]) { 31| 0| _decoder = [FBSDKBase64 new]; 32| 0| _encoder = [FBSDKBase64 new]; 33| 0| } 34| 0|} 35| | 36| |+ (NSData *)decodeAsData:(NSString *)string 37| 0|{ 38| 0| return [_decoder decodeAsData:string]; 39| 0|} 40| | 41| |+ (NSString *)decodeAsString:(NSString *)string 42| 0|{ 43| 0| return [_decoder decodeAsString:string]; 44| 0|} 45| | 46| |+ (NSString *)encodeData:(NSData *)data 47| 0|{ 48| 0| return [_encoder encodeData:data]; 49| 0|} 50| | 51| |+ (NSString *)encodeString:(NSString *)string 52| 0|{ 53| 0| return [_encoder encodeString:string]; 54| 0|} 55| | 56| |+ (NSString *)base64FromBase64Url:(NSString *)base64Url 57| 0|{ 58| 0| NSString *base64 = [base64Url stringByReplacingOccurrencesOfString:@"-" withString:@"+"]; 59| 0| base64 = [base64 stringByReplacingOccurrencesOfString:@"_" withString:@"/"]; 60| | 61| 0| return base64; 62| 0|} 63| | 64| |#pragma mark - Object Lifecycle 65| | 66| |#pragma mark - Implementation Methods 67| | 68| |- (NSData *)decodeAsData:(NSString *)string 69| 0|{ 70| 0| if (!string) { 71| 0| return nil; 72| 0| } 73| | // This padding will be appended before stripping unknown characters, so if there are unknown characters of count % 4 74| | // it will not be able to decode. Since we assume valid base64 data, we will take this as is. 75| 0| int needPadding = string.length % 4; 76| 0| if (needPadding > 0) { 77| 0| needPadding = 4 - needPadding; 78| 0| string = [string stringByPaddingToLength:string.length + needPadding withString:@"=" startingAtIndex:0]; 79| 0| } 80| | 81| 0| return [[NSData alloc] initWithBase64EncodedString:string options:NSDataBase64DecodingIgnoreUnknownCharacters]; 82| 0|} 83| | 84| |- (NSString *)decodeAsString:(NSString *)string 85| 0|{ 86| 0| NSData *data = [self decodeAsData:string]; 87| 0| if (!data) { 88| 0| return nil; 89| 0| } 90| 0| return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 91| 0|} 92| | 93| |- (NSString *)encodeData:(NSData *)data 94| 0|{ 95| 0| if (!data) { 96| 0| return nil; 97| 0| } 98| | 99| 0| return [data base64EncodedStringWithOptions:0]; 100| 0|} 101| | 102| |- (NSString *)encodeString:(NSString *)string 103| 0|{ 104| 0| return [self encodeData:[string dataUsingEncoding:NSUTF8StringEncoding]]; 105| 0|} 106| | 107| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKBasicUtility.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKBasicUtility.h" 20| | 21| |#import 22| |#import 23| | 24| |#import "FBSDKTypeUtility.h" 25| | 26| 0|#define kChunkSize 1024 27| | 28| |static NSString *const FBSDK_BASICUTILITY_ANONYMOUSIDFILENAME = @"com-facebook-sdk-PersistedAnonymousID.json"; 29| |static NSString *const FBSDK_BASICUTILITY_ANONYMOUSID_KEY = @"anon_id"; 30| | 31| |void fb_dispatch_on_main_thread(dispatch_block_t block) 32| 0|{ 33| 0| if (block != nil) { 34| 0| if ([NSThread isMainThread]) { 35| 0| block(); 36| 0| } else { 37| 0| dispatch_async(dispatch_get_main_queue(), block); 38| 0| } 39| 0| } 40| 0|} 41| | 42| |void fb_dispatch_on_default_thread(dispatch_block_t block) 43| 0|{ 44| 0| if (block != nil) { 45| 0| dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block); 46| 0| } 47| 0|} 48| | 49| |@protocol BASIC_FBSDKError 50| | 51| |+ (NSError *)invalidArgumentErrorWithName:(NSString *)name value:(id)value message:(NSString *)message; 52| | 53| |@end 54| | 55| |@implementation FBSDKBasicUtility 56| | 57| |+ (NSString *)JSONStringForObject:(id)object 58| | error:(NSError *__autoreleasing *)errorRef 59| | invalidObjectHandler:(FBSDKInvalidObjectHandler)invalidObjectHandler 60| 0|{ 61| 0| if (invalidObjectHandler || ![FBSDKTypeUtility isValidJSONObject:object]) { 62| 0| object = [self _convertObjectToJSONObject:object invalidObjectHandler:invalidObjectHandler stop:NULL]; 63| 0| if (![FBSDKTypeUtility isValidJSONObject:object]) { 64| 0| if (errorRef != NULL) { 65| 0| Class FBSDKErrorClass = NSClassFromString(@"FBSDKError"); 66| 0| if ([FBSDKErrorClass respondsToSelector:@selector(invalidArgumentErrorWithName:value:message:)]) { 67| 0| *errorRef = [FBSDKErrorClass invalidArgumentErrorWithName:@"object" 68| 0| value:object 69| 0| message:@"Invalid object for JSON serialization."]; 70| 0| } 71| 0| } 72| 0| return nil; 73| 0| } 74| 0| } 75| 0| NSData *data = [FBSDKTypeUtility dataWithJSONObject:object options:0 error:errorRef]; 76| 0| if (!data) { 77| 0| return nil; 78| 0| } 79| 0| return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 80| 0|} 81| | 82| |+ (BOOL) dictionary:(NSMutableDictionary *)dictionary 83| | setJSONStringForObject:(id)object 84| | forKey:(id)key 85| | error:(NSError *__autoreleasing *)errorRef 86| 0|{ 87| 0| if (!object || !key) { 88| 0| return YES; 89| 0| } 90| 0| NSString *JSONString = [self JSONStringForObject:object error:errorRef invalidObjectHandler:NULL]; 91| 0| if (!JSONString) { 92| 0| return NO; 93| 0| } 94| 0| [FBSDKTypeUtility dictionary:dictionary setObject:JSONString forKey:key]; 95| 0| return YES; 96| 0|} 97| | 98| |+ (id)_convertObjectToJSONObject:(id)object 99| | invalidObjectHandler:(FBSDKInvalidObjectHandler)invalidObjectHandler 100| | stop:(BOOL *)stopRef 101| 0|{ 102| 0| __block BOOL stop = NO; 103| 0| if ([object isKindOfClass:[NSString class]] || [object isKindOfClass:[NSNumber class]]) { 104| | // good to go, keep the object 105| 0| } else if ([object isKindOfClass:[NSURL class]]) { 106| 0| object = ((NSURL *)object).absoluteString; 107| 0| } else if ([object isKindOfClass:[NSDictionary class]]) { 108| 0| NSMutableDictionary *dictionary = [NSMutableDictionary new]; 109| 0| [FBSDKTypeUtility dictionary:(NSDictionary *) object enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *dictionaryStop) { 110| 0| [FBSDKTypeUtility dictionary:dictionary 111| 0| setObject:[self _convertObjectToJSONObject:obj invalidObjectHandler:invalidObjectHandler stop:&stop] 112| 0| forKey:[FBSDKTypeUtility coercedToStringValue:key]]; 113| 0| if (stop) { 114| 0| *dictionaryStop = YES; 115| 0| } 116| 0| }]; 117| 0| object = dictionary; 118| 0| } else if ([object isKindOfClass:[NSArray class]]) { 119| 0| NSMutableArray *array = [NSMutableArray new]; 120| 0| for (id obj in (NSArray *)object) { 121| 0| id convertedObj = [self _convertObjectToJSONObject:obj invalidObjectHandler:invalidObjectHandler stop:&stop]; 122| 0| [FBSDKTypeUtility array:array addObject:convertedObj]; 123| 0| if (stop) { 124| 0| break; 125| 0| } 126| 0| } 127| 0| object = array; 128| 0| } else { 129| 0| object = invalidObjectHandler(object, stopRef); 130| 0| } 131| 0| if (stopRef != NULL) { 132| 0| *stopRef = stop; 133| 0| } 134| 0| return object; 135| 0|} 136| | 137| |+ (id)objectForJSONString:(NSString *)string error:(NSError *__autoreleasing *)errorRef 138| 0|{ 139| 0| NSData *data = [[FBSDKTypeUtility stringValueOrNil:string] dataUsingEncoding:NSUTF8StringEncoding]; 140| 0| if (!data) { 141| 0| if (errorRef != NULL) { 142| 0| *errorRef = nil; 143| 0| } 144| 0| return nil; 145| 0| } 146| 0| return [FBSDKTypeUtility JSONObjectWithData:data options:NSJSONReadingAllowFragments error:errorRef]; 147| 0|} 148| | 149| |+ (nullable NSString *)queryStringWithDictionary:(NSDictionary *)dictionary 150| | error:(NSError *__autoreleasing *)errorRef 151| | invalidObjectHandler:(FBSDKInvalidObjectHandler)invalidObjectHandler 152| 0|{ 153| 0| NSMutableString *queryString = [NSMutableString new]; 154| 0| __block BOOL hasParameters = NO; 155| 0| if (dictionary) { 156| 0| NSMutableArray *keys = [dictionary.allKeys mutableCopy]; 157| | // remove non-string keys, as they are not valid 158| 0| [keys filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL (id evaluatedObject, NSDictionary *bindings) { 159| 0| return [evaluatedObject isKindOfClass:[NSString class]]; 160| 0| }]]; 161| | // sort the keys so that the query string order is deterministic 162| 0| [keys sortUsingSelector:@selector(compare:)]; 163| 0| BOOL stop = NO; 164| 0| for (NSString *key in keys) { 165| 0| id value = [self convertRequestValue:dictionary[key]]; 166| 0| if ([value isKindOfClass:[NSString class]]) { 167| 0| value = [self URLEncode:value]; 168| 0| } 169| 0| if (invalidObjectHandler && ![value isKindOfClass:[NSString class]]) { 170| 0| value = invalidObjectHandler(value, &stop); 171| 0| if (stop) { 172| 0| break; 173| 0| } 174| 0| } 175| 0| if (value) { 176| 0| if (hasParameters) { 177| 0| [queryString appendString:@"&"]; 178| 0| } 179| 0| [queryString appendFormat:@"%@=%@", key, value]; 180| 0| hasParameters = YES; 181| 0| } 182| 0| } 183| 0| } 184| 0| if (errorRef != NULL) { 185| 0| *errorRef = nil; 186| 0| } 187| 0| return (queryString.length ? [queryString copy] : nil); 188| 0|} 189| | 190| |+ (id)convertRequestValue:(id)value 191| 0|{ 192| 0| if ([value isKindOfClass:[NSNumber class]]) { 193| 0| value = ((NSNumber *)value).stringValue; 194| 0| } else if ([value isKindOfClass:[NSURL class]]) { 195| 0| value = ((NSURL *)value).absoluteString; 196| 0| } 197| 0| return value; 198| 0|} 199| | 200| |#pragma clang diagnostic push 201| |#pragma clang diagnostic ignored "-Wdeprecated-declarations" 202| |+ (NSString *)URLEncode:(NSString *)value 203| 0|{ 204| 0| return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes( 205| 0| NULL, 206| 0| (CFStringRef)value, 207| 0| NULL, // characters to leave unescaped 208| 0| CFSTR(":!*();@/&?+$,='"), 209| 0| kCFStringEncodingUTF8 210| 0| ); 211| 0|} 212| | 213| |#pragma clang diagnostic pop 214| | 215| |+ (NSDictionary *)dictionaryWithQueryString:(NSString *)queryString 216| 0|{ 217| 0| NSMutableDictionary *result = [NSMutableDictionary new]; 218| 0| NSArray *parts = [queryString componentsSeparatedByString:@"&"]; 219| | 220| 0| for (NSString *part in parts) { 221| 0| if (part.length == 0) { 222| 0| continue; 223| 0| } 224| | 225| 0| NSRange index = [part rangeOfString:@"="]; 226| 0| NSString *key; 227| 0| NSString *value; 228| | 229| 0| if (index.location == NSNotFound) { 230| 0| key = part; 231| 0| value = @""; 232| 0| } else { 233| 0| key = [part substringToIndex:index.location]; 234| 0| value = [part substringFromIndex:index.location + index.length]; 235| 0| } 236| | 237| 0| key = [self URLDecode:key]; 238| 0| value = [self URLDecode:value]; 239| 0| if (key && value) { 240| 0| [FBSDKTypeUtility dictionary:result setObject:value forKey:key]; 241| 0| } 242| 0| } 243| 0| return result; 244| 0|} 245| | 246| |+ (NSString *)URLDecode:(NSString *)value 247| 0|{ 248| 0| value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "]; 249| 0| #pragma clang diagnostic push 250| 0| #pragma clang diagnostic ignored "-Wdeprecated-declarations" 251| 0| value = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 252| 0| #pragma clang diagnostic pop 253| 0| return value; 254| 0|} 255| | 256| |+ (NSData *)gzip:(NSData *)data 257| 0|{ 258| 0| const void *bytes = data.bytes; 259| 0| const NSUInteger length = data.length; 260| | 261| 0| if (!bytes || !length) { 262| 0| return nil; 263| 0| } 264| | 265| 0|#if defined(__LP64__) && __LP64__ 266| 0| if (length > UINT_MAX) { 267| 0| return nil; 268| 0| } 269| 0|#endif 270| | 271| | // initialze stream 272| 0| z_stream stream; 273| 0| bzero(&stream, sizeof(z_stream)); 274| | 275| 0| if (deflateInit2(&stream, -1, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) != Z_OK) { 276| 0| return nil; 277| 0| } 278| 0| stream.avail_in = (uint)length; 279| 0| stream.next_in = (Bytef *)bytes; 280| | 281| 0| int retCode; 282| 0| NSMutableData *result = [NSMutableData dataWithCapacity:(length / 4)]; 283| 0| unsigned char output[kChunkSize]; 284| 0| do { 285| 0| stream.avail_out = kChunkSize; 286| 0| stream.next_out = output; 287| 0| retCode = deflate(&stream, Z_FINISH); 288| 0| if (retCode != Z_OK && retCode != Z_STREAM_END) { 289| 0| deflateEnd(&stream); 290| 0| return nil; 291| 0| } 292| 0| unsigned size = kChunkSize - stream.avail_out; 293| 0| if (size > 0) { 294| 0| [result appendBytes:output length:size]; 295| 0| } 296| 0| } while (retCode == Z_OK); 297| | 298| 0| deflateEnd(&stream); 299| | 300| 0| return result; 301| 0|} 302| | 303| |+ (NSString *)anonymousID 304| 0|{ 305| | // Grab previously written anonymous ID and, if none have been generated, create and 306| | // persist a new one which will remain associated with this app. 307| 0| NSString *result = [[self class] retrievePersistedAnonymousID]; 308| 0| if (!result) { 309| | // Generate a new anonymous ID. Create as a UUID, but then prepend the fairly 310| | // arbitrary 'XZ' to the front so it's easily distinguishable from IDFA's which 311| | // will only contain hex. 312| 0| result = [NSString stringWithFormat:@"XZ%@", [NSUUID UUID].UUIDString]; 313| | 314| 0| [self persistAnonymousID:result]; 315| 0| } 316| 0| return result; 317| 0|} 318| | 319| |+ (NSString *)retrievePersistedAnonymousID 320| 0|{ 321| 0| NSString *file = [[self class] persistenceFilePath:FBSDK_BASICUTILITY_ANONYMOUSIDFILENAME]; 322| 0| NSString *content = [[NSString alloc] initWithContentsOfFile:file 323| 0| encoding:NSASCIIStringEncoding 324| 0| error:nil]; 325| 0| NSDictionary *results = [FBSDKBasicUtility objectForJSONString:content error:NULL]; 326| 0| return results[FBSDK_BASICUTILITY_ANONYMOUSID_KEY]; 327| 0|} 328| | 329| |+ (NSString *)persistenceFilePath:(NSString *)filename 330| 0|{ 331| 0| NSSearchPathDirectory directory = NSLibraryDirectory; 332| 0| NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES); 333| 0| NSString *docDirectory = [FBSDKTypeUtility array:paths objectAtIndex:0]; 334| 0| return [docDirectory stringByAppendingPathComponent:filename]; 335| 0|} 336| | 337| |+ (void)persistAnonymousID:(NSString *)anonymousID 338| 0|{ 339| 0| NSDictionary *data = @{ FBSDK_BASICUTILITY_ANONYMOUSID_KEY : anonymousID }; 340| 0| NSString *content = [self JSONStringForObject:data error:NULL invalidObjectHandler:NULL]; 341| | 342| 0| [content writeToFile:[[self class] persistenceFilePath:FBSDK_BASICUTILITY_ANONYMOUSIDFILENAME] 343| 0| atomically:YES 344| 0| encoding:NSASCIIStringEncoding 345| 0| error:nil]; 346| 0|} 347| | 348| |+ (NSString *)SHA256Hash:(NSObject *)input 349| 0|{ 350| 0| NSData *data = nil; 351| | 352| 0| if ([input isKindOfClass:[NSData class]]) { 353| 0| data = (NSData *)input; 354| 0| } else if ([input isKindOfClass:[NSString class]]) { 355| 0| data = [(NSString *)input dataUsingEncoding:NSUTF8StringEncoding]; 356| 0| } 357| | 358| 0| if (!data) { 359| 0| return nil; 360| 0| } 361| | 362| 0| uint8_t digest[CC_SHA256_DIGEST_LENGTH]; 363| 0| CC_SHA256(data.bytes, (CC_LONG)data.length, digest); 364| 0| NSMutableString *hashed = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; 365| 0| for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) { 366| 0| [hashed appendFormat:@"%02x", digest[i]]; 367| 0| } 368| | 369| 0| return [hashed copy]; 370| 0|} 371| | 372| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKCrashHandler.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKCrashHandler.h" 20| | 21| |#import 22| | 23| |#import 24| | 25| |#import "FBSDKCrashObserving.h" 26| |#import "FBSDKFileDataExtracting.h" 27| |#import "FBSDKFileManaging.h" 28| |#import "FBSDKLibAnalyzer.h" 29| |#import "FBSDKTypeUtility.h" 30| |#import "NSBundle+InfoDictionaryProviding.h" 31| | 32| |#define FBSDK_MAX_CRASH_LOGS 5 33| 0|#define FBSDK_CRASH_PATH_NAME @"instrument" 34| |#ifndef FBSDK_VERSION_STRING 35| 0| #define FBSDK_VERSION_STRING @"11.0.1" 36| |#endif 37| | 38| |static NSUncaughtExceptionHandler *previousExceptionHandler = NULL; 39| |static NSString *mappingTableIdentifier = NULL; 40| |static NSString *directoryPath; 41| | 42| |NSString *const kFBSDKAppVersion = @"app_version"; 43| |NSString *const kFBSDKCallstack = @"callstack"; 44| |NSString *const kFBSDKCrashReason = @"reason"; 45| |NSString *const kFBSDKCrashTimestamp = @"timestamp"; 46| |NSString *const kFBSDKDeviceModel = @"device_model"; 47| |NSString *const kFBSDKDeviceOSVersion = @"device_os_version"; 48| | 49| |NSString *const kFBSDKMapingTable = @"mapping_table"; 50| |NSString *const kFBSDKMappingTableIdentifier = @"mapping_table_identifier"; 51| | 52| |@interface FBSDKCrashHandler () 53| | 54| |@property (nonatomic) BOOL isTurnedOn; 55| |@property (nonatomic) id fileManager; 56| |@property (nonatomic, strong) Class dataExtractor; 57| |@property (nonatomic) id bundle; 58| |@property (nonatomic) NSHashTable> *observers; 59| |@property (nonatomic) NSArray *> *processedCrashLogs; 60| | 61| |@end 62| | 63| |@implementation FBSDKCrashHandler 64| | 65| |- (instancetype)init 66| 0|{ 67| 0| return [self initWithFileManager:NSFileManager.defaultManager 68| 0| bundle:NSBundle.mainBundle 69| 0| fileDataExtractor:NSData.class 70| 0| ]; 71| 0|} 72| | 73| |- (instancetype)initWithFileManager:(id)fileManager 74| | bundle:(id)bundle 75| | fileDataExtractor:(nonnull Class)dataExtractor 76| 0|{ 77| 0| if ((self = [super init])) { 78| 0| _observers = [NSHashTable new]; 79| 0| _isTurnedOn = YES; 80| 0| _fileManager = fileManager; 81| 0| _bundle = bundle; 82| 0| _dataExtractor = dataExtractor; 83| | 84| 0| NSString *dirPath = [NSTemporaryDirectory() stringByAppendingPathComponent:FBSDK_CRASH_PATH_NAME]; 85| 0| if (![_fileManager fileExistsAtPath:dirPath]) { 86| 0| [_fileManager createDirectoryAtPath:dirPath withIntermediateDirectories:NO attributes:NULL error:NULL]; 87| 0| } 88| 0| directoryPath = dirPath; 89| 0| NSString *identifier = [[NSUUID UUID] UUIDString]; 90| 0| mappingTableIdentifier = [identifier stringByReplacingOccurrencesOfString:@"-" withString:@""]; 91| 0| } 92| 0| return self; 93| 0|} 94| | 95| |+ (instancetype)shared 96| 0|{ 97| 0| static dispatch_once_t nonce; 98| 0| static id instance; 99| 0| dispatch_once(&nonce, ^{ 100| 0| instance = [self new]; 101| 0| }); 102| 0| return instance; 103| 0|} 104| | 105| |#pragma mark - Public API 106| | 107| |+ (NSString *)getFBSDKVersion 108| 0|{ 109| 0| return FBSDK_VERSION_STRING; 110| 0|} 111| | 112| |+ (void)disable 113| 0|{ 114| 0| [FBSDKCrashHandler.shared disable]; 115| 0|} 116| | 117| |- (void)disable 118| 0|{ 119| 0| self.isTurnedOn = NO; 120| 0| [FBSDKCrashHandler.shared _uninstallExceptionsHandler]; 121| 0| self.observers = nil; 122| 0|} 123| | 124| |+ (void)addObserver:(id)observer 125| 0|{ 126| 0| [FBSDKCrashHandler.shared addObserver:observer]; 127| 0|} 128| | 129| |- (void)addObserver:(id)observer 130| 0|{ 131| 0| if (!self.isTurnedOn || ![self _isSafeToGenerateMapping]) { 132| 0| return; 133| 0| } 134| 0| static dispatch_once_t onceToken; 135| 0| dispatch_once(&onceToken, ^{ 136| 0| [FBSDKCrashHandler.shared _installExceptionsHandler]; 137| 0| _processedCrashLogs = [self _getProcessedCrashLogs]; 138| 0| }); 139| 0| @synchronized(_observers) { 140| 0| if (![self.observers containsObject:observer]) { 141| 0| [self.observers addObject:observer]; 142| 0| dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) { 143| 0| [self _generateMethodMapping:observer]; 144| 0| }); 145| 0| [self _sendCrashLogs]; 146| 0| } 147| 0| } 148| 0|} 149| | 150| |+ (void)removeObserver:(id)observer 151| 0|{ 152| 0| [FBSDKCrashHandler.shared removeObserver:observer]; 153| 0|} 154| | 155| |- (void)removeObserver:(id)observer 156| 0|{ 157| 0| @synchronized(_observers) { 158| 0| if ([self.observers containsObject:observer]) { 159| 0| [self.observers removeObject:observer]; 160| 0| if (self.observers.count == 0) { 161| 0| [FBSDKCrashHandler.shared _uninstallExceptionsHandler]; 162| 0| } 163| 0| } 164| 0| } 165| 0|} 166| | 167| |+ (void)clearCrashReportFiles 168| 0|{ 169| 0| [FBSDKCrashHandler.shared clearCrashReportFiles]; 170| 0|} 171| | 172| |- (void)clearCrashReportFiles 173| 0|{ 174| 0| NSArray *files = [self.fileManager contentsOfDirectoryAtPath:directoryPath error:nil]; 175| | 176| 0| for (NSUInteger i = 0; i < files.count; i++) { 177| | // remove all crash related files except for the current mapping table 178| 0| if ([[FBSDKTypeUtility array:files objectAtIndex:i] hasPrefix:@"crash_"] && ![[FBSDKTypeUtility array:files objectAtIndex:i] containsString:mappingTableIdentifier]) { 179| 0| [self.fileManager removeItemAtPath:[directoryPath stringByAppendingPathComponent:[FBSDKTypeUtility array:files objectAtIndex:i]] error:nil]; 180| 0| } 181| 0| } 182| 0|} 183| | 184| |# pragma mark - Handler 185| | 186| |+ (void)_installExceptionsHandler 187| 0|{ 188| 0| [FBSDKCrashHandler.shared _installExceptionsHandler]; 189| 0|} 190| | 191| |- (void)_installExceptionsHandler 192| 0|{ 193| 0| NSUncaughtExceptionHandler *currentHandler = NSGetUncaughtExceptionHandler(); 194| | 195| 0| if (currentHandler != FBSDKExceptionHandler) { 196| 0| previousExceptionHandler = currentHandler; 197| 0| NSSetUncaughtExceptionHandler(&FBSDKExceptionHandler); 198| 0| } 199| 0|} 200| | 201| |+ (void)_uninstallExceptionsHandler 202| 0|{ 203| 0| [FBSDKCrashHandler.shared _uninstallExceptionsHandler]; 204| 0|} 205| | 206| |- (void)_uninstallExceptionsHandler 207| 0|{ 208| 0| NSSetUncaughtExceptionHandler(previousExceptionHandler); 209| 0| previousExceptionHandler = nil; 210| 0|} 211| | 212| |static void FBSDKExceptionHandler(NSException *exception) 213| 0|{ 214| 0| [FBSDKCrashHandler.shared _saveException:exception]; 215| 0| if (previousExceptionHandler) { 216| 0| previousExceptionHandler(exception); 217| 0| } 218| 0|} 219| | 220| |#pragma mark - Storage & Process 221| | 222| |+ (void)_saveException:(NSException *)exception 223| 0|{ 224| 0| [FBSDKCrashHandler.shared _saveException:exception]; 225| 0|} 226| | 227| |- (void)_saveException:(NSException *)exception 228| 0|{ 229| 0| if (exception.callStackSymbols && exception.name) { 230| 0| NSArray *stackSymbols = [NSArray arrayWithArray:exception.callStackSymbols]; 231| 0| [self _saveCrashLog:@{ 232| 0| kFBSDKCallstack : stackSymbols, 233| 0| kFBSDKCrashReason : exception.name, 234| 0| }]; 235| 0| } 236| 0|} 237| | 238| |+ (NSArray *> *)_getProcessedCrashLogs 239| 0|{ 240| 0| return [FBSDKCrashHandler.shared _getProcessedCrashLogs]; 241| 0|} 242| | 243| |- (NSArray *> *)_getProcessedCrashLogs 244| 0|{ 245| 0| NSArray *> *crashLogs = [self _loadCrashLogs]; 246| 0| if (0 == crashLogs.count) { 247| 0| [self clearCrashReportFiles]; 248| 0| return nil; 249| 0| } 250| 0| NSMutableArray *> *processedCrashLogs = [NSMutableArray array]; 251| | 252| 0| for (NSDictionary *crashLog in crashLogs) { 253| 0| NSArray *callstack = crashLog[kFBSDKCallstack]; 254| 0| NSData *data = [self _loadLibData:crashLog]; 255| 0| if (!data) { 256| 0| continue; 257| 0| } 258| 0| NSDictionary *methodMapping = [FBSDKTypeUtility JSONObjectWithData:data 259| 0| options:kNilOptions 260| 0| error:nil]; 261| 0| NSArray *symbolicatedCallstack = [FBSDKLibAnalyzer symbolicateCallstack:callstack methodMapping:methodMapping]; 262| 0| NSMutableDictionary *symbolicatedCrashLog = [NSMutableDictionary dictionaryWithDictionary:crashLog]; 263| 0| if (symbolicatedCallstack) { 264| 0| [FBSDKTypeUtility dictionary:symbolicatedCrashLog setObject:symbolicatedCallstack forKey:kFBSDKCallstack]; 265| 0| [symbolicatedCrashLog removeObjectForKey:kFBSDKMappingTableIdentifier]; 266| 0| [FBSDKTypeUtility array:processedCrashLogs addObject:symbolicatedCrashLog]; 267| 0| } 268| 0| } 269| 0| return processedCrashLogs; 270| 0|} 271| | 272| |+ (NSArray *> *)_loadCrashLogs 273| 0|{ 274| 0| return [FBSDKCrashHandler.shared _loadCrashLogs]; 275| 0|} 276| | 277| |- (NSArray *> *)_loadCrashLogs 278| 0|{ 279| 0| NSArray *files = [self.fileManager contentsOfDirectoryAtPath:directoryPath error:NULL]; 280| 0| NSArray *fileNames = [[self _getCrashLogFileNames:files] sortedArrayUsingComparator:^NSComparisonResult (id _Nonnull obj1, id _Nonnull obj2) { 281| 0| return [obj2 compare:obj1]; 282| 0| }]; 283| 0| NSMutableArray *> *crashLogArray = [NSMutableArray array]; 284| | 285| 0| for (NSUInteger i = 0; i < MIN(fileNames.count, FBSDK_MAX_CRASH_LOGS); i++) { 286| 0| NSData *data = [self _loadCrashLog:[FBSDKTypeUtility array:fileNames objectAtIndex:i]]; 287| 0| if (!data) { 288| 0| continue; 289| 0| } 290| 0| NSDictionary *crashLog = [FBSDKTypeUtility JSONObjectWithData:data 291| 0| options:kNilOptions 292| 0| error:nil]; 293| 0| if (crashLog) { 294| 0| [FBSDKTypeUtility array:crashLogArray addObject:crashLog]; 295| 0| } 296| 0| } 297| 0| return [crashLogArray copy]; 298| 0|} 299| | 300| |+ (nullable NSData *)_loadCrashLog:(NSString *)fileName 301| 0|{ 302| 0| return [FBSDKCrashHandler.shared _loadCrashLog:fileName]; 303| 0|} 304| | 305| |- (nullable NSData *)_loadCrashLog:(NSString *)fileName 306| 0|{ 307| 0| return [self.dataExtractor dataWithContentsOfFile:[directoryPath stringByAppendingPathComponent:fileName] options:NSDataReadingMappedIfSafe error:nil]; 308| 0|} 309| | 310| |+ (NSArray *)_getCrashLogFileNames:(NSArray *)files 311| 0|{ 312| 0| return [FBSDKCrashHandler.shared _getCrashLogFileNames:files]; 313| 0|} 314| | 315| |- (NSArray *)_getCrashLogFileNames:(NSArray *)files 316| 0|{ 317| 0| NSMutableArray *fileNames = [NSMutableArray array]; 318| | 319| 0| for (NSString *fileName in files) { 320| 0| if ([fileName hasPrefix:@"crash_log_"] && [fileName hasSuffix:@".json"]) { 321| 0| [FBSDKTypeUtility array:fileNames addObject:fileName]; 322| 0| } 323| 0| } 324| | 325| 0| return fileNames; 326| 0|} 327| | 328| |+ (void)_saveCrashLog:(NSDictionary *)crashLog 329| 0|{ 330| 0| [FBSDKCrashHandler.shared _saveCrashLog:crashLog]; 331| 0|} 332| | 333| |- (void)_saveCrashLog:(NSDictionary *)crashLog 334| 0|{ 335| 0| NSMutableDictionary *completeCrashLog = [NSMutableDictionary dictionaryWithDictionary:crashLog]; 336| 0| NSString *currentTimestamp = [NSString stringWithFormat:@"%.0lf", [[NSDate date] timeIntervalSince1970]]; 337| | 338| 0| [FBSDKTypeUtility dictionary:completeCrashLog setObject:currentTimestamp forKey:kFBSDKCrashTimestamp]; 339| 0| [FBSDKTypeUtility dictionary:completeCrashLog setObject:mappingTableIdentifier forKey:kFBSDKMappingTableIdentifier]; 340| | 341| 0| NSString *version = [self.bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; 342| 0| NSString *build = [self.bundle objectForInfoDictionaryKey:@"CFBundleVersion"]; 343| 0| [FBSDKTypeUtility dictionary:completeCrashLog setObject:[NSString stringWithFormat:@"%@(%@)", version, build] forKey:kFBSDKAppVersion]; 344| | 345| 0| struct utsname systemInfo; 346| 0| uname(&systemInfo); 347| 0| [FBSDKTypeUtility dictionary:completeCrashLog setObject:@(systemInfo.machine) forKey:kFBSDKDeviceModel]; 348| | 349| 0| [FBSDKTypeUtility dictionary:completeCrashLog setObject:[UIDevice currentDevice].systemVersion forKey:kFBSDKDeviceOSVersion]; 350| | 351| 0| NSData *data = [FBSDKTypeUtility dataWithJSONObject:completeCrashLog options:0 error:nil]; 352| | 353| 0| [data writeToFile:[self _getPathToCrashFile:currentTimestamp] 354| 0| atomically:YES]; 355| 0|} 356| | 357| |+ (void)_sendCrashLogs 358| 0|{ 359| 0| [FBSDKCrashHandler.shared _sendCrashLogs]; 360| 0|} 361| | 362| |- (void)_sendCrashLogs 363| 0|{ 364| 0| for (id observer in _observers) { 365| 0| if (observer) { 366| 0| NSArray *> *filteredCrashLogs = [self _filterCrashLogs:observer.prefixes processedCrashLogs:_processedCrashLogs]; 367| 0| [observer didReceiveCrashLogs:filteredCrashLogs]; 368| 0| } 369| 0| } 370| 0|} 371| | 372| |+ (NSArray *> *)_filterCrashLogs:(NSArray *)prefixList 373| | processedCrashLogs:(NSArray *> *)processedCrashLogs 374| 0|{ 375| 0| return [FBSDKCrashHandler.shared _filterCrashLogs:prefixList processedCrashLogs:processedCrashLogs]; 376| 0|} 377| | 378| |- (NSArray *> *)_filterCrashLogs:(NSArray *)prefixList 379| | processedCrashLogs:(NSArray *> *)processedCrashLogs 380| 0|{ 381| 0| NSMutableArray *> *crashLogs = [NSMutableArray array]; 382| 0| for (NSDictionary *crashLog in processedCrashLogs) { 383| 0| NSArray *callstack = crashLog[kFBSDKCallstack]; 384| 0| if ([self _callstack:callstack containsPrefix:prefixList]) { 385| 0| [FBSDKTypeUtility array:crashLogs addObject:crashLog]; 386| 0| } 387| 0| } 388| 0| return crashLogs; 389| 0|} 390| | 391| |+ (BOOL)_callstack:(NSArray *)callstack 392| | containsPrefix:(NSArray *)prefixList 393| 0|{ 394| 0| return [FBSDKCrashHandler.shared _callstack:callstack containsPrefix:prefixList]; 395| 0|} 396| | 397| |- (BOOL)_callstack:(NSArray *)callstack 398| | containsPrefix:(NSArray *)prefixList 399| 0|{ 400| 0| NSString *callStackString = [callstack componentsJoinedByString:@""]; 401| 0| for (NSString *prefix in prefixList) { 402| 0| if ([callStackString containsString:prefix]) { 403| 0| return YES; 404| 0| } 405| 0| } 406| 0| return NO; 407| 0|} 408| | 409| |#pragma mark - Method Mapping 410| | 411| |+ (void)_generateMethodMapping:(id)observer 412| 0|{ 413| 0| [FBSDKCrashHandler.shared _generateMethodMapping:observer]; 414| 0|} 415| | 416| |- (void)_generateMethodMapping:(id)observer 417| 0|{ 418| 0| if (observer.prefixes.count == 0) { 419| 0| return; 420| 0| } 421| 0| [[NSUserDefaults standardUserDefaults] setObject:mappingTableIdentifier forKey:kFBSDKMappingTableIdentifier]; 422| 0| NSDictionary *methodMapping = [FBSDKLibAnalyzer getMethodsTable:observer.prefixes 423| 0| frameworks:observer.frameworks]; 424| 0| if (methodMapping.count > 0) { 425| 0| NSData *data = [FBSDKTypeUtility dataWithJSONObject:methodMapping options:0 error:nil]; 426| 0| [data writeToFile:[self _getPathToLibDataFile:mappingTableIdentifier] 427| 0| atomically:YES]; 428| 0| } 429| 0|} 430| | 431| |+ (nullable NSData *)_loadLibData:(NSDictionary *)crashLog 432| 0|{ 433| 0| return [FBSDKCrashHandler.shared _loadLibData:crashLog]; 434| 0|} 435| | 436| |- (nullable NSData *)_loadLibData:(NSDictionary *)crashLog 437| 0|{ 438| 0| NSString *identifier = [FBSDKTypeUtility dictionary:crashLog objectForKey:kFBSDKMappingTableIdentifier ofType:NSObject.class]; 439| 0| return [self.dataExtractor dataWithContentsOfFile:[self _getPathToLibDataFile:identifier] options:NSDataReadingMappedIfSafe error:nil]; 440| 0|} 441| | 442| |+ (NSString *)_getPathToCrashFile:(NSString *)timestamp 443| 0|{ 444| 0| return [FBSDKCrashHandler.shared _getPathToCrashFile:timestamp]; 445| 0|} 446| | 447| |- (NSString *)_getPathToCrashFile:(NSString *)timestamp 448| 0|{ 449| 0| return [directoryPath stringByAppendingPathComponent: 450| 0| [NSString stringWithFormat:@"crash_log_%@.json", timestamp]]; 451| 0|} 452| | 453| |+ (NSString *)_getPathToLibDataFile:(NSString *)identifier 454| 0|{ 455| 0| return [FBSDKCrashHandler.shared _getPathToLibDataFile:identifier]; 456| 0|} 457| | 458| |- (NSString *)_getPathToLibDataFile:(NSString *)identifier 459| 0|{ 460| 0| return [directoryPath stringByAppendingPathComponent: 461| 0| [NSString stringWithFormat:@"crash_lib_data_%@.json", identifier]]; 462| 0|} 463| | 464| |+ (BOOL)_isSafeToGenerateMapping 465| 0|{ 466| 0| return [FBSDKCrashHandler.shared _isSafeToGenerateMapping]; 467| 0|} 468| | 469| |- (BOOL)_isSafeToGenerateMapping 470| 0|{ 471| 0|#if TARGET_OS_SIMULATOR 472| 0| return YES; 473| |#else 474| | NSString *identifier = [[NSUserDefaults standardUserDefaults] objectForKey:kFBSDKMappingTableIdentifier]; 475| | // first app start 476| | if (!identifier) { 477| | return YES; 478| | } 479| | 480| | return [self.fileManager fileExistsAtPath:[self _getPathToLibDataFile:identifier]]; 481| |#endif 482| 0|} 483| | 484| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKJSONValue.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKJSONValue.h" 20| | 21| |#import 22| | 23| |#import "FBSDKBasicUtility.h" 24| |#import "FBSDKSafeCast.h" 25| |#import "FBSDKTypeUtility.h" 26| | 27| |@interface FBSDKJSONField () 28| |- (instancetype)initWithPotentialJSONField:(id)obj; 29| |@end 30| | 31| |static NSArray *createArray(id obj) 32| 0|{ 33| 0| NSArray *const original = FBSDK_CAST_TO_CLASS_OR_NIL(obj, NSArray); 34| 0| if (!original) { 35| 0| return @[]; 36| 0| } 37| | 38| 0| NSMutableArray *const fields = 39| 0| [[NSMutableArray alloc] initWithCapacity:original.count]; 40| | 41| 0| for (id field in original) { 42| 0| FBSDKJSONField *const f = [[FBSDKJSONField alloc] initWithPotentialJSONField:field]; 43| 0| if (f) { 44| 0| [fields addObject:f]; 45| 0| } 46| 0| } 47| | 48| 0| return fields; 49| 0|} 50| | 51| |static NSDictionary *createDictionary(id obj) 52| 0|{ 53| 0| NSDictionary *const original = FBSDK_CAST_TO_CLASS_OR_NIL(obj, NSDictionary); 54| 0| if (!original) { 55| 0| return @{}; 56| 0| } 57| | 58| 0| NSMutableDictionary *const fields = 59| 0| [[NSMutableDictionary alloc] initWithCapacity:original.count]; 60| | 61| 0| for (id key in original) { 62| | // This is just a sanity check. Apple should only give us string keys 63| | // anyway. 64| 0| if (![key respondsToSelector:@selector(isKindOfClass:)] || ![key isKindOfClass:NSString.class]) { 65| 0| continue; 66| 0| } 67| 0| NSString *const stringKey = (NSString *)key; 68| | 69| 0| FBSDKJSONField *const typedField = [[FBSDKJSONField alloc] initWithPotentialJSONField:original[key]]; 70| 0| if (typedField) { 71| 0| fields[stringKey] = typedField; 72| 0| } 73| 0| } 74| | 75| 0| return fields; 76| 0|} 77| | 78| |@implementation FBSDKJSONValue 79| | 80| |- (instancetype)initWithPotentialJSONObject:(id)obj 81| 0|{ 82| | // If this isn't a real JSON object, dump it. 83| 0| if (![FBSDKTypeUtility isValidJSONObject:obj]) { 84| 0| return nil; 85| 0| } 86| 0| _rawObject = obj; 87| | 88| 0| return self; 89| 0|} 90| | 91| |- (void)matchArray:(void (^)(NSArray *))arrayMatcher 92| | dictionary:(void (^)(NSDictionary *))dictMatcher 93| 0|{ 94| 0| if (arrayMatcher && [_rawObject isKindOfClass:[NSArray class]]) { 95| 0| arrayMatcher(createArray(_rawObject)); 96| 0| } else if (dictMatcher && [_rawObject isKindOfClass:[NSDictionary class]]) { 97| 0| dictMatcher(createDictionary(_rawObject)); 98| 0| } 99| 0|} 100| | 101| |- (NSDictionary *_Nullable)matchDictionaryOrNil 102| 0|{ 103| 0| __block NSDictionary *result = nil; 104| 0| [self matchArray:nil dictionary:^(NSDictionary *_Nonnull value) { 105| 0| result = value; 106| 0| }]; 107| 0| return result; 108| 0|} 109| | 110| |- (NSDictionary *_Nullable)unsafe_matchDictionaryOrNil 111| 0|{ 112| 0| return [_rawObject isKindOfClass:NSDictionary.class] ? _rawObject : nil; 113| 0|} 114| | 115| |- (NSArray *_Nullable)matchArrayOrNil 116| 0|{ 117| 0| __block NSArray *result = nil; 118| 0| [self matchArray:^(NSArray *_Nonnull value) { 119| 0| result = value; 120| 0| } dictionary:nil]; 121| 0| return result; 122| 0|} 123| | 124| |- (NSArray *_Nullable)unsafe_matchArrayOrNil 125| 0|{ 126| 0| __block BOOL isArray = NO; 127| 0| [self matchArray:^(NSArray *_Nonnull _) { 128| 0| isArray = YES; 129| 0| } dictionary:nil]; 130| | 131| 0| return [_rawObject isKindOfClass:NSArray.class] ? _rawObject : nil; 132| 0|} 133| | 134| |@end 135| | 136| |@implementation FBSDKJSONField 137| | 138| |- (instancetype)initWithPotentialJSONField:(id)obj 139| 0|{ 140| | // If this is nil, don't wrap it. 141| 0| if (obj == nil) { 142| 0| return nil; 143| 0| } 144| | 145| | // Per Apple's Docs, these are the only types FBSDKTypeUtility can return. 146| 0| if ( 147| 0| ![obj isKindOfClass:NSString.class] 148| 0| && ![obj isKindOfClass:NSNumber.class] 149| 0| && ![obj isKindOfClass:NSNull.class] 150| 0| && ![obj isKindOfClass:NSDictionary.class] 151| 0| && ![obj isKindOfClass:NSArray.class]) { 152| 0| return nil; 153| 0| } 154| | 155| 0| if (self = [super init]) { 156| 0| _rawObject = obj; 157| 0| } 158| | 159| 0| return self; 160| 0|} 161| | 162| |- (void)matchArray:(void (^)(NSArray *))arrayMatcher 163| | dictionary:(void (^)(NSDictionary *_Nonnull))dictionaryMatcher 164| | string:(void (^)(NSString *_Nonnull))stringMatcher 165| | number:(void (^)(NSNumber *_Nonnull))numberMatcher 166| | null:(void (^)(void))nullMatcher 167| 0|{ 168| 0| if (nullMatcher && [_rawObject isKindOfClass:NSNull.class]) { 169| 0| nullMatcher(); 170| 0| } else if (numberMatcher && [_rawObject isKindOfClass:NSNumber.class]) { 171| 0| numberMatcher(_rawObject); 172| 0| } else if (stringMatcher && [_rawObject isKindOfClass:NSString.class]) { 173| 0| stringMatcher(_rawObject); 174| 0| } else if (arrayMatcher && [_rawObject isKindOfClass:NSArray.class]) { 175| 0| arrayMatcher(createArray(_rawObject)); 176| 0| } else if (dictionaryMatcher && [_rawObject isKindOfClass:NSDictionary.class]) { 177| 0| dictionaryMatcher(createDictionary(_rawObject)); 178| 0| } 179| 0|} 180| | 181| |- (NSArray *_Nullable)arrayOrNil 182| 0|{ 183| 0| __block NSArray *result = nil; 184| 0| [self matchArray:^(NSArray *_Nonnull a) { 185| 0| result = [a copy]; 186| 0| } dictionary:nil string:nil number:nil null:nil]; 187| 0| return result; 188| 0|} 189| | 190| |- (NSDictionary *_Nullable)dictionaryOrNil 191| 0|{ 192| 0| __block NSDictionary *result = nil; 193| 0| [self matchArray:nil dictionary:^(NSDictionary *_Nonnull d) { 194| 0| result = [d copy]; 195| 0| } string:nil number:nil null:nil]; 196| 0| return result; 197| 0|} 198| | 199| |- (NSString *_Nullable)stringOrNil 200| 0|{ 201| 0| __block NSString *result = nil; 202| 0| [self matchArray:nil dictionary:nil string:^(NSString *_Nonnull s) { 203| 0| result = [s copy]; 204| 0| } number:nil null:nil]; 205| 0| return result; 206| 0|} 207| | 208| |- (NSNumber *_Nullable)numberOrNil 209| 0|{ 210| 0| __block NSNumber *result = nil; 211| 0| [self matchArray:nil dictionary:nil string:nil number:^(NSNumber *_Nonnull n) { 212| 0| result = n; 213| 0| } null:nil]; 214| 0| return result; 215| 0|} 216| | 217| |- (NSNull *_Nullable)nullOrNil 218| 0|{ 219| 0| __block NSNull *result = nil; 220| 0| [self matchArray:nil dictionary:nil string:nil number:nil null:^{ 221| 0| result = [NSNull null]; 222| 0| }]; 223| 0| return result; 224| 0|} 225| | 226| |@end 227| | 228| |FBSDKJSONValue *_Nullable FBSDKCreateJSONFromString(NSString *_Nullable string, NSError *__autoreleasing *errorRef) 229| 0|{ 230| 0| return 231| 0| [[FBSDKJSONValue alloc] initWithPotentialJSONObject:[FBSDKBasicUtility objectForJSONString:string error:errorRef]]; 232| 0|} /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKLibAnalyzer.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKLibAnalyzer.h" 20| | 21| |#import 22| | 23| |#import "FBSDKTypeUtility.h" 24| | 25| |@implementation FBSDKLibAnalyzer 26| | 27| |static NSMutableDictionary *_methodMapping; 28| | 29| |+ (void)initialize 30| 0|{ 31| 0| _methodMapping = [NSMutableDictionary dictionary]; 32| 0|} 33| | 34| |+ (NSDictionary *)getMethodsTable:(NSArray *)prefixes 35| | frameworks:(NSArray *)frameworks 36| 0|{ 37| 0| NSArray *allClasses = [self _getClassNames:prefixes frameworks:frameworks]; 38| 0| for (NSString *className in allClasses) { 39| 0| Class class = NSClassFromString(className); 40| 0| if (class) { 41| 0| [self _addClass:class isClassMethod:NO]; 42| 0| [self _addClass:object_getClass(class) isClassMethod:YES]; 43| 0| } 44| 0| } 45| 0| @synchronized(_methodMapping) { 46| 0| return [_methodMapping copy]; 47| 0| } 48| 0|} 49| | 50| |+ (nullable NSArray *)symbolicateCallstack:(NSArray *)callstack 51| | methodMapping:(NSDictionary *)methodMapping 52| 0|{ 53| 0| if (!callstack || !methodMapping) { 54| 0| return nil; 55| 0| } 56| 0| NSArray *sortedAllAddress = [methodMapping.allKeys sortedArrayUsingComparator:^NSComparisonResult (id _Nonnull obj1, id _Nonnull obj2) { 57| 0| return [obj1 compare:obj2]; 58| 0| }]; 59| | 60| 0| BOOL containsFBSDKFunction = NO; 61| 0| NSInteger nonSDKMethodCount = 0; 62| 0| NSMutableArray *symbolicatedCallstack = [NSMutableArray array]; 63| | 64| 0| for (NSUInteger i = 0; i < callstack.count; i++) { 65| 0| NSString *rawAddress = [self _getAddress:[FBSDKTypeUtility array:callstack objectAtIndex:i]]; 66| 0| if (rawAddress.length < 10) { 67| 0| continue; 68| 0| } 69| 0| NSString *addressString = [NSString stringWithFormat:@"0x%@", [rawAddress substringWithRange:NSMakeRange(rawAddress.length - 10, 10)]]; 70| 0| NSString *methodAddress = [self _searchMethod:addressString sortedAllAddress:sortedAllAddress]; 71| | 72| 0| if (methodAddress) { 73| 0| containsFBSDKFunction = YES; 74| 0| nonSDKMethodCount == 0 ?: [FBSDKTypeUtility array:symbolicatedCallstack addObject:[NSString stringWithFormat:@"(%ld DEV METHODS)", (long)nonSDKMethodCount]]; 75| 0| nonSDKMethodCount = 0; 76| 0| NSString *methodName = [FBSDKTypeUtility dictionary:methodMapping objectForKey:methodAddress ofType:NSObject.class]; 77| | 78| | // filter out cxx_destruct 79| 0| if ([methodName containsString:@".cxx_destruct"]) { 80| 0| return nil; 81| 0| } 82| 0| [FBSDKTypeUtility array:symbolicatedCallstack addObject:[NSString stringWithFormat:@"%@%@", methodName, [self _getOffset:addressString secondString:methodAddress]]]; 83| 0| } else { 84| 0| nonSDKMethodCount++; 85| 0| } 86| 0| } 87| 0| nonSDKMethodCount == 0 ?: [FBSDKTypeUtility array:symbolicatedCallstack addObject:[NSString stringWithFormat:@"(%ld DEV METHODS)", (long)nonSDKMethodCount]]; 88| | 89| 0| return containsFBSDKFunction ? symbolicatedCallstack : nil; 90| 0|} 91| | 92| |#pragma mark - Private Methods 93| | 94| |+ (NSArray *)_getClassNames:(NSArray *)prefixes 95| | frameworks:(NSArray *)frameworks 96| 0|{ 97| 0| NSMutableArray *classNames = [NSMutableArray new]; 98| | // from main bundle 99| 0| [classNames addObjectsFromArray:[self _getClassesFrom:[[NSBundle mainBundle] executablePath] 100| 0| prefixes:prefixes]]; 101| | // from dynamic libraries 102| 0| if (frameworks.count > 0) { 103| 0| unsigned int count = 0; 104| 0| const char **images = objc_copyImageNames(&count); 105| 0| for (int i = 0; i < count; i++) { 106| 0| NSString *image = [NSString stringWithUTF8String:images[i]]; 107| 0| for (NSString *framework in frameworks) { 108| 0| if ([image containsString:framework]) { 109| 0| [classNames addObjectsFromArray:[self _getClassesFrom:image 110| 0| prefixes:nil]]; 111| 0| } 112| 0| } 113| 0| } 114| 0| free(images); 115| 0| } 116| | 117| 0| return [classNames copy]; 118| 0|} 119| | 120| |+ (NSArray *)_getClassesFrom:(NSString *)image 121| | prefixes:(NSArray *)prefixes 122| 0|{ 123| 0| NSMutableArray *classNames = [NSMutableArray array]; 124| 0| unsigned int count = 0; 125| 0| const char **classes = objc_copyClassNamesForImage([image UTF8String], &count); 126| 0| for (unsigned int i = 0; i < count; i++) { 127| 0| NSString *className = [NSString stringWithUTF8String:classes[i]]; 128| 0| if (prefixes.count > 0) { 129| 0| for (NSString *prefix in prefixes) { 130| 0| if ([className hasPrefix:prefix]) { 131| 0| [FBSDKTypeUtility array:classNames addObject:className]; 132| 0| break; 133| 0| } 134| 0| } 135| 0| } else { 136| 0| [FBSDKTypeUtility array:classNames addObject:className]; 137| 0| } 138| 0| } 139| 0| free(classes); 140| 0| return [classNames copy]; 141| 0|} 142| | 143| |+ (void)_addClass:(Class)class 144| | isClassMethod:(BOOL)isClassMethod 145| 0|{ 146| 0| unsigned int methodsCount = 0; 147| 0| Method *methods = class_copyMethodList(class, &methodsCount); 148| | 149| 0| NSString *methodType = isClassMethod ? @"+" : @"-"; 150| | 151| 0| for (unsigned int i = 0; i < methodsCount; i++) { 152| 0| Method method = methods[i]; 153| | 154| 0| if (method) { 155| 0| SEL selector = method_getName(method); 156| | 157| 0| IMP methodImplementation = class_getMethodImplementation(class, selector); 158| 0| NSString *methodAddress = [NSString stringWithFormat:@"0x%010lx", (unsigned long)methodImplementation]; 159| 0| NSString *methodName = [NSString stringWithFormat:@"%@[%@ %@]", 160| 0| methodType, 161| 0| NSStringFromClass(class), 162| 0| NSStringFromSelector(selector)]; 163| | 164| 0| if (methodAddress && methodName) { 165| 0| @synchronized(_methodMapping) { 166| 0| [FBSDKTypeUtility dictionary:_methodMapping setObject:methodName forKey:methodAddress]; 167| 0| } 168| 0| } 169| 0| } 170| 0| } 171| 0| free(methods); 172| 0|} 173| | 174| |+ (nullable NSString *)_getAddress:(nullable NSString *)callstackEntry 175| 0|{ 176| 0| if ([callstackEntry isKindOfClass:[NSString class]]) { 177| 0| NSArray *components = [callstackEntry componentsSeparatedByString:@" "]; 178| 0| for (NSString *component in components) { 179| 0| if ([component containsString:@"0x"]) { 180| 0| return component; 181| 0| } 182| 0| } 183| 0| } 184| 0| return nil; 185| 0|} 186| | 187| |+ (NSString *)_getOffset:(NSString *)firstString 188| | secondString:(NSString *)secondString 189| 0|{ 190| 0| unsigned long long first = 0, second = 0; 191| 0| NSScanner *scanner = [NSScanner scannerWithString:firstString]; 192| 0| [scanner scanHexLongLong:&first]; 193| | 194| 0| scanner = [NSScanner scannerWithString:secondString]; 195| 0| [scanner scanHexLongLong:&second]; 196| | 197| 0| unsigned long long difference = first - second; 198| 0| return [NSString stringWithFormat:@"+%llu", difference]; 199| 0|} 200| | 201| |+ (nullable NSString *)_searchMethod:(NSString *)address 202| | sortedAllAddress:(NSArray *)sortedAllAddress 203| 0|{ 204| 0| if (0 == sortedAllAddress.count) { 205| 0| return nil; 206| 0| } 207| 0| NSString *lowestAddress = [FBSDKTypeUtility array:sortedAllAddress objectAtIndex:0]; 208| 0| NSString *highestAddress = [FBSDKTypeUtility array:sortedAllAddress objectAtIndex:sortedAllAddress.count - 1]; 209| | 210| 0| if ([address compare:lowestAddress] == NSOrderedAscending || [address compare:highestAddress] == NSOrderedDescending) { 211| 0| return nil; 212| 0| } 213| | 214| 0| if ([address compare:lowestAddress] == NSOrderedSame) { 215| 0| return lowestAddress; 216| 0| } 217| | 218| 0| if ([address compare:highestAddress] == NSOrderedSame) { 219| 0| return highestAddress; 220| 0| } 221| | 222| 0| NSUInteger index = [sortedAllAddress indexOfObject:address 223| 0| inSortedRange:NSMakeRange(0, sortedAllAddress.count - 1) 224| 0| options:NSBinarySearchingInsertionIndex 225| 0| usingComparator:^NSComparisonResult (id _Nonnull obj1, id _Nonnull obj2) { 226| 0| return [obj1 compare:obj2]; 227| 0| }]; 228| 0| return [FBSDKTypeUtility array:sortedAllAddress objectAtIndex:index - 1]; 229| 0|} 230| | 231| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKSafeCast.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKSafeCast.h" 20| | 21| |id _FBSDKCastToClassOrNilUnsafeInternal(id object, Class klass) 22| 0|{ 23| 0| return [(NSObject *)object isKindOfClass:klass] ? object : nil; 24| 0|} 25| | 26| |id _FBSDKCastToProtocolOrNilUnsafeInternal(id object, Protocol *protocol) 27| 0|{ 28| 0| return [(NSObject *)object conformsToProtocol:protocol] ? object : nil; 29| 0|} /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKTypeUtility.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKTypeUtility.h" 20| | 21| |@implementation FBSDKTypeUtility 22| | 23| |#pragma mark - Class Methods 24| | 25| |+ (NSArray *)arrayValue:(id)object 26| 0|{ 27| 0| return (NSArray *)[self _objectValue:object ofClass:[NSArray class]]; 28| 0|} 29| | 30| |+ (nullable id)array:(NSArray *)array objectAtIndex:(NSUInteger)index 31| 0|{ 32| 0| if ([self arrayValue:array] && index < array.count) { 33| 0| return [array objectAtIndex:index]; 34| 0| } 35| | 36| 0| return nil; 37| 0|} 38| | 39| |+ (void)array:(NSMutableArray *)array addObject:(id)object 40| 0|{ 41| 0| if (object && [array isKindOfClass:NSMutableArray.class]) { 42| 0| [array addObject:object]; 43| 0| } 44| 0|} 45| | 46| |+ (void)array:(NSMutableArray *)array addObject:(nullable id)object atIndex:(NSUInteger)index 47| 0|{ 48| 0| if (object && [array isKindOfClass:NSMutableArray.class]) { 49| 0| if (index < array.count) { 50| 0| [array insertObject:object atIndex:index]; 51| 0| } else if (index == array.count) { 52| 0| [array addObject:object]; 53| 0| } 54| 0| } 55| 0|} 56| | 57| |+ (BOOL)boolValue:(id)object 58| 0|{ 59| 0| if ([object isKindOfClass:[NSNumber class]]) { 60| | // @0 or @NO returns NO, otherwise YES 61| 0| return ((NSNumber *)object).boolValue; 62| 0| } else if ([object isKindOfClass:[NSString class]]) { 63| | // Returns YES on encountering one of "Y", "y", "T", "t", or a digit 1-9, otherwise NO 64| 0| return ((NSString *)object).boolValue; 65| 0| } else { 66| 0| return ([self objectValue:object] != nil); 67| 0| } 68| 0|} 69| | 70| |+ (NSDictionary *)dictionaryValue:(id)object 71| 0|{ 72| 0| return (NSDictionary *)[self _objectValue:object ofClass:[NSDictionary class]]; 73| 0|} 74| | 75| |+ (id)dictionary:(NSDictionary *)dictionary objectForKey:(NSString *)key ofType:(Class)type 76| 0|{ 77| 0| id potentialValue = [[self dictionaryValue:dictionary] objectForKey:key]; 78| | 79| 0| if ([potentialValue isKindOfClass:type]) { 80| 0| return potentialValue; 81| 0| } else { 82| 0| return nil; 83| 0| } 84| 0|} 85| | 86| |+ (void)dictionary:(NSMutableDictionary *)dictionary setObject:(id)object forKey:(id)key 87| 0|{ 88| 0| if (object && key) { 89| 0| dictionary[key] = object; 90| 0| } 91| 0|} 92| | 93| |+ (void)dictionary:(NSDictionary *)dictionary enumerateKeysAndObjectsUsingBlock:(void(NS_NOESCAPE ^)(id key, id obj, BOOL *stop))block 94| 0|{ 95| 0| NSDictionary *validDictionary = [self dictionaryValue:dictionary]; 96| 0| if (validDictionary) { 97| 0| [validDictionary enumerateKeysAndObjectsUsingBlock:block]; 98| 0| } 99| 0|} 100| | 101| |+ (NSNumber *)numberValue:(id)object 102| 0|{ 103| 0| return [self _objectValue:object ofClass:NSNumber.class]; 104| 0|} 105| | 106| |+ (NSInteger)integerValue:(id)object 107| 0|{ 108| 0| if ([object isKindOfClass:[NSNumber class]]) { 109| 0| return ((NSNumber *)object).integerValue; 110| 0| } else if ([object isKindOfClass:[NSString class]]) { 111| 0| return ((NSString *)object).integerValue; 112| 0| } else { 113| 0| return 0; 114| 0| } 115| 0|} 116| | 117| |+ (NSString *)stringValueOrNil:(id)object 118| 0|{ 119| 0| return [self _objectValue:object ofClass:NSString.class]; 120| 0|} 121| | 122| |+ (id)objectValue:(id)object 123| 0|{ 124| 0| return ([object isKindOfClass:[NSNull class]] ? nil : object); 125| 0|} 126| | 127| |+ (NSString *)coercedToStringValue:(id)object 128| 0|{ 129| 0| if ([object isKindOfClass:[NSString class]]) { 130| 0| return (NSString *)object; 131| 0| } else if ([object isKindOfClass:[NSNumber class]]) { 132| 0| return ((NSNumber *)object).stringValue; 133| 0| } else if ([object isKindOfClass:[NSURL class]]) { 134| 0| return ((NSURL *)object).absoluteString; 135| 0| } else { 136| 0| return nil; 137| 0| } 138| 0|} 139| | 140| |+ (NSTimeInterval)timeIntervalValue:(id)object 141| 0|{ 142| 0| if ([object isKindOfClass:[NSNumber class]]) { 143| 0| return ((NSNumber *)object).doubleValue; 144| 0| } else if ([object isKindOfClass:[NSString class]]) { 145| 0| return ((NSString *)object).doubleValue; 146| 0| } else { 147| 0| return 0; 148| 0| } 149| 0|} 150| | 151| |+ (NSUInteger)unsignedIntegerValue:(id)object 152| 0|{ 153| 0| if ([object isKindOfClass:[NSNumber class]]) { 154| 0| return ((NSNumber *)object).unsignedIntegerValue; 155| 0| } else { 156| | // there is no direct support for strings containing unsigned values > NSIntegerMax - not worth writing ourselves 157| | // right now, so just cap unsigned values at NSIntegerMax until we have a need for larger 158| 0| NSInteger integerValue = [self integerValue:object]; 159| 0| if (integerValue < 0) { 160| 0| integerValue = 0; 161| 0| } 162| 0| return (NSUInteger)integerValue; 163| 0| } 164| 0|} 165| | 166| |+ (NSURL *)URLValue:(id)object 167| 0|{ 168| 0| if ([object isKindOfClass:[NSURL class]]) { 169| 0| return (NSURL *)object; 170| 0| } else if ([object isKindOfClass:[NSString class]]) { 171| 0| return [NSURL URLWithString:(NSString *)object]; 172| 0| } else { 173| 0| return nil; 174| 0| } 175| 0|} 176| | 177| |+ (BOOL)isValidJSONObject:(id)obj 178| 0|{ 179| 0| return [NSJSONSerialization isValidJSONObject:obj]; 180| 0|} 181| | 182| |+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError *__autoreleasing _Nullable *)error 183| 0|{ 184| 0| NSData *data; 185| | 186| 0| @try { 187| 0| data = [NSJSONSerialization dataWithJSONObject:obj options:opt error:error]; 188| 0| } @catch (NSException *exception) { 189| 0| NSLog(@"FBSDKJSONSerialization - dataWithJSONObject:options:error failed: %@", exception.reason); 190| 0| } 191| 0| return data; 192| 0|} 193| | 194| |+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError *__autoreleasing _Nullable *)error 195| 0|{ 196| 0| if (![data isKindOfClass:NSData.class]) { 197| 0| return nil; 198| 0| } 199| | 200| 0| id object; 201| 0| @try { 202| 0| object = [NSJSONSerialization JSONObjectWithData:data options:opt error:error]; 203| 0| } @catch (NSException *exception) { 204| 0| NSLog(@"FBSDKJSONSerialization - JSONObjectWithData:options:error failed: %@", exception.reason); 205| 0| } 206| 0| return object; 207| 0|} 208| | 209| |#pragma mark - Helper Methods 210| | 211| |+ (id)_objectValue:(id)object ofClass:(Class)expectedClass 212| 0|{ 213| 0| return ([object isKindOfClass:expectedClass] ? object : nil); 214| 0|} 215| | 216| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKURLSession.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKURLSession.h" 20| | 21| |#import 22| | 23| |#import "FBSDKBasicUtility.h" 24| |#import "FBSDKURLSessionTask.h" 25| | 26| |// At some point this default conformance declaration needs to be moved out of 27| |// this class and treated like the dependency it is. 28| |@interface NSURLSession (SessionProviding) 29| |@end 30| | 31| |@implementation FBSDKURLSession 32| | 33| |- (instancetype)initWithDelegate:(id)delegate 34| | delegateQueue:(NSOperationQueue *)queue 35| 0|{ 36| 0| if ((self = [super init])) { 37| 0| self.delegate = delegate; 38| 0| self.delegateQueue = queue; 39| 0| } 40| 0| return self; 41| 0|} 42| | 43| |- (void)executeURLRequest:(NSURLRequest *)request 44| | completionHandler:(FBSDKURLSessionTaskBlock)handler 45| 0|{ 46| 0| if (!self.valid) { 47| 0| [self updateSessionWithBlock:^{ 48| 0| FBSDKURLSessionTask *task = [[FBSDKURLSessionTask alloc] initWithRequest:request fromSession:self.session completionHandler:handler]; 49| 0| [task start]; 50| 0| }]; 51| 0| } else { 52| 0| FBSDKURLSessionTask *task = [[FBSDKURLSessionTask alloc] initWithRequest:request fromSession:self.session completionHandler:handler]; 53| 0| [task start]; 54| 0| } 55| 0|} 56| | 57| |- (void)updateSessionWithBlock:(dispatch_block_t)block 58| 0|{ 59| 0| if (!self.valid) { 60| 0| self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] 61| 0| delegate:_delegate 62| 0| delegateQueue:_delegateQueue]; 63| 0| } 64| 0| block(); 65| 0|} 66| | 67| |- (void)invalidateAndCancel 68| 0|{ 69| 0| [self.session invalidateAndCancel]; 70| 0| self.session = nil; 71| 0|} 72| | 73| |- (BOOL)valid 74| 0|{ 75| 0| return self.session != nil; 76| 0|} 77| | 78| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKURLSessionTask.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKURLSessionTask.h" 20| | 21| |#import "FBSDKSessionProviding.h" 22| | 23| |@implementation FBSDKURLSessionTask 24| | 25| |- (instancetype)init 26| 0|{ 27| 0| if ((self = [super init])) { 28| 0| _requestStartDate = [NSDate date]; 29| 0| } 30| 0| return self; 31| 0|} 32| | 33| |- (instancetype)initWithRequest:(NSURLRequest *)request 34| | fromSession:(id)session 35| | completionHandler:(FBSDKURLSessionTaskBlock)handler 36| 0|{ 37| 0| if ((self = [self init])) { 38| 0| self.requestStartTime = (uint64_t)([self.requestStartDate timeIntervalSince1970] * 1000); 39| 0| self.task = [session dataTaskWithRequest:request completionHandler:handler]; 40| 0| } 41| 0| return self; 42| 0|} 43| | 44| |- (NSURLSessionTaskState)state 45| 0|{ 46| 0| return self.task.state; 47| 0|} 48| | 49| |#pragma mark - Task State 50| | 51| |- (void)start 52| 0|{ 53| 0| [self.task resume]; 54| 0|} 55| | 56| |- (void)cancel 57| 0|{ 58| 0| [self.task cancel]; 59| 0| self.handler = nil; 60| 0|} 61| | 62| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKUserDataStore.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKUserDataStore.h" 20| | 21| |#import "FBSDKBasicUtility.h" 22| |#import "FBSDKTypeUtility.h" 23| | 24| |static NSString *const FBSDKUserDataKey = @"com.facebook.appevents.UserDataStore.userData"; 25| |static NSString *const FBSDKInternalUserDataKey = @"com.facebook.appevents.UserDataStore.internalUserData"; 26| | 27| |static NSMutableDictionary *hashedUserData; 28| |static NSMutableDictionary *internalHashedUserData; 29| |static NSMutableSet *enabledRules; 30| | 31| |static dispatch_queue_t serialQueue; 32| | 33| |// 34| |// Public event user data types 35| |// 36| | 37| |FBSDKAppEventUserDataType FBSDKAppEventEmail = @"em"; 38| |FBSDKAppEventUserDataType FBSDKAppEventFirstName = @"fn"; 39| |FBSDKAppEventUserDataType FBSDKAppEventLastName = @"ln"; 40| |FBSDKAppEventUserDataType FBSDKAppEventPhone = @"ph"; 41| |FBSDKAppEventUserDataType FBSDKAppEventDateOfBirth = @"dob"; 42| |FBSDKAppEventUserDataType FBSDKAppEventGender = @"ge"; 43| |FBSDKAppEventUserDataType FBSDKAppEventCity = @"ct"; 44| |FBSDKAppEventUserDataType FBSDKAppEventState = @"st"; 45| |FBSDKAppEventUserDataType FBSDKAppEventZip = @"zp"; 46| |FBSDKAppEventUserDataType FBSDKAppEventCountry = @"country"; 47| |FBSDKAppEventUserDataType FBSDKAppEventExternalId = @"external_id"; 48| | 49| |@implementation FBSDKUserDataStore 50| | 51| |+ (void)initialize 52| 0|{ 53| 0| serialQueue = dispatch_queue_create("com.facebook.appevents.UserDataStore", DISPATCH_QUEUE_SERIAL); 54| 0| hashedUserData = [FBSDKUserDataStore initializeUserData:FBSDKUserDataKey]; 55| 0| internalHashedUserData = [FBSDKUserDataStore initializeUserData:FBSDKInternalUserDataKey]; 56| 0| enabledRules = [NSMutableSet new]; 57| 0|} 58| | 59| |+ (void)setUserEmail:(nullable NSString *)email 60| | firstName:(nullable NSString *)firstName 61| | lastName:(nullable NSString *)lastName 62| | phone:(nullable NSString *)phone 63| | dateOfBirth:(nullable NSString *)dateOfBirth 64| | gender:(nullable NSString *)gender 65| | city:(nullable NSString *)city 66| | state:(nullable NSString *)state 67| | zip:(nullable NSString *)zip 68| | country:(nullable NSString *)country 69| | externalId:(nullable NSString *)externalId 70| 0|{ 71| 0| NSMutableDictionary *ud = [NSMutableDictionary new]; 72| 0| if (email) { 73| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:email type:FBSDKAppEventEmail] forKey:FBSDKAppEventEmail]; 74| 0| } 75| 0| if (firstName) { 76| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:firstName type:FBSDKAppEventFirstName] forKey:FBSDKAppEventFirstName]; 77| 0| } 78| 0| if (lastName) { 79| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:lastName type:FBSDKAppEventLastName] forKey:FBSDKAppEventLastName]; 80| 0| } 81| 0| if (phone) { 82| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:phone type:FBSDKAppEventPhone] forKey:FBSDKAppEventPhone]; 83| 0| } 84| 0| if (dateOfBirth) { 85| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:dateOfBirth type:FBSDKAppEventDateOfBirth] forKey:FBSDKAppEventDateOfBirth]; 86| 0| } 87| 0| if (gender) { 88| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:gender type:FBSDKAppEventGender] forKey:FBSDKAppEventGender]; 89| 0| } 90| 0| if (city) { 91| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:city type:FBSDKAppEventCity] forKey:FBSDKAppEventCity]; 92| 0| } 93| 0| if (state) { 94| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:state type:FBSDKAppEventState] forKey:FBSDKAppEventState]; 95| 0| } 96| 0| if (zip) { 97| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:zip type:FBSDKAppEventZip] forKey:FBSDKAppEventZip]; 98| 0| } 99| 0| if (country) { 100| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:country type:FBSDKAppEventCountry] forKey:FBSDKAppEventCountry]; 101| 0| } 102| 0| if (externalId) { 103| 0| [FBSDKTypeUtility dictionary:ud setObject:[FBSDKUserDataStore encryptData:externalId type:FBSDKAppEventExternalId] forKey:FBSDKAppEventExternalId]; 104| 0| } 105| | 106| 0| dispatch_async(serialQueue, ^{ 107| 0| hashedUserData = [ud mutableCopy]; 108| 0| [[NSUserDefaults standardUserDefaults] setObject:[FBSDKUserDataStore stringByHashedData:hashedUserData] 109| 0| forKey:FBSDKUserDataKey]; 110| 0| }); 111| 0|} 112| | 113| |+ (void)setUserData:(nullable NSString *)data 114| | forType:(FBSDKAppEventUserDataType)type 115| 0|{ 116| 0| [FBSDKUserDataStore setHashData:[FBSDKUserDataStore encryptData:data type:type] 117| 0| forType:type]; 118| 0|} 119| | 120| |+ (void)setHashData:(nullable NSString *)hashData 121| | forType:(FBSDKAppEventUserDataType)type 122| 0|{ 123| 0| dispatch_async(serialQueue, ^{ 124| 0| if (!hashData) { 125| 0| [hashedUserData removeObjectForKey:type]; 126| 0| } else { 127| 0| [FBSDKTypeUtility dictionary:hashedUserData setObject:hashData forKey:type]; 128| 0| } 129| 0| [[NSUserDefaults standardUserDefaults] setObject:[FBSDKUserDataStore stringByHashedData:hashedUserData] 130| 0| forKey:FBSDKUserDataKey]; 131| 0| }); 132| 0|} 133| | 134| |+ (void)setInternalHashData:(nullable NSString *)hashData 135| | forType:(FBSDKAppEventUserDataType)type 136| 0|{ 137| 0| dispatch_async(serialQueue, ^{ 138| 0| if (!hashData) { 139| 0| [internalHashedUserData removeObjectForKey:type]; 140| 0| } else { 141| 0| internalHashedUserData[type] = hashData; 142| 0| } 143| 0| [[NSUserDefaults standardUserDefaults] setObject:[FBSDKUserDataStore stringByHashedData:internalHashedUserData] 144| 0| forKey:FBSDKInternalUserDataKey]; 145| 0| }); 146| 0|} 147| | 148| |+ (void)setEnabledRules:(NSArray *)rules 149| 0|{ 150| 0| if (rules.count > 0) { 151| 0| [enabledRules addObjectsFromArray:rules]; 152| 0| } 153| 0|} 154| | 155| |+ (void)clearUserDataForType:(FBSDKAppEventUserDataType)type 156| 0|{ 157| 0| [FBSDKUserDataStore setUserData:nil forType:type]; 158| 0|} 159| | 160| |+ (NSString *)getUserData 161| 0|{ 162| 0| return [FBSDKUserDataStore getHashedData]; 163| 0|} 164| | 165| |+ (NSString *)getHashedData 166| 0|{ 167| 0| __block NSString *hashedUserDataString; 168| 0| dispatch_sync(serialQueue, ^{ 169| 0| NSMutableDictionary *hashedUD = [NSMutableDictionary new]; 170| 0| [hashedUD addEntriesFromDictionary:hashedUserData]; 171| 0| for (NSString *key in enabledRules) { 172| 0| if (internalHashedUserData[key]) { 173| 0| hashedUD[key] = internalHashedUserData[key]; 174| 0| } 175| 0| } 176| 0| hashedUserDataString = [FBSDKUserDataStore stringByHashedData:hashedUD]; 177| 0| }); 178| 0| return hashedUserDataString; 179| 0|} 180| | 181| |+ (void)clearUserData 182| 0|{ 183| 0| [FBSDKUserDataStore setUserEmail:nil 184| 0| firstName:nil 185| 0| lastName:nil 186| 0| phone:nil 187| 0| dateOfBirth:nil 188| 0| gender:nil 189| 0| city:nil 190| 0| state:nil 191| 0| zip:nil 192| 0| country:nil 193| 0| externalId:nil]; 194| 0|} 195| | 196| |+ (NSString *)getInternalHashedDataForType:(FBSDKAppEventUserDataType)type 197| 0|{ 198| 0| __block NSString *hashedData; 199| 0| dispatch_sync(serialQueue, ^{ 200| 0| hashedData = [FBSDKTypeUtility dictionary:internalHashedUserData objectForKey:type ofType:NSObject.class]; 201| 0| }); 202| 0| return hashedData; 203| 0|} 204| | 205| |#pragma mark - Helper Methods 206| | 207| |+ (NSMutableDictionary *)initializeUserData:(NSString *)userDataKey 208| 0|{ 209| 0| NSString *userData = [[NSUserDefaults standardUserDefaults] stringForKey:userDataKey]; 210| 0| NSMutableDictionary *hashedUD = nil; 211| 0| if (userData) { 212| 0| hashedUD = (NSMutableDictionary *)[FBSDKTypeUtility JSONObjectWithData:[userData dataUsingEncoding:NSUTF8StringEncoding] 213| 0| options: NSJSONReadingMutableContainers 214| 0| error: nil]; 215| 0| } 216| 0| if (!hashedUD) { 217| 0| hashedUD = [NSMutableDictionary new]; 218| 0| } 219| 0| return hashedUD; 220| 0|} 221| | 222| |+ (NSString *)stringByHashedData:(id)hashedData 223| 0|{ 224| 0| NSError *error; 225| 0| NSData *jsonData = [FBSDKTypeUtility dataWithJSONObject:hashedData 226| 0| options:0 227| 0| error:&error]; 228| 0| if (jsonData) { 229| 0| return [[NSString alloc] initWithData:jsonData 230| 0| encoding:NSUTF8StringEncoding]; 231| 0| } else { 232| 0| return @""; 233| 0| } 234| 0|} 235| | 236| |+ (NSString *)encryptData:(NSString *)data 237| | type:(FBSDKAppEventUserDataType)type 238| 0|{ 239| 0| if (data.length == 0 || [FBSDKUserDataStore maybeSHA256Hashed:data]) { 240| 0| return data; 241| 0| } 242| 0| return [FBSDKBasicUtility SHA256Hash:[FBSDKUserDataStore normalizeData:data type:type]]; 243| 0|} 244| | 245| |+ (NSString *)normalizeData:(NSString *)data 246| | type:(FBSDKAppEventUserDataType)type 247| 0|{ 248| 0| NSString *normalizedData = @""; 249| 0| NSSet *set = [NSSet setWithArray: 250| 0| @[FBSDKAppEventEmail, FBSDKAppEventFirstName, FBSDKAppEventLastName, FBSDKAppEventCity, FBSDKAppEventState, FBSDKAppEventCountry]]; 251| 0| if ([set containsObject:type]) { 252| 0| normalizedData = [data stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 253| 0| normalizedData = normalizedData.lowercaseString; 254| 0| } else if ([type isEqualToString:FBSDKAppEventPhone]) { 255| 0| NSError *error = nil; 256| 0| NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^0-9]" 257| 0| options:NSRegularExpressionCaseInsensitive 258| 0| error:&error 259| 0| ]; 260| 0| normalizedData = [regex stringByReplacingMatchesInString:data 261| 0| options:0 262| 0| range:NSMakeRange(0, data.length) 263| 0| withTemplate:@"" 264| 0| ]; 265| 0| } else if ([type isEqualToString:FBSDKAppEventGender]) { 266| 0| NSString *temp = [data stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 267| 0| temp = temp.lowercaseString; 268| 0| normalizedData = temp.length > 0 ? [temp substringToIndex:1] : @""; 269| 0| } else if ([type isEqualToString:FBSDKAppEventExternalId]) { 270| 0| normalizedData = data; 271| 0| } 272| 0| return normalizedData; 273| 0|} 274| | 275| |+ (BOOL)maybeSHA256Hashed:(NSString *)data 276| 0|{ 277| 0| NSRange range = [data rangeOfString:@"[A-Fa-f0-9]{64}" options:NSRegularExpressionSearch]; 278| 0| return (data.length == 64) && (range.location != NSNotFound); 279| 0|} 280| | 281| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/include/FBSDKSafeCast.h: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import 20| | 21| |#ifndef FBSDK_CAST_TO_CLASS_OR_NIL_FUNC 22| | #define FBSDK_CAST_TO_CLASS_OR_NIL_FUNC 23| | #ifdef __cplusplus 24| |extern "C" { 25| | #endif 26| |/** Use the type-safe FBSDK_CAST_TO_CLASS_OR_NIL instead. */ 27| |id _FBSDKCastToClassOrNilUnsafeInternal(id object, Class klass); 28| | #ifdef __cplusplus 29| |} 30| | #endif 31| |#endif 32| | 33| |#ifndef FBSDK_CAST_TO_CLASS_OR_NIL 34| 0| #define FBSDK_CAST_TO_CLASS_OR_NIL(obj_, class_) ((class_ *)_FBSDKCastToClassOrNilUnsafeInternal(obj_, [class_ class])) 35| |#endif 36| | 37| |#ifndef FBSDK_CAST_TO_PROTOCOL_OR_NIL_FUNC 38| | #define FBSDK_CAST_TO_PROTOCOL_OR_NIL_FUNC 39| | #ifdef __cplusplus 40| |extern "C" { 41| | #endif 42| |/** Use the type-safe FBSDK_CAST_TO_PROTOCOL_OR_NIL instead. */ 43| |id _FBSDKCastToProtocolOrNilUnsafeInternal(id object, Protocol *protocol); 44| | #ifdef __cplusplus 45| |} 46| | #endif 47| |#endif 48| | 49| |#ifndef FBSDK_CAST_TO_PROTOCOL_OR_NIL 50| | #define FBSDK_CAST_TO_PROTOCOL_OR_NIL(obj_, protocol_) ((id)_FBSDKCastToProtocolOrNilUnsafeInternal(obj_, @protocol(protocol_))) 51| |#endif <<<<<< EOF # path=Bolts#Common#BFCancellationTokenSource.h.gcov.reduced -: 0:Source:Bolts/Common/BFCancellationTokenSource.h <<<<<< EOF # path=Parse#Internal#Commands#PFRESTObjectCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTObjectCommand.m <<<<<< EOF # path=Parse#Internal#Purchase#Controller#PFPurchaseController.m.gcov.reduced -: 0:Source:Parse/Internal/Purchase/Controller/PFPurchaseController.m <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKDynamicFrameworkLoader.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKDynamicFrameworkLoader.m <<<<<< EOF # path=FBSDKCoreKit#Internal#ServerConfiguration#FBSDKDialogConfiguration.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/ServerConfiguration/FBSDKDialogConfiguration.m <<<<<< EOF # path=Parse#Internal#LocalDataStore#SQLite#PFSQLiteDatabaseController.h.gcov.reduced -: 0:Source:Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.h <<<<<< EOF # path=Parse#PFPolygon.h.gcov.reduced -: 0:Source:Parse/PFPolygon.h <<<<<< EOF # path=Parse#Internal#Commands#PFRESTObjectBatchCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTObjectBatchCommand.m <<<<<< EOF # path=Parse#Internal#Commands#PFRESTCloudCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTCloudCommand.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#dispatch#queue.h.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/dispatch/queue.h #####:584: #####:585: #####:586: <<<<<< EOF # path=Parse#Internal#Commands#PFRESTCommand.h.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTCommand.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#SKAdNetwork#FBSDKSKAdNetworkReporter.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/SKAdNetwork/FBSDKSKAdNetworkReporter.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#__bits.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/__bits #####:41: <<<<<< EOF # path=FBSDKCoreKit#FBSDKURL.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKURL.m <<<<<< EOF # path=Parse#Internal#Commands#PFRESTUserCommand.h.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTUserCommand.h <<<<<< EOF # path=Parse#Internal#Relation#State#PFMutableRelationState.m.gcov.reduced -: 0:Source:Parse/Internal/Relation/State/PFMutableRelationState.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#new.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/new #####:233: #####:235: #####:243: #####:245: #####:249: #####:252: #####:261: #####:266: #####:269: #####:276: #####:279: <<<<<< EOF # path=FBSDKCoreKit#FBSDKProfile.h.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKProfile.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#PFCoreManager.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/PFCoreManager.m #####:98: <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#ML#FBSDKModelParser.mm.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/ML/FBSDKModelParser.mm <<<<<< EOF # path=FBSDKCoreKit#Internal#Cryptography#FBSDKCrypto.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Cryptography/FBSDKCrypto.m <<<<<< EOF # path=Parse#Internal#HTTPRequest#PFURLConstructor.m.gcov.reduced -: 0:Source:Parse/Internal/HTTPRequest/PFURLConstructor.m <<<<<< EOF # path=Parse#Internal#Push#ChannelsController#PFPushChannelsController.h.gcov.reduced -: 0:Source:Parse/Internal/Push/ChannelsController/PFPushChannelsController.h <<<<<< EOF # path=Parse#Internal#ACL#State#PFACLState.m.gcov.reduced -: 0:Source:Parse/Internal/ACL/State/PFACLState.m <<<<<< EOF # path=Parse#Internal#PFCommandResult.m.gcov.reduced -: 0:Source:Parse/Internal/PFCommandResult.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#__memory#base.h.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/__memory/base.h #####:33: #####:34: #####:35: <<<<<< EOF # path=Parse#Internal#Persistence#PFPersistenceController.h.gcov.reduced -: 0:Source:Parse/Internal/Persistence/PFPersistenceController.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#KeyValueCache#PFKeyValueCache.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/KeyValueCache/PFKeyValueCache.m #####:151: <<<<<< EOF # path=OCMock#OCMRealObjectForwarder.m.gcov.reduced -: 0:Source:OCMock/OCMRealObjectForwarder.m <<<<<< EOF # path=Parse#Internal#ACL#State#PFMutableACLState.m.gcov.reduced -: 0:Source:Parse/Internal/ACL/State/PFMutableACLState.m <<<<<< EOF # path=Parse#Internal#Object#PinningStore#PFPinningObjectStore.h.gcov.reduced -: 0:Source:Parse/Internal/Object/PinningStore/PFPinningObjectStore.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKPaymentObserver.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKPaymentObserver.m <<<<<< EOF # path=Parse#Internal#Config#Controller#PFCurrentConfigController.m.gcov.reduced -: 0:Source:Parse/Internal/Config/Controller/PFCurrentConfigController.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKAppEventsAtePublisher.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsAtePublisher.h <<<<<< EOF # path=Parse#Internal#Query#State#PFQueryState.m.gcov.reduced -: 0:Source:Parse/Internal/Query/State/PFQueryState.m <<<<<< EOF # path=Parse#Internal#ParseManager.m.gcov.reduced -: 0:Source:Parse/Internal/ParseManager.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#Sources#FBSDKCoreKit_Basics#FBSDKBasicUtility.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKBasicUtility.m #####:31: #####:32: #####:33: #####:34: #####:35: #####:36: #####:37: #####:39: #####:40: #####:42: #####:43: #####:44: #####:45: #####:46: #####:47: 1:57: 1:61: #####:62: #####:63: #####:64: #####:65: #####:66: #####:67: #####:68: #####:70: #####:71: #####:72: #####:74: 1:75: 1:76: #####:77: 1:79: 1:80: #####:82: #####:87: #####:88: #####:90: #####:91: #####:92: #####:94: #####:95: #####:96: #####:98: #####:102: #####:103: #####:105: #####:106: #####:107: #####:108: #####:109: #####:110: #####:111: #####:112: #####:113: #####:114: #####:115: #####:116: #####:117: #####:118: #####:119: #####:120: #####:121: #####:122: #####:123: #####:124: #####:126: #####:127: #####:128: #####:129: #####:131: #####:132: #####:133: #####:134: #####:135: 1:137: 1:139: 1:140: 1:141: #####:142: #####:143: 1:144: #####:146: 1:147: 1:149: 1:153: 1:154: 1:155: 1:156: 6:158: 5:159: 5:160: 1:162: 1:163: 5:164: 5:165: 5:166: 5:167: 5:168: 5:169: #####:170: #####:171: #####:172: #####:174: 5:175: 5:176: 4:177: 4:178: 5:179: 5:180: 5:181: 5:182: 1:183: 1:184: #####:185: #####:186: 1:187: 1:188: 10:190: 10:192: #####:193: 10:194: #####:195: #####:196: 10:197: 10:198: 5:202: 5:204: 5:206: 5:211: 1:215: 1:217: 1:218: 1:220: #####:221: #####:222: #####:225: #####:226: #####:227: #####:229: #####:230: #####:231: #####:232: #####:233: #####:234: #####:237: #####:238: #####:239: #####:240: #####:241: 1:242: 1:243: 1:244: #####:246: #####:248: #####:251: #####:253: #####:254: #####:256: #####:258: #####:259: #####:261: #####:262: #####:266: #####:267: #####:273: #####:275: #####:276: #####:278: #####:279: #####:282: #####:284: #####:285: #####:286: #####:287: #####:288: #####:289: #####:290: #####:292: #####:293: #####:294: #####:295: #####:296: #####:298: #####:300: #####:301: 1:303: 1:307: 1:308: 1:312: 1:314: 1:315: 1:316: 1:317: 1:319: 1:321: 1:322: 1:325: 1:326: 1:327: 5:329: 5:331: 5:332: 5:333: 5:334: 5:335: 1:337: 1:339: 1:340: 1:342: 1:346: #####:348: #####:350: #####:352: #####:353: #####:354: #####:355: #####:356: #####:358: #####:359: #####:363: #####:364: #####:365: #####:366: #####:367: #####:369: #####:370: <<<<<< EOF # path=Parse#Internal#Commands#CommandRunner#URLSession#Session#TaskDelegate#PFURLSessionJSONDataTaskDelegate.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.m <<<<<< EOF # path=Parse#Internal#Query#State#PFMutableQueryState.m.gcov.reduced -: 0:Source:Parse/Internal/Query/State/PFMutableQueryState.m <<<<<< EOF # path=OCMock#NSMethodSignature+OCMAdditions.m.gcov.reduced -: 0:Source:OCMock/NSMethodSignature+OCMAdditions.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKUtility.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKUtility.m <<<<<< EOF # path=Parse#Internal#User#CurrentUserController#PFCurrentUserController.h.gcov.reduced -: 0:Source:Parse/Internal/User/CurrentUserController/PFCurrentUserController.h <<<<<< EOF # path=FBSDKCoreKit#GraphAPI#FBSDKGraphRequestConnection.m.gcov.reduced -: 0:Source:FBSDKCoreKit/GraphAPI/FBSDKGraphRequestConnection.m <<<<<< EOF # path=Parse#Internal#Session#Controller#PFSessionController.m.gcov.reduced -: 0:Source:Parse/Internal/Session/Controller/PFSessionController.m <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKAuthenticationTokenFactory.m.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKAuthenticationTokenFactory.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#__memory#pointer_traits.h.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/__memory/pointer_traits.h #####:151: #####:153: <<<<<< EOF # path=FBSDKCoreKit#Internal#UI#FBSDKUIUtility.h.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/UI/FBSDKUIUtility.h <<<<<< EOF # path=Parse#Internal#LocalDataStore#OfflineStore#PFOfflineStore.h.gcov.reduced -: 0:Source:Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKAppEventsNumberParser.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsNumberParser.m <<<<<< EOF # path=Parse#Internal#BFTask+Private.m.gcov.reduced -: 0:Source:Parse/Internal/BFTask+Private.m <<<<<< EOF # path=Parse#Internal#ACL#DefaultACLController#PFDefaultACLController.m.gcov.reduced -: 0:Source:Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.m <<<<<< EOF # path=FBSDKLoginKit#FBSDKLoginConfiguration.h.gcov.reduced -: 0:Source:FBSDKLoginKit/FBSDKLoginConfiguration.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMEvent.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMEvent.h <<<<<< EOF # path=OCMock#OCMLocation.m.gcov.reduced -: 0:Source:OCMock/OCMLocation.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKSettings.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKSettings.m <<<<<< EOF # path=Parse#Internal#PFSystemLogger.m.gcov.reduced -: 0:Source:Parse/Internal/PFSystemLogger.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKAccessToken.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKAccessToken.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMConfiguration.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMConfiguration.h <<<<<< EOF # path=Parse#Internal#Persistence#Group#PFFilePersistenceGroup.h.gcov.reduced -: 0:Source:Parse/Internal/Persistence/Group/PFFilePersistenceGroup.h <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#algorithm.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/algorithm #####:725: #####:1646: #####:1647: #####:1648: #####:1731: #####:1732: #####:1733: #####:1734: #####:1735: #####:1736: #####:1742: #####:1743: #####:1748: #####:1749: #####:2585: #####:2586: #####:2587: #####:2594: #####:2595: #####:2596: #####:2658: #####:2659: #####:2660: #####:2667: #####:2668: #####:2669: <<<<<< EOF # path=FBSDKCoreKit#Internal#TokenCaching#FBSDKTokenCache.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/TokenCaching/FBSDKTokenCache.m <<<<<< EOF # path=ParseFacebookUtils#Internal#AuthenticationProvider#iOS#PFFacebookMobileAuthenticationProvider.h.gcov.reduced -: 0:Source:ParseFacebookUtils/Internal/AuthenticationProvider/iOS/PFFacebookMobileAuthenticationProvider.h <<<<<< EOF # path=FBSDKLoginKit#FBSDKLoginManager.h.gcov.reduced -: 0:Source:FBSDKLoginKit/FBSDKLoginManager.h <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#iterator.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/iterator #####:655: #####:657: #####:658: #####:659: #####:663: #####:664: #####:668: #####:669: #####:670: #####:686: #####:687: #####:688: #####:694: #####:695: #####:696: #####:1474: #####:1475: #####:1480: #####:1490: #####:1491: #####:1496: #####:1497: #####:1537: #####:1546: #####:1631: #####:1632: #####:1633: #####:1683: #####:1684: #####:1685: <<<<<< EOF # path=Parse#Internal#PFLocationManager.m.gcov.reduced -: 0:Source:Parse/Internal/PFLocationManager.m <<<<<< EOF # path=Parse#Internal#Commands#PFRESTQueryCommand.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/PFRESTQueryCommand.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#ML#FBSDKTensor.hpp.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/ML/FBSDKTensor.hpp <<<<<< EOF # path=FBSDKCoreKit#Internal#Network#FBSDKURLSessionProxyFactory.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Network/FBSDKURLSessionProxyFactory.m <<<<<< EOF # path=FBSDKCoreKit#Internal#UI#FBSDKLogo.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/UI/FBSDKLogo.m <<<<<< EOF # path=OCMock#OCMArgAction.m.gcov.reduced -: 0:Source:OCMock/OCMArgAction.m <<<<<< EOF # path=FBSDKCoreKit#Internal#WebDialog#FBSDKWebDialogView.h.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.h <<<<<< EOF # path=OCMock#OCPartialMockObject.m.gcov.reduced -: 0:Source:OCMock/OCPartialMockObject.m <<<<<< EOF # path=Parse#Internal#PFPinningEventuallyQueue.m.gcov.reduced -: 0:Source:Parse/Internal/PFPinningEventuallyQueue.m <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKUnarchiverProvider.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKUnarchiverProvider.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#PFRelation.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/PFRelation.m #####:109: <<<<<< EOF # path=Parse#Internal#Purchase#PaymentTransactionObserver#PFPaymentTransactionObserver.m.gcov.reduced -: 0:Source:Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.m <<<<<< EOF # path=Parse#Internal#KeyValueCache#PFKeyValueCache.m.gcov.reduced -: 0:Source:Parse/Internal/KeyValueCache/PFKeyValueCache.m <<<<<< EOF # path=FBSDKCoreKit#Internal#TokenCaching#FBSDKKeychainStore.h.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.h <<<<<< EOF # path=FBSDKCoreKit#AppLink#FBSDKAppLinkTarget.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppLink/FBSDKAppLinkTarget.h <<<<<< EOF # path=OCMock#OCMInvocationStub.m.gcov.reduced -: 0:Source:OCMock/OCMInvocationStub.m <<<<<< EOF # path=Parse#Internal#File#Controller#PFFileStagingController.m.gcov.reduced -: 0:Source:Parse/Internal/File/Controller/PFFileStagingController.m <<<<<< EOF # path=FBSDKCoreKit#Internal#ServerConfiguration#FBSDKServerConfiguration.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.m <<<<<< EOF # path=Parse#Internal#Relation#State#PFRelationState.h.gcov.reduced -: 0:Source:Parse/Internal/Relation/State/PFRelationState.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#PFObject.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/PFObject.m #####:234: <<<<<< EOF # path=Parse#Internal#HTTPRequest#PFHTTPURLRequestConstructor.m.gcov.reduced -: 0:Source:Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#ViewHierarchy#FBSDKViewHierarchy.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/ViewHierarchy/FBSDKViewHierarchy.m <<<<<< EOF # path=Parse#PFGeoPoint.h.gcov.reduced -: 0:Source:Parse/PFGeoPoint.h <<<<<< EOF # path=Parse#Internal#Installation#Controller#PFInstallationController.h.gcov.reduced -: 0:Source:Parse/Internal/Installation/Controller/PFInstallationController.h <<<<<< EOF # path=OCMock#OCMInvocationMatcher.m.gcov.reduced -: 0:Source:OCMock/OCMInvocationMatcher.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Query#Controller#PFQueryController.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Query/Controller/PFQueryController.m #####:57: <<<<<< EOF # path=Parse#Internal#Push#Manager#PFPushManager.h.gcov.reduced -: 0:Source:Parse/Internal/Push/Manager/PFPushManager.h <<<<<< EOF # path=Parse#Internal#Relation#State#PFRelationState_Private.h.gcov.reduced -: 0:Source:Parse/Internal/Relation/State/PFRelationState_Private.h <<<<<< EOF # path=FBSDKCoreKit#Internal#ServerConfiguration#FBSDKErrorRecoveryConfiguration.h.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#PFEventuallyPin.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/PFEventuallyPin.m #####:167: <<<<<< EOF # path=FBSDKCoreKit#AppEvents#FBSDKAppEvents.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/FBSDKAppEvents.m <<<<<< EOF # path=Parse#Internal#PropertyInfo#PFPropertyInfo.h.gcov.reduced -: 0:Source:Parse/Internal/PropertyInfo/PFPropertyInfo.h <<<<<< EOF # path=Parse#Internal#Product#ProductsRequestHandler#PFProductsRequestHandler.m.gcov.reduced -: 0:Source:Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.m <<<<<< EOF # path=Parse#Internal#PFKeychainStore.m.gcov.reduced -: 0:Source:Parse/Internal/PFKeychainStore.m <<<<<< EOF # path=Parse#Internal#Push#State#PFPushState.h.gcov.reduced -: 0:Source:Parse/Internal/Push/State/PFPushState.h <<<<<< EOF # path=FBSDKCoreKit#FBSDKLocation.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKLocation.m <<<<<< EOF # path=Parse#Internal#File#Controller#PFFileController.m.gcov.reduced -: 0:Source:Parse/Internal/File/Controller/PFFileController.m <<<<<< EOF # path=Parse#Internal#Object#Controller#PFObjectController.m.gcov.reduced -: 0:Source:Parse/Internal/Object/Controller/PFObjectController.m <<<<<< EOF # path=FBSDKCoreKit#Internal#UI#FBSDKIcon.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/UI/FBSDKIcon.m <<<<<< EOF # path=Parse#Internal#Query#Controller#PFCachedQueryController.m.gcov.reduced -: 0:Source:Parse/Internal/Query/Controller/PFCachedQueryController.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Carthage#Checkouts#facebook-ios-sdk#Sources#FBSDKCoreKit_Basics#FBSDKSafeCast.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/Sources/FBSDKCoreKit_Basics/FBSDKSafeCast.m #####:21: #####:22: #####:23: #####:24: #####:26: #####:27: #####:28: #####:29: <<<<<< EOF # path=OCMock#OCMBoxedReturnValueProvider.m.gcov.reduced -: 0:Source:OCMock/OCMBoxedReturnValueProvider.m <<<<<< EOF # path=Parse#Internal#Object#Subclassing#PFObjectSubclassInfo.h.gcov.reduced -: 0:Source:Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKPaymentProductRequestor.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKPaymentProductRequestor.m <<<<<< EOF # path=FBSDKCoreKit#FBSDKAuthenticationToken.h.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKAuthenticationToken.h <<<<<< EOF # path=FBSDKCoreKit#Internal#Network#FBSDKGraphRequestMetadata.h.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Object#FilePersistence#PFObjectFilePersistenceController.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.m #####:46: <<<<<< EOF # path=FBSDKCoreKit#FBSDKAuthenticationTokenClaims.h.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKAuthenticationTokenClaims.h <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKLoginCompletion.h.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKLoginCompletion.h <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#SKAdNetwork#FBSDKSKAdNetworkConversionConfiguration.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/SKAdNetwork/FBSDKSKAdNetworkConversionConfiguration.h <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#PFACL.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/PFACL.m #####:263: <<<<<< EOF # path=FBSDKCoreKit#Internal#ServerConfiguration#FBSDKErrorConfiguration.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfiguration.m <<<<<< EOF # path=FBSDKCoreKit#Internal#ServerConfiguration#FBSDKGateKeeperManager.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/ServerConfiguration/FBSDKGateKeeperManager.m <<<<<< EOF # path=Parse#Internal#Analytics#Controller#PFAnalyticsController.m.gcov.reduced -: 0:Source:Parse/Internal/Analytics/Controller/PFAnalyticsController.m <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKProfileFactory.m.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKProfileFactory.m <<<<<< EOF # path=Parse#Internal#Object#State#PFMutableObjectState.m.gcov.reduced -: 0:Source:Parse/Internal/Object/State/PFMutableObjectState.m <<<<<< EOF # path=OCMock#NSNotificationCenter+OCMAdditions.m.gcov.reduced -: 0:Source:OCMock/NSNotificationCenter+OCMAdditions.m <<<<<< EOF # path=Parse#Internal#FieldOperation#PFFieldOperation.h.gcov.reduced -: 0:Source:Parse/Internal/FieldOperation/PFFieldOperation.h <<<<<< EOF # path=Parse#Internal#Object#LocalIdStore#PFObjectLocalIdStore.m.gcov.reduced -: 0:Source:Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKPaymentProductRequestorFactory.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKPaymentProductRequestorFactory.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#Codeless#FBSDKCodelessIndexer.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/Codeless/FBSDKCodelessIndexer.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#SKAdNetwork#FBSDKSKAdNetworkRule.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/SKAdNetwork/FBSDKSKAdNetworkRule.m <<<<<< EOF # path=Parse#Internal#PFCoreManager.m.gcov.reduced -: 0:Source:Parse/Internal/PFCoreManager.m <<<<<< EOF # path=Parse#Internal#PFEventuallyQueue.m.gcov.reduced -: 0:Source:Parse/Internal/PFEventuallyQueue.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#PFDateFormatter.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/PFDateFormatter.m #####:73: <<<<<< EOF # path=Parse#Internal#PFHash.m.gcov.reduced -: 0:Source:Parse/Internal/PFHash.m <<<<<< EOF # path=Parse#Internal#Push#Controller#PFPushController.h.gcov.reduced -: 0:Source:Parse/Internal/Push/Controller/PFPushController.h <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#vector.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/vector #####:305: #####:349: #####:350: #####:352: #####:353: #####:355: #####:356: #####:358: #####:359: #####:362: #####:366: #####:371: #####:373: #####:374: #####:380: #####:381: #####:382: #####:385: #####:389: #####:390: #####:405: #####:406: #####:409: #####:411: #####:412: #####:413: #####:424: #####:425: #####:426: #####:427: #####:428: #####:429: #####:430: #####:434: #####:436: #####:437: #####:438: #####:439: #####:440: #####:454: #####:455: #####:456: #####:457: #####:461: #####:462: #####:463: #####:465: #####:466: #####:467: #####:468: #####:497: #####:498: #####:502: #####:515: #####:519: #####:551: #####:552: #####:553: #####:557: #####:566: #####:657: #####:658: #####:660: #####:661: #####:699: #####:700: #####:771: #####:772: #####:773: #####:774: #####:775: #####:776: #####:777: #####:831: #####:832: #####:833: #####:834: #####:835: #####:836: #####:837: #####:868: #####:869: #####:872: #####:873: #####:874: #####:875: #####:878: #####:879: #####:880: #####:881: #####:891: #####:892: #####:893: #####:894: #####:895: #####:898: #####:899: #####:903: #####:904: #####:905: #####:911: #####:924: #####:925: #####:926: #####:927: #####:928: #####:929: #####:950: #####:951: #####:953: #####:954: #####:955: #####:956: #####:957: #####:958: #####:959: #####:960: #####:961: #####:989: #####:990: #####:991: #####:992: #####:993: #####:994: #####:995: #####:996: #####:1000: #####:1001: #####:1002: #####:1004: #####:1005: #####:1006: #####:1007: #####:1008: #####:1012: #####:1013: #####:1014: #####:1015: #####:1022: #####:1023: #####:1024: #####:1025: #####:1026: #####:1027: #####:1028: #####:1029: #####:1030: #####:1031: #####:1040: #####:1041: #####:1042: #####:1043: #####:1044: #####:1045: #####:1046: #####:1047: #####:1058: #####:1059: #####:1060: #####:1061: #####:1062: #####:1063: #####:1064: #####:1065: #####:1074: #####:1075: #####:1076: #####:1077: #####:1078: #####:1119: #####:1120: #####:1124: #####:1126: #####:1127: #####:1128: #####:1129: #####:1148: #####:1149: #####:1153: #####:1155: #####:1156: #####:1157: #####:1158: #####:1249: #####:1250: #####:1251: #####:1255: #####:1256: #####:1258: #####:1259: #####:1260: #####:1261: #####:1327: #####:1328: #####:1332: #####:1334: #####:1335: #####:1336: #####:1337: #####:1357: #####:1359: #####:1360: #####:1362: #####:1381: #####:1383: #####:1384: #####:1385: #####:1386: #####:1387: #####:1388: #####:1389: #####:1393: #####:1400: #####:1401: #####:1402: #####:1404: #####:1405: #####:1406: #####:1407: #####:1438: #####:1439: #####:1440: #####:1441: #####:1443: #####:1444: #####:1445: #####:1447: #####:1448: #####:1449: #####:1450: #####:1451: #####:1452: #####:1453: #####:1455: #####:1456: #####:1459: #####:1460: #####:1461: #####:1463: #####:1464: #####:1503: #####:1504: #####:1508: #####:1523: #####:1524: #####:1525: #####:1539: #####:1540: #####:1541: #####:1547: #####:1548: #####:1550: #####:1556: #####:1557: #####:1559: #####:1618: #####:1622: #####:1623: #####:1624: #####:1626: #####:1627: #####:1628: #####:1629: #####:1634: #####:1635: #####:1636: #####:1638: #####:1639: #####:1641: #####:1642: #####:2122: #####:2123: #####:2127: #####:2133: #####:2149: <<<<<< EOF # path=FBSDKCoreKit#FBSDKBridgeAPI.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKBridgeAPI.m <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKNonceUtility.m.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKNonceUtility.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMAdvertiserSingleEntryRule.h.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMAdvertiserSingleEntryRule.h <<<<<< EOF # path=FBSDKCoreKit#FBSDKUserAgeRange.m.gcov.reduced -: 0:Source:FBSDKCoreKit/FBSDKUserAgeRange.m <<<<<< EOF # path=Parse#ParseClientConfiguration.m.gcov.reduced -: 0:Source:Parse/ParseClientConfiguration.m <<<<<< EOF # path=Parse#Internal#Session#Utilities#PFSessionUtilities.m.gcov.reduced -: 0:Source:Parse/Internal/Session/Utilities/PFSessionUtilities.m <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKLoggerFactory.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKLoggerFactory.m <<<<<< EOF # path=Parse#Internal#PFInternalUtils.m.gcov.reduced -: 0:Source:Parse/Internal/PFInternalUtils.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#Object#Subclassing#PFObjectSubclassingController.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m #####:115: <<<<<< EOF # path=FBSDKCoreKit#Internal#Network#FBSDKGraphRequestBody.h.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.h <<<<<< EOF # path=Parse#Internal#Installation#InstallationIdentifierStore#PFInstallationIdentifierStore.m.gcov.reduced -: 0:Source:Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.m <<<<<< EOF # path=FBSDKCoreKit#GraphAPI#FBSDKGraphRequestDataAttachment.h.gcov.reduced -: 0:Source:FBSDKCoreKit/GraphAPI/FBSDKGraphRequestDataAttachment.h <<<<<< EOF # path=Parse#Internal#LocalDataStore#SQLite#PFSQLiteStatement.h.gcov.reduced -: 0:Source:Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.h <<<<<< EOF # path=Parse#Internal#PFDateFormatter.m.gcov.reduced -: 0:Source:Parse/Internal/PFDateFormatter.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#__split_buffer.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/__split_buffer #####:56: #####:58: #####:59: #####:85: #####:86: #####:89: #####:136: #####:137: #####:296: #####:297: #####:298: #####:299: #####:300: #####:311: #####:312: #####:313: #####:314: #####:315: #####:316: #####:317: #####:342: #####:343: #####:344: #####:345: #####:346: #####:347: <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKTimeSpentData.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKTimeSpentData.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKAppEventsDeviceInfo.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsDeviceInfo.m <<<<<< EOF # path=Parse#Internal#Query#Controller#PFOfflineQueryController.h.gcov.reduced -: 0:Source:Parse/Internal/Query/Controller/PFOfflineQueryController.h <<<<<< EOF # path=FBSDKCoreKit#Internal#Network#FBSDKGraphRequestFactory.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/Network/FBSDKGraphRequestFactory.m <<<<<< EOF # path=Parse#PFConfig.m.gcov.reduced -: 0:Source:Parse/PFConfig.m <<<<<< EOF # path=#Applications#Xcode_13.1.app#Contents#Developer#Platforms#iPhoneSimulator.platform#Developer#SDKs#iPhoneSimulator15.0.sdk#usr#include#c++#v1#string.gcov.reduced -: 0:Source:/Applications/Xcode_13.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.0.sdk/usr/include/c++/v1/string #####:839: #####:841: #####:845: #####:969: #####:970: #####:1268: #####:1275: #####:1461: #####:1462: #####:1478: #####:1479: #####:1510: #####:1514: #####:1523: #####:1524: #####:1543: #####:1544: #####:1549: #####:1550: #####:1555: #####:1556: #####:1559: #####:1560: #####:1561: #####:1562: #####:1563: #####:1564: #####:1817: #####:1823: #####:1824: #####:1828: #####:1829: #####:4045: #####:4047: #####:4048: #####:4049: #####:4050: #####:4051: #####:4052: #####:4053: #####:4054: #####:4055: #####:4056: #####:4057: #####:4058: #####:4059: #####:4271: #####:4272: #####:4273: #####:4274: #####:4275: #####:4276: #####:4277: #####:4278: #####:4279: #####:4418: #####:4419: <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#FBSDKAtePublisherFactory.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/FBSDKAtePublisherFactory.m <<<<<< EOF # path=Parse#Internal#Commands#CommandRunner#URLSession#Session#TaskDelegate#PFURLSessionDataTaskDelegate.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.m <<<<<< EOF # path=FBSDKCoreKit#Internal#ServerConfiguration#FBSDKErrorConfigurationProvider.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfigurationProvider.m <<<<<< EOF # path=Bolts#Common#BFTaskCompletionSource.h.gcov.reduced -: 0:Source:Bolts/Common/BFTaskCompletionSource.h <<<<<< EOF # path=FBSDKLoginKit#Internal#FBSDKLoginManagerLoginResult+Internal.h.gcov.reduced -: 0:Source:FBSDKLoginKit/Internal/FBSDKLoginManagerLoginResult+Internal.h <<<<<< EOF # path=Parse#Internal#Commands#CommandRunner#URLSession#Session#TaskDelegate#PFURLSessionFileDownloadTaskDelegate.m.gcov.reduced -: 0:Source:Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.m <<<<<< EOF # path=#Users#runner#work#Parse-SDK-iOS-OSX#Parse-SDK-iOS-OSX#Parse#Parse#Internal#File#Controller#PFFileController.m.gcov.reduced -: 0:Source:/Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Parse/Parse/Internal/File/Controller/PFFileController.m #####:72: <<<<<< EOF # path=Parse#Internal#PFWeakValue.m.gcov.reduced -: 0:Source:Parse/Internal/PFWeakValue.m <<<<<< EOF # path=FBSDKCoreKit#AppEvents#Internal#AEM#FBSDKAEMAdvertiserMultiEntryRule.m.gcov.reduced -: 0:Source:FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMAdvertiserMultiEntryRule.m <<<<<< EOF # path=Parse#Internal#Object#Coder#File#PFObjectFileCodingLogic.m.gcov.reduced -: 0:Source:Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.m <<<<<< EOF # path=Parse#Internal#MultiProcessLock#PFMultiProcessFileLock.m.gcov.reduced -: 0:Source:Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.m <<<<<< EOF # path=FBSDKCoreKit#Internal#FBSDKObjectDecoder.m.gcov.reduced -: 0:Source:FBSDKCoreKit/Internal/FBSDKObjectDecoder.m <<<<<< EOF # path=OCMock#OCClassMockObject.m.gcov.reduced -: 0:Source:OCMock/OCClassMockObject.m <<<<<< EOF # path=Parse#Internal#PFDevice.m.gcov.reduced -: 0:Source:Parse/Internal/PFDevice.m <<<<<< EOF # path=Parse#Internal#Object#BatchController#PFObjectBatchController.h.gcov.reduced -: 0:Source:Parse/Internal/Object/BatchController/PFObjectBatchController.h <<<<<< EOF # path=./ParseFacebookUtilsV4-UnitTests.xctest.coverage.txt /Users/runner/Library/Developer/Xcode/DerivedData/Parse-dscfcsmewbetpzfilnzorrkjyefy/Build/Products/Debug-iphonesimulator/FBSDKCoreKit.framework/Headers/FBSDKCoreKitVersions.h: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| 0|#define FBSDK_VERSION_STRING @"11.0.1" 20| |#define FBSDK_TARGET_PLATFORM_VERSION @"v11.0" /Users/runner/Library/Developer/Xcode/DerivedData/Parse-dscfcsmewbetpzfilnzorrkjyefy/Build/Products/Debug-iphonesimulator/FBSDKCoreKit_Basics.framework/Headers/FBSDKSafeCast.h: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import 20| | 21| |#ifndef FBSDK_CAST_TO_CLASS_OR_NIL_FUNC 22| | #define FBSDK_CAST_TO_CLASS_OR_NIL_FUNC 23| | #ifdef __cplusplus 24| |extern "C" { 25| | #endif 26| |/** Use the type-safe FBSDK_CAST_TO_CLASS_OR_NIL instead. */ 27| |id _FBSDKCastToClassOrNilUnsafeInternal(id object, Class klass); 28| | #ifdef __cplusplus 29| |} 30| | #endif 31| |#endif 32| | 33| |#ifndef FBSDK_CAST_TO_CLASS_OR_NIL 34| 0| #define FBSDK_CAST_TO_CLASS_OR_NIL(obj_, class_) ((class_ *)_FBSDKCastToClassOrNilUnsafeInternal(obj_, [class_ class])) 35| |#endif 36| | 37| |#ifndef FBSDK_CAST_TO_PROTOCOL_OR_NIL_FUNC 38| | #define FBSDK_CAST_TO_PROTOCOL_OR_NIL_FUNC 39| | #ifdef __cplusplus 40| |extern "C" { 41| | #endif 42| |/** Use the type-safe FBSDK_CAST_TO_PROTOCOL_OR_NIL instead. */ 43| |id _FBSDKCastToProtocolOrNilUnsafeInternal(id object, Protocol *protocol); 44| | #ifdef __cplusplus 45| |} 46| | #endif 47| |#endif 48| | 49| |#ifndef FBSDK_CAST_TO_PROTOCOL_OR_NIL 50| 0| #define FBSDK_CAST_TO_PROTOCOL_OR_NIL(obj_, protocol_) ((id)_FBSDKCastToProtocolOrNilUnsafeInternal(obj_, @protocol(protocol_))) 51| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/Bolts-ObjC/Bolts/Common/BFCancellationToken.m: 1| |/* 2| | * Copyright (c) 2014, Facebook, Inc. 3| | * All rights reserved. 4| | * 5| | * This source code is licensed under the BSD-style license found in the 6| | * LICENSE file in the root directory of this source tree. An additional grant 7| | * of patent rights can be found in the PATENTS file in the same directory. 8| | * 9| | */ 10| | 11| |#import "BFCancellationToken.h" 12| |#import "BFCancellationTokenRegistration.h" 13| | 14| |NS_ASSUME_NONNULL_BEGIN 15| | 16| |@interface BFCancellationToken () 17| | 18| |@property (nullable, nonatomic, strong) NSMutableArray *registrations; 19| |@property (nonatomic, strong) NSObject *lock; 20| |@property (nonatomic) BOOL disposed; 21| | 22| |@end 23| | 24| |@interface BFCancellationTokenRegistration (BFCancellationToken) 25| | 26| |+ (instancetype)registrationWithToken:(BFCancellationToken *)token delegate:(BFCancellationBlock)delegate; 27| | 28| |- (void)notifyDelegate; 29| | 30| |@end 31| | 32| |@implementation BFCancellationToken 33| | 34| |@synthesize cancellationRequested = _cancellationRequested; 35| | 36| |#pragma mark - Initializer 37| | 38| 0|- (instancetype)init { 39| 0| self = [super init]; 40| 0| if (!self) return self; 41| | 42| 0| _registrations = [NSMutableArray array]; 43| 0| _lock = [NSObject new]; 44| | 45| 0| return self; 46| 0|} 47| | 48| |#pragma mark - Custom Setters/Getters 49| | 50| 0|- (BOOL)isCancellationRequested { 51| 0| @synchronized(self.lock) { 52| 0| [self throwIfDisposed]; 53| 0| return _cancellationRequested; 54| 0| } 55| 0|} 56| | 57| 0|- (void)cancel { 58| 0| NSArray *registrations; 59| 0| @synchronized(self.lock) { 60| 0| [self throwIfDisposed]; 61| 0| if (_cancellationRequested) { 62| 0| return; 63| 0| } 64| 0| [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil]; 65| 0| _cancellationRequested = YES; 66| 0| registrations = [self.registrations copy]; 67| 0| } 68| | 69| 0| [self notifyCancellation:registrations]; 70| 0|} 71| | 72| 0|- (void)notifyCancellation:(NSArray *)registrations { 73| 0| for (BFCancellationTokenRegistration *registration in registrations) { 74| 0| [registration notifyDelegate]; 75| 0| } 76| 0|} 77| | 78| 0|- (BFCancellationTokenRegistration *)registerCancellationObserverWithBlock:(BFCancellationBlock)block { 79| 0| @synchronized(self.lock) { 80| 0| BFCancellationTokenRegistration *registration = [BFCancellationTokenRegistration registrationWithToken:self delegate:[block copy]]; 81| 0| [self.registrations addObject:registration]; 82| | 83| 0| return registration; 84| 0| } 85| 0|} 86| | 87| 0|- (void)unregisterRegistration:(BFCancellationTokenRegistration *)registration { 88| 0| @synchronized(self.lock) { 89| 0| [self throwIfDisposed]; 90| 0| [self.registrations removeObject:registration]; 91| 0| } 92| 0|} 93| | 94| |// Delay on a non-public method to prevent interference with a user calling performSelector or 95| |// cancelPreviousPerformRequestsWithTarget on the public method 96| 0|- (void)cancelPrivate { 97| 0| [self cancel]; 98| 0|} 99| | 100| 0|- (void)cancelAfterDelay:(int)millis { 101| 0| [self throwIfDisposed]; 102| 0| if (millis < -1) { 103| 0| [NSException raise:NSInvalidArgumentException format:@"Delay must be >= -1"]; 104| 0| } 105| | 106| 0| if (millis == 0) { 107| 0| [self cancel]; 108| 0| return; 109| 0| } 110| | 111| 0| @synchronized(self.lock) { 112| 0| [self throwIfDisposed]; 113| 0| [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil]; 114| 0| if (self.cancellationRequested) { 115| 0| return; 116| 0| } 117| | 118| 0| if (millis != -1) { 119| 0| double delay = (double)millis / 1000; 120| 0| [self performSelector:@selector(cancelPrivate) withObject:nil afterDelay:delay]; 121| 0| } 122| 0| } 123| 0|} 124| | 125| 0|- (void)dispose { 126| 0| @synchronized(self.lock) { 127| 0| if (self.disposed) { 128| 0| return; 129| 0| } 130| 0| [self.registrations makeObjectsPerformSelector:@selector(dispose)]; 131| 0| self.registrations = nil; 132| 0| self.disposed = YES; 133| 0| } 134| 0|} 135| | 136| 0|- (void)throwIfDisposed { 137| 0| if (self.disposed) { 138| 0| [NSException raise:NSInternalInconsistencyException format:@"Object already disposed"]; 139| 0| } 140| 0|} 141| | 142| |@end 143| | 144| |NS_ASSUME_NONNULL_END /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/Bolts-ObjC/Bolts/Common/BFCancellationTokenRegistration.m: 1| |/* 2| | * Copyright (c) 2014, Facebook, Inc. 3| | * All rights reserved. 4| | * 5| | * This source code is licensed under the BSD-style license found in the 6| | * LICENSE file in the root directory of this source tree. An additional grant 7| | * of patent rights can be found in the PATENTS file in the same directory. 8| | * 9| | */ 10| | 11| |#import "BFCancellationTokenRegistration.h" 12| | 13| |#import "BFCancellationToken.h" 14| | 15| |NS_ASSUME_NONNULL_BEGIN 16| | 17| |@interface BFCancellationTokenRegistration () 18| | 19| |@property (nonatomic, weak) BFCancellationToken *token; 20| |@property (nullable, nonatomic, strong) BFCancellationBlock cancellationObserverBlock; 21| |@property (nonatomic, strong) NSObject *lock; 22| |@property (nonatomic) BOOL disposed; 23| | 24| |@end 25| | 26| |@interface BFCancellationToken (BFCancellationTokenRegistration) 27| | 28| |- (void)unregisterRegistration:(BFCancellationTokenRegistration *)registration; 29| | 30| |@end 31| | 32| |@implementation BFCancellationTokenRegistration 33| | 34| 0|+ (instancetype)registrationWithToken:(BFCancellationToken *)token delegate:(BFCancellationBlock)delegate { 35| 0| BFCancellationTokenRegistration *registration = [BFCancellationTokenRegistration new]; 36| 0| registration.token = token; 37| 0| registration.cancellationObserverBlock = delegate; 38| 0| return registration; 39| 0|} 40| | 41| 0|- (instancetype)init { 42| 0| self = [super init]; 43| 0| if (!self) return self; 44| | 45| 0| _lock = [NSObject new]; 46| | 47| 0| return self; 48| 0|} 49| | 50| 0|- (void)dispose { 51| 0| @synchronized(self.lock) { 52| 0| if (self.disposed) { 53| 0| return; 54| 0| } 55| 0| self.disposed = YES; 56| 0| } 57| | 58| 0| BFCancellationToken *token = self.token; 59| 0| if (token != nil) { 60| 0| [token unregisterRegistration:self]; 61| 0| self.token = nil; 62| 0| } 63| 0| self.cancellationObserverBlock = nil; 64| 0|} 65| | 66| 0|- (void)notifyDelegate { 67| 0| @synchronized(self.lock) { 68| 0| [self throwIfDisposed]; 69| 0| self.cancellationObserverBlock(); 70| 0| } 71| 0|} 72| | 73| 0|- (void)throwIfDisposed { 74| 0| NSAssert(!self.disposed, @"Object already disposed"); 75| 0|} 76| | 77| |@end 78| | 79| |NS_ASSUME_NONNULL_END /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/Bolts-ObjC/Bolts/Common/BFCancellationTokenSource.m: 1| |/* 2| | * Copyright (c) 2014, Facebook, Inc. 3| | * All rights reserved. 4| | * 5| | * This source code is licensed under the BSD-style license found in the 6| | * LICENSE file in the root directory of this source tree. An additional grant 7| | * of patent rights can be found in the PATENTS file in the same directory. 8| | * 9| | */ 10| | 11| |#import "BFCancellationTokenSource.h" 12| | 13| |#import "BFCancellationToken.h" 14| | 15| |NS_ASSUME_NONNULL_BEGIN 16| | 17| |@interface BFCancellationToken (BFCancellationTokenSource) 18| | 19| |- (void)cancel; 20| |- (void)cancelAfterDelay:(int)millis; 21| | 22| |- (void)dispose; 23| |- (void)throwIfDisposed; 24| | 25| |@end 26| | 27| |@implementation BFCancellationTokenSource 28| | 29| |#pragma mark - Initializer 30| | 31| 0|- (instancetype)init { 32| 0| self = [super init]; 33| 0| if (!self) return self; 34| | 35| 0| _token = [BFCancellationToken new]; 36| | 37| 0| return self; 38| 0|} 39| | 40| 0|+ (instancetype)cancellationTokenSource { 41| 0| return [BFCancellationTokenSource new]; 42| 0|} 43| | 44| |#pragma mark - Custom Setters/Getters 45| | 46| 0|- (BOOL)isCancellationRequested { 47| 0| return _token.isCancellationRequested; 48| 0|} 49| | 50| 0|- (void)cancel { 51| 0| [_token cancel]; 52| 0|} 53| | 54| 0|- (void)cancelAfterDelay:(int)millis { 55| 0| [_token cancelAfterDelay:millis]; 56| 0|} 57| | 58| 0|- (void)dispose { 59| 0| [_token dispose]; 60| 0|} 61| | 62| |@end 63| | 64| |NS_ASSUME_NONNULL_END /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/Bolts-ObjC/Bolts/Common/BFExecutor.m: 1| |/* 2| | * Copyright (c) 2014, Facebook, Inc. 3| | * All rights reserved. 4| | * 5| | * This source code is licensed under the BSD-style license found in the 6| | * LICENSE file in the root directory of this source tree. An additional grant 7| | * of patent rights can be found in the PATENTS file in the same directory. 8| | * 9| | */ 10| | 11| |#import "BFExecutor.h" 12| | 13| |#import 14| | 15| |NS_ASSUME_NONNULL_BEGIN 16| | 17| |/*! 18| | Get the remaining stack-size of the current thread. 19| | 20| | @param totalSize The total stack size of the current thread. 21| | 22| | @return The remaining size, in bytes, available to the current thread. 23| | 24| | @note This function cannot be inlined, as otherwise the internal implementation could fail to report the proper 25| | remaining stack space. 26| | */ 27| 0|__attribute__((noinline)) static size_t remaining_stack_size(size_t *restrict totalSize) { 28| 0| pthread_t currentThread = pthread_self(); 29| | 30| | // NOTE: We must store stack pointers as uint8_t so that the pointer math is well-defined 31| 0| uint8_t *endStack = pthread_get_stackaddr_np(currentThread); 32| 0| *totalSize = pthread_get_stacksize_np(currentThread); 33| | 34| | // NOTE: If the function is inlined, this value could be incorrect 35| 0| uint8_t *frameAddr = __builtin_frame_address(0); 36| | 37| 0| return (*totalSize) - (size_t)(endStack - frameAddr); 38| 0|} 39| | 40| |@interface BFExecutor () 41| | 42| |@property (nonatomic, copy) void(^block)(void(^block)(void)); 43| | 44| |@end 45| | 46| |@implementation BFExecutor 47| | 48| |#pragma mark - Executor methods 49| | 50| 0|+ (instancetype)defaultExecutor { 51| 0| static BFExecutor *defaultExecutor = NULL; 52| 0| static dispatch_once_t onceToken; 53| 0| dispatch_once(&onceToken, ^{ 54| 0| defaultExecutor = [self executorWithBlock:^void(void(^block)(void)) { 55| | // We prefer to run everything possible immediately, so that there is callstack information 56| | // when debugging. However, we don't want the stack to get too deep, so if the remaining stack space 57| | // is less than 10% of the total space, we dispatch to another GCD queue. 58| 0| size_t totalStackSize = 0; 59| 0| size_t remainingStackSize = remaining_stack_size(&totalStackSize); 60| | 61| 0| if (remainingStackSize < (totalStackSize / 10)) { 62| 0| dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block); 63| 0| } else { 64| 0| @autoreleasepool { 65| 0| block(); 66| 0| } 67| 0| } 68| 0| }]; 69| 0| }); 70| 0| return defaultExecutor; 71| 0|} 72| | 73| 0|+ (instancetype)immediateExecutor { 74| 0| static BFExecutor *immediateExecutor = NULL; 75| 0| static dispatch_once_t onceToken; 76| 0| dispatch_once(&onceToken, ^{ 77| 0| immediateExecutor = [self executorWithBlock:^void(void(^block)(void)) { 78| 0| block(); 79| 0| }]; 80| 0| }); 81| 0| return immediateExecutor; 82| 0|} 83| | 84| 0|+ (instancetype)mainThreadExecutor { 85| 0| static BFExecutor *mainThreadExecutor = NULL; 86| 0| static dispatch_once_t onceToken; 87| 0| dispatch_once(&onceToken, ^{ 88| 0| mainThreadExecutor = [self executorWithBlock:^void(void(^block)(void)) { 89| 0| if (![NSThread isMainThread]) { 90| 0| dispatch_async(dispatch_get_main_queue(), block); 91| 0| } else { 92| 0| @autoreleasepool { 93| 0| block(); 94| 0| } 95| 0| } 96| 0| }]; 97| 0| }); 98| 0| return mainThreadExecutor; 99| 0|} 100| | 101| 0|+ (instancetype)executorWithBlock:(void(^)(void(^block)(void)))block { 102| 0| return [[self alloc] initWithBlock:block]; 103| 0|} 104| | 105| 0|+ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue { 106| 0| return [self executorWithBlock:^void(void(^block)(void)) { 107| 0| dispatch_async(queue, block); 108| 0| }]; 109| 0|} 110| | 111| 0|+ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue { 112| 0| return [self executorWithBlock:^void(void(^block)(void)) { 113| 0| [queue addOperation:[NSBlockOperation blockOperationWithBlock:block]]; 114| 0| }]; 115| 0|} 116| | 117| |#pragma mark - Initializer 118| | 119| 0|- (instancetype)initWithBlock:(void(^)(void(^block)(void)))block { 120| 0| self = [super init]; 121| 0| if (!self) return self; 122| | 123| 0| _block = block; 124| | 125| 0| return self; 126| 0|} 127| | 128| |#pragma mark - Execution 129| | 130| 0|- (void)execute:(void(^)(void))block { 131| 0| self.block(block); 132| 0|} 133| | 134| |@end 135| | 136| |NS_ASSUME_NONNULL_END /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/Bolts-ObjC/Bolts/Common/BFTask.m: 1| |/* 2| | * Copyright (c) 2014, Facebook, Inc. 3| | * All rights reserved. 4| | * 5| | * This source code is licensed under the BSD-style license found in the 6| | * LICENSE file in the root directory of this source tree. An additional grant 7| | * of patent rights can be found in the PATENTS file in the same directory. 8| | * 9| | */ 10| | 11| |#import "BFTask.h" 12| | 13| |#import 14| | 15| |#import "Bolts.h" 16| | 17| |NS_ASSUME_NONNULL_BEGIN 18| | 19| 0|__attribute__ ((noinline)) void warnBlockingOperationOnMainThread() { 20| 0| NSLog(@"Warning: A long-running operation is being executed on the main thread. \n" 21| 0| " Break on warnBlockingOperationOnMainThread() to debug."); 22| 0|} 23| | 24| |NSString *const BFTaskErrorDomain = @"bolts"; 25| |NSInteger const kBFMultipleErrorsError = 80175001; 26| | 27| |NSString *const BFTaskMultipleErrorsUserInfoKey = @"errors"; 28| | 29| |@interface BFTask () { 30| | id _result; 31| | NSError *_error; 32| |} 33| | 34| |@property (nonatomic, assign, readwrite, getter=isCancelled) BOOL cancelled; 35| |@property (nonatomic, assign, readwrite, getter=isFaulted) BOOL faulted; 36| |@property (nonatomic, assign, readwrite, getter=isCompleted) BOOL completed; 37| | 38| |@property (nonatomic, strong) NSObject *lock; 39| |@property (nonatomic, strong) NSCondition *condition; 40| |@property (nonatomic, strong) NSMutableArray *callbacks; 41| | 42| |@end 43| | 44| |@implementation BFTask 45| | 46| |#pragma mark - Initializer 47| | 48| 0|- (instancetype)init { 49| 0| self = [super init]; 50| 0| if (!self) return self; 51| | 52| 0| _lock = [[NSObject alloc] init]; 53| 0| _condition = [[NSCondition alloc] init]; 54| 0| _callbacks = [NSMutableArray array]; 55| | 56| 0| return self; 57| 0|} 58| | 59| 0|- (instancetype)initWithResult:(nullable id)result { 60| 0| self = [super init]; 61| 0| if (!self) return self; 62| | 63| 0| [self trySetResult:result]; 64| | 65| 0| return self; 66| 0|} 67| | 68| 0|- (instancetype)initWithError:(NSError *)error { 69| 0| self = [super init]; 70| 0| if (!self) return self; 71| | 72| 0| [self trySetError:error]; 73| | 74| 0| return self; 75| 0|} 76| | 77| 0|- (instancetype)initCancelled { 78| 0| self = [super init]; 79| 0| if (!self) return self; 80| | 81| 0| [self trySetCancelled]; 82| | 83| 0| return self; 84| 0|} 85| | 86| |#pragma mark - Task Class methods 87| | 88| 0|+ (instancetype)taskWithResult:(nullable id)result { 89| 0| return [[self alloc] initWithResult:result]; 90| 0|} 91| | 92| 0|+ (instancetype)taskWithError:(NSError *)error { 93| 0| return [[self alloc] initWithError:error]; 94| 0|} 95| | 96| 0|+ (instancetype)cancelledTask { 97| 0| return [[self alloc] initCancelled]; 98| 0|} 99| | 100| 0|+ (instancetype)taskForCompletionOfAllTasks:(nullable NSArray *)tasks { 101| 0| __block int32_t total = (int32_t)tasks.count; 102| 0| if (total == 0) { 103| 0| return [self taskWithResult:nil]; 104| 0| } 105| | 106| 0| __block int32_t cancelled = 0; 107| 0| NSObject *lock = [[NSObject alloc] init]; 108| 0| NSMutableArray *errors = [NSMutableArray array]; 109| | 110| 0| BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; 111| 0| for (BFTask *task in tasks) { 112| 0| [task continueWithBlock:^id(BFTask *t) { 113| 0| if (t.error) { 114| 0| @synchronized (lock) { 115| 0| [errors addObject:t.error]; 116| 0| } 117| 0| } else if (t.cancelled) { 118| 0| OSAtomicIncrement32Barrier(&cancelled); 119| 0| } 120| | 121| 0| if (OSAtomicDecrement32Barrier(&total) == 0) { 122| 0| if (errors.count > 0) { 123| 0| if (errors.count == 1) { 124| 0| tcs.error = [errors firstObject]; 125| 0| } else { 126| 0| NSError *error = [NSError errorWithDomain:BFTaskErrorDomain 127| 0| code:kBFMultipleErrorsError 128| 0| userInfo:@{ BFTaskMultipleErrorsUserInfoKey: errors }]; 129| 0| tcs.error = error; 130| 0| } 131| 0| } else if (cancelled > 0) { 132| 0| [tcs cancel]; 133| 0| } else { 134| 0| tcs.result = nil; 135| 0| } 136| 0| } 137| 0| return nil; 138| 0| }]; 139| 0| } 140| 0| return tcs.task; 141| 0|} 142| | 143| 0|+ (instancetype)taskForCompletionOfAllTasksWithResults:(nullable NSArray *)tasks { 144| 0| return [[self taskForCompletionOfAllTasks:tasks] continueWithSuccessBlock:^id(BFTask * __unused task) { 145| 0| return [tasks valueForKey:@"result"]; 146| 0| }]; 147| 0|} 148| | 149| |+ (instancetype)taskForCompletionOfAnyTask:(nullable NSArray *)tasks 150| 0|{ 151| 0| __block int32_t total = (int32_t)tasks.count; 152| 0| if (total == 0) { 153| 0| return [self taskWithResult:nil]; 154| 0| } 155| | 156| 0| __block int completed = 0; 157| 0| __block int32_t cancelled = 0; 158| | 159| 0| NSObject *lock = [NSObject new]; 160| 0| NSMutableArray *errors = [NSMutableArray new]; 161| | 162| 0| BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource]; 163| 0| for (BFTask *task in tasks) { 164| 0| [task continueWithBlock:^id(BFTask *t) { 165| 0| if (t.error != nil) { 166| 0| @synchronized(lock) { 167| 0| [errors addObject:t.error]; 168| 0| } 169| 0| } else if (t.cancelled) { 170| 0| OSAtomicIncrement32Barrier(&cancelled); 171| 0| } else { 172| 0| if(OSAtomicCompareAndSwap32Barrier(0, 1, &completed)) { 173| 0| [source setResult:t.result]; 174| 0| } 175| 0| } 176| | 177| 0| if (OSAtomicDecrement32Barrier(&total) == 0 && 178| 0| OSAtomicCompareAndSwap32Barrier(0, 1, &completed)) { 179| 0| if (cancelled > 0) { 180| 0| [source cancel]; 181| 0| } else if (errors.count > 0) { 182| 0| if (errors.count == 1) { 183| 0| source.error = errors.firstObject; 184| 0| } else { 185| 0| NSError *error = [NSError errorWithDomain:BFTaskErrorDomain 186| 0| code:kBFMultipleErrorsError 187| 0| userInfo:@{ @"errors": errors }]; 188| 0| source.error = error; 189| 0| } 190| 0| } 191| 0| } 192| | // Abort execution of per tasks continuations 193| 0| return nil; 194| 0| }]; 195| 0| } 196| 0| return source.task; 197| 0|} 198| | 199| | 200| 0|+ (BFTask *)taskWithDelay:(int)millis { 201| 0| BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; 202| 0| dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC); 203| 0| dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ 204| 0| tcs.result = nil; 205| 0| }); 206| 0| return tcs.task; 207| 0|} 208| | 209| 0|+ (BFTask *)taskWithDelay:(int)millis cancellationToken:(nullable BFCancellationToken *)token { 210| 0| if (token.cancellationRequested) { 211| 0| return [BFTask cancelledTask]; 212| 0| } 213| | 214| 0| BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; 215| 0| dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC); 216| 0| dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ 217| 0| if (token.cancellationRequested) { 218| 0| [tcs cancel]; 219| 0| return; 220| 0| } 221| 0| tcs.result = nil; 222| 0| }); 223| 0| return tcs.task; 224| 0|} 225| | 226| 0|+ (instancetype)taskFromExecutor:(BFExecutor *)executor withBlock:(nullable id (^)(void))block { 227| 0| return [[self taskWithResult:nil] continueWithExecutor:executor withBlock:^id(BFTask *task) { 228| 0| return block(); 229| 0| }]; 230| 0|} 231| | 232| |#pragma mark - Custom Setters/Getters 233| | 234| 0|- (nullable id)result { 235| 0| @synchronized(self.lock) { 236| 0| return _result; 237| 0| } 238| 0|} 239| | 240| 0|- (BOOL)trySetResult:(nullable id)result { 241| 0| @synchronized(self.lock) { 242| 0| if (self.completed) { 243| 0| return NO; 244| 0| } 245| 0| self.completed = YES; 246| 0| _result = result; 247| 0| [self runContinuations]; 248| 0| return YES; 249| 0| } 250| 0|} 251| | 252| 0|- (nullable NSError *)error { 253| 0| @synchronized(self.lock) { 254| 0| return _error; 255| 0| } 256| 0|} 257| | 258| 0|- (BOOL)trySetError:(NSError *)error { 259| 0| @synchronized(self.lock) { 260| 0| if (self.completed) { 261| 0| return NO; 262| 0| } 263| 0| self.completed = YES; 264| 0| self.faulted = YES; 265| 0| _error = error; 266| 0| [self runContinuations]; 267| 0| return YES; 268| 0| } 269| 0|} 270| | 271| 0|- (BOOL)isCancelled { 272| 0| @synchronized(self.lock) { 273| 0| return _cancelled; 274| 0| } 275| 0|} 276| | 277| 0|- (BOOL)isFaulted { 278| 0| @synchronized(self.lock) { 279| 0| return _faulted; 280| 0| } 281| 0|} 282| | 283| 0|- (BOOL)trySetCancelled { 284| 0| @synchronized(self.lock) { 285| 0| if (self.completed) { 286| 0| return NO; 287| 0| } 288| 0| self.completed = YES; 289| 0| self.cancelled = YES; 290| 0| [self runContinuations]; 291| 0| return YES; 292| 0| } 293| 0|} 294| | 295| 0|- (BOOL)isCompleted { 296| 0| @synchronized(self.lock) { 297| 0| return _completed; 298| 0| } 299| 0|} 300| | 301| 0|- (void)runContinuations { 302| 0| @synchronized(self.lock) { 303| 0| [self.condition lock]; 304| 0| [self.condition broadcast]; 305| 0| [self.condition unlock]; 306| 0| for (void (^callback)(void) in self.callbacks) { 307| 0| callback(); 308| 0| } 309| 0| [self.callbacks removeAllObjects]; 310| 0| } 311| 0|} 312| | 313| |#pragma mark - Chaining methods 314| | 315| 0|- (BFTask *)continueWithExecutor:(BFExecutor *)executor withBlock:(BFContinuationBlock)block { 316| 0| return [self continueWithExecutor:executor block:block cancellationToken:nil]; 317| 0|} 318| | 319| |- (BFTask *)continueWithExecutor:(BFExecutor *)executor 320| | block:(BFContinuationBlock)block 321| 0| cancellationToken:(nullable BFCancellationToken *)cancellationToken { 322| 0| BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; 323| | 324| | // Capture all of the state that needs to used when the continuation is complete. 325| 0| dispatch_block_t executionBlock = ^{ 326| 0| if (cancellationToken.cancellationRequested) { 327| 0| [tcs cancel]; 328| 0| return; 329| 0| } 330| | 331| 0| id result = block(self); 332| 0| if ([result isKindOfClass:[BFTask class]]) { 333| | 334| 0| id (^setupWithTask) (BFTask *) = ^id(BFTask *task) { 335| 0| if (cancellationToken.cancellationRequested || task.cancelled) { 336| 0| [tcs cancel]; 337| 0| } else if (task.error) { 338| 0| tcs.error = task.error; 339| 0| } else { 340| 0| tcs.result = task.result; 341| 0| } 342| 0| return nil; 343| 0| }; 344| | 345| 0| BFTask *resultTask = (BFTask *)result; 346| | 347| 0| if (resultTask.completed) { 348| 0| setupWithTask(resultTask); 349| 0| } else { 350| 0| [resultTask continueWithBlock:setupWithTask]; 351| 0| } 352| | 353| 0| } else { 354| 0| tcs.result = result; 355| 0| } 356| 0| }; 357| | 358| 0| BOOL completed; 359| 0| @synchronized(self.lock) { 360| 0| completed = self.completed; 361| 0| if (!completed) { 362| 0| [self.callbacks addObject:[^{ 363| 0| [executor execute:executionBlock]; 364| 0| } copy]]; 365| 0| } 366| 0| } 367| 0| if (completed) { 368| 0| [executor execute:executionBlock]; 369| 0| } 370| | 371| 0| return tcs.task; 372| 0|} 373| | 374| 0|- (BFTask *)continueWithBlock:(BFContinuationBlock)block { 375| 0| return [self continueWithExecutor:[BFExecutor defaultExecutor] block:block cancellationToken:nil]; 376| 0|} 377| | 378| 0|- (BFTask *)continueWithBlock:(BFContinuationBlock)block cancellationToken:(nullable BFCancellationToken *)cancellationToken { 379| 0| return [self continueWithExecutor:[BFExecutor defaultExecutor] block:block cancellationToken:cancellationToken]; 380| 0|} 381| | 382| |- (BFTask *)continueWithExecutor:(BFExecutor *)executor 383| 0| withSuccessBlock:(BFContinuationBlock)block { 384| 0| return [self continueWithExecutor:executor successBlock:block cancellationToken:nil]; 385| 0|} 386| | 387| |- (BFTask *)continueWithExecutor:(BFExecutor *)executor 388| | successBlock:(BFContinuationBlock)block 389| 0| cancellationToken:(nullable BFCancellationToken *)cancellationToken { 390| 0| if (cancellationToken.cancellationRequested) { 391| 0| return [BFTask cancelledTask]; 392| 0| } 393| | 394| 0| return [self continueWithExecutor:executor block:^id(BFTask *task) { 395| 0| if (task.faulted || task.cancelled) { 396| 0| return task; 397| 0| } else { 398| 0| return block(task); 399| 0| } 400| 0| } cancellationToken:cancellationToken]; 401| 0|} 402| | 403| 0|- (BFTask *)continueWithSuccessBlock:(BFContinuationBlock)block { 404| 0| return [self continueWithExecutor:[BFExecutor defaultExecutor] successBlock:block cancellationToken:nil]; 405| 0|} 406| | 407| 0|- (BFTask *)continueWithSuccessBlock:(BFContinuationBlock)block cancellationToken:(nullable BFCancellationToken *)cancellationToken { 408| 0| return [self continueWithExecutor:[BFExecutor defaultExecutor] successBlock:block cancellationToken:cancellationToken]; 409| 0|} 410| | 411| |#pragma mark - Syncing Task (Avoid it) 412| | 413| 0|- (void)warnOperationOnMainThread { 414| 0| warnBlockingOperationOnMainThread(); 415| 0|} 416| | 417| 0|- (void)waitUntilFinished { 418| 0| if ([NSThread isMainThread]) { 419| 0| [self warnOperationOnMainThread]; 420| 0| } 421| | 422| 0| @synchronized(self.lock) { 423| 0| if (self.completed) { 424| 0| return; 425| 0| } 426| 0| [self.condition lock]; 427| 0| } 428| | // TODO: (nlutsenko) Restructure this to use Bolts-Swift thread access synchronization architecture 429| | // In the meantime, it's absolutely safe to get `_completed` aka an ivar, as long as it's a `BOOL` aka less than word size. 430| 0| while (!_completed) { 431| 0| [self.condition wait]; 432| 0| } 433| 0| [self.condition unlock]; 434| 0|} 435| | 436| |#pragma mark - NSObject 437| | 438| 0|- (NSString *)description { 439| | // Acquire the data from the locked properties 440| 0| BOOL completed; 441| 0| BOOL cancelled; 442| 0| BOOL faulted; 443| 0| NSString *resultDescription = nil; 444| | 445| 0| @synchronized(self.lock) { 446| 0| completed = self.completed; 447| 0| cancelled = self.cancelled; 448| 0| faulted = self.faulted; 449| 0| resultDescription = completed ? [NSString stringWithFormat:@" result = %@", self.result] : @""; 450| 0| } 451| | 452| | // Description string includes status information and, if available, the 453| | // result since in some ways this is what a promise actually "is". 454| 0| return [NSString stringWithFormat:@"<%@: %p; completed = %@; cancelled = %@; faulted = %@;%@>", 455| 0| NSStringFromClass([self class]), 456| 0| self, 457| 0| completed ? @"YES" : @"NO", 458| 0| cancelled ? @"YES" : @"NO", 459| 0| faulted ? @"YES" : @"NO", 460| 0| resultDescription]; 461| 0|} 462| | 463| |@end 464| | 465| |NS_ASSUME_NONNULL_END /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/Bolts-ObjC/Bolts/Common/BFTaskCompletionSource.m: 1| |/* 2| | * Copyright (c) 2014, Facebook, Inc. 3| | * All rights reserved. 4| | * 5| | * This source code is licensed under the BSD-style license found in the 6| | * LICENSE file in the root directory of this source tree. An additional grant 7| | * of patent rights can be found in the PATENTS file in the same directory. 8| | * 9| | */ 10| | 11| |#import "BFTaskCompletionSource.h" 12| | 13| |#import "BFTask.h" 14| | 15| |NS_ASSUME_NONNULL_BEGIN 16| | 17| |@interface BFTask (BFTaskCompletionSource) 18| | 19| |- (BOOL)trySetResult:(nullable id)result; 20| |- (BOOL)trySetError:(NSError *)error; 21| |- (BOOL)trySetCancelled; 22| | 23| |@end 24| | 25| |@implementation BFTaskCompletionSource 26| | 27| |#pragma mark - Initializer 28| | 29| 0|+ (instancetype)taskCompletionSource { 30| 0| return [[self alloc] init]; 31| 0|} 32| | 33| 0|- (instancetype)init { 34| 0| self = [super init]; 35| 0| if (!self) return self; 36| | 37| 0| _task = [[BFTask alloc] init]; 38| | 39| 0| return self; 40| 0|} 41| | 42| |#pragma mark - Custom Setters/Getters 43| | 44| 0|- (void)setResult:(nullable id)result { 45| 0| if (![self.task trySetResult:result]) { 46| 0| [NSException raise:NSInternalInconsistencyException 47| 0| format:@"Cannot set the result on a completed task."]; 48| 0| } 49| 0|} 50| | 51| 0|- (void)setError:(NSError *)error { 52| 0| if (![self.task trySetError:error]) { 53| 0| [NSException raise:NSInternalInconsistencyException 54| 0| format:@"Cannot set the error on a completed task."]; 55| 0| } 56| 0|} 57| | 58| 0|- (void)cancel { 59| 0| if (![self.task trySetCancelled]) { 60| 0| [NSException raise:NSInternalInconsistencyException 61| 0| format:@"Cannot cancel a completed task."]; 62| 0| } 63| 0|} 64| | 65| 0|- (BOOL)trySetResult:(nullable id)result { 66| 0| return [self.task trySetResult:result]; 67| 0|} 68| | 69| 0|- (BOOL)trySetError:(NSError *)error { 70| 0| return [self.task trySetError:error]; 71| 0|} 72| | 73| 0|- (BOOL)trySetCancelled { 74| 0| return [self.task trySetCancelled]; 75| 0|} 76| | 77| |@end 78| | 79| |NS_ASSUME_NONNULL_END /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEvents.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAppEvents.h" 20| |#import "FBSDKAppEvents+EventLogging.h" 21| |#import "FBSDKAppEvents+Internal.h" 22| | 23| |#import 24| |#import 25| | 26| |#import 27| | 28| |#import "FBSDKAEMReporter.h" 29| |#import "FBSDKAccessToken.h" 30| |#import "FBSDKAppEventsConfiguration.h" 31| |#import "FBSDKAppEventsConfigurationProviding.h" 32| |#import "FBSDKAppEventsDeviceInfo.h" 33| |#import "FBSDKAppEventsParameterProcessing.h" 34| |#import "FBSDKAppEventsState.h" 35| |#import "FBSDKAppEventsStatePersisting.h" 36| |#import "FBSDKAppEventsStateProviding.h" 37| |#import "FBSDKAppEventsUtility.h" 38| |#import "FBSDKAtePublisherCreating.h" 39| |#import "FBSDKAtePublishing.h" 40| |#import "FBSDKCodelessIndexer.h" 41| |#import "FBSDKConstants.h" 42| |#import "FBSDKCoreKitBasicsImport.h" 43| |#import "FBSDKDataPersisting.h" 44| |#import "FBSDKDynamicFrameworkLoader.h" 45| |#import "FBSDKError.h" 46| |#import "FBSDKEventsProcessing.h" 47| |#import "FBSDKFeatureChecking.h" 48| |#import "FBSDKGateKeeperManaging.h" 49| |#import "FBSDKGraphRequestProtocol.h" 50| |#import "FBSDKGraphRequestProviding.h" 51| |#import "FBSDKInternalUtility.h" 52| |#import "FBSDKLogger.h" 53| |#import "FBSDKLogging.h" 54| |#import "FBSDKMetadataIndexing.h" 55| |#import "FBSDKPaymentObserving.h" 56| |#import "FBSDKSKAdNetworkReporter.h" 57| |#import "FBSDKServerConfiguration.h" 58| |#import "FBSDKServerConfigurationProviding.h" 59| |#import "FBSDKSettingsProtocol.h" 60| |#import "FBSDKSwizzling.h" 61| |#import "FBSDKTimeSpentRecordingCreating.h" 62| |#import "FBSDKUtility.h" 63| | 64| |#if !TARGET_OS_TV 65| | 66| | #import "FBSDKEventBindingManager.h" 67| | #import "FBSDKEventProcessing.h" 68| | #import "FBSDKHybridAppEventsScriptMessageHandler.h" 69| | #import "FBSDKIntegrityParametersProcessorProvider.h" 70| | 71| |#endif 72| | 73| |// 74| |// Public event names 75| |// 76| | 77| |// General purpose 78| |FBSDKAppEventName FBSDKAppEventNameCompletedRegistration = @"fb_mobile_complete_registration"; 79| |FBSDKAppEventName FBSDKAppEventNameViewedContent = @"fb_mobile_content_view"; 80| |FBSDKAppEventName FBSDKAppEventNameSearched = @"fb_mobile_search"; 81| |FBSDKAppEventName FBSDKAppEventNameRated = @"fb_mobile_rate"; 82| |FBSDKAppEventName FBSDKAppEventNameCompletedTutorial = @"fb_mobile_tutorial_completion"; 83| |FBSDKAppEventName FBSDKAppEventNameContact = @"Contact"; 84| |FBSDKAppEventName FBSDKAppEventNameCustomizeProduct = @"CustomizeProduct"; 85| |FBSDKAppEventName FBSDKAppEventNameDonate = @"Donate"; 86| |FBSDKAppEventName FBSDKAppEventNameFindLocation = @"FindLocation"; 87| |FBSDKAppEventName FBSDKAppEventNameSchedule = @"Schedule"; 88| |FBSDKAppEventName FBSDKAppEventNameStartTrial = @"StartTrial"; 89| |FBSDKAppEventName FBSDKAppEventNameSubmitApplication = @"SubmitApplication"; 90| |FBSDKAppEventName FBSDKAppEventNameSubscribe = @"Subscribe"; 91| |FBSDKAppEventName FBSDKAppEventNameSubscriptionHeartbeat = @"SubscriptionHeartbeat"; 92| |FBSDKAppEventName FBSDKAppEventNameAdImpression = @"AdImpression"; 93| |FBSDKAppEventName FBSDKAppEventNameAdClick = @"AdClick"; 94| | 95| |// Ecommerce related 96| |FBSDKAppEventName FBSDKAppEventNameAddedToCart = @"fb_mobile_add_to_cart"; 97| |FBSDKAppEventName FBSDKAppEventNameAddedToWishlist = @"fb_mobile_add_to_wishlist"; 98| |FBSDKAppEventName FBSDKAppEventNameInitiatedCheckout = @"fb_mobile_initiated_checkout"; 99| |FBSDKAppEventName FBSDKAppEventNameAddedPaymentInfo = @"fb_mobile_add_payment_info"; 100| |FBSDKAppEventName FBSDKAppEventNameProductCatalogUpdate = @"fb_mobile_catalog_update"; 101| |FBSDKAppEventName FBSDKAppEventNamePurchased = @"fb_mobile_purchase"; 102| | 103| |// Gaming related 104| |FBSDKAppEventName FBSDKAppEventNameAchievedLevel = @"fb_mobile_level_achieved"; 105| |FBSDKAppEventName FBSDKAppEventNameUnlockedAchievement = @"fb_mobile_achievement_unlocked"; 106| |FBSDKAppEventName FBSDKAppEventNameSpentCredits = @"fb_mobile_spent_credits"; 107| | 108| |// 109| |// Public event parameter names 110| |// 111| | 112| |FBSDKAppEventParameterName FBSDKAppEventParameterNameCurrency = @"fb_currency"; 113| |FBSDKAppEventParameterName FBSDKAppEventParameterNameRegistrationMethod = @"fb_registration_method"; 114| |FBSDKAppEventParameterName FBSDKAppEventParameterNameContentType = @"fb_content_type"; 115| |FBSDKAppEventParameterName FBSDKAppEventParameterNameContent = @"fb_content"; 116| |FBSDKAppEventParameterName FBSDKAppEventParameterNameContentID = @"fb_content_id"; 117| |FBSDKAppEventParameterName FBSDKAppEventParameterNameSearchString = @"fb_search_string"; 118| |FBSDKAppEventParameterName FBSDKAppEventParameterNameSuccess = @"fb_success"; 119| |FBSDKAppEventParameterName FBSDKAppEventParameterNameMaxRatingValue = @"fb_max_rating_value"; 120| |FBSDKAppEventParameterName FBSDKAppEventParameterNamePaymentInfoAvailable = @"fb_payment_info_available"; 121| |FBSDKAppEventParameterName FBSDKAppEventParameterNameNumItems = @"fb_num_items"; 122| |FBSDKAppEventParameterName FBSDKAppEventParameterNameLevel = @"fb_level"; 123| |FBSDKAppEventParameterName FBSDKAppEventParameterNameDescription = @"fb_description"; 124| |FBSDKAppEventParameterName FBSDKAppEventParameterNameAdType = @"ad_type"; 125| |FBSDKAppEventParameterName FBSDKAppEventParameterNameOrderID = @"fb_order_id"; 126| | 127| |// 128| |// Public event parameter names for DPA Catalog 129| |// 130| | 131| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel0 = @"fb_product_custom_label_0"; 132| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel1 = @"fb_product_custom_label_1"; 133| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel2 = @"fb_product_custom_label_2"; 134| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel3 = @"fb_product_custom_label_3"; 135| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel4 = @"fb_product_custom_label_4"; 136| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCategory = @"fb_product_category"; 137| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSUrl = @"fb_product_applink_ios_url"; 138| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSAppStoreID = @"fb_product_applink_ios_app_store_id"; 139| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSAppName = @"fb_product_applink_ios_app_name"; 140| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneUrl = @"fb_product_applink_iphone_url"; 141| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneAppStoreID = @"fb_product_applink_iphone_app_store_id"; 142| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneAppName = @"fb_product_applink_iphone_app_name"; 143| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadUrl = @"fb_product_applink_ipad_url"; 144| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadAppStoreID = @"fb_product_applink_ipad_app_store_id"; 145| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadAppName = @"fb_product_applink_ipad_app_name"; 146| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidUrl = @"fb_product_applink_android_url"; 147| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidPackage = @"fb_product_applink_android_package"; 148| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidAppName = @"fb_product_applink_android_app_name"; 149| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneUrl = @"fb_product_applink_windows_phone_url"; 150| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneAppID = @"fb_product_applink_windows_phone_app_id"; 151| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneAppName = @"fb_product_applink_windows_phone_app_name"; 152| | 153| |// 154| |// Public event parameter values 155| |// 156| | 157| |FBSDKAppEventParameterValue FBSDKAppEventParameterValueNo = @"0"; 158| |FBSDKAppEventParameterValue FBSDKAppEventParameterValueYes = @"1"; 159| | 160| |// 161| |// Event names internal to this file 162| |// 163| |FBSDKAppEventName FBSDKAppEventNameShareSheetLaunch = @"fb_share_sheet_launch"; 164| |FBSDKAppEventName FBSDKAppEventNameShareSheetDismiss = @"fb_share_sheet_dismiss"; 165| |FBSDKAppEventName FBSDKAppEventNameShareTrayDidLaunch = @"fb_share_tray_did_launch"; 166| |FBSDKAppEventName FBSDKAppEventNameShareTrayDidSelectActivity = @"fb_share_tray_did_select_activity"; 167| |FBSDKAppEventName FBSDKAppEventNamePermissionsUILaunch = @"fb_permissions_ui_launch"; 168| |FBSDKAppEventName FBSDKAppEventNamePermissionsUIDismiss = @"fb_permissions_ui_dismiss"; 169| |FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentShareDialog = @"fb_dialogs_present_share"; 170| |FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentShareDialogPhoto = @"fb_dialogs_present_share_photo"; 171| |FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentShareDialogOG = @"fb_dialogs_present_share_og"; 172| |FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentLikeDialogOG = @"fb_dialogs_present_like_og"; 173| |FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentMessageDialog = @"fb_dialogs_present_message"; 174| |FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentMessageDialogPhoto = @"fb_dialogs_present_message_photo"; 175| | 176| |FBSDKAppEventName FBSDKAppEventNameFBSDKLikeButtonImpression = @"fb_like_button_impression"; 177| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingButtonImpression = @"fb_live_streaming_button_impression"; 178| | 179| |FBSDKAppEventName FBSDKAppEventNameFBSDKLikeButtonDidTap = @"fb_like_button_did_tap"; 180| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingButtonDidTap = @"fb_live_streaming_button_did_tap"; 181| | 182| |FBSDKAppEventName FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult = @"fb_app_invite_dialog_share_result"; 183| | 184| |FBSDKAppEventName FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow = @"fb_app_invite_share_show"; 185| | 186| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingStart = @"fb_sdk_live_streaming_start"; 187| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingStop = @"fb_sdk_live_streaming_stop"; 188| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingPause = @"fb_sdk_live_streaming_pause"; 189| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingResume = @"fb_sdk_live_streaming_resume"; 190| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingError = @"fb_sdk_live_streaming_error"; 191| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingUpdateStatus = @"fb_sdk_live_streaming_update_status"; 192| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingVideoID = @"fb_sdk_live_streaming_video_id"; 193| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingMic = @"fb_sdk_live_streaming_mic"; 194| |FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingCamera = @"fb_sdk_live_streaming_camera"; 195| | 196| |// Event Parameters internal to this file 197| |NSString *const FBSDKAppEventParameterShareTrayActivityName = @"fb_share_tray_activity"; 198| |NSString *const FBSDKAppEventParameterShareTrayResult = @"fb_share_tray_result"; 199| |NSString *const FBSDKAppEventParameterLogTime = @"_logTime"; 200| |NSString *const FBSDKAppEventParameterEventName = @"_eventName"; 201| |NSString *const FBSDKAppEventParameterImplicitlyLogged = @"_implicitlyLogged"; 202| |NSString *const FBSDKAppEventParameterInBackground = @"_inBackground"; 203| | 204| |NSString *const FBSDKAppEventParameterLiveStreamingPrevStatus = @"live_streaming_prev_status"; 205| |NSString *const FBSDKAppEventParameterLiveStreamingStatus = @"live_streaming_status"; 206| |NSString *const FBSDKAppEventParameterLiveStreamingError = @"live_streaming_error"; 207| |NSString *const FBSDKAppEventParameterLiveStreamingVideoID = @"live_streaming_video_id"; 208| |NSString *const FBSDKAppEventParameterLiveStreamingMicEnabled = @"live_streaming_mic_enabled"; 209| |NSString *const FBSDKAppEventParameterLiveStreamingCameraEnabled = @"live_streaming_camera_enabled"; 210| | 211| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductItemID = @"fb_product_item_id"; 212| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAvailability = @"fb_product_availability"; 213| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCondition = @"fb_product_condition"; 214| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductDescription = @"fb_product_description"; 215| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductImageLink = @"fb_product_image_link"; 216| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductLink = @"fb_product_link"; 217| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductTitle = @"fb_product_title"; 218| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductGTIN = @"fb_product_gtin"; 219| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductMPN = @"fb_product_mpn"; 220| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductBrand = @"fb_product_brand"; 221| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductPriceAmount = @"fb_product_price_amount"; 222| |FBSDKAppEventParameterProduct FBSDKAppEventParameterProductPriceCurrency = @"fb_product_price_currency"; 223| | 224| |// Event parameter values internal to this file 225| | 226| |NSString *const FBSDKGateKeeperAppEventsKillSwitch = @"app_events_killswitch"; 227| | 228| |#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 229| | 230| |NSNotificationName const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBSDKAppEventsLoggingResultNotification"; 231| | 232| |#else 233| | 234| |NSString *const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBSDKAppEventsLoggingResultNotification"; 235| | 236| |#endif 237| | 238| |NSString *const FBSDKAppEventsOverrideAppIDBundleKey = @"FacebookLoggingOverrideAppID"; 239| | 240| |// 241| |// Push Notifications 242| |// 243| |// Activities Endpoint Parameter 244| |static NSString *const FBSDKActivitesParameterPushDeviceToken = @"device_token"; 245| |// Event Names 246| |static FBSDKAppEventName FBSDKAppEventNamePushTokenObtained = @"fb_mobile_obtain_push_token"; 247| |static FBSDKAppEventName FBSDKAppEventNamePushOpened = @"fb_mobile_push_opened"; 248| |// Event Parameter 249| |static NSString *const FBSDKAppEventParameterPushCampaign = @"fb_push_campaign"; 250| |static NSString *const FBSDKAppEventParameterPushAction = @"fb_push_action"; 251| |// Payload Keys 252| |static NSString *const FBSDKAppEventsPushPayloadKey = @"fb_push_payload"; 253| |static NSString *const FBSDKAppEventsPushPayloadCampaignKey = @"campaign"; 254| | 255| |// 256| |// Augmentation of web browser constants 257| |// 258| |NSString *const FBSDKAppEventsWKWebViewMessagesPixelIDKey = @"pixelID"; 259| |NSString *const FBSDKAppEventsWKWebViewMessagesHandlerKey = @"fbmqHandler"; 260| |NSString *const FBSDKAppEventsWKWebViewMessagesEventKey = @"event"; 261| |NSString *const FBSDKAppEventsWKWebViewMessagesParamsKey = @"params"; 262| |NSString *const FBSDKAPPEventsWKWebViewMessagesProtocolKey = @"fbmq-0.1"; 263| | 264| 0|#define NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER 100 265| 0|#define FLUSH_PERIOD_IN_SECONDS 15 266| 0|#define USER_ID_USER_DEFAULTS_KEY @"com.facebook.sdk.appevents.userid" 267| | 268| 0|#define FBUnityUtilityClassName "FBUnityUtility" 269| 0|#define FBUnityUtilityUpdateBindingsSelector @"triggerUpdateBindings:" 270| | 271| |static NSString *g_overrideAppID = nil; 272| |static BOOL g_explicitEventsLoggedYet; 273| |static Class g_gateKeeperManager; 274| |static Class g_appEventsConfigurationProvider; 275| |static Class g_serverConfigurationProvider; 276| |static id g_graphRequestProvider; 277| |static id g_featureChecker; 278| |static Class g_logger; 279| |static id g_settings; 280| |static id g_paymentObserver; 281| |static id g_appEventsStateStore; 282| |static id g_eventDeactivationParameterProcessor; 283| |static id g_restrictiveDataFilterParameterProcessor; 284| | 285| |#if !TARGET_OS_TV 286| |static id g_onDeviceMLModelManager = nil; 287| |static id g_metadataIndexer = nil; 288| |#endif 289| | 290| |@interface FBSDKAppEvents () 291| | 292| |@property (nullable, nonatomic) id store; 293| |@property (nonatomic, assign) FBSDKAppEventsFlushBehavior flushBehavior; 294| |@property (nonatomic) UIApplicationState applicationState; 295| |@property (nonatomic, copy) NSString *pushNotificationsDeviceTokenString; 296| |@property (nonatomic, strong) dispatch_source_t flushTimer; 297| |@property (nonatomic, copy) NSString *userID; 298| |@property (nonatomic, strong) id atePublisher; 299| |@property (nullable, nonatomic) Class swizzler; 300| |@property (nullable, nonatomic) id timeSpentRecorder; 301| |@property (nonatomic, strong) id appEventsStateProvider; 302| |@property (nonatomic) BOOL isConfigured; 303| | 304| |@property (nonatomic, assign) BOOL disableTimer; // for testing only. 305| | 306| |@end 307| | 308| |@implementation FBSDKAppEvents 309| |{ 310| | FBSDKServerConfiguration *_serverConfiguration; 311| | FBSDKAppEventsState *_appEventsState; 312| |#if !TARGET_OS_TV 313| | FBSDKEventBindingManager *_eventBindingManager; 314| |#endif 315| | BOOL _isUnityInit; 316| |} 317| | 318| |#pragma mark - Object Lifecycle 319| | 320| |+ (void)initialize 321| 0|{ 322| 0| if (self == [FBSDKAppEvents class]) { 323| 0| g_overrideAppID = [[[NSBundle mainBundle] objectForInfoDictionaryKey:FBSDKAppEventsOverrideAppIDBundleKey] copy]; 324| 0| dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) { 325| 0| [FBSDKBasicUtility anonymousID]; 326| 0| }); 327| 0| } 328| 0|} 329| | 330| |- (instancetype)init 331| 0|{ 332| 0| return [self initWithFlushBehavior:FBSDKAppEventsFlushBehaviorAuto 333| 0| flushPeriodInSeconds:FLUSH_PERIOD_IN_SECONDS]; 334| 0|} 335| | 336| |- (instancetype)initWithFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior 337| | flushPeriodInSeconds:(int)flushPeriodInSeconds 338| 0|{ 339| 0| self = [super init]; 340| 0| if (self) { 341| 0| _flushBehavior = flushBehavior; 342| | 343| 0| __weak FBSDKAppEvents *weakSelf = self; 344| 0| self.flushTimer = [FBSDKUtility startGCDTimerWithInterval:flushPeriodInSeconds 345| 0| block:^{ 346| 0| [weakSelf flushTimerFired:nil]; 347| 0| }]; 348| | 349| 0| self.applicationState = UIApplicationStateInactive; 350| 0| } 351| | 352| 0| return self; 353| 0|} 354| | 355| |- (void)startObservingApplicationLifecycleNotifications 356| 0|{ 357| 0| [[NSNotificationCenter defaultCenter] 358| 0| addObserver:self 359| 0| selector:@selector(applicationMovingFromActiveStateOrTerminating) 360| 0| name:UIApplicationWillResignActiveNotification 361| 0| object:NULL]; 362| | 363| 0| [[NSNotificationCenter defaultCenter] 364| 0| addObserver:self 365| 0| selector:@selector(applicationMovingFromActiveStateOrTerminating) 366| 0| name:UIApplicationWillTerminateNotification 367| 0| object:NULL]; 368| | 369| 0| [[NSNotificationCenter defaultCenter] 370| 0| addObserver:self 371| 0| selector:@selector(applicationDidBecomeActive) 372| 0| name:UIApplicationDidBecomeActiveNotification 373| 0| object:NULL]; 374| 0|} 375| | 376| |- (void)dealloc 377| 0|{ 378| 0| [[NSNotificationCenter defaultCenter] removeObserver:self]; 379| 0| [FBSDKUtility stopGCDTimer:self.flushTimer]; 380| 0|} 381| | 382| |#pragma mark - Public Methods 383| | 384| |+ (void)logEvent:(FBSDKAppEventName)eventName 385| 0|{ 386| 0| [self.singleton logEvent:eventName]; 387| 0|} 388| | 389| |- (void)logEvent:(FBSDKAppEventName)eventName 390| 0|{ 391| 0| [self logEvent:eventName 392| 0| parameters:@{}]; 393| 0|} 394| | 395| |+ (void)logEvent:(FBSDKAppEventName)eventName 396| | valueToSum:(double)valueToSum 397| 0|{ 398| 0| [self.singleton logEvent:eventName 399| 0| valueToSum:valueToSum]; 400| 0|} 401| | 402| |- (void)logEvent:(FBSDKAppEventName)eventName 403| | valueToSum:(double)valueToSum 404| 0|{ 405| 0| [self logEvent:eventName 406| 0| valueToSum:valueToSum 407| 0| parameters:@{}]; 408| 0|} 409| | 410| |+ (void)logEvent:(FBSDKAppEventName)eventName 411| | parameters:(NSDictionary *)parameters 412| 0|{ 413| 0| [self.singleton logEvent:eventName 414| 0| parameters:parameters]; 415| 0|} 416| | 417| |- (void)logEvent:(NSString *)eventName 418| | parameters:(NSDictionary *)parameters 419| 0|{ 420| 0| [FBSDKAppEvents logEvent:eventName 421| 0| valueToSum:nil 422| 0| parameters:parameters 423| 0| accessToken:nil]; 424| 0|} 425| | 426| |+ (void)logEvent:(FBSDKAppEventName)eventName 427| | valueToSum:(double)valueToSum 428| | parameters:(NSDictionary *)parameters 429| 0|{ 430| 0| [self.singleton logEvent:eventName 431| 0| valueToSum:valueToSum 432| 0| parameters:parameters]; 433| 0|} 434| | 435| |- (void)logEvent:(FBSDKAppEventName)eventName 436| | valueToSum:(double)valueToSum 437| | parameters:(NSDictionary *)parameters 438| 0|{ 439| 0| [FBSDKAppEvents logEvent:eventName 440| 0| valueToSum:@(valueToSum) 441| 0| parameters:parameters 442| 0| accessToken:nil]; 443| 0|} 444| | 445| |+ (void)logEvent:(FBSDKAppEventName)eventName 446| | valueToSum:(NSNumber *)valueToSum 447| | parameters:(NSDictionary *)parameters 448| | accessToken:(FBSDKAccessToken *)accessToken 449| 0|{ 450| 0| [self.singleton logEvent:eventName 451| 0| valueToSum:valueToSum 452| 0| parameters:parameters 453| 0| accessToken:accessToken]; 454| 0|} 455| | 456| |- (void)logEvent:(FBSDKAppEventName)eventName 457| | valueToSum:(NSNumber *)valueToSum 458| | parameters:(NSDictionary *)parameters 459| | accessToken:(FBSDKAccessToken *)accessToken 460| 0|{ 461| 0| [self instanceLogEvent:eventName 462| 0| valueToSum:valueToSum 463| 0| parameters:parameters 464| 0| isImplicitlyLogged:[parameters[FBSDKAppEventParameterImplicitlyLogged] boolValue] 465| 0| accessToken:accessToken]; 466| 0|} 467| | 468| |+ (void)logPurchase:(double)purchaseAmount 469| | currency:(NSString *)currency 470| 0|{ 471| 0| [FBSDKAppEvents logPurchase:purchaseAmount 472| 0| currency:currency 473| 0| parameters:@{}]; 474| 0|} 475| | 476| |+ (void)logPurchase:(double)purchaseAmount 477| | currency:(NSString *)currency 478| | parameters:(NSDictionary *)parameters 479| 0|{ 480| 0| [FBSDKAppEvents logPurchase:purchaseAmount 481| 0| currency:currency 482| 0| parameters:parameters 483| 0| accessToken:nil]; 484| 0|} 485| | 486| |+ (void)logPurchase:(double)purchaseAmount 487| | currency:(NSString *)currency 488| | parameters:(NSDictionary *)parameters 489| | accessToken:(FBSDKAccessToken *)accessToken 490| 0|{ 491| 0| [self.singleton validateConfiguration]; 492| | 493| | // A purchase event is just a regular logged event with a given event name 494| | // and treating the currency value as going into the parameters dictionary. 495| 0| NSDictionary *newParameters; 496| 0| if (!parameters) { 497| 0| newParameters = @{ FBSDKAppEventParameterNameCurrency : currency }; 498| 0| } else { 499| 0| newParameters = [NSMutableDictionary dictionaryWithDictionary:parameters]; 500| 0| [newParameters setValue:currency forKey:FBSDKAppEventParameterNameCurrency]; 501| 0| } 502| | 503| 0| [FBSDKAppEvents logEvent:FBSDKAppEventNamePurchased 504| 0| valueToSum:@(purchaseAmount) 505| 0| parameters:newParameters 506| 0| accessToken:accessToken]; 507| | 508| | // Unless the behavior is set to only allow explicit flushing, we go ahead and flush, since purchase events 509| | // are relatively rare and relatively high value and worth getting across on wire right away. 510| 0| if ([FBSDKAppEvents flushBehavior] != FBSDKAppEventsFlushBehaviorExplicitOnly) { 511| 0| [[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent]; 512| 0| } 513| 0|} 514| | 515| |/* 516| | * Push Notifications Logging 517| | */ 518| | 519| |+ (void)logPushNotificationOpen:(NSDictionary *)payload 520| 0|{ 521| 0| [self logPushNotificationOpen:payload action:@""]; 522| 0|} 523| | 524| |+ (void)logPushNotificationOpen:(NSDictionary *)payload action:(NSString *)action 525| 0|{ 526| 0| [self.singleton validateConfiguration]; 527| | 528| 0| NSDictionary *facebookPayload = payload[FBSDKAppEventsPushPayloadKey]; 529| 0| if (!facebookPayload) { 530| 0| return; 531| 0| } 532| 0| NSString *campaign = facebookPayload[FBSDKAppEventsPushPayloadCampaignKey]; 533| 0| if (campaign.length == 0) { 534| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors 535| 0| logEntry:@"Malformed payload specified for logging a push notification open."]; 536| 0| return; 537| 0| } 538| | 539| 0| NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObject:campaign forKey:FBSDKAppEventParameterPushCampaign]; 540| 0| if (action && action.length > 0) { 541| 0| [FBSDKTypeUtility dictionary:parameters setObject:action forKey:FBSDKAppEventParameterPushAction]; 542| 0| } 543| 0| [self logEvent:FBSDKAppEventNamePushOpened parameters:parameters]; 544| 0|} 545| | 546| |/* 547| | * Uploads product catalog product item as an app event 548| | */ 549| |+ (void)logProductItem:(NSString *)itemID 550| | availability:(FBSDKProductAvailability)availability 551| | condition:(FBSDKProductCondition)condition 552| | description:(NSString *)description 553| | imageLink:(NSString *)imageLink 554| | link:(NSString *)link 555| | title:(NSString *)title 556| | priceAmount:(double)priceAmount 557| | currency:(NSString *)currency 558| | gtin:(NSString *)gtin 559| | mpn:(NSString *)mpn 560| | brand:(NSString *)brand 561| | parameters:(NSDictionary *)parameters 562| 0|{ 563| 0| [self.singleton validateConfiguration]; 564| | 565| 0| if (itemID == nil) { 566| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors 567| 0| logEntry:@"itemID cannot be null"]; 568| 0| return; 569| 0| } else if (description == nil) { 570| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors 571| 0| logEntry:@"description cannot be null"]; 572| 0| return; 573| 0| } else if (imageLink == nil) { 574| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors 575| 0| logEntry:@"imageLink cannot be null"]; 576| 0| return; 577| 0| } else if (link == nil) { 578| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors 579| 0| logEntry:@"link cannot be null"]; 580| 0| return; 581| 0| } else if (title == nil) { 582| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors 583| 0| logEntry:@"title cannot be null"]; 584| 0| return; 585| 0| } else if (currency == nil) { 586| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors 587| 0| logEntry:@"currency cannot be null"]; 588| 0| return; 589| 0| } else if (gtin == nil && mpn == nil && brand == nil) { 590| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors 591| 0| logEntry:@"Either gtin, mpn or brand is required"]; 592| 0| return; 593| 0| } 594| | 595| 0| NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 596| 0| if (nil != parameters) { 597| 0| [dict setValuesForKeysWithDictionary:parameters]; 598| 0| } 599| | 600| 0| [FBSDKTypeUtility dictionary:dict setObject:itemID forKey:FBSDKAppEventParameterProductItemID]; 601| | 602| 0| NSString *avail = nil; 603| 0| switch (availability) { 604| 0| case FBSDKProductAvailabilityInStock: 605| 0| avail = @"IN_STOCK"; break; 606| 0| case FBSDKProductAvailabilityOutOfStock: 607| 0| avail = @"OUT_OF_STOCK"; break; 608| 0| case FBSDKProductAvailabilityPreOrder: 609| 0| avail = @"PREORDER"; break; 610| 0| case FBSDKProductAvailabilityAvailableForOrder: 611| 0| avail = @"AVALIABLE_FOR_ORDER"; break; 612| 0| case FBSDKProductAvailabilityDiscontinued: 613| 0| avail = @"DISCONTINUED"; break; 614| 0| } 615| 0| if (avail) { 616| 0| [FBSDKTypeUtility dictionary:dict setObject:avail forKey:FBSDKAppEventParameterProductAvailability]; 617| 0| } 618| | 619| 0| NSString *cond = nil; 620| 0| switch (condition) { 621| 0| case FBSDKProductConditionNew: 622| 0| cond = @"NEW"; break; 623| 0| case FBSDKProductConditionRefurbished: 624| 0| cond = @"REFURBISHED"; break; 625| 0| case FBSDKProductConditionUsed: 626| 0| cond = @"USED"; break; 627| 0| } 628| 0| if (cond) { 629| 0| [FBSDKTypeUtility dictionary:dict setObject:cond forKey:FBSDKAppEventParameterProductCondition]; 630| 0| } 631| | 632| 0| [FBSDKTypeUtility dictionary:dict setObject:description forKey:FBSDKAppEventParameterProductDescription]; 633| 0| [FBSDKTypeUtility dictionary:dict setObject:imageLink forKey:FBSDKAppEventParameterProductImageLink]; 634| 0| [FBSDKTypeUtility dictionary:dict setObject:link forKey:FBSDKAppEventParameterProductLink]; 635| 0| [FBSDKTypeUtility dictionary:dict setObject:title forKey:FBSDKAppEventParameterProductTitle]; 636| 0| [FBSDKTypeUtility dictionary:dict setObject:[NSString stringWithFormat:@"%.3lf", priceAmount] forKey:FBSDKAppEventParameterProductPriceAmount]; 637| 0| [FBSDKTypeUtility dictionary:dict setObject:currency forKey:FBSDKAppEventParameterProductPriceCurrency]; 638| 0| if (gtin) { 639| 0| [FBSDKTypeUtility dictionary:dict setObject:gtin forKey:FBSDKAppEventParameterProductGTIN]; 640| 0| } 641| 0| if (mpn) { 642| 0| [FBSDKTypeUtility dictionary:dict setObject:mpn forKey:FBSDKAppEventParameterProductMPN]; 643| 0| } 644| 0| if (brand) { 645| 0| [FBSDKTypeUtility dictionary:dict setObject:brand forKey:FBSDKAppEventParameterProductBrand]; 646| 0| } 647| | 648| 0| [FBSDKAppEvents logEvent:FBSDKAppEventNameProductCatalogUpdate 649| 0| parameters:dict]; 650| 0|} 651| | 652| |+ (void)activateApp 653| 0|{ 654| 0| [self.singleton activateApp]; 655| 0|} 656| | 657| |- (void)activateApp 658| 0|{ 659| 0| [self validateConfiguration]; 660| | 661| 0| [FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self.class)]; 662| | 663| | // Fetch app settings and register for transaction notifications only if app supports implicit purchase 664| | // events 665| 0| [self publishInstall]; 666| 0| [self fetchServerConfiguration:NULL]; 667| | 668| | // Restore time spent data, indicating that we're being called from "activateApp", which will, 669| | // when appropriate, result in logging an "activated app" and "deactivated app" (for the 670| | // previous session) App Event. 671| 0| [self.timeSpentRecorder restore:YES]; 672| 0|} 673| | 674| |+ (void)setPushNotificationsDeviceToken:(NSData *)deviceToken 675| 0|{ 676| 0| [self.singleton validateConfiguration]; 677| | 678| 0| NSString *deviceTokenString = [FBSDKInternalUtility hexadecimalStringFromData:deviceToken]; 679| 0| [FBSDKAppEvents setPushNotificationsDeviceTokenString:deviceTokenString]; 680| 0|} 681| | 682| |+ (void)setPushNotificationsDeviceTokenString:(NSString *)deviceTokenString 683| 0|{ 684| 0| [self.singleton validateConfiguration]; 685| | 686| 0| if (deviceTokenString == nil) { 687| 0| [FBSDKAppEvents singleton].pushNotificationsDeviceTokenString = nil; 688| 0| return; 689| 0| } 690| | 691| 0| if (![deviceTokenString isEqualToString:([FBSDKAppEvents singleton].pushNotificationsDeviceTokenString)]) { 692| 0| [FBSDKAppEvents singleton].pushNotificationsDeviceTokenString = deviceTokenString; 693| | 694| 0| [FBSDKAppEvents logEvent:FBSDKAppEventNamePushTokenObtained]; 695| | 696| | // Unless the behavior is set to only allow explicit flushing, we go ahead and flush the event 697| 0| if ([FBSDKAppEvents flushBehavior] != FBSDKAppEventsFlushBehaviorExplicitOnly) { 698| 0| [[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent]; 699| 0| } 700| 0| } 701| 0|} 702| | 703| |+ (FBSDKAppEventsFlushBehavior)flushBehavior 704| 0|{ 705| 0| return [FBSDKAppEvents singleton].flushBehavior; 706| 0|} 707| | 708| |+ (void)setFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior 709| 0|{ 710| 0| [self.singleton validateConfiguration]; 711| | 712| 0| self.singleton.flushBehavior = flushBehavior; 713| 0|} 714| | 715| |+ (NSString *)loggingOverrideAppID 716| 0|{ 717| 0| return g_overrideAppID; 718| 0|} 719| | 720| |+ (void)setLoggingOverrideAppID:(NSString *)appID 721| 0|{ 722| 0| [self.singleton validateConfiguration]; 723| | 724| 0| if (![g_overrideAppID isEqualToString:appID]) { 725| 0| FBSDKConditionalLog( 726| 0| !g_explicitEventsLoggedYet, 727| 0| FBSDKLoggingBehaviorDeveloperErrors, 728| 0| @"[FBSDKAppEvents setLoggingOverrideAppID:] should only be called prior to any events being logged." 729| 0| ); 730| 0| g_overrideAppID = appID; 731| 0| } 732| 0|} 733| | 734| |+ (void)flush 735| 0|{ 736| 0| [self.singleton validateConfiguration]; 737| 0| [self.singleton flushForReason:FBSDKAppEventsFlushReasonExplicit]; 738| 0|} 739| | 740| |+ (void)setUserID:(NSString *)userID 741| 0|{ 742| 0| self.singleton.userID = userID; 743| 0|} 744| | 745| |- (void)setUserID:(NSString *)userID 746| 0|{ 747| 0| [self validateConfiguration]; 748| 0| _userID = [userID copy]; 749| 0| [self.store setObject:userID forKey:USER_ID_USER_DEFAULTS_KEY]; 750| 0|} 751| | 752| |+ (void)clearUserID 753| 0|{ 754| 0| [self.singleton clearUserID]; 755| 0|} 756| | 757| |- (void)clearUserID 758| 0|{ 759| 0| [self validateConfiguration]; 760| | 761| 0| self.userID = nil; 762| 0|} 763| | 764| |+ (NSString *)userID 765| 0|{ 766| 0| [self.singleton validateConfiguration]; 767| | 768| 0| return self.singleton.userID; 769| 0|} 770| | 771| |+ (void)setUserEmail:(nullable NSString *)email 772| | firstName:(nullable NSString *)firstName 773| | lastName:(nullable NSString *)lastName 774| | phone:(nullable NSString *)phone 775| | dateOfBirth:(nullable NSString *)dateOfBirth 776| | gender:(nullable NSString *)gender 777| | city:(nullable NSString *)city 778| | state:(nullable NSString *)state 779| | zip:(nullable NSString *)zip 780| | country:(nullable NSString *)country 781| 0|{ 782| 0| [FBSDKUserDataStore setUserEmail:email 783| 0| firstName:firstName 784| 0| lastName:lastName 785| 0| phone:phone 786| 0| dateOfBirth:dateOfBirth 787| 0| gender:gender 788| 0| city:city 789| 0| state:state 790| 0| zip:zip 791| 0| country:country 792| 0| externalId:nil]; 793| 0|} 794| | 795| |+ (NSString *)getUserData 796| 0|{ 797| 0| return [FBSDKUserDataStore getUserData]; 798| 0|} 799| | 800| |+ (void)clearUserData 801| 0|{ 802| 0| [FBSDKUserDataStore clearUserData]; 803| 0|} 804| | 805| |+ (void)setUserData:(nullable NSString *)data 806| | forType:(FBSDKAppEventUserDataType)type 807| 0|{ 808| 0| [FBSDKUserDataStore setUserData:data forType:type]; 809| 0|} 810| | 811| |+ (void)clearUserDataForType:(FBSDKAppEventUserDataType)type 812| 0|{ 813| 0| [FBSDKUserDataStore clearUserDataForType:type]; 814| 0|} 815| | 816| |+ (NSString *)anonymousID 817| 0|{ 818| 0| return [FBSDKBasicUtility anonymousID]; 819| 0|} 820| | 821| |#if !TARGET_OS_TV 822| |+ (void)augmentHybridWKWebView:(WKWebView *)webView 823| 0|{ 824| 0| [self.singleton validateConfiguration]; 825| | 826| 0| if ([webView isKindOfClass:WKWebView.class]) { 827| 0| if (WKUserScript.class != nil) { 828| 0| WKUserContentController *controller = webView.configuration.userContentController; 829| 0| FBSDKHybridAppEventsScriptMessageHandler *scriptHandler = [FBSDKHybridAppEventsScriptMessageHandler new]; 830| 0| [controller addScriptMessageHandler:scriptHandler name:FBSDKAppEventsWKWebViewMessagesHandlerKey]; 831| | 832| 0| NSString *js = [NSString stringWithFormat:@"window.fbmq_%@={'sendEvent': function(pixel_id,event_name,custom_data){var msg={\"%@\":pixel_id, \"%@\":event_name,\"%@\":custom_data};window.webkit.messageHandlers[\"%@\"].postMessage(msg);}, 'getProtocol':function(){return \"%@\";}}", 833| 0| [[self singleton] appID], 834| 0| FBSDKAppEventsWKWebViewMessagesPixelIDKey, 835| 0| FBSDKAppEventsWKWebViewMessagesEventKey, 836| 0| FBSDKAppEventsWKWebViewMessagesParamsKey, 837| 0| FBSDKAppEventsWKWebViewMessagesHandlerKey, 838| 0| FBSDKAPPEventsWKWebViewMessagesProtocolKey 839| 0| ]; 840| | 841| 0| [controller addUserScript:[[WKUserScript.class alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]]; 842| 0| } 843| 0| } else { 844| 0| [FBSDKAppEventsUtility logAndNotify:@"You must call augmentHybridWKWebView with WebKit linked to your project and a WKWebView instance"]; 845| 0| } 846| 0|} 847| | 848| |#endif 849| | 850| |+ (void)setIsUnityInit:(BOOL)isUnityInit 851| 0|{ 852| 0| [FBSDKAppEvents singleton]->_isUnityInit = isUnityInit; 853| 0|} 854| | 855| |#pragma clang diagnostic push 856| |#pragma clang diagnostic ignored "-Warc-performSelector-leaks" 857| |+ (void)sendEventBindingsToUnity 858| 0|{ 859| 0| [self.singleton validateConfiguration]; 860| | 861| | // Send event bindings to Unity only Unity is initialized 862| 0| if ([FBSDKAppEvents singleton]->_isUnityInit 863| 0| && [FBSDKAppEvents singleton]->_serverConfiguration 864| 0| && [FBSDKTypeUtility isValidJSONObject:[FBSDKAppEvents singleton]->_serverConfiguration.eventBindings] 865| 0| ) { 866| 0| NSData *jsonData = [FBSDKTypeUtility dataWithJSONObject:[FBSDKAppEvents singleton]->_serverConfiguration.eventBindings ?: @"" 867| 0| options:0 868| 0| error:nil]; 869| 0| NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 870| 0| Class classFBUnityUtility = objc_lookUpClass(FBUnityUtilityClassName); 871| 0| SEL updateBindingSelector = NSSelectorFromString(FBUnityUtilityUpdateBindingsSelector); 872| 0| if ([classFBUnityUtility respondsToSelector:updateBindingSelector]) { 873| 0| [classFBUnityUtility performSelector:updateBindingSelector withObject:jsonString]; 874| 0| } 875| 0| } 876| 0|} 877| | 878| |#pragma clang diagnostic pop 879| | 880| |#pragma mark - Internal Methods 881| | 882| |- (void) configureWithGateKeeperManager:(Class)gateKeeperManager 883| | appEventsConfigurationProvider:(Class)appEventsConfigurationProvider 884| | serverConfigurationProvider:(Class)serverConfigurationProvider 885| | graphRequestProvider:(id)provider 886| | featureChecker:(id)featureChecker 887| | store:(id)store 888| | logger:(Class)logger 889| | settings:(id)settings 890| | paymentObserver:(id)paymentObserver 891| | timeSpentRecorderFactory:(id)timeSpentRecorderFactory 892| | appEventsStateStore:(id)appEventsStateStore 893| | eventDeactivationParameterProcessor:(id)eventDeactivationParameterProcessor 894| | restrictiveDataFilterParameterProcessor:(id)restrictiveDataFilterParameterProcessor 895| | atePublisherFactory:(id)atePublisherFactory 896| | appEventsStateProvider:(id)appEventsStateProvider 897| | swizzler:(Class)swizzler 898| 0|{ 899| 0| [FBSDKAppEvents setAppEventsConfigurationProvider:appEventsConfigurationProvider]; 900| 0| [FBSDKAppEvents setServerConfigurationProvider:serverConfigurationProvider]; 901| 0| g_gateKeeperManager = gateKeeperManager; 902| 0| g_logger = logger; 903| 0| [FBSDKAppEvents setRequestProvider:provider]; 904| 0| [FBSDKAppEvents setFeatureChecker:featureChecker]; 905| 0| g_settings = settings; 906| 0| g_paymentObserver = paymentObserver; 907| 0| g_appEventsStateStore = appEventsStateStore; 908| 0| g_eventDeactivationParameterProcessor = eventDeactivationParameterProcessor; 909| 0| g_restrictiveDataFilterParameterProcessor = restrictiveDataFilterParameterProcessor; 910| 0| self.swizzler = swizzler; 911| 0| self.store = store; 912| 0| self.atePublisher = [atePublisherFactory createPublisherWithAppID:self.appID]; 913| 0| self.timeSpentRecorder = [timeSpentRecorderFactory createTimeSpentRecorder]; 914| 0| self.appEventsStateProvider = appEventsStateProvider; 915| | 916| 0| self.isConfigured = YES; 917| | 918| 0| self.userID = [store stringForKey:USER_ID_USER_DEFAULTS_KEY]; 919| 0|} 920| | 921| |+ (void)setFeatureChecker:(id)checker 922| 0|{ 923| 0| if (g_featureChecker != checker) { 924| 0| g_featureChecker = checker; 925| 0| } 926| 0|} 927| | 928| |+ (void)setRequestProvider:(id)provider 929| 0|{ 930| 0| if (g_graphRequestProvider != provider) { 931| 0| g_graphRequestProvider = provider; 932| 0| } 933| 0|} 934| | 935| |+ (void)setAppEventsConfigurationProvider:(Class)provider 936| 0|{ 937| 0| if (g_appEventsConfigurationProvider != provider) { 938| 0| g_appEventsConfigurationProvider = provider; 939| 0| } 940| 0|} 941| | 942| |+ (void)setServerConfigurationProvider:(Class)provider 943| 0|{ 944| 0| if (g_serverConfigurationProvider != provider) { 945| 0| g_serverConfigurationProvider = provider; 946| 0| } 947| 0|} 948| | 949| |#if !TARGET_OS_TV 950| | 951| |+ (void)configureNonTVComponentsWithOnDeviceMLModelManager:(id)modelManager 952| | metadataIndexer:(id)metadataIndexer 953| 0|{ 954| 0| g_onDeviceMLModelManager = modelManager; 955| 0| g_metadataIndexer = metadataIndexer; 956| 0|} 957| | 958| |#endif 959| | 960| |+ (void)logInternalEvent:(FBSDKAppEventName)eventName 961| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 962| 0|{ 963| 0| [self.singleton logInternalEvent:eventName 964| 0| isImplicitlyLogged:isImplicitlyLogged]; 965| 0|} 966| | 967| |- (void)logInternalEvent:(FBSDKAppEventName)eventName 968| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 969| 0|{ 970| 0| [self logInternalEvent:eventName 971| 0| parameters:@{} 972| 0| isImplicitlyLogged:isImplicitlyLogged]; 973| 0|} 974| | 975| |+ (void)logInternalEvent:(FBSDKAppEventName)eventName 976| | valueToSum:(double)valueToSum 977| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 978| 0|{ 979| 0| [self.singleton logInternalEvent:eventName 980| 0| valueToSum:valueToSum 981| 0| isImplicitlyLogged:isImplicitlyLogged]; 982| 0|} 983| | 984| |- (void)logInternalEvent:(FBSDKAppEventName)eventName 985| | valueToSum:(double)valueToSum 986| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 987| 0|{ 988| 0| [self logInternalEvent:eventName 989| 0| valueToSum:valueToSum 990| 0| parameters:@{} 991| 0| isImplicitlyLogged:isImplicitlyLogged]; 992| 0|} 993| | 994| |+ (void)logInternalEvent:(FBSDKAppEventName)eventName 995| | parameters:(NSDictionary *)parameters 996| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 997| 0|{ 998| 0| [self.singleton logInternalEvent:eventName 999| 0| parameters:parameters 1000| 0| isImplicitlyLogged:isImplicitlyLogged]; 1001| 0|} 1002| | 1003| |- (void)logInternalEvent:(FBSDKAppEventName)eventName 1004| | parameters:(NSDictionary *)parameters 1005| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 1006| 0|{ 1007| 0| [self logInternalEvent:eventName 1008| 0| valueToSum:nil 1009| 0| parameters:parameters 1010| 0| isImplicitlyLogged:isImplicitlyLogged 1011| 0| accessToken:nil]; 1012| 0|} 1013| | 1014| |+ (void)logInternalEvent:(FBSDKAppEventName)eventName 1015| | parameters:(NSDictionary *)parameters 1016| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 1017| | accessToken:(FBSDKAccessToken *)accessToken 1018| 0|{ 1019| 0| [self.singleton logInternalEvent:eventName 1020| 0| parameters:parameters 1021| 0| isImplicitlyLogged:isImplicitlyLogged 1022| 0| accessToken:accessToken]; 1023| 0|} 1024| | 1025| |- (void)logInternalEvent:(FBSDKAppEventName)eventName 1026| | parameters:(NSDictionary *)parameters 1027| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 1028| | accessToken:(FBSDKAccessToken *)accessToken 1029| 0|{ 1030| 0| [self logInternalEvent:eventName 1031| 0| valueToSum:nil 1032| 0| parameters:parameters 1033| 0| isImplicitlyLogged:isImplicitlyLogged 1034| 0| accessToken:accessToken]; 1035| 0|} 1036| | 1037| |+ (void)logInternalEvent:(FBSDKAppEventName)eventName 1038| | valueToSum:(double)valueToSum 1039| | parameters:(NSDictionary *)parameters 1040| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 1041| 0|{ 1042| 0| [self.singleton logInternalEvent:eventName 1043| 0| valueToSum:valueToSum 1044| 0| parameters:parameters 1045| 0| isImplicitlyLogged:isImplicitlyLogged]; 1046| 0|} 1047| | 1048| |- (void)logInternalEvent:(FBSDKAppEventName)eventName 1049| | valueToSum:(double)valueToSum 1050| | parameters:(NSDictionary *)parameters 1051| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 1052| 0|{ 1053| 0| [self logInternalEvent:eventName 1054| 0| valueToSum:@(valueToSum) 1055| 0| parameters:parameters 1056| 0| isImplicitlyLogged:isImplicitlyLogged 1057| 0| accessToken:nil]; 1058| 0|} 1059| | 1060| |+ (void)logInternalEvent:(NSString *)eventName 1061| | valueToSum:(NSNumber *)valueToSum 1062| | parameters:(NSDictionary *)parameters 1063| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 1064| | accessToken:(FBSDKAccessToken *)accessToken 1065| 0|{ 1066| 0| [self.singleton logInternalEvent:eventName 1067| 0| valueToSum:valueToSum 1068| 0| parameters:parameters 1069| 0| isImplicitlyLogged:isImplicitlyLogged 1070| 0| accessToken:accessToken]; 1071| 0|} 1072| | 1073| |- (void)logInternalEvent:(NSString *)eventName 1074| | valueToSum:(NSNumber *)valueToSum 1075| | parameters:(NSDictionary *)parameters 1076| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 1077| | accessToken:(FBSDKAccessToken *)accessToken 1078| 0|{ 1079| 0| if ([g_settings isAutoLogAppEventsEnabled]) { 1080| 0| [self instanceLogEvent:eventName 1081| 0| valueToSum:valueToSum 1082| 0| parameters:parameters 1083| 0| isImplicitlyLogged:isImplicitlyLogged 1084| 0| accessToken:accessToken]; 1085| 0| } 1086| 0|} 1087| | 1088| |+ (void)logImplicitEvent:(NSString *)eventName 1089| | valueToSum:(NSNumber *)valueToSum 1090| | parameters:(NSDictionary *)parameters 1091| | accessToken:(FBSDKAccessToken *)accessToken 1092| 0|{ 1093| 0| [self.singleton instanceLogEvent:eventName 1094| 0| valueToSum:valueToSum 1095| 0| parameters:parameters 1096| 0| isImplicitlyLogged:YES 1097| 0| accessToken:accessToken]; 1098| 0|} 1099| | 1100| |- (void)logImplicitEvent:(NSString *)eventName 1101| | valueToSum:(NSNumber *)valueToSum 1102| | parameters:(NSDictionary *)parameters 1103| | accessToken:(FBSDKAccessToken *)accessToken 1104| 0|{ 1105| 0| [self instanceLogEvent:eventName 1106| 0| valueToSum:valueToSum 1107| 0| parameters:parameters 1108| 0| isImplicitlyLogged:YES 1109| 0| accessToken:accessToken]; 1110| 0|} 1111| | 1112| |+ (FBSDKAppEvents *)singleton 1113| 0|{ 1114| 0| static dispatch_once_t onceToken; 1115| 0| static FBSDKAppEvents *shared = nil; 1116| 0| dispatch_once(&onceToken, ^{ 1117| 0| shared = [self new]; 1118| 0| }); 1119| 0| return shared; 1120| 0|} 1121| | 1122| |- (void)flushForReason:(FBSDKAppEventsFlushReason)flushReason 1123| 0|{ 1124| | // Always flush asynchronously, even on main thread, for two reasons: 1125| | // - most consistent code path for all threads. 1126| | // - allow locks being held by caller to be released prior to actual flushing work being done. 1127| 0| @synchronized(self) { 1128| 0| if (!_appEventsState) { 1129| 0| return; 1130| 0| } 1131| 0| FBSDKAppEventsState *copy = [_appEventsState copy]; 1132| 0| _appEventsState = [self.appEventsStateProvider createStateWithToken:copy.tokenString 1133| 0| appID:copy.appID]; 1134| 0| dispatch_async(dispatch_get_main_queue(), ^{ 1135| 0| [self flushOnMainQueue:copy forReason:flushReason]; 1136| 0| }); 1137| 0| } 1138| 0|} 1139| | 1140| |#pragma mark - Source Application Tracking 1141| | 1142| |- (void)setSourceApplication:(NSString *)sourceApplication openURL:(NSURL *)url 1143| 0|{ 1144| 0| [self.timeSpentRecorder setSourceApplication:sourceApplication openURL:url]; 1145| 0|} 1146| | 1147| |- (void)setSourceApplication:(NSString *)sourceApplication isFromAppLink:(BOOL)isFromAppLink 1148| 0|{ 1149| 0| [self.timeSpentRecorder setSourceApplication:sourceApplication isFromAppLink:isFromAppLink]; 1150| 0|} 1151| | 1152| |- (void)registerAutoResetSourceApplication 1153| 0|{ 1154| 0| [self.timeSpentRecorder registerAutoResetSourceApplication]; 1155| 0|} 1156| | 1157| |#pragma mark - Private Methods 1158| |- (NSString *)appID 1159| 0|{ 1160| 0| return [FBSDKAppEvents loggingOverrideAppID] ?: [g_settings appID]; 1161| 0|} 1162| | 1163| |- (void)publishInstall 1164| 0|{ 1165| 0| NSString *appID = [self appID]; 1166| 0| if (appID.length == 0) { 1167| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Missing [FBSDKAppEvents appID] for [FBSDKAppEvents publishInstall:]"]; 1168| 0| return; 1169| 0| } 1170| 0| NSString *lastAttributionPingString = [NSString stringWithFormat:@"com.facebook.sdk:lastAttributionPing%@", appID]; 1171| 0| if ([self.store objectForKey:lastAttributionPingString]) { 1172| 0| return; 1173| 0| } 1174| 0| [self fetchServerConfiguration:^{ 1175| 0| if ([FBSDKAppEventsUtility shouldDropAppEvent]) { 1176| 0| return; 1177| 0| } 1178| 0| NSMutableDictionary *params = [FBSDKAppEventsUtility activityParametersDictionaryForEvent:@"MOBILE_APP_INSTALL" 1179| 0| shouldAccessAdvertisingID:self->_serverConfiguration.isAdvertisingIDEnabled]; 1180| 0| [self appendInstallTimestamp:params]; 1181| 0| NSString *path = [NSString stringWithFormat:@"%@/activities", appID]; 1182| 0| id request = [g_graphRequestProvider createGraphRequestWithGraphPath:path 1183| 0| parameters:params 1184| 0| tokenString:nil 1185| 0| HTTPMethod:FBSDKHTTPMethodPOST 1186| 0| flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; 1187| 0| __block id weakStore = self.store; 1188| 0| [request startWithCompletion:^(id connection, id result, NSError *error) { 1189| 0| if (!error) { 1190| 0| [weakStore setObject:[NSDate date] forKey:lastAttributionPingString]; 1191| 0| NSString *lastInstallResponseKey = [NSString stringWithFormat:@"com.facebook.sdk:lastInstallResponse%@", appID]; 1192| 0| [weakStore setObject:result forKey:lastInstallResponseKey]; 1193| 0| } 1194| 0| }]; 1195| 0| }]; 1196| 0|} 1197| | 1198| |- (void)publishATE 1199| 0|{ 1200| 0| if (self.appID.length == 0) { 1201| 0| return; 1202| 0| } 1203| | 1204| 0|#if FBSDKTEST 1205| 0| [self.atePublisher publishATE]; 1206| |#else 1207| | __weak FBSDKAppEvents *weakSelf = self; 1208| | fb_dispatch_on_default_thread(^(void) { 1209| | [weakSelf.atePublisher publishATE]; 1210| | }); 1211| |#endif 1212| 0|} 1213| | 1214| |- (void)appendInstallTimestamp:(NSMutableDictionary *)parameters 1215| 0|{ 1216| 0| if (@available(iOS 14.0, *)) { 1217| 0| if ([g_settings isSetATETimeExceedsInstallTime]) { 1218| 0| NSDate *setAteTimestamp = g_settings.advertiserTrackingEnabledTimestamp; 1219| 0| [FBSDKTypeUtility dictionary:parameters setObject:@([FBSDKAppEventsUtility convertToUnixTime:setAteTimestamp]) forKey:@"install_timestamp"]; 1220| 0| } else { 1221| 0| NSDate *installTimestamp = g_settings.installTimestamp; 1222| 0| [FBSDKTypeUtility dictionary:parameters setObject:@([FBSDKAppEventsUtility convertToUnixTime:installTimestamp]) forKey:@"install_timestamp"]; 1223| 0| } 1224| 0| } 1225| 0|} 1226| | 1227| |#if !TARGET_OS_TV 1228| |- (void)enableCodelessEvents 1229| 0|{ 1230| 0| if (_serverConfiguration.isCodelessEventsEnabled) { 1231| 0| [FBSDKCodelessIndexer enable]; 1232| | 1233| 0| if (!_eventBindingManager) { 1234| 0| _eventBindingManager = [FBSDKEventBindingManager new]; 1235| 0| } 1236| | 1237| 0| if ([FBSDKInternalUtility isUnity]) { 1238| 0| [FBSDKAppEvents sendEventBindingsToUnity]; 1239| 0| } else { 1240| 0| FBSDKEventBindingManager *manager = [[FBSDKEventBindingManager alloc] initWithSwizzler:self.swizzler 1241| 0| eventLogger:self]; 1242| 0| [_eventBindingManager updateBindings:[manager parseArray:_serverConfiguration.eventBindings]]; 1243| 0| } 1244| 0| } 1245| 0|} 1246| | 1247| |#endif 1248| | 1249| |// app events can use a server configuration up to 24 hours old to minimize network traffic. 1250| |- (void)fetchServerConfiguration:(FBSDKCodeBlock)callback 1251| 0|{ 1252| 0| [g_appEventsConfigurationProvider loadAppEventsConfigurationWithBlock:^{ 1253| 0| [g_serverConfigurationProvider loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) { 1254| 0| self->_serverConfiguration = serverConfiguration; 1255| | 1256| 0| if ([g_settings isAutoLogAppEventsEnabled] && self->_serverConfiguration.implicitPurchaseLoggingEnabled) { 1257| 0| [g_paymentObserver startObservingTransactions]; 1258| 0| } else { 1259| 0| [g_paymentObserver stopObservingTransactions]; 1260| 0| } 1261| 0| [g_featureChecker checkFeature:FBSDKFeatureRestrictiveDataFiltering completionBlock:^(BOOL enabled) { 1262| 0| if (enabled) { 1263| 0| [g_restrictiveDataFilterParameterProcessor enable]; 1264| 0| } 1265| 0| }]; 1266| 0| [g_featureChecker checkFeature:FBSDKFeatureEventDeactivation completionBlock:^(BOOL enabled) { 1267| 0| if (enabled) { 1268| 0| [g_eventDeactivationParameterProcessor enable]; 1269| 0| } 1270| 0| }]; 1271| 0| if (@available(iOS 14.0, *)) { 1272| 0| __weak FBSDKAppEvents *weakSelf = self; 1273| 0| [g_featureChecker checkFeature:FBSDKFeatureATELogging completionBlock:^(BOOL enabled) { 1274| 0| if (enabled) { 1275| 0| [weakSelf publishATE]; 1276| 0| } 1277| 0| }]; 1278| 0| } 1279| 0| #if !TARGET_OS_TV 1280| 0| [g_featureChecker checkFeature:FBSDKFeatureCodelessEvents completionBlock:^(BOOL enabled) { 1281| 0| if (enabled) { 1282| 0| [self enableCodelessEvents]; 1283| 0| } 1284| 0| }]; 1285| 0| [g_featureChecker checkFeature:FBSDKFeatureAAM completionBlock:^(BOOL enabled) { 1286| 0| if (enabled) { 1287| 0| [g_metadataIndexer enable]; 1288| 0| } 1289| 0| }]; 1290| 0| [g_featureChecker checkFeature:FBSDKFeaturePrivacyProtection completionBlock:^(BOOL enabled) { 1291| 0| if (enabled) { 1292| 0| [g_onDeviceMLModelManager enable]; 1293| 0| } 1294| 0| }]; 1295| 0| if (@available(iOS 11.3, *)) { 1296| 0| if ([g_settings isSKAdNetworkReportEnabled]) { 1297| 0| [g_featureChecker checkFeature:FBSDKFeatureSKAdNetwork completionBlock:^(BOOL SKAdNetworkEnabled) { 1298| 0| if (SKAdNetworkEnabled) { 1299| 0| [SKAdNetwork registerAppForAdNetworkAttribution]; 1300| 0| [g_featureChecker checkFeature:FBSDKFeatureSKAdNetworkConversionValue completionBlock:^(BOOL SKAdNetworkConversionValueEnabled) { 1301| 0| if (SKAdNetworkConversionValueEnabled) { 1302| 0| [FBSDKSKAdNetworkReporter enable]; 1303| 0| } 1304| 0| }]; 1305| 0| } 1306| 0| }]; 1307| 0| } 1308| 0| } 1309| 0| if (@available(iOS 14.0, *)) { 1310| 0| [g_featureChecker checkFeature:FBSDKFeatureAEM completionBlock:^(BOOL AEMEnabled) { 1311| 0| if (AEMEnabled) { 1312| 0| [FBSDKAEMReporter enable]; 1313| 0| } 1314| 0| }]; 1315| 0| } 1316| 0| #endif 1317| 0| if (callback) { 1318| 0| callback(); 1319| 0| } 1320| 0| }]; 1321| 0| }]; 1322| 0|} 1323| | 1324| |#pragma clang diagnostic push 1325| |#pragma clang diagnostic ignored "-Wdeprecated-declarations" 1326| |- (void)instanceLogEvent:(FBSDKAppEventName)eventName 1327| | valueToSum:(NSNumber *)valueToSum 1328| | parameters:(NSDictionary *)parameters 1329| | isImplicitlyLogged:(BOOL)isImplicitlyLogged 1330| | accessToken:(FBSDKAccessToken *)accessToken 1331| 0|{ 1332| 0| [self validateConfiguration]; 1333| | 1334| | // Kill events if kill-switch is enabled 1335| 0| if (!g_gateKeeperManager) { 1336| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents 1337| 0| logEntry:@"FBSDKAppEvents: Cannot log app events before the SDK is initialized."]; 1338| 0| return; 1339| 0| } else if ([g_gateKeeperManager boolForKey:FBSDKGateKeeperAppEventsKillSwitch 1340| 0| defaultValue:NO]) { 1341| 0| NSString *message = [NSString stringWithFormat:@"FBSDKAppEvents: KillSwitch is enabled and fail to log app event: %@", eventName]; 1342| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents 1343| 0| logEntry:message]; 1344| 0| return; 1345| 0| } 1346| 0|#if !TARGET_OS_TV 1347| | // Update conversion value for SKAdNetwork if needed 1348| 0| [FBSDKSKAdNetworkReporter recordAndUpdateEvent:eventName currency:[FBSDKTypeUtility dictionary:parameters objectForKey:FBSDKAppEventParameterNameCurrency ofType:NSString.class] value:valueToSum]; 1349| | // Update conversion value for AEM if needed 1350| 0| [FBSDKAEMReporter recordAndUpdateEvent:eventName 1351| 0| currency:[FBSDKTypeUtility dictionary:parameters objectForKey:FBSDKAppEventParameterNameCurrency ofType:NSString.class] 1352| 0| value:valueToSum 1353| 0| parameters:parameters]; 1354| 0|#endif 1355| | 1356| 0| if ([FBSDKAppEventsUtility shouldDropAppEvent]) { 1357| 0| return; 1358| 0| } 1359| | 1360| 0| if (isImplicitlyLogged && _serverConfiguration && !_serverConfiguration.isImplicitLoggingSupported) { 1361| 0| return; 1362| 0| } 1363| | 1364| 0| if (!isImplicitlyLogged && !g_explicitEventsLoggedYet) { 1365| 0| g_explicitEventsLoggedYet = YES; 1366| 0| } 1367| 0| __block BOOL failed = ![FBSDKAppEventsUtility validateIdentifier:eventName]; 1368| | 1369| | // Make sure parameter dictionary is well formed. Log and exit if not. 1370| 0| [FBSDKTypeUtility dictionary:parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { 1371| 0| if (![key isKindOfClass:[NSString class]]) { 1372| 0| [FBSDKAppEventsUtility logAndNotify:[NSString stringWithFormat:@"The keys in the parameters must be NSStrings, '%@' is not.", key]]; 1373| 0| failed = YES; 1374| 0| } 1375| 0| if (![FBSDKAppEventsUtility validateIdentifier:key]) { 1376| 0| failed = YES; 1377| 0| } 1378| 0| if (![obj isKindOfClass:[NSString class]] && ![obj isKindOfClass:[NSNumber class]]) { 1379| 0| [FBSDKAppEventsUtility logAndNotify:[NSString stringWithFormat:@"The values in the parameters dictionary must be NSStrings or NSNumbers, '%@' is not.", obj]]; 1380| 0| failed = YES; 1381| 0| } 1382| 0| }]; 1383| | 1384| 0| if (failed) { 1385| 0| return; 1386| 0| } 1387| | // Filter out deactivated params 1388| 0| parameters = [g_eventDeactivationParameterProcessor processParameters:parameters eventName:eventName]; 1389| | 1390| 0|#if !TARGET_OS_TV 1391| | // Filter out restrictive data with on-device ML 1392| 0| if (g_onDeviceMLModelManager.integrityParametersProcessor) { 1393| 0| parameters = [g_onDeviceMLModelManager.integrityParametersProcessor processParameters:parameters eventName:eventName]; 1394| 0| } 1395| 0|#endif 1396| | // Filter out restrictive keys 1397| 0| parameters = [g_restrictiveDataFilterParameterProcessor processParameters:parameters 1398| 0| eventName:eventName]; 1399| | 1400| 0| NSMutableDictionary *eventDictionary = [NSMutableDictionary dictionaryWithDictionary:parameters]; 1401| 0| [FBSDKTypeUtility dictionary:eventDictionary setObject:eventName forKey:FBSDKAppEventParameterEventName]; 1402| 0| if (!eventDictionary[FBSDKAppEventParameterLogTime]) { 1403| 0| [FBSDKTypeUtility dictionary:eventDictionary setObject:@([FBSDKAppEventsUtility unixTimeNow]) forKey:FBSDKAppEventParameterLogTime]; 1404| 0| } 1405| 0| [FBSDKTypeUtility dictionary:eventDictionary setObject:valueToSum forKey:@"_valueToSum"]; 1406| 0| if (isImplicitlyLogged) { 1407| 0| [FBSDKTypeUtility dictionary:eventDictionary setObject:@"1" forKey:FBSDKAppEventParameterImplicitlyLogged]; 1408| 0| } 1409| | 1410| 0| NSString *currentViewControllerName; 1411| 0| UIApplicationState applicationState; 1412| 0| if ([NSThread isMainThread]) { 1413| | // We only collect the view controller when on the main thread, as the behavior off 1414| | // the main thread is unpredictable. Besides, UI state for off-main-thread computations 1415| | // isn't really relevant anyhow. 1416| 0| UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController; 1417| 0| vc = vc.presentedViewController ?: vc; 1418| 0| if (vc) { 1419| 0| currentViewControllerName = [[vc class] description]; 1420| 0| } else { 1421| 0| currentViewControllerName = @"no_ui"; 1422| 0| } 1423| 0| applicationState = [UIApplication sharedApplication].applicationState; 1424| 0| } else { 1425| 0| currentViewControllerName = @"off_thread"; 1426| 0| applicationState = self.applicationState; 1427| 0| } 1428| 0| [FBSDKTypeUtility dictionary:eventDictionary setObject:currentViewControllerName forKey:@"_ui"]; 1429| | 1430| 0| if (applicationState == UIApplicationStateBackground) { 1431| 0| [FBSDKTypeUtility dictionary:eventDictionary setObject:@"1" forKey:FBSDKAppEventParameterInBackground]; 1432| 0| } 1433| | 1434| 0| NSString *tokenString = [FBSDKAppEventsUtility tokenStringToUseFor:accessToken]; 1435| 0| NSString *appID = [self appID]; 1436| | 1437| 0| @synchronized(self) { 1438| 0| if (!_appEventsState) { 1439| 0| _appEventsState = [self.appEventsStateProvider createStateWithToken:tokenString appID:appID]; 1440| 0| } else if (![_appEventsState isCompatibleWithTokenString:tokenString appID:appID]) { 1441| 0| if (self.flushBehavior == FBSDKAppEventsFlushBehaviorExplicitOnly) { 1442| 0| [g_appEventsStateStore persistAppEventsData:_appEventsState]; 1443| 0| } else { 1444| 0| [self flushForReason:FBSDKAppEventsFlushReasonSessionChange]; 1445| 0| } 1446| 0| _appEventsState = [self.appEventsStateProvider createStateWithToken:tokenString appID:appID]; 1447| 0| } 1448| | 1449| 0| [_appEventsState addEvent:eventDictionary isImplicit:isImplicitlyLogged]; 1450| 0| if (!isImplicitlyLogged) { 1451| 0| NSString *message = [NSString stringWithFormat:@"FBSDKAppEvents: Recording event @ %f: %@", 1452| 0| [FBSDKAppEventsUtility unixTimeNow], 1453| 0| eventDictionary]; 1454| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents 1455| 0| logEntry:message]; 1456| 0| } 1457| | 1458| 0| [self checkPersistedEvents]; 1459| | 1460| 0| if (_appEventsState.events.count > NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER 1461| 0| && self.flushBehavior != FBSDKAppEventsFlushBehaviorExplicitOnly) { 1462| 0| [self flushForReason:FBSDKAppEventsFlushReasonEventThreshold]; 1463| 0| } 1464| 0| } 1465| 0|} 1466| | 1467| |#pragma clang diagnostic pop 1468| | 1469| |// this fetches persisted event states. 1470| |// for those matching the currently tracked events, add it. 1471| |// otherwise, either flush (if not explicitonly behavior) or persist them back. 1472| |- (void)checkPersistedEvents 1473| 0|{ 1474| 0| NSArray *existingEventsStates = [g_appEventsStateStore retrievePersistedAppEventsStates]; 1475| 0| if (existingEventsStates.count == 0) { 1476| 0| return; 1477| 0| } 1478| 0| FBSDKAppEventsState *matchingEventsPreviouslySaved = nil; 1479| | // reduce lock time by creating a new FBSDKAppEventsState to collect matching persisted events. 1480| 0| @synchronized(self) { 1481| 0| if (_appEventsState) { 1482| 0| matchingEventsPreviouslySaved = [self.appEventsStateProvider createStateWithToken:_appEventsState.tokenString 1483| 0| appID:_appEventsState.appID]; 1484| 0| } 1485| 0| } 1486| 0| for (FBSDKAppEventsState *saved in existingEventsStates) { 1487| 0| if ([saved isCompatibleWithAppEventsState:matchingEventsPreviouslySaved]) { 1488| 0| [matchingEventsPreviouslySaved addEventsFromAppEventState:saved]; 1489| 0| } else { 1490| 0| if (self.flushBehavior == FBSDKAppEventsFlushBehaviorExplicitOnly) { 1491| 0| [g_appEventsStateStore persistAppEventsData:saved]; 1492| 0| } else { 1493| 0| dispatch_async(dispatch_get_main_queue(), ^{ 1494| 0| [self flushOnMainQueue:saved forReason:FBSDKAppEventsFlushReasonPersistedEvents]; 1495| 0| }); 1496| 0| } 1497| 0| } 1498| 0| } 1499| 0| if (matchingEventsPreviouslySaved.events.count > 0) { 1500| 0| @synchronized(self) { 1501| 0| if ([_appEventsState isCompatibleWithAppEventsState:matchingEventsPreviouslySaved]) { 1502| 0| [_appEventsState addEventsFromAppEventState:matchingEventsPreviouslySaved]; 1503| 0| } 1504| 0| } 1505| 0| } 1506| 0|} 1507| | 1508| |- (void)flushOnMainQueue:(FBSDKAppEventsState *)appEventsState 1509| | forReason:(FBSDKAppEventsFlushReason)reason 1510| 0|{ 1511| 0| if (appEventsState.events.count == 0) { 1512| 0| return; 1513| 0| } 1514| | 1515| 0| if (appEventsState.appID.length == 0) { 1516| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Missing [FBSDKAppEvents appEventsState.appID] for [FBSDKAppEvents flushOnMainQueue:]"]; 1517| 0| return; 1518| 0| } 1519| | 1520| 0| [FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])]; 1521| | 1522| 0| [self fetchServerConfiguration:^(void) { 1523| 0| if ([FBSDKAppEventsUtility shouldDropAppEvent]) { 1524| 0| return; 1525| 0| } 1526| 0| NSString *receipt_data = appEventsState.extractReceiptData; 1527| 0| const BOOL shouldIncludeImplicitEvents = (self->_serverConfiguration.implicitLoggingEnabled && g_settings.isAutoLogAppEventsEnabled); 1528| 0| NSString *encodedEvents = [appEventsState JSONStringForEventsIncludingImplicitEvents:shouldIncludeImplicitEvents]; 1529| 0| if (!encodedEvents || appEventsState.events.count == 0) { 1530| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents 1531| 0| logEntry:@"FBSDKAppEvents: Flushing skipped - no events after removing implicitly logged ones.\n"]; 1532| 0| return; 1533| 0| } 1534| 0| NSMutableDictionary *postParameters = [FBSDKAppEventsUtility 1535| 0| activityParametersDictionaryForEvent:@"CUSTOM_APP_EVENTS" 1536| 0| shouldAccessAdvertisingID:self->_serverConfiguration.advertisingIDEnabled]; 1537| 0| NSInteger length = receipt_data.length; 1538| 0| if (length > 0) { 1539| 0| [FBSDKTypeUtility dictionary:postParameters setObject:receipt_data forKey:@"receipt_data"]; 1540| 0| } 1541| | 1542| 0| [FBSDKTypeUtility dictionary:postParameters setObject:encodedEvents forKey:@"custom_events"]; 1543| 0| if (appEventsState.numSkipped > 0) { 1544| 0| [FBSDKTypeUtility dictionary:postParameters setObject:[NSString stringWithFormat:@"%lu", (unsigned long)appEventsState.numSkipped] forKey:@"num_skipped_events"]; 1545| 0| } 1546| 0| if (self.pushNotificationsDeviceTokenString) { 1547| 0| [FBSDKTypeUtility dictionary:postParameters setObject:self.pushNotificationsDeviceTokenString forKey:FBSDKActivitesParameterPushDeviceToken]; 1548| 0| } 1549| | 1550| 0| NSString *loggingEntry = nil; 1551| 0| if ([g_settings.loggingBehaviors containsObject:FBSDKLoggingBehaviorAppEvents]) { 1552| 0| NSData *prettyJSONData = [FBSDKTypeUtility dataWithJSONObject:appEventsState.events 1553| 0| options:NSJSONWritingPrettyPrinted 1554| 0| error:NULL]; 1555| 0| NSString *prettyPrintedJsonEvents = [[NSString alloc] initWithData:prettyJSONData 1556| 0| encoding:NSUTF8StringEncoding]; 1557| | // Remove this param -- just an encoding of the events which we pretty print later. 1558| 0| NSMutableDictionary *paramsForPrinting = [postParameters mutableCopy]; 1559| 0| [paramsForPrinting removeObjectForKey:@"custom_events_file"]; 1560| | 1561| 0| loggingEntry = [NSString stringWithFormat:@"FBSDKAppEvents: Flushed @ %f, %lu events due to '%@' - %@\nEvents: %@", 1562| 0| [FBSDKAppEventsUtility unixTimeNow], 1563| 0| (unsigned long)appEventsState.events.count, 1564| 0| [FBSDKAppEventsUtility flushReasonToString:reason], 1565| 0| paramsForPrinting, 1566| 0| prettyPrintedJsonEvents]; 1567| 0| } 1568| 0| id request = [g_graphRequestProvider createGraphRequestWithGraphPath:[NSString stringWithFormat:@"%@/activities", appEventsState.appID] 1569| 0| parameters:postParameters 1570| 0| tokenString:appEventsState.tokenString 1571| 0| HTTPMethod:FBSDKHTTPMethodPOST 1572| 0| flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; 1573| 0| [request startWithCompletion:^(id connection, id result, NSError *error) { 1574| 0| [self handleActivitiesPostCompletion:error 1575| 0| loggingEntry:loggingEntry 1576| 0| appEventsState:(FBSDKAppEventsState *)appEventsState]; 1577| 0| }]; 1578| 0| }]; 1579| 0|} 1580| | 1581| |- (void)handleActivitiesPostCompletion:(NSError *)error 1582| | loggingEntry:(NSString *)loggingEntry 1583| | appEventsState:(FBSDKAppEventsState *)appEventsState 1584| 0|{ 1585| 0| typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushResult) { 1586| 0| FlushResultSuccess, 1587| 0| FlushResultServerError, 1588| 0| FlushResultNoConnectivity, 1589| 0| }; 1590| | 1591| 0| [FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])]; 1592| | 1593| 0| FBSDKAppEventsFlushResult flushResult = FlushResultSuccess; 1594| 0| if (error) { 1595| 0| NSInteger errorCode = [error.userInfo[FBSDKGraphRequestErrorHTTPStatusCodeKey] integerValue]; 1596| | 1597| | // We interpret a 400 coming back from FBRequestConnection as a server error due to improper data being 1598| | // sent down. Otherwise we assume no connectivity, or another condition where we could treat it as no connectivity. 1599| | // Adding 404 as having wrong/missing appID results in 404 and that is not a connectivity issue 1600| 0| flushResult = (errorCode == 400 || errorCode == 404) ? FlushResultServerError : FlushResultNoConnectivity; 1601| 0| } 1602| | 1603| 0| if (flushResult == FlushResultServerError) { 1604| | // Only log events that developer can do something with (i.e., if parameters are incorrect). 1605| | // as opposed to cases where the token is bad. 1606| 0| if ([error.userInfo[FBSDKGraphRequestErrorKey] unsignedIntegerValue] == FBSDKGraphRequestErrorOther) { 1607| 0| NSString *message = [NSString stringWithFormat:@"Failed to send AppEvents: %@", error]; 1608| 0| [FBSDKAppEventsUtility logAndNotify:message allowLogAsDeveloperError:!appEventsState.areAllEventsImplicit]; 1609| 0| } 1610| 0| } else if (flushResult == FlushResultNoConnectivity) { 1611| 0| @synchronized(self) { 1612| 0| if ([appEventsState isCompatibleWithAppEventsState:_appEventsState]) { 1613| 0| [_appEventsState addEventsFromAppEventState:appEventsState]; 1614| 0| } else { 1615| | // flush failed due to connectivity. Persist to be tried again later. 1616| 0| [g_appEventsStateStore persistAppEventsData:appEventsState]; 1617| 0| } 1618| 0| } 1619| 0| } 1620| | 1621| 0| NSString *resultString = @""; 1622| 0| switch (flushResult) { 1623| 0| case FlushResultSuccess: 1624| 0| resultString = @"Success"; 1625| 0| break; 1626| | 1627| 0| case FlushResultNoConnectivity: 1628| 0| resultString = @"No Connectivity"; 1629| 0| break; 1630| | 1631| 0| case FlushResultServerError: 1632| 0| resultString = [NSString stringWithFormat:@"Server Error - %@", error.description]; 1633| 0| break; 1634| 0| } 1635| | 1636| 0| NSString *message = [NSString stringWithFormat:@"%@\nFlush Result : %@", loggingEntry, resultString]; 1637| 0| [g_logger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents 1638| 0| logEntry:message]; 1639| 0|} 1640| | 1641| |- (void)flushTimerFired:(id)arg 1642| 0|{ 1643| 0| [FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])]; 1644| 0| if (self.flushBehavior != FBSDKAppEventsFlushBehaviorExplicitOnly && !self.disableTimer) { 1645| 0| [self flushForReason:FBSDKAppEventsFlushReasonTimer]; 1646| 0| } 1647| 0|} 1648| | 1649| |- (void)applicationDidBecomeActive 1650| 0|{ 1651| 0| [FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])]; 1652| | 1653| | // This must happen here to avoid a race condition with the shared `Settings` object. 1654| 0| [self fetchServerConfiguration:nil]; 1655| | 1656| 0| [self checkPersistedEvents]; 1657| | 1658| | // Restore time spent data, indicating that we're not being called from "activateApp". 1659| 0| [self.timeSpentRecorder restore:NO]; 1660| 0|} 1661| | 1662| |- (void)applicationMovingFromActiveStateOrTerminating 1663| 0|{ 1664| | // When moving from active state, we don't have time to wait for the result of a flush, so 1665| | // just persist events to storage, and we'll process them at the next activation. 1666| 0| FBSDKAppEventsState *copy = nil; 1667| 0| @synchronized(self) { 1668| 0| copy = [_appEventsState copy]; 1669| 0| _appEventsState = nil; 1670| 0| } 1671| 0| if (copy) { 1672| 0| [g_appEventsStateStore persistAppEventsData:copy]; 1673| 0| } 1674| 0| [self.timeSpentRecorder suspend]; 1675| 0|} 1676| | 1677| |#pragma mark - Configuration Validation 1678| | 1679| |- (void)validateConfiguration 1680| 0|{ 1681| 0|#if DEBUG 1682| 0| if (!self.isConfigured) { 1683| 0| static NSString *const reason = @"As of v9.0, you must initialize the SDK prior to calling any methods or setting any properties. " 1684| 0| "You can do this by calling `FBSDKApplicationDelegate`'s `application:didFinishLaunchingWithOptions:` method. " 1685| 0| "Learn more: https://developers.facebook.com/docs/ios/getting-started"; 1686| 0| @throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil]; 1687| 0| } 1688| 0|#endif 1689| 0|} 1690| | 1691| |#pragma mark - Custom Audience 1692| | 1693| |+ (id)requestForCustomAudienceThirdPartyIDWithAccessToken:(FBSDKAccessToken *)accessToken 1694| 0|{ 1695| 0| [self.singleton validateConfiguration]; 1696| | 1697| 0| accessToken = accessToken ?: [FBSDKAccessToken currentAccessToken]; 1698| | // Rules for how we use the attribution ID / advertiser ID for an 'custom_audience_third_party_id' Graph API request 1699| | // 1) if the OS tells us that the user has Limited Ad Tracking, then just don't send, and return a nil in the token. 1700| | // 2) if the app has set 'limitEventAndDataUsage', this effectively implies that app-initiated ad targeting shouldn't happen, 1701| | // so use that data here to return nil as well. 1702| | // 3) if we have a user session token, then no need to send attribution ID / advertiser ID back as the udid parameter 1703| | // 4) otherwise, send back the udid parameter. 1704| 0| if (g_settings.advertisingTrackingStatus == FBSDKAdvertisingTrackingDisallowed || g_settings.shouldLimitEventAndDataUsage) { 1705| 0| return nil; 1706| 0| } 1707| | 1708| 0| NSString *tokenString = [FBSDKAppEventsUtility tokenStringToUseFor:accessToken]; 1709| 0| NSString *udid = nil; 1710| 0| if (!accessToken) { 1711| | // We don't have a logged in user, so we need some form of udid representation. Prefer advertiser ID if 1712| | // available. Note that this function only makes sense to be called in the context of advertising. 1713| 0| udid = [FBSDKAppEventsUtility.shared advertiserID]; 1714| 0| if (!udid) { 1715| | // No udid, and no user token. No point in making the request. 1716| 0| return nil; 1717| 0| } 1718| 0| } 1719| | 1720| 0| NSDictionary *parameters = @{}; 1721| 0| if (udid) { 1722| 0| parameters = @{ @"udid" : udid }; 1723| 0| } 1724| | 1725| 0| NSString *graphPath = [NSString stringWithFormat:@"%@/custom_audience_third_party_id", [[self singleton] appID]]; 1726| | 1727| 0| id request = [g_graphRequestProvider createGraphRequestWithGraphPath:graphPath 1728| 0| parameters:parameters 1729| 0| tokenString:tokenString 1730| 0| HTTPMethod:FBSDKHTTPMethodGET 1731| 0| flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; 1732| 0| return request; 1733| 0|} 1734| | 1735| |#pragma mark - Testability 1736| | 1737| |#if DEBUG 1738| | 1739| |+ (void)reset 1740| 0|{ 1741| 0| self.singleton.isConfigured = NO; 1742| 0| [self resetApplicationState]; 1743| 0| g_gateKeeperManager = nil; 1744| 0| g_graphRequestProvider = nil; 1745| 0|} 1746| | 1747| |+ (void)resetApplicationState 1748| 0|{ 1749| 0| self.singleton.applicationState = UIApplicationStateInactive; 1750| 0|} 1751| | 1752| |+ (id)featureChecker 1753| 0|{ 1754| 0| return g_featureChecker; 1755| 0|} 1756| | 1757| |+ (id)requestProvider 1758| 0|{ 1759| 0| return g_graphRequestProvider; 1760| 0|} 1761| | 1762| |+ (Class)serverConfigurationProvider 1763| 0|{ 1764| 0| return g_serverConfigurationProvider; 1765| 0|} 1766| | 1767| |+ (Class)appEventsConfigurationProvider 1768| 0|{ 1769| 0| return g_appEventsConfigurationProvider; 1770| 0|} 1771| | 1772| |+ (Class)gateKeeperManager 1773| 0|{ 1774| 0| return g_gateKeeperManager; 1775| 0|} 1776| | 1777| |+ (Class)logger 1778| 0|{ 1779| 0| return g_logger; 1780| 0|} 1781| | 1782| |+ (id)settings 1783| 0|{ 1784| 0| return g_settings; 1785| 0|} 1786| | 1787| |+ (void)setSettings:(id)settings 1788| 0|{ 1789| 0| g_settings = settings; 1790| 0|} 1791| | 1792| |+ (id)paymentObserver 1793| 0|{ 1794| 0| return g_paymentObserver; 1795| 0|} 1796| | 1797| |+ (void)setPaymentObserver:(id)paymentObserver 1798| 0|{ 1799| 0| g_paymentObserver = paymentObserver; 1800| 0|} 1801| | 1802| |+ (id)appEventsStateStore 1803| 0|{ 1804| 0| return g_appEventsStateStore; 1805| 0|} 1806| | 1807| |- (void)setFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior 1808| 0|{ 1809| 0| _flushBehavior = flushBehavior; 1810| 0|} 1811| | 1812| | #if !TARGET_OS_TV 1813| | 1814| |+ (id)onDeviceMLModelManager 1815| 0|{ 1816| 0| return g_onDeviceMLModelManager; 1817| 0|} 1818| | 1819| |+ (id)metadataIndexer 1820| 0|{ 1821| 0| return g_metadataIndexer; 1822| 0|} 1823| | 1824| |+ (id)eventDeactivationParameterProcessor 1825| 0|{ 1826| 0| return g_eventDeactivationParameterProcessor; 1827| 0|} 1828| | 1829| |+ (id)restrictiveDataFilterParameterProcessor 1830| 0|{ 1831| 0| return g_restrictiveDataFilterParameterProcessor; 1832| 0|} 1833| | 1834| | #endif 1835| | 1836| |#endif 1837| | 1838| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AAM/FBSDKMetadataIndexer.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKMetadataIndexer.h" 24| | 25| | #import 26| | 27| | #import 28| | #import 29| | #import 30| | 31| | #import "FBSDKAppEventsUtility.h" 32| | #import "FBSDKCoreKitBasicsImport.h" 33| | #import "FBSDKServerConfigurationManager.h" 34| | #import "FBSDKSwizzler.h" 35| | #import "FBSDKUtility.h" 36| | #import "FBSDKViewHierarchy.h" 37| | 38| |@interface FBSDKUserDataStore (Internal) 39| | 40| |+ (void)setInternalHashData:(nullable NSString *)hashData 41| | forType:(FBSDKAppEventUserDataType)type; 42| |+ (void)setEnabledRules:(NSArray *)rules; 43| | 44| |+ (nullable NSString *)getInternalHashedDataForType:(FBSDKAppEventUserDataType)type; 45| | 46| |@end 47| | 48| |static const int FBSDKMetadataIndexerMaxTextLength = 100; 49| |static const int FBSDKMetadataIndexerMaxIndicatorLength = 100; 50| |static const int FBSDKMetadataIndexerMaxValue = 5; 51| | 52| |static NSString *const FIELD_K = @"k"; 53| |static NSString *const FIELD_V = @"v"; 54| |static NSString *const FIELD_K_DELIMITER = @","; 55| | 56| |@interface FBSDKMetadataIndexer () 57| | 58| |@property (nonatomic, readonly, strong) NSMutableDictionary *> *rules; 59| |@property (nonatomic, readonly, strong) NSMutableDictionary *> *store; 60| |@property (nonatomic, readonly, strong) dispatch_queue_t serialQueue; 61| | 62| |@end 63| | 64| |@implementation FBSDKMetadataIndexer 65| | 66| |+ (instancetype)shared 67| 0|{ 68| 0| static dispatch_once_t nonce; 69| 0| static FBSDKMetadataIndexer *instance; 70| 0| dispatch_once(&nonce, ^{ 71| 0| instance = [self new]; 72| 0| }); 73| 0| return instance; 74| 0|} 75| | 76| |- (instancetype)init 77| 0|{ 78| 0| _rules = [NSMutableDictionary new]; 79| 0| _serialQueue = dispatch_queue_create("com.facebook.appevents.MetadataIndexer", DISPATCH_QUEUE_SERIAL); 80| 0| return self; 81| 0|} 82| | 83| |- (void)enable 84| 0|{ 85| 0| @try { 86| 0| if ([FBSDKAppEventsUtility shouldDropAppEvent]) { 87| 0| return; 88| 0| } 89| | 90| 0| static dispatch_once_t onceToken; 91| 0| dispatch_once(&onceToken, ^{ 92| 0| NSDictionary *AAMRules = [FBSDKServerConfigurationManager cachedServerConfiguration].AAMRules; 93| 0| if (AAMRules) { 94| 0| [self setupWithRules:AAMRules]; 95| 0| } 96| 0| }); 97| 0| } @catch (NSException *exception) { 98| 0| NSLog(@"Fail to enable Automatic Advanced Matching, exception reason: %@", exception.reason); 99| 0| } 100| 0|} 101| | 102| |- (void)setupWithRules:(NSDictionary *_Nullable)rules 103| 0|{ 104| 0| if (0 == rules.count) { 105| 0| return; 106| 0| } 107| 0| static dispatch_once_t onceToken; 108| 0| dispatch_once(&onceToken, ^{ 109| 0| [self constructRules:rules]; 110| 0| [self initStore]; 111| | 112| 0| BOOL isEnabled = NO; 113| 0| for (NSString *key in _rules) { 114| 0| if (_rules[key]) { 115| 0| isEnabled = YES; 116| 0| break; 117| 0| } 118| 0| } 119| | 120| 0| if (isEnabled) { 121| 0| [FBSDKUserDataStore setEnabledRules:_rules.allKeys]; 122| 0| [self setupMetadataIndexing]; 123| 0| } 124| 0| }); 125| 0|} 126| | 127| |- (void)initStore 128| 0|{ 129| 0| _store = [NSMutableDictionary new]; 130| 0| for (NSString *key in _rules) { 131| 0| NSString *data = [FBSDKUserDataStore getInternalHashedDataForType:key]; 132| 0| if (data.length > 0) { 133| 0| [FBSDKTypeUtility dictionary:_store setObject:[NSMutableArray arrayWithArray:[data componentsSeparatedByString:FIELD_K_DELIMITER]] forKey:key]; 134| 0| } 135| 0| } 136| | 137| 0| for (NSString *key in _rules) { 138| 0| if (!_store[key]) { 139| 0| [FBSDKTypeUtility dictionary:_store setObject:[NSMutableArray new] forKey:key]; 140| 0| } 141| 0| } 142| 0|} 143| | 144| |- (void)constructRules:(NSDictionary *_Nullable)rules 145| 0|{ 146| 0| for (NSString *key in rules) { 147| 0| NSDictionary *value = [FBSDKTypeUtility dictionaryValue:rules[key]]; 148| 0| if (value[FIELD_K].length > 0 && value[FIELD_V]) { 149| 0| [FBSDKTypeUtility dictionary:_rules setObject:value forKey:key]; 150| 0| } 151| 0| } 152| 0|} 153| | 154| |- (void)setupMetadataIndexing 155| 0|{ 156| 0| void (^block)(UIView *) = ^(UIView *view) { 157| | // Indexing when the view is removed from window and conforms to UITextInput, and skip UIFieldEditor, which is an internval view of UITextField 158| 0| if (![view window] && ![NSStringFromClass([view class]) isEqualToString:@"UIFieldEditor"] && [view conformsToProtocol:@protocol(UITextInput)]) { 159| 0| NSString *text = [FBSDKViewHierarchy getText:view]; 160| 0| NSString *placeholder = [FBSDKViewHierarchy getHint:view]; 161| 0| BOOL secureTextEntry = [self checkSecureTextEntry:view]; 162| 0| NSArray *labels = [self getLabelsOfView:view]; 163| 0| UIKeyboardType keyboardType = [self getKeyboardType:view]; 164| 0| dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { 165| 0| [self getMetadataWithText:text 166| 0| placeholder:placeholder 167| 0| labels:labels 168| 0| secureTextEntry:secureTextEntry 169| 0| inputType:keyboardType]; 170| 0| }); 171| 0| } 172| 0| }; 173| | 174| 0| [FBSDKSwizzler swizzleSelector:@selector(didMoveToWindow) onClass:[UIView class] withBlock:block named:@"metadataIndexingUIView"]; 175| | 176| | // iOS 12: UITextField implements didMoveToWindow without calling parent implementation 177| 0| if (@available(iOS 12, *)) { 178| 0| [FBSDKSwizzler swizzleSelector:@selector(didMoveToWindow) onClass:[UITextField class] withBlock:block named:@"metadataIndexingUITextField"]; 179| 0| } else { 180| 0| [FBSDKSwizzler swizzleSelector:@selector(didMoveToWindow) onClass:[UIControl class] withBlock:block named:@"metadataIndexingUIControl"]; 181| 0| } 182| 0|} 183| | 184| |- (NSArray *)getSiblingViewsOfView:(UIView *)view 185| 0|{ 186| 0| NSObject *parent = [FBSDKViewHierarchy getParent:view]; 187| 0| if (parent) { 188| 0| NSArray *views = [FBSDKViewHierarchy getChildren:parent]; 189| 0| if (views) { 190| 0| NSMutableArray *siblings = [NSMutableArray arrayWithArray:views]; 191| 0| [siblings removeObject:view]; 192| 0| return [siblings copy]; 193| 0| } 194| 0| } 195| 0| return nil; 196| 0|} 197| | 198| |- (NSArray *)getLabelsOfView:(UIView *)view 199| 0|{ 200| 0| NSMutableArray *labels = [NSMutableArray new]; 201| | 202| 0| NSString *placeholder = [self normalizeField:[FBSDKViewHierarchy getHint:view]]; 203| 0| if (placeholder.length > 0) { 204| 0| [FBSDKTypeUtility array:labels addObject:placeholder]; 205| 0| } 206| | 207| 0| NSArray *siblingViews = [self getSiblingViewsOfView:view]; 208| 0| for (id sibling in siblingViews) { 209| 0| if ([sibling isKindOfClass:[UILabel class]]) { 210| 0| NSString *text = [self normalizeField:[FBSDKViewHierarchy getText:sibling]]; 211| 0| if (text.length > 0) { 212| 0| [FBSDKTypeUtility array:labels addObject:text]; 213| 0| } 214| 0| } 215| 0| } 216| 0| return [labels copy]; 217| 0|} 218| | 219| |- (BOOL)checkSecureTextEntry:(UIView *)view 220| 0|{ 221| 0| if ([view isKindOfClass:[UITextField class]]) { 222| 0| return ((UITextField *)view).secureTextEntry; 223| 0| } 224| 0| if ([view isKindOfClass:[UITextView class]]) { 225| 0| return ((UITextView *)view).secureTextEntry; 226| 0| } 227| | 228| 0| return NO; 229| 0|} 230| | 231| |- (UIKeyboardType)getKeyboardType:(UIView *)view 232| 0|{ 233| 0| if ([view isKindOfClass:[UITextField class]]) { 234| 0| return ((UITextField *)view).keyboardType; 235| 0| } 236| 0| if ([view isKindOfClass:[UITextView class]]) { 237| 0| return ((UITextView *)view).keyboardType; 238| 0| } 239| | 240| 0| return UIKeyboardTypeDefault; 241| 0|} 242| | 243| |- (void)getMetadataWithText:(NSString *)text 244| | placeholder:(NSString *)placeholder 245| | labels:(NSArray *)labels 246| | secureTextEntry:(BOOL)secureTextEntry 247| | inputType:(UIKeyboardType)inputType 248| 0|{ 249| 0| text = [self normalizeValue:text]; 250| 0| placeholder = [self normalizeField:placeholder]; 251| 0| if (secureTextEntry || [placeholder containsString:@"password"] 252| 0| || text.length == 0 253| 0| || text.length > FBSDKMetadataIndexerMaxTextLength 254| 0| || placeholder.length >= FBSDKMetadataIndexerMaxIndicatorLength) { 255| 0| return; 256| 0| } 257| | 258| 0| for (NSString *key in _rules) { 259| 0| NSDictionary *rule = _rules[key]; 260| 0| BOOL isRuleKMatched = [self checkMetadataHint:placeholder matchRuleK:rule[FIELD_K]] 261| 0| || [self checkMetadataLabels:labels matchRuleK:rule[FIELD_K]]; 262| 0| if (!isRuleKMatched) { 263| 0| continue; 264| 0| } 265| | 266| 0| NSString *preProcessedText = text; 267| 0| if ([key isEqualToString:@"r2"]) { 268| 0| preProcessedText = [[text componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"+- ()."]] componentsJoinedByString:@""]; 269| 0| } 270| 0| BOOL isRuleVMatched = [rule[FIELD_V] isEqualToString:@""] || [self checkMetadataText:preProcessedText matchRuleV:rule[FIELD_V]]; 271| 0| if (isRuleVMatched) { 272| 0| NSString *prunedText = [self pruneValue:preProcessedText forKey:key]; 273| 0| [self checkAndAppendData:prunedText forKey:key]; 274| 0| continue; 275| 0| } 276| 0| } 277| 0|} 278| | 279| | #pragma mark - Helper Methods 280| | 281| |- (void)checkAndAppendData:(NSString *)data 282| | forKey:(NSString *)key 283| 0|{ 284| 0| NSString *hashData = [FBSDKUtility SHA256Hash:data]; 285| 0| __weak typeof(_store) weakStore = _store; 286| 0| dispatch_block_t checkAndAppendDataBlock = ^{ 287| 0| if (hashData.length == 0 || [weakStore[key] containsObject:hashData]) { 288| 0| return; 289| 0| } 290| | 291| 0| while (weakStore[key].count >= FBSDKMetadataIndexerMaxValue) { 292| 0| [weakStore[key] removeObjectAtIndex:0]; 293| 0| } 294| 0| [FBSDKTypeUtility array:weakStore[key] addObject:hashData]; 295| 0| [FBSDKUserDataStore setInternalHashData:[weakStore[key] componentsJoinedByString:FIELD_K_DELIMITER] 296| 0| forType:key]; 297| 0| }; 298| 0|#ifdef FBSDKTEST 299| 0| checkAndAppendDataBlock(); 300| |#else 301| | dispatch_async(_serialQueue, checkAndAppendDataBlock); 302| |#endif 303| 0|} 304| | 305| |- (BOOL)checkMetadataLabels:(NSArray *)labels 306| | matchRuleK:(NSString *)ruleK 307| 0|{ 308| 0| for (NSString *label in labels) { 309| 0| if ([self checkMetadataHint:label matchRuleK:ruleK]) { 310| 0| return YES; 311| 0| } 312| 0| } 313| 0| return NO; 314| 0|} 315| | 316| |- (BOOL)checkMetadataHint:(NSString *)hint 317| | matchRuleK:(NSString *)ruleK 318| 0|{ 319| 0| if (hint.length > 0 && ruleK) { 320| 0| NSArray *items = [ruleK componentsSeparatedByString:FIELD_K_DELIMITER]; 321| 0| for (NSString *item in items) { 322| 0| if ([hint containsString:item]) { 323| 0| return YES; 324| 0| } 325| 0| } 326| 0| } 327| 0| return NO; 328| 0|} 329| | 330| |- (BOOL)checkMetadataText:(NSString *)text 331| | matchRuleV:(NSString *)ruleV 332| 0|{ 333| 0| if (text.length > 0 && ruleV) { 334| 0| NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:ruleV 335| 0| options:NSRegularExpressionCaseInsensitive 336| 0| error:nil]; 337| 0| return [regex numberOfMatchesInString:text options:0 range:NSMakeRange(0, text.length)] == 1; 338| 0| } 339| 0| return NO; 340| 0|} 341| | 342| |- (NSString *)normalizeField:(NSString *)field 343| 0|{ 344| 0| if (field.length == 0) { 345| 0| return @""; 346| 0| } 347| 0| NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[_-]|\\s" 348| 0| options:NSRegularExpressionCaseInsensitive 349| 0| error:nil]; 350| 0| return [regex stringByReplacingMatchesInString:field 351| 0| options:0 352| 0| range:NSMakeRange(0, field.length) 353| 0| withTemplate:@""].lowercaseString; 354| 0|} 355| | 356| |- (NSString *)normalizeValue:(NSString *)value 357| 0|{ 358| 0| if (value.length == 0) { 359| 0| return @""; 360| 0| } 361| 0| return [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].lowercaseString; 362| 0|} 363| | 364| |- (NSString *)pruneValue:(NSString *)value forKey:(NSString *)key 365| 0|{ 366| 0| if (value.length == 0) { 367| 0| return @""; 368| 0| } 369| 0| if ([key isEqualToString:@"r3"]) { 370| 0| if ([value hasPrefix:@"m"] || [value hasPrefix:@"b"] || [value hasPrefix:@"ge"]) { 371| 0| value = @"m"; 372| 0| } else { 373| 0| value = @"f"; 374| 0| } 375| 0| } else if ([key isEqualToString:@"r4"] || [key isEqualToString:@"r5"]) { 376| 0| value = [[value componentsSeparatedByCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]] componentsJoinedByString:@""]; 377| 0| } else if ([key isEqualToString:@"r6"]) { 378| 0| value = [FBSDKTypeUtility array:[value componentsSeparatedByString:@"-"] objectAtIndex:0]; 379| 0| } 380| 0| return value; 381| 0|} 382| | 383| |@end 384| | 385| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMAdvertiserMultiEntryRule.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKAEMAdvertiserMultiEntryRule.h" 24| | 25| | #import "FBSDKAEMAdvertiserSingleEntryRule.h" 26| | 27| |static NSString *const OPERATOR_KEY = @"operator"; 28| |static NSString *const RULES_KEY = @"rules"; 29| | 30| |@implementation FBSDKAEMAdvertiserMultiEntryRule 31| | 32| |- (instancetype)initWithOperator:(FBSDKAEMAdvertiserRuleOperator)op 33| | rules:(NSArray> *)rules 34| 0|{ 35| 0| if (self = [super init]) { 36| 0| _operator = op; 37| 0| _rules = rules; 38| 0| } 39| 0| return self; 40| 0|} 41| | 42| | #pragma mark - FBSDKAEMAdvertiserRuleMatching 43| | 44| |- (BOOL)isMatchedEventParameters:(nullable NSDictionary *)eventParams 45| 0|{ 46| 0| @try { 47| 0| BOOL isMatched = _operator == FBSDKAEMAdvertiserRuleOperatorOr ? NO : YES; 48| 0| for (id rule in _rules) { 49| 0| BOOL doesSubruleMatch = [rule isMatchedEventParameters:eventParams]; 50| 0| if (_operator == FBSDKAEMAdvertiserRuleOperatorAnd) { 51| 0| isMatched = isMatched & doesSubruleMatch; 52| 0| } 53| 0| if (_operator == FBSDKAEMAdvertiserRuleOperatorOr) { 54| 0| isMatched = isMatched | doesSubruleMatch; 55| 0| } 56| 0| if (_operator == FBSDKAEMAdvertiserRuleOperatorNot) { 57| 0| isMatched = isMatched & !doesSubruleMatch; 58| 0| } 59| 0| } 60| 0| return isMatched; 61| 0| } @catch (NSException *exception) { 62| 0| #if DEBUG 63| 0| #if FBSDKTEST 64| 0| @throw exception; 65| 0| #endif 66| 0| #endif 67| 0| return NO; 68| 0| } 69| 0|} 70| | 71| | #pragma mark - NSCoding 72| | 73| |+ (BOOL)supportsSecureCoding 74| 0|{ 75| 0| return YES; 76| 0|} 77| | 78| |- (instancetype)initWithCoder:(NSCoder *)decoder 79| 0|{ 80| 0| FBSDKAEMAdvertiserRuleOperator op = [decoder decodeIntegerForKey:OPERATOR_KEY]; 81| 0| NSSet *classes = [NSSet setWithArray:@[NSArray.class, FBSDKAEMAdvertiserMultiEntryRule.class, FBSDKAEMAdvertiserSingleEntryRule.class]]; 82| 0| NSArray> *rules = [decoder decodeObjectOfClasses:classes forKey:RULES_KEY]; 83| 0| return [self initWithOperator:op rules:rules]; 84| 0|} 85| | 86| |- (void)encodeWithCoder:(NSCoder *)encoder 87| 0|{ 88| 0| [encoder encodeInteger:_operator forKey:OPERATOR_KEY]; 89| 0| [encoder encodeObject:_rules forKey:RULES_KEY]; 90| 0|} 91| | 92| | #pragma mark - NSCopying 93| | 94| |- (instancetype)copyWithZone:(NSZone *)zone 95| 0|{ 96| 0| return self; 97| 0|} 98| | 99| |@end 100| | 101| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMAdvertiserRuleFactory.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKAEMAdvertiserRuleFactory.h" 24| | 25| | #import "FBSDKAEMAdvertiserMultiEntryRule.h" 26| | #import "FBSDKAEMAdvertiserSingleEntryRule.h" 27| | #import "FBSDKCoreKitBasicsImport.h" 28| | #import "FBSDKLogger.h" 29| | 30| |@implementation FBSDKAEMAdvertiserRuleFactory 31| | 32| |- (nullable id)createRuleWithJson:(nullable NSString *)json 33| 0|{ 34| 0| @try { 35| 0| json = [FBSDKTypeUtility stringValueOrNil:json]; 36| 0| if (!json) { 37| 0| return nil; 38| 0| } 39| 0| NSDictionary *rule = [FBSDKBasicUtility objectForJSONString:json error:nil]; 40| 0| return [self createRuleWithDict:rule]; 41| 0| } @catch (NSException *exception) { 42| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents logEntry:@"Fail to parse Advertiser Rules with JSON"]; 43| 0| } 44| 0| return nil; 45| 0|} 46| | 47| |- (nullable id)createRuleWithDict:(NSDictionary *)dict 48| 0|{ 49| 0| @try { 50| 0| dict = [FBSDKTypeUtility dictionaryValue:dict]; 51| 0| if (!dict) { 52| 0| return nil; 53| 0| } 54| 0| FBSDKAEMAdvertiserRuleOperator op = [self getOperator:dict]; 55| 0| if ([self isOperatorForMultiEntryRule:op]) { 56| 0| return [self createMultiEntryRuleWithDict:dict]; 57| 0| } else { 58| 0| return [self createSingleEntryRuleWithDict:dict]; 59| 0| } 60| 0| } @catch (NSException *exception) { 61| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents logEntry:@"Fail to parse Advertiser Rules with Dict"]; 62| 0| } 63| 0| return nil; 64| 0|} 65| | 66| |- (nullable FBSDKAEMAdvertiserMultiEntryRule *)createMultiEntryRuleWithDict:(NSDictionary *)dict 67| 0|{ 68| 0| dict = [FBSDKTypeUtility dictionaryValue:dict]; 69| 0| if (!dict) { 70| 0| return nil; 71| 0| } 72| 0| NSString *opString = [self primaryKeyForRule:dict]; 73| 0| FBSDKAEMAdvertiserRuleOperator operator = [self getOperator:dict]; 74| 0| if (![self isOperatorForMultiEntryRule:operator]) { 75| 0| return nil; 76| 0| } 77| 0| NSArray *subrules = [FBSDKTypeUtility dictionary:dict objectForKey:opString ofType:NSArray.class]; 78| 0| NSMutableArray> *rules = [NSMutableArray new]; 79| 0| for (NSDictionary *subrule in subrules) { 80| 0| id entryRule = [self createRuleWithDict:subrule]; 81| 0| if (!entryRule) { 82| 0| return nil; 83| 0| } 84| 0| [FBSDKTypeUtility array:rules addObject:entryRule]; 85| 0| } 86| 0| if (!rules.count) { 87| 0| return nil; 88| 0| } 89| 0| return [[FBSDKAEMAdvertiserMultiEntryRule alloc] initWithOperator:operator rules:rules]; 90| 0|} 91| | 92| |- (nullable FBSDKAEMAdvertiserSingleEntryRule *)createSingleEntryRuleWithDict:(NSDictionary *)dict 93| 0|{ 94| 0| dict = [FBSDKTypeUtility dictionaryValue:dict]; 95| 0| if (!dict) { 96| 0| return nil; 97| 0| } 98| 0| NSString *paramKey = [self primaryKeyForRule:dict]; 99| 0| NSDictionary *rawRule = [FBSDKTypeUtility dictionary:dict objectForKey:paramKey ofType:NSDictionary.class]; 100| 0| NSString *encodedOperator = [self primaryKeyForRule:rawRule]; 101| 0| FBSDKAEMAdvertiserRuleOperator operator = [self getOperator:rawRule]; 102| 0| NSString *linguisticCondition = nil; 103| 0| NSNumber *numericalCondition = nil; 104| 0| NSArray *arrayCondition = nil; 105| 0| switch (operator) { 106| 0| case Unknown: 107| 0| default: 108| 0| return nil; 109| 0| case FBSDKAEMAdvertiserRuleOperatorContains: 110| 0| case FBSDKAEMAdvertiserRuleOperatorNotContains: 111| 0| case FBSDKAEMAdvertiserRuleOperatorStartsWith: 112| 0| case FBSDKAEMAdvertiserRuleOperatorI_Contains: 113| 0| case FBSDKAEMAdvertiserRuleOperatorI_NotContains: 114| 0| case FBSDKAEMAdvertiserRuleOperatorI_StartsWith: 115| 0| case FBSDKAEMAdvertiserRuleOperatorRegexMatch: 116| 0| case FBSDKAEMAdvertiserRuleOperatorEqual: 117| 0| case FBSDKAEMAdvertiserRuleOperatorNotEqual: 118| 0| linguisticCondition = [FBSDKTypeUtility dictionary:rawRule objectForKey:encodedOperator ofType:NSString.class]; break; 119| 0| case FBSDKAEMAdvertiserRuleOperatorLessThan: 120| 0| case FBSDKAEMAdvertiserRuleOperatorLessThanOrEqual: 121| 0| case FBSDKAEMAdvertiserRuleOperatorGreaterThan: 122| 0| case FBSDKAEMAdvertiserRuleOperatorGreaterThanOrEqual: 123| 0| numericalCondition = [FBSDKTypeUtility dictionary:rawRule objectForKey:encodedOperator ofType:NSNumber.class]; break; 124| 0| case FBSDKAEMAdvertiserRuleOperatorI_IsAny: 125| 0| case FBSDKAEMAdvertiserRuleOperatorI_IsNotAny: 126| 0| case FBSDKAEMAdvertiserRuleOperatorIsAny: 127| 0| case FBSDKAEMAdvertiserRuleOperatorIsNotAny: 128| 0| arrayCondition = [FBSDKTypeUtility dictionary:rawRule objectForKey:encodedOperator ofType:NSArray.class]; break; 129| 0| } 130| 0| if (linguisticCondition || numericalCondition != nil || arrayCondition.count > 0) { 131| 0| return [[FBSDKAEMAdvertiserSingleEntryRule alloc] initWithOperator:operator paramKey:paramKey linguisticCondition:linguisticCondition numericalCondition:numericalCondition arrayCondition:arrayCondition]; 132| 0| } 133| 0| return nil; 134| 0|} 135| | 136| |- (nullable NSString *)primaryKeyForRule:(NSDictionary *)rule 137| 0|{ 138| 0| NSArray *keys = [rule allKeys]; 139| 0| NSString *key = keys.firstObject; 140| 0| return [FBSDKTypeUtility stringValueOrNil:key]; 141| 0|} 142| | 143| |- (FBSDKAEMAdvertiserRuleOperator)getOperator:(NSDictionary *)rule 144| 0|{ 145| 0| NSString *key = [self primaryKeyForRule:rule]; 146| 0| if (!key) { 147| 0| return Unknown; 148| 0| } 149| 0| NSArray *operatorKeys = @[ 150| 0| @"unknown", 151| 0| @"and", 152| 0| @"or", 153| 0| @"not", 154| 0| @"contains", 155| 0| @"not_contains", 156| 0| @"starts_with", 157| 0| @"i_contains", 158| 0| @"i_not_contains", 159| 0| @"i_starts_with", 160| 0| @"regex_match", 161| 0| @"eq", 162| 0| @"neq", 163| 0| @"lt", 164| 0| @"lte", 165| 0| @"gt", 166| 0| @"gte", 167| 0| @"i_is_any", 168| 0| @"i_is_not_any", 169| 0| @"is_any", 170| 0| @"is_not_any" 171| 0| ]; 172| 0| NSInteger index = [operatorKeys indexOfObject:key.lowercaseString]; 173| 0| return index == NSNotFound ? Unknown : index; 174| 0|} 175| | 176| |- (BOOL)isOperatorForMultiEntryRule:(FBSDKAEMAdvertiserRuleOperator)operator 177| 0|{ 178| 0| return operator == FBSDKAEMAdvertiserRuleOperatorAnd 179| 0| || operator == FBSDKAEMAdvertiserRuleOperatorOr 180| 0| || operator == FBSDKAEMAdvertiserRuleOperatorNot; 181| 0|} 182| | 183| |@end 184| | 185| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMAdvertiserSingleEntryRule.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKAEMAdvertiserSingleEntryRule.h" 24| | 25| | #import "FBSDKCoreKitBasicsImport.h" 26| | 27| |static NSString *const OPERATOR_KEY = @"operator"; 28| |static NSString *const PARAMKEY_KEY = @"param_key"; 29| |static NSString *const STRING_VALUE_KEY = @"string_value"; 30| |static NSString *const NUMBER_VALUE_KEY = @"number_value"; 31| |static NSString *const ARRAY_VALUE_KEY = @"array_value"; 32| |static NSString *const PARAM_DELIMETER = @"."; 33| |static NSString *const ASTERISK_DELIMETER = @"[*]"; 34| | 35| |@implementation FBSDKAEMAdvertiserSingleEntryRule 36| | 37| |- (instancetype)initWithOperator:(FBSDKAEMAdvertiserRuleOperator)op 38| | paramKey:(NSString *)paramKey 39| | linguisticCondition:(nullable NSString *)linguisticCondition 40| | numericalCondition:(nullable NSNumber *)numericalCondition 41| | arrayCondition:(nullable NSArray *)arrayCondition 42| 0|{ 43| 0| if ((self = [super init])) { 44| 0| _operator = op; 45| 0| _paramKey = paramKey; 46| 0| _linguisticCondition = linguisticCondition; 47| 0| _numericalCondition = numericalCondition; 48| 0| _arrayCondition = arrayCondition; 49| 0| } 50| 0| return self; 51| 0|} 52| | 53| | #pragma mark - FBSDKAEMAdvertiserRuleMatching 54| | 55| |- (BOOL)isMatchedEventParameters:(nullable NSDictionary *)eventParams 56| 0|{ 57| 0| @try { 58| 0| NSArray *paramPath = [_paramKey componentsSeparatedByString:PARAM_DELIMETER]; 59| 0| return [self isMatchedEventParameters:eventParams paramPath:paramPath]; 60| 0| } @catch (NSException *exception) { 61| 0| #if DEBUG 62| 0| #if FBSDKTEST 63| 0| @throw exception; 64| 0| #endif 65| 0| #endif 66| 0| return NO; 67| 0| } 68| 0|} 69| | 70| |- (BOOL)isMatchedEventParameters:(nullable NSDictionary *)eventParams 71| | paramPath:(NSArray *)paramPath 72| 0|{ 73| 0| eventParams = [FBSDKTypeUtility dictionaryValue:eventParams]; 74| 0| if (!eventParams || !paramPath.count) { 75| 0| return NO; 76| 0| } 77| 0| NSString *param = [FBSDKTypeUtility stringValueOrNil:paramPath.firstObject]; 78| 0| if ([param hasSuffix:ASTERISK_DELIMETER]) { 79| 0| return [self isMatchedWithAsteriskParam:param eventParameters:eventParams paramPath:paramPath]; 80| 0| } 81| | // if data does not contain the key, we should return false directly. 82| 0| if (!param || ![[eventParams allKeys] containsObject:param]) { 83| 0| return NO; 84| 0| } 85| | // Apply operator rule if the last param is reached 86| 0| if (paramPath.count == 1) { 87| 0| NSString *stringValue = nil; 88| 0| NSNumber *numericalValue = nil; 89| 0| switch (_operator) { 90| 0| case FBSDKAEMAdvertiserRuleOperatorContains: 91| 0| case FBSDKAEMAdvertiserRuleOperatorNotContains: 92| 0| case FBSDKAEMAdvertiserRuleOperatorStartsWith: 93| 0| case FBSDKAEMAdvertiserRuleOperatorI_Contains: 94| 0| case FBSDKAEMAdvertiserRuleOperatorI_NotContains: 95| 0| case FBSDKAEMAdvertiserRuleOperatorI_StartsWith: 96| 0| case FBSDKAEMAdvertiserRuleOperatorRegexMatch: 97| 0| case FBSDKAEMAdvertiserRuleOperatorEqual: 98| 0| case FBSDKAEMAdvertiserRuleOperatorNotEqual: 99| 0| case FBSDKAEMAdvertiserRuleOperatorI_IsAny: 100| 0| case FBSDKAEMAdvertiserRuleOperatorI_IsNotAny: 101| 0| case FBSDKAEMAdvertiserRuleOperatorIsAny: 102| 0| case FBSDKAEMAdvertiserRuleOperatorIsNotAny: 103| 0| stringValue = [FBSDKTypeUtility dictionary:eventParams objectForKey:param ofType:NSString.class]; break; 104| 0| case FBSDKAEMAdvertiserRuleOperatorLessThan: 105| 0| case FBSDKAEMAdvertiserRuleOperatorLessThanOrEqual: 106| 0| case FBSDKAEMAdvertiserRuleOperatorGreaterThan: 107| 0| case FBSDKAEMAdvertiserRuleOperatorGreaterThanOrEqual: 108| 0| numericalValue = [FBSDKTypeUtility dictionary:eventParams objectForKey:param ofType:NSNumber.class]; break; 109| 0| default: break; 110| 0| } 111| 0| return [self isMatchedWithStringValue:stringValue numericalValue:numericalValue]; 112| 0| } 113| 0| NSDictionary *subParams = [FBSDKTypeUtility dictionary:eventParams objectForKey:param ofType:NSDictionary.class]; 114| 0| NSRange range = NSMakeRange(1, paramPath.count - 1); 115| 0| NSArray *subParamPath = [paramPath subarrayWithRange:range]; 116| 0| return [self isMatchedEventParameters:subParams paramPath:subParamPath]; 117| 0|} 118| | 119| |- (BOOL)isMatchedWithAsteriskParam:(NSString *)param 120| | eventParameters:(NSDictionary *)eventParams 121| | paramPath:(NSArray *)paramPath 122| 0|{ 123| 0| param = [param substringToIndex:param.length - ASTERISK_DELIMETER.length]; 124| 0| NSArray *items = [FBSDKTypeUtility dictionary:eventParams objectForKey:param ofType:NSArray.class]; 125| 0| if (!items.count || paramPath.count < 2) { 126| 0| return NO; 127| 0| } 128| 0| BOOL isMatched = NO; 129| 0| NSRange range = NSMakeRange(1, paramPath.count - 1); 130| 0| NSArray *subParamPath = [paramPath subarrayWithRange:range]; 131| 0| for (NSDictionary *item in items) { 132| 0| isMatched |= [self isMatchedEventParameters:item paramPath:subParamPath]; 133| 0| if (isMatched) { 134| 0| break; 135| 0| } 136| 0| } 137| 0| return isMatched; 138| 0|} 139| | 140| |- (BOOL)isMatchedWithStringValue:(nullable NSString *)stringValue 141| | numericalValue:(nullable NSNumber *)numericalValue 142| 0|{ 143| 0| BOOL isMatched = NO; 144| 0| switch (_operator) { 145| 0| case FBSDKAEMAdvertiserRuleOperatorContains: 146| 0| isMatched = stringValue && [stringValue containsString:_linguisticCondition]; break; 147| 0| case FBSDKAEMAdvertiserRuleOperatorNotContains: 148| 0| isMatched = !(stringValue && [stringValue containsString:_linguisticCondition]); break; 149| 0| case FBSDKAEMAdvertiserRuleOperatorStartsWith: 150| 0| isMatched = stringValue && [stringValue hasPrefix:_linguisticCondition]; break; 151| 0| case FBSDKAEMAdvertiserRuleOperatorI_Contains: 152| 0| isMatched = stringValue && [stringValue.lowercaseString containsString:_linguisticCondition.lowercaseString]; break; 153| 0| case FBSDKAEMAdvertiserRuleOperatorI_NotContains: 154| 0| isMatched = !(stringValue && [stringValue.lowercaseString containsString:_linguisticCondition.lowercaseString]); break; 155| 0| case FBSDKAEMAdvertiserRuleOperatorI_StartsWith: 156| 0| isMatched = stringValue && [stringValue.lowercaseString hasPrefix:_linguisticCondition.lowercaseString]; break; 157| 0| case FBSDKAEMAdvertiserRuleOperatorRegexMatch: 158| 0| isMatched = stringValue && [self isRegexMatch:stringValue]; break; 159| 0| case FBSDKAEMAdvertiserRuleOperatorEqual: 160| 0| isMatched = stringValue && [stringValue isEqualToString:_linguisticCondition]; break; 161| 0| case FBSDKAEMAdvertiserRuleOperatorNotEqual: 162| 0| isMatched = !(stringValue && [stringValue isEqualToString:_linguisticCondition]); break; 163| 0| case FBSDKAEMAdvertiserRuleOperatorI_IsAny: 164| 0| isMatched = stringValue && [self isAnyOf:_arrayCondition stringValue:stringValue ignoreCase:YES]; break; 165| 0| case FBSDKAEMAdvertiserRuleOperatorI_IsNotAny: 166| 0| isMatched = !(stringValue && [self isAnyOf:_arrayCondition stringValue:stringValue ignoreCase:YES]); break; 167| 0| case FBSDKAEMAdvertiserRuleOperatorIsAny: 168| 0| isMatched = stringValue && [self isAnyOf:_arrayCondition stringValue:stringValue ignoreCase:NO]; break; 169| 0| case FBSDKAEMAdvertiserRuleOperatorIsNotAny: 170| 0| isMatched = !(stringValue && [self isAnyOf:_arrayCondition stringValue:stringValue ignoreCase:NO]); break; 171| 0| case FBSDKAEMAdvertiserRuleOperatorLessThan: 172| 0| isMatched = (numericalValue != nil) && ([numericalValue compare:_numericalCondition] == NSOrderedAscending); break; 173| 0| case FBSDKAEMAdvertiserRuleOperatorLessThanOrEqual: 174| 0| isMatched = (numericalValue != nil) && ([numericalValue compare:_numericalCondition] != NSOrderedDescending); break; 175| 0| case FBSDKAEMAdvertiserRuleOperatorGreaterThan: 176| 0| isMatched = (numericalValue != nil) && ([numericalValue compare:_numericalCondition] == NSOrderedDescending); break; 177| 0| case FBSDKAEMAdvertiserRuleOperatorGreaterThanOrEqual: 178| 0| isMatched = (numericalValue != nil) && ([numericalValue compare:_numericalCondition] != NSOrderedAscending); break; 179| 0| default: break; 180| 0| } 181| 0| return isMatched; 182| 0|} 183| | 184| |- (BOOL)isRegexMatch:(NSString *)stringValue 185| 0|{ 186| 0| if (!_linguisticCondition.length) { 187| 0| return NO; 188| 0| } 189| 0| NSError *error = nil; 190| 0| NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:_linguisticCondition options:0 error:&error]; 191| 0| if (!regex || error) { 192| 0| return NO; 193| 0| } 194| 0| NSRange searchedRange = NSMakeRange(0, stringValue.length); 195| 0| NSArray *matches = [regex matchesInString:stringValue options:0 range:searchedRange]; 196| 0| return matches.count > 0; 197| 0|} 198| | 199| |- (BOOL)isAnyOf:(NSArray *)arrayCondition 200| | stringValue:(NSString *)stringValue 201| | ignoreCase:(BOOL)ignoreCase 202| 0|{ 203| 0| NSMutableSet *set = [NSMutableSet new]; 204| 0| for (NSString *item in arrayCondition) { 205| 0| if (ignoreCase) { 206| 0| [set addObject:item.lowercaseString]; 207| 0| } else { 208| 0| [set addObject:item]; 209| 0| } 210| 0| } 211| 0| if (ignoreCase) { 212| 0| stringValue = stringValue.lowercaseString; 213| 0| } 214| 0| return [set containsObject:stringValue]; 215| 0|} 216| | 217| | #pragma mark - NSCoding 218| | 219| |+ (BOOL)supportsSecureCoding 220| 0|{ 221| 0| return YES; 222| 0|} 223| | 224| |- (instancetype)initWithCoder:(NSCoder *)decoder 225| 0|{ 226| 0| FBSDKAEMAdvertiserRuleOperator op = [decoder decodeIntegerForKey:OPERATOR_KEY]; 227| 0| NSString *paramKey = [decoder decodeObjectOfClass:NSString.class forKey:PARAMKEY_KEY]; 228| 0| NSString *linguisticCondition = [decoder decodeObjectOfClass:NSString.class forKey:STRING_VALUE_KEY]; 229| 0| NSNumber *numericalCondition = [decoder decodeObjectOfClass:NSNumber.class forKey:NUMBER_VALUE_KEY]; 230| 0| NSArray *arrayCondition = [decoder decodeObjectOfClass:NSArray.class forKey:ARRAY_VALUE_KEY]; 231| 0| return [self initWithOperator:op 232| 0| paramKey:paramKey 233| 0| linguisticCondition:linguisticCondition 234| 0| numericalCondition:numericalCondition 235| 0| arrayCondition:arrayCondition]; 236| 0|} 237| | 238| |- (void)encodeWithCoder:(NSCoder *)encoder 239| 0|{ 240| 0| [encoder encodeInteger:_operator forKey:OPERATOR_KEY]; 241| 0| [encoder encodeObject:_paramKey forKey:PARAMKEY_KEY]; 242| 0| [encoder encodeObject:_linguisticCondition forKey:STRING_VALUE_KEY]; 243| 0| [encoder encodeObject:_numericalCondition forKey:NUMBER_VALUE_KEY]; 244| 0| [encoder encodeObject:_arrayCondition forKey:ARRAY_VALUE_KEY]; 245| 0|} 246| | 247| | #pragma mark - NSCopying 248| | 249| |- (instancetype)copyWithZone:(NSZone *)zone 250| 0|{ 251| 0| return self; 252| 0|} 253| | 254| | #if DEBUG 255| | #if FBSDKTEST 256| | 257| |- (void)setOperator:(FBSDKAEMAdvertiserRuleOperator)operator 258| 0|{ 259| 0| _operator = operator; 260| 0|} 261| | 262| | #endif 263| | #endif 264| | 265| |@end 266| | 267| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMConfiguration.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKAEMConfiguration.h" 24| | 25| | #import "FBSDKAEMAdvertiserMultiEntryRule.h" 26| | #import "FBSDKAEMAdvertiserSingleEntryRule.h" 27| | #import "FBSDKCoreKitBasicsImport.h" 28| | 29| |static NSString *const DEFAULT_CURRENCY_KEY = @"default_currency"; 30| |static NSString *const CUTOFF_TIME_KEY = @"cutoff_time"; 31| |static NSString *const CONVERSION_RULES_KEY = @"conversion_value_rules"; 32| |static NSString *const VALID_FROM_KEY = @"valid_from"; 33| |static NSString *const CONFIG_MODE_KEY = @"config_mode"; 34| |static NSString *const CONFIG_BUSINESS_ID_KEY = @"advertiser_id"; 35| |static NSString *const BUSINESS_ID_KEY = @"business_id"; 36| |static NSString *const PARAM_RULE_KEY = @"param_rule"; 37| | 38| |static id _ruleProvider; 39| | 40| |@implementation FBSDKAEMConfiguration 41| | 42| |+ (void)configureWithRuleProvider:(id)ruleProvider 43| 0|{ 44| 0| if (self == [FBSDKAEMConfiguration class]) { 45| 0| _ruleProvider = ruleProvider; 46| 0| } 47| 0|} 48| | 49| |+ (id)ruleProvider 50| 0|{ 51| 0| return _ruleProvider; 52| 0|} 53| | 54| |- (nullable instancetype)initWithJSON:(nullable NSDictionary *)dict 55| 0|{ 56| 0| if ((self = [super init])) { 57| 0| @try { 58| 0| dict = [FBSDKTypeUtility dictionaryValue:dict]; 59| 0| if (!dict) { 60| 0| return nil; 61| 0| } 62| 0| NSString *defaultCurrency = [FBSDKTypeUtility dictionary:dict objectForKey:DEFAULT_CURRENCY_KEY ofType:NSString.class]; 63| 0| NSNumber *cutoffTime = [FBSDKTypeUtility dictionary:dict objectForKey:CUTOFF_TIME_KEY ofType:NSNumber.class]; 64| 0| NSNumber *validFrom = [FBSDKTypeUtility dictionary:dict objectForKey:VALID_FROM_KEY ofType:NSNumber.class]; 65| 0| NSString *configMode = [FBSDKTypeUtility dictionary:dict objectForKey:CONFIG_MODE_KEY ofType:NSString.class]; 66| 0| NSString *businessID = [FBSDKTypeUtility dictionary:dict objectForKey:CONFIG_BUSINESS_ID_KEY ofType:NSString.class]; 67| 0| NSString *paramRuleJson = [FBSDKTypeUtility dictionary:dict objectForKey:PARAM_RULE_KEY ofType:NSString.class]; 68| 0| id matchingRule = [FBSDKAEMConfiguration.ruleProvider createRuleWithJson:paramRuleJson]; 69| 0| NSArray *rules = [FBSDKAEMConfiguration parseRules:[FBSDKTypeUtility dictionary:dict objectForKey:CONVERSION_RULES_KEY ofType:NSArray.class]]; 70| 0| if (!defaultCurrency || cutoffTime == nil || validFrom == nil || !configMode || 0 == rules.count) { 71| 0| return nil; 72| 0| } 73| | // Advertiser Config must have param rule 74| 0| if (businessID && !matchingRule) { 75| 0| return nil; 76| 0| } 77| 0| _defaultCurrency = defaultCurrency; 78| 0| _cutoffTime = cutoffTime.integerValue; 79| 0| _validFrom = validFrom.integerValue; 80| 0| _configMode = configMode; 81| 0| _businessID = businessID; 82| 0| _matchingRule = matchingRule; 83| 0| _conversionValueRules = rules; 84| 0| _eventSet = [FBSDKAEMConfiguration getEventSetFromRules:_conversionValueRules]; 85| 0| _currencySet = [FBSDKAEMConfiguration getCurrencySetFromRules:_conversionValueRules]; 86| 0| } @catch (NSException *exception) { 87| 0| return nil; 88| 0| } 89| 0| } 90| 0| return self; 91| 0|} 92| | 93| |- (instancetype)initWithDefaultCurrency:(NSString *)defaultCurrency 94| | cutoffTime:(NSInteger)cutoffTime 95| | validFrom:(NSInteger)validFrom 96| | configMode:(NSString *)configMode 97| | businessID:(nullable NSString *)businessID 98| | matchingRule:(id)matchingRule 99| | conversionValueRules:(NSArray *)conversionValueRules 100| 0|{ 101| 0| if ((self = [super init])) { 102| 0| _defaultCurrency = defaultCurrency; 103| 0| _cutoffTime = cutoffTime; 104| 0| _validFrom = validFrom; 105| 0| _configMode = configMode; 106| 0| _businessID = businessID; 107| 0| _matchingRule = matchingRule; 108| 0| _conversionValueRules = conversionValueRules; 109| 0| _eventSet = [FBSDKAEMConfiguration getEventSetFromRules:_conversionValueRules]; 110| 0| _currencySet = [FBSDKAEMConfiguration getCurrencySetFromRules:_conversionValueRules]; 111| 0| } 112| 0| return self; 113| 0|} 114| | 115| |+ (nullable NSArray *)parseRules:(nullable NSArray *> *)rules 116| 0|{ 117| 0| if (0 == rules.count) { 118| 0| return nil; 119| 0| } 120| 0| NSMutableArray *parsedRules = [NSMutableArray new]; 121| 0| for (NSDictionary *ruleEntry in rules) { 122| 0| FBSDKAEMRule *rule = [[FBSDKAEMRule alloc] initWithJSON:ruleEntry]; 123| 0| if (!rule) { 124| 0| return nil; 125| 0| } 126| 0| [FBSDKTypeUtility array:parsedRules addObject:rule]; 127| 0| } 128| | // Sort the rules in descending priority order 129| 0| [parsedRules sortUsingComparator:^NSComparisonResult (FBSDKAEMRule *obj1, FBSDKAEMRule *obj2) { 130| 0| if (obj1.priority < obj2.priority) { 131| 0| return NSOrderedDescending; 132| 0| } 133| 0| if (obj1.priority > obj2.priority) { 134| 0| return NSOrderedAscending; 135| 0| } 136| 0| return NSOrderedSame; 137| 0| }]; 138| 0| return [parsedRules copy]; 139| 0|} 140| | 141| |+ (NSSet *)getEventSetFromRules:(NSArray *)rules 142| 0|{ 143| 0| NSMutableSet *eventSet = [NSMutableSet new]; 144| 0| for (FBSDKAEMRule *rule in rules) { 145| 0| if (!rule) { 146| 0| continue; 147| 0| } 148| 0| for (FBSDKAEMEvent *event in rule.events) { 149| 0| if (event.eventName) { 150| 0| [eventSet addObject:event.eventName]; 151| 0| } 152| 0| } 153| 0| } 154| 0| return [eventSet copy]; 155| 0|} 156| | 157| |+ (NSSet *)getCurrencySetFromRules:(NSArray *)rules 158| 0|{ 159| 0| NSMutableSet *currencySet = [NSMutableSet new]; 160| 0| for (FBSDKAEMRule *rule in rules) { 161| 0| if (!rule) { 162| 0| continue; 163| 0| } 164| 0| for (FBSDKAEMEvent *event in rule.events) { 165| 0| for (NSString *currency in event.values) { 166| 0| [currencySet addObject:[currency uppercaseString]]; 167| 0| } 168| 0| } 169| 0| } 170| 0| return [currencySet copy]; 171| 0|} 172| | 173| |- (BOOL)isSameValidFrom:(NSInteger)validFrom 174| | businessID:(nullable NSString *)businessID 175| 0|{ 176| 0| return (_validFrom == validFrom) && [self isSameBusinessID:businessID]; 177| 0|} 178| | 179| |- (BOOL)isSameBusinessID:(nullable NSString *)businessID 180| 0|{ 181| 0| return (_businessID && [_businessID isEqualToString:businessID]) 182| 0| || (!_businessID && !businessID); 183| 0|} 184| | 185| | #pragma mark - NSCoding 186| | 187| |+ (BOOL)supportsSecureCoding 188| 0|{ 189| 0| return YES; 190| 0|} 191| | 192| |- (instancetype)initWithCoder:(NSCoder *)decoder 193| 0|{ 194| 0| NSString *defaultCurrency = [decoder decodeObjectOfClass:NSString.class forKey:DEFAULT_CURRENCY_KEY]; 195| 0| NSInteger cutoffTime = [decoder decodeIntegerForKey:CUTOFF_TIME_KEY]; 196| 0| NSInteger validFrom = [decoder decodeIntegerForKey:VALID_FROM_KEY]; 197| 0| NSString *configMode = [decoder decodeObjectOfClass:NSString.class forKey:CONFIG_MODE_KEY]; 198| 0| NSString *businessID = [decoder decodeObjectOfClass:NSString.class forKey:BUSINESS_ID_KEY]; 199| 0| NSSet *matchingRuleClasses = [NSSet setWithArray:@[NSArray.class, FBSDKAEMAdvertiserMultiEntryRule.class, FBSDKAEMAdvertiserSingleEntryRule.class]]; 200| 0| id matchingRule = [decoder decodeObjectOfClasses:matchingRuleClasses forKey:PARAM_RULE_KEY]; 201| 0| NSArray *rules = [decoder decodeObjectOfClasses:[NSSet setWithArray:@[NSArray.class, FBSDKAEMRule.class, FBSDKAEMEvent.class]] forKey:CONVERSION_RULES_KEY]; 202| 0| return [self initWithDefaultCurrency:defaultCurrency 203| 0| cutoffTime:cutoffTime 204| 0| validFrom:validFrom 205| 0| configMode:configMode 206| 0| businessID:businessID 207| 0| matchingRule:matchingRule 208| 0| conversionValueRules:rules]; 209| 0|} 210| | 211| |- (void)encodeWithCoder:(NSCoder *)encoder 212| 0|{ 213| 0| [encoder encodeObject:_defaultCurrency forKey:DEFAULT_CURRENCY_KEY]; 214| 0| [encoder encodeInteger:_cutoffTime forKey:CUTOFF_TIME_KEY]; 215| 0| [encoder encodeInteger:_validFrom forKey:VALID_FROM_KEY]; 216| 0| [encoder encodeObject:_configMode forKey:CONFIG_MODE_KEY]; 217| 0| [encoder encodeObject:_businessID forKey:BUSINESS_ID_KEY]; 218| 0| [encoder encodeObject:_matchingRule forKey:PARAM_RULE_KEY]; 219| 0| [encoder encodeObject:_conversionValueRules forKey:CONVERSION_RULES_KEY]; 220| 0|} 221| | 222| | #pragma mark - NSCopying 223| | 224| |- (instancetype)copyWithZone:(NSZone *)zone 225| 0|{ 226| 0| return self; 227| 0|} 228| | 229| |@end 230| | 231| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMEvent.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKAEMEvent.h" 24| | 25| | #import "FBSDKCoreKitBasicsImport.h" 26| | 27| |static NSString *const EVENT_NAME_KEY = @"event_name"; 28| |static NSString *const VALUES_KEY = @"values"; 29| |static NSString *const CURRENCY_KEY = @"currency"; 30| |static NSString *const AMOUNT_KEY = @"amount"; 31| | 32| |@implementation FBSDKAEMEvent 33| | 34| |- (nullable instancetype)initWithJSON:(nullable NSDictionary *)dict 35| 0|{ 36| 0| if ((self = [super init])) { 37| 0| dict = [FBSDKTypeUtility dictionaryValue:dict]; 38| 0| if (!dict) { 39| 0| return nil; 40| 0| } 41| 0| _eventName = [FBSDKTypeUtility dictionary:dict objectForKey:EVENT_NAME_KEY ofType:NSString.class]; 42| | // Event name is a required field 43| 0| if (!_eventName) { 44| 0| return nil; 45| 0| } 46| | // Values is an optional field 47| 0| NSArray *> *valueEntries = [FBSDKTypeUtility dictionary:dict objectForKey:VALUES_KEY ofType:NSArray.class]; 48| 0| if (valueEntries.count > 0) { 49| 0| NSMutableDictionary *valueDict = [NSMutableDictionary new]; 50| 0| for (NSDictionary *valueEntry in valueEntries) { 51| 0| NSDictionary *value = [FBSDKTypeUtility dictionaryValue:valueEntry]; 52| 0| NSString *currency = [FBSDKTypeUtility dictionary:value objectForKey:CURRENCY_KEY ofType:NSString.class]; 53| 0| NSNumber *amount = [FBSDKTypeUtility dictionary:value objectForKey:AMOUNT_KEY ofType:NSNumber.class]; 54| 0| if (!currency || amount == nil) { 55| 0| return nil; 56| 0| } 57| 0| [FBSDKTypeUtility dictionary:valueDict setObject:amount forKey:[currency uppercaseString]]; 58| 0| } 59| 0| _values = [valueDict copy]; 60| 0| } 61| 0| } 62| 0| return self; 63| 0|} 64| | 65| |- (instancetype)initWithEventName:(NSString *)eventName 66| | values:(NSDictionary *)values 67| 0|{ 68| 0| if ((self = [super init])) { 69| 0| _eventName = eventName; 70| 0| _values = values; 71| 0| } 72| 0| return self; 73| 0|} 74| | 75| | #pragma mark - NSCoding 76| | 77| |+ (BOOL)supportsSecureCoding 78| 0|{ 79| 0| return YES; 80| 0|} 81| | 82| |- (instancetype)initWithCoder:(NSCoder *)decoder 83| 0|{ 84| 0| NSString *eventName = [decoder decodeObjectOfClass:NSString.class forKey:EVENT_NAME_KEY]; 85| 0| NSDictionary *values = [decoder decodeObjectOfClass:NSDictionary.class forKey:VALUES_KEY]; 86| 0| return [self initWithEventName:eventName values:values]; 87| 0|} 88| | 89| |- (void)encodeWithCoder:(NSCoder *)encoder 90| 0|{ 91| 0| [encoder encodeObject:_eventName forKey:EVENT_NAME_KEY]; 92| 0| if (_values) { 93| 0| [encoder encodeObject:_values forKey:VALUES_KEY]; 94| 0| } 95| 0|} 96| | 97| | #pragma mark - NSCopying 98| | 99| |- (instancetype)copyWithZone:(NSZone *)zone 100| 0|{ 101| 0| return self; 102| 0|} 103| | 104| |@end 105| | 106| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMInvocation.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKAEMInvocation.h" 24| | 25| | #import 26| | 27| | #import "FBSDKCoreKitBasicsImport.h" 28| | 29| 0| #define SEC_IN_DAY 86400 30| | 31| |static NSString *const CAMPAIGN_ID_KEY = @"campaign_ids"; 32| |static NSString *const ACS_TOKEN_KEY = @"acs_token"; 33| |static NSString *const ACS_SHARED_SECRET_KEY = @"shared_secret"; 34| |static NSString *const ACS_CONFIG_ID_KEY = @"acs_config_id"; 35| |static NSString *const BUSINESS_ID_KEY = @"advertiser_id"; 36| |static NSString *const TIMESTAMP_KEY = @"timestamp"; 37| |static NSString *const CONFIG_MODE_KEY = @"config_mode"; 38| |static NSString *const CONFIG_ID_KEY = @"config_id"; 39| |static NSString *const RECORDED_EVENTS_KEY = @"recorded_events"; 40| |static NSString *const RECORDED_VALUES_KEY = @"recorded_values"; 41| |static NSString *const CONVERSION_VALUE_KEY = @"conversion_value"; 42| |static NSString *const PRIORITY_KEY = @"priority"; 43| |static NSString *const CONVERSION_TIMESTAMP_KEY = @"conversion_timestamp"; 44| |static NSString *const IS_AGGREGATED_KEY = @"is_aggregated"; 45| | 46| |typedef NSString *const FBSDKAEMInvocationConfigMode; 47| | 48| |FBSDKAEMInvocationConfigMode FBSDKAEMInvocationConfigDefaultMode = @"DEFAULT"; 49| |FBSDKAEMInvocationConfigMode FBSDKAEMInvocationConfigBrandMode = @"BRAND"; 50| | 51| |@implementation FBSDKAEMInvocation 52| | 53| |+ (nullable instancetype)invocationWithAppLinkData:(nullable NSDictionary *)applinkData 54| 0|{ 55| 0| @try { 56| 0| applinkData = [FBSDKTypeUtility dictionaryValue:applinkData]; 57| 0| if (!applinkData) { 58| 0| return nil; 59| 0| } 60| | 61| 0| NSString *campaignID = [FBSDKTypeUtility dictionary:applinkData objectForKey:CAMPAIGN_ID_KEY ofType:NSString.class]; 62| 0| NSString *ACSToken = [FBSDKTypeUtility dictionary:applinkData objectForKey:ACS_TOKEN_KEY ofType:NSString.class]; 63| 0| NSString *ACSSharedSecret = [FBSDKTypeUtility dictionary:applinkData objectForKey:ACS_SHARED_SECRET_KEY ofType:NSString.class]; 64| 0| NSString *ACSConfigID = [FBSDKTypeUtility dictionary:applinkData objectForKey:CONFIG_ID_KEY ofType:NSString.class]; 65| 0| NSString *businessID = [FBSDKTypeUtility dictionary:applinkData objectForKey:BUSINESS_ID_KEY ofType:NSString.class]; 66| 0| if (campaignID == nil || ACSToken == nil) { 67| 0| return nil; 68| 0| } 69| 0| return [[FBSDKAEMInvocation alloc] initWithCampaignID:campaignID 70| 0| ACSToken:ACSToken 71| 0| ACSSharedSecret:ACSSharedSecret 72| 0| ACSConfigID:ACSConfigID 73| 0| businessID:businessID]; 74| 0| } @catch (NSException *exception) { 75| 0| return nil; 76| 0| } 77| 0|} 78| | 79| |- (nullable instancetype)initWithCampaignID:(NSString *)campaignID 80| | ACSToken:(NSString *)ACSToken 81| | ACSSharedSecret:(nullable NSString *)ACSSharedSecret 82| | ACSConfigID:(nullable NSString *)ACSConfigID 83| | businessID:(nullable NSString *)businessID 84| 0|{ 85| 0| return [self initWithCampaignID:campaignID 86| 0| ACSToken:ACSToken 87| 0| ACSSharedSecret:ACSSharedSecret 88| 0| ACSConfigID:ACSConfigID 89| 0| businessID:businessID 90| 0| timestamp:nil 91| 0| configMode:nil 92| 0| configID:-1 93| 0| recordedEvents:nil 94| 0| recordedValues:nil 95| 0| conversionValue:-1 96| 0| priority:-1 97| 0| conversionTimestamp:nil 98| 0| isAggregated:YES]; 99| 0|} 100| | 101| |- (nullable instancetype)initWithCampaignID:(NSString *)campaignID 102| | ACSToken:(NSString *)ACSToken 103| | ACSSharedSecret:(nullable NSString *)ACSSharedSecret 104| | ACSConfigID:(nullable NSString *)ACSConfigID 105| | businessID:(nullable NSString *)businessID 106| | timestamp:(nullable NSDate *)timestamp 107| | configMode:(nullable NSString *)configMode 108| | configID:(NSInteger)configID 109| | recordedEvents:(nullable NSMutableSet *)recordedEvents 110| | recordedValues:(nullable NSMutableDictionary *)recordedValues 111| | conversionValue:(NSInteger)conversionValue 112| | priority:(NSInteger)priority 113| | conversionTimestamp:(nullable NSDate *)conversionTimestamp 114| | isAggregated:(BOOL)isAggregated 115| 0|{ 116| 0| if ((self = [super init])) { 117| 0| _campaignID = campaignID; 118| 0| _ACSToken = ACSToken; 119| 0| _ACSSharedSecret = ACSSharedSecret; 120| 0| _ACSConfigID = ACSConfigID; 121| 0| _businessID = businessID; 122| 0| if ([timestamp isKindOfClass:NSDate.class]) { 123| 0| _timestamp = timestamp; 124| 0| } else { 125| 0| _timestamp = [NSDate date]; 126| 0| } 127| 0| _configMode = configMode; 128| 0| _configID = configID; 129| 0| if ([recordedEvents isKindOfClass:NSMutableSet.class]) { 130| 0| _recordedEvents = recordedEvents; 131| 0| } else { 132| 0| _recordedEvents = [NSMutableSet new]; 133| 0| } 134| 0| if ([recordedValues isKindOfClass:NSMutableDictionary.class]) { 135| 0| _recordedValues = recordedValues; 136| 0| } else { 137| 0| _recordedValues = [NSMutableDictionary new]; 138| 0| } 139| 0| _conversionValue = conversionValue; 140| 0| _priority = priority; 141| 0| _conversionTimestamp = conversionTimestamp; 142| 0| _isAggregated = isAggregated; 143| 0| } 144| 0| return self; 145| 0|} 146| | 147| |- (BOOL)attributeEvent:(NSString *)event 148| | currency:(nullable NSString *)currency 149| | value:(nullable NSNumber *)value 150| | parameters:(nullable NSDictionary *)parameters 151| | configs:(nullable NSDictionary *> *)configs 152| 0|{ 153| 0| FBSDKAEMConfiguration *config = [self _findConfig:configs]; 154| 0| if ([self _isOutOfWindowWithConfig:config] || ![config.eventSet containsObject:event]) { 155| 0| return NO; 156| 0| } 157| | // Check advertiser rule matching 158| 0| if (config.matchingRule && ![config.matchingRule isMatchedEventParameters:parameters]) { 159| 0| return NO; 160| 0| } 161| 0| BOOL isAttributed = NO; 162| 0| if (![_recordedEvents containsObject:event]) { 163| 0| [_recordedEvents addObject:event]; 164| 0| isAttributed = YES; 165| 0| } 166| | // Change currency to default currency if currency is not found in currencySet 167| 0| NSString *valueCurrency = [currency uppercaseString]; 168| 0| if (![config.currencySet containsObject:valueCurrency]) { 169| 0| valueCurrency = config.defaultCurrency; 170| 0| } 171| 0| if (value != nil) { 172| 0| NSMutableDictionary *mapping = [[FBSDKTypeUtility dictionary:_recordedValues objectForKey:event ofType:NSDictionary.class] mutableCopy] ?: [NSMutableDictionary new]; 173| 0| NSNumber *valueInMapping = [FBSDKTypeUtility dictionary:mapping objectForKey:valueCurrency ofType:NSNumber.class] ?: [NSNumber numberWithDouble:0]; 174| | // Overwrite values when the incoming event's value is greater than the cached one 175| 0| if (value.doubleValue > valueInMapping.doubleValue) { 176| 0| [FBSDKTypeUtility dictionary:mapping setObject:[NSNumber numberWithDouble:value.doubleValue] forKey:valueCurrency]; 177| 0| [FBSDKTypeUtility dictionary:_recordedValues setObject:mapping forKey:event]; 178| 0| isAttributed = YES; 179| 0| } 180| 0| } 181| 0| return isAttributed; 182| 0|} 183| | 184| |- (BOOL)updateConversionValueWithConfigs:(nullable NSDictionary *> *)configs 185| 0|{ 186| 0| FBSDKAEMConfiguration *config = [self _findConfig:configs]; 187| 0| if (!config) { 188| 0| return NO; 189| 0| } 190| | // Update conversion value if a rule is matched 191| 0| for (FBSDKAEMRule *rule in config.conversionValueRules) { 192| 0| if (rule.priority <= _priority) { 193| 0| break; 194| 0| } 195| 0| if ([rule isMatchedWithRecordedEvents:_recordedEvents recordedValues:_recordedValues]) { 196| 0| _conversionValue = rule.conversionValue; 197| 0| _priority = rule.priority; 198| 0| _conversionTimestamp = [NSDate date]; 199| 0| _isAggregated = NO; 200| 0| return YES; 201| 0| } 202| 0| } 203| 0| return NO; 204| 0|} 205| | 206| |- (BOOL)isOutOfWindowWithConfigs:(nullable NSDictionary *> *)configs 207| 0|{ 208| 0| FBSDKAEMConfiguration *config = [self _findConfig:configs]; 209| 0| return [self _isOutOfWindowWithConfig:config]; 210| 0|} 211| | 212| |- (nullable NSString *)getHMAC:(NSInteger)delay 213| 0|{ 214| 0| if (!_ACSSharedSecret || !_ACSConfigID) { 215| 0| return nil; 216| 0| } 217| 0| @try { 218| 0| NSData *secretData = [self decodeBase64UrlSafeString:_ACSSharedSecret]; 219| 0| if (!secretData) { 220| 0| return nil; 221| 0| } 222| 0| NSMutableData *hmac = [NSMutableData dataWithLength:CC_SHA512_DIGEST_LENGTH]; 223| 0| NSString *text = [NSString stringWithFormat:@"%@|%@|%@|%@", _campaignID, @(_conversionValue), @(delay), @"server"]; 224| 0| NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding]; 225| 0| CCHmac(kCCHmacAlgSHA512, [secretData bytes], [secretData length], [clearTextData bytes], [clearTextData length], hmac.mutableBytes); 226| 0| NSString *base64UrlSafeString = [hmac base64EncodedStringWithOptions:0]; 227| 0| base64UrlSafeString = [base64UrlSafeString stringByReplacingOccurrencesOfString:@"/" 228| 0| withString:@"_"]; 229| 0| base64UrlSafeString = [base64UrlSafeString stringByReplacingOccurrencesOfString:@"+" 230| 0| withString:@"-"]; 231| 0| base64UrlSafeString = [base64UrlSafeString stringByReplacingOccurrencesOfString:@"=" 232| 0| withString:@""]; 233| 0| return base64UrlSafeString; 234| 0| } @catch (NSException *exception) { 235| 0| return nil; 236| 0| } 237| 0|} 238| | 239| |- (nullable NSData *)decodeBase64UrlSafeString:(NSString *)base64UrlSafeString 240| 0|{ 241| 0| if (!base64UrlSafeString.length) { 242| 0| return nil; 243| 0| } 244| 0| NSString *base64String = [base64UrlSafeString stringByReplacingOccurrencesOfString:@"-" withString:@"+"]; 245| 0| base64String = [base64String stringByReplacingOccurrencesOfString:@"_" withString:@"/"]; 246| 0| base64String = [base64String stringByReplacingOccurrencesOfString:@"-" withString:@"+"]; 247| 0| NSString *padding = [@"" stringByPaddingToLength:(4 - base64String.length % 4) withString:@"=" startingAtIndex:0]; 248| 0| base64String = [base64String stringByAppendingString:padding]; 249| 0| NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0]; 250| 0| return decodedData; 251| 0|} 252| | 253| |- (BOOL)_isOutOfWindowWithConfig:(nullable FBSDKAEMConfiguration *)config 254| 0|{ 255| 0| if (!config) { 256| 0| return true; 257| 0| } 258| 0| BOOL isCutoff = [[NSDate date] timeIntervalSinceDate:_timestamp] > config.cutoffTime * SEC_IN_DAY; 259| 0| BOOL isOverLastConversionWindow = _conversionTimestamp && [[NSDate date] timeIntervalSinceDate:_conversionTimestamp] > SEC_IN_DAY; 260| 0| return isCutoff || isOverLastConversionWindow; 261| 0|} 262| | 263| |- (nullable FBSDKAEMConfiguration *)_findConfig:(nullable NSDictionary *> *)configs 264| 0|{ 265| 0| NSString *configMode = _businessID ? FBSDKAEMInvocationConfigBrandMode : FBSDKAEMInvocationConfigDefaultMode; 266| 0| NSArray *configList = [FBSDKTypeUtility dictionary:configs objectForKey:configMode ofType:NSArray.class]; 267| 0| if (0 == configList.count) { 268| 0| return nil; 269| 0| } 270| 0| if (_configID > 0) { 271| 0| for (FBSDKAEMConfiguration *config in configList) { 272| 0| if ([config isSameValidFrom:_configID businessID:_businessID]) { 273| 0| return config; 274| 0| } 275| 0| } 276| 0| return nil; 277| 0| } else { 278| 0| FBSDKAEMConfiguration *config = nil; 279| 0| for (FBSDKAEMConfiguration *c in [configList reverseObjectEnumerator]) { 280| 0| if (c.validFrom <= _timestamp.timeIntervalSince1970 && [c isSameBusinessID:_businessID]) { 281| 0| config = c; 282| 0| break; 283| 0| } 284| 0| } 285| 0| if (!config) { 286| 0| return nil; 287| 0| } 288| 0| [self _setConfig:config]; 289| 0| return config; 290| 0| } 291| 0|} 292| | 293| |- (void)_setConfig:(FBSDKAEMConfiguration *)config 294| 0|{ 295| 0| _configID = config.validFrom; 296| 0| _configMode = config.configMode; 297| 0|} 298| | 299| | #pragma mark - NSCoding 300| | 301| |+ (BOOL)supportsSecureCoding 302| 0|{ 303| 0| return YES; 304| 0|} 305| | 306| |- (instancetype)initWithCoder:(NSCoder *)decoder 307| 0|{ 308| 0| NSString *campaignID = [decoder decodeObjectOfClass:NSString.class forKey:CAMPAIGN_ID_KEY]; 309| 0| NSString *ACSToken = [decoder decodeObjectOfClass:NSString.class forKey:ACS_TOKEN_KEY]; 310| 0| NSString *ACSSharedSecret = [decoder decodeObjectOfClass:NSString.class forKey:ACS_SHARED_SECRET_KEY]; 311| 0| NSString *ACSConfigID = [decoder decodeObjectOfClass:NSString.class forKey:ACS_CONFIG_ID_KEY]; 312| 0| NSString *businessID = [decoder decodeObjectOfClass:NSString.class forKey:BUSINESS_ID_KEY]; 313| 0| NSDate *timestamp = [decoder decodeObjectOfClass:NSDate.class forKey:TIMESTAMP_KEY]; 314| 0| NSString *configMode = [decoder decodeObjectOfClass:NSString.class forKey:CONFIG_MODE_KEY]; 315| 0| NSInteger configID = [decoder decodeIntegerForKey:CONFIG_ID_KEY]; 316| 0| NSMutableSet *recordedEvents = [decoder decodeObjectOfClass:NSMutableSet.class forKey:RECORDED_EVENTS_KEY]; 317| 0| NSMutableDictionary *recordedValues = [decoder decodeObjectOfClass:NSMutableDictionary.class forKey:RECORDED_VALUES_KEY]; 318| 0| NSInteger conversionValue = [decoder decodeIntegerForKey:CONVERSION_VALUE_KEY]; 319| 0| NSInteger priority = [decoder decodeIntegerForKey:PRIORITY_KEY]; 320| 0| NSDate *conversionTimestamp = [decoder decodeObjectOfClass:NSDate.class forKey:CONVERSION_TIMESTAMP_KEY]; 321| 0| BOOL isAggregated = [decoder decodeBoolForKey:IS_AGGREGATED_KEY]; 322| 0| return [self initWithCampaignID:campaignID 323| 0| ACSToken:ACSToken 324| 0| ACSSharedSecret:ACSSharedSecret 325| 0| ACSConfigID:ACSConfigID 326| 0| businessID:businessID 327| 0| timestamp:timestamp 328| 0| configMode:configMode 329| 0| configID:configID 330| 0| recordedEvents:recordedEvents 331| 0| recordedValues:recordedValues 332| 0| conversionValue:conversionValue 333| 0| priority:priority 334| 0| conversionTimestamp:conversionTimestamp 335| 0| isAggregated:isAggregated]; 336| 0|} 337| | 338| |- (void)encodeWithCoder:(NSCoder *)encoder 339| 0|{ 340| 0| [encoder encodeObject:_campaignID forKey:CAMPAIGN_ID_KEY]; 341| 0| [encoder encodeObject:_ACSToken forKey:ACS_TOKEN_KEY]; 342| 0| [encoder encodeObject:_ACSSharedSecret forKey:ACS_SHARED_SECRET_KEY]; 343| 0| [encoder encodeObject:_ACSConfigID forKey:ACS_CONFIG_ID_KEY]; 344| 0| [encoder encodeObject:_businessID forKey:BUSINESS_ID_KEY]; 345| 0| [encoder encodeObject:_timestamp forKey:TIMESTAMP_KEY]; 346| 0| [encoder encodeObject:_configMode forKey:CONFIG_MODE_KEY]; 347| 0| [encoder encodeInteger:_configID forKey:CONFIG_ID_KEY]; 348| 0| [encoder encodeObject:_recordedEvents forKey:RECORDED_EVENTS_KEY]; 349| 0| [encoder encodeObject:_recordedValues forKey:RECORDED_VALUES_KEY]; 350| 0| [encoder encodeInteger:_conversionValue forKey:CONVERSION_VALUE_KEY]; 351| 0| [encoder encodeInteger:_priority forKey:PRIORITY_KEY]; 352| 0| [encoder encodeObject:_conversionTimestamp forKey:CONVERSION_TIMESTAMP_KEY]; 353| 0| [encoder encodeBool:_isAggregated forKey:IS_AGGREGATED_KEY]; 354| 0|} 355| | 356| | #pragma mark - NSCopying 357| | 358| |- (instancetype)copyWithZone:(NSZone *)zone 359| 0|{ 360| 0| return self; 361| 0|} 362| | 363| | #if DEBUG 364| | #if FBSDKTEST 365| | 366| |- (void)setRecordedEvents:(NSMutableSet *)recordedEvents 367| 0|{ 368| 0| _recordedEvents = recordedEvents; 369| 0|} 370| | 371| |- (void)setRecordedValues:(NSMutableDictionary *)recordedValues 372| 0|{ 373| 0| _recordedValues = recordedValues; 374| 0|} 375| | 376| |- (void)setPriority:(NSInteger)priority 377| 0|{ 378| 0| _priority = priority; 379| 0|} 380| | 381| |- (void)setConfigID:(NSInteger)configID 382| 0|{ 383| 0| _configID = configID; 384| 0|} 385| | 386| |- (void)setBusinessID:(NSString *_Nullable)businessID 387| 0|{ 388| 0| _businessID = businessID; 389| 0|} 390| | 391| |- (void)setConversionTimestamp:(NSDate *_Nonnull)conversionTimestamp 392| 0|{ 393| 0| _conversionTimestamp = conversionTimestamp; 394| 0|} 395| | 396| |- (void)setConversionValue:(NSInteger)conversionValue 397| 0|{ 398| 0| _conversionValue = conversionValue; 399| 0|} 400| | 401| |- (void)setCampaignID:(NSString *_Nonnull)campaignID 402| 0|{ 403| 0| _campaignID = campaignID; 404| 0|} 405| | 406| |- (void)setACSSharedSecret:(NSString *_Nullable)ACSSharedSecret 407| 0|{ 408| 0| _ACSSharedSecret = ACSSharedSecret; 409| 0|} 410| | 411| |- (void)setACSConfigID:(NSString *_Nullable)ACSConfigID 412| 0|{ 413| 0| _ACSConfigID = ACSConfigID; 414| 0|} 415| | 416| |- (void)reset 417| 0|{ 418| 0| _timestamp = [NSDate date]; 419| 0| _configMode = @"DEFAULT"; 420| 0| _configID = -1; 421| 0| _businessID = nil; 422| 0| _recordedEvents = [NSMutableSet new]; 423| 0| _recordedValues = [NSMutableDictionary new]; 424| 0| _conversionValue = -1; 425| 0| _priority = -1; 426| 0| _conversionTimestamp = [NSDate date]; 427| 0| _isAggregated = YES; 428| 0|} 429| | 430| | #endif 431| | #endif 432| | 433| |@end 434| | 435| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMReporter.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKAEMReporter.h" 24| | 25| | #include 26| | 27| | #import "FBSDKAEMAdvertiserRuleFactory.h" 28| | #import "FBSDKAEMConfiguration.h" 29| | #import "FBSDKAEMInvocation.h" 30| | #import "FBSDKCoreKitBasicsImport.h" 31| | #import "FBSDKGraphRequestProtocol.h" 32| | #import "FBSDKGraphRequestProviding.h" 33| | #import "FBSDKLogger.h" 34| | #import "FBSDKSettings.h" 35| | 36| 0| #define FBSDK_AEM_CONFIG_TIME_OUT 86400 37| | 38| |typedef void (^FBSDKAEMReporterBlock)(NSError *); 39| | 40| |static NSString *const BUSINESS_ID_KEY = @"advertiser_id"; 41| |static NSString *const BUSINESS_IDS_KEY = @"advertiser_ids"; 42| |static NSString *const AL_APPLINK_DATA_KEY = @"al_applink_data"; 43| |static NSString *const CAMPAIGN_ID_KEY = @"campaign_id"; 44| |static NSString *const CONVERSION_DATA_KEY = @"conversion_data"; 45| |static NSString *const CONSUMPTION_HOUR_KEY = @"consumption_hour"; 46| |static NSString *const TOKEN_KEY = @"token"; 47| |static NSString *const HMAC_KEY = @"hmac"; 48| |static NSString *const CONFIG_ID_KEY = @"config_id"; 49| |static NSString *const DELAY_FLOW_KEY = @"delay_flow"; 50| | 51| |static NSString *const FBSDKAEMConfigurationKey = @"com.facebook.sdk:FBSDKAEMConfiguration"; 52| |static NSString *const FBSDKAEMReporterKey = @"com.facebook.sdk:FBSDKAEMReporter"; 53| |static NSString *const FBSDKAEMReporterFileName = @"FBSDKAEMReportData.report"; 54| |static NSString *const FBSDKAEMConfigFileName = @"FBSDKAEMReportData.config"; 55| | 56| |static BOOL g_isAEMReportEnabled = NO; 57| |static BOOL g_isLoadingConfiguration = NO; 58| |static dispatch_queue_t g_serialQueue; 59| |static NSString *g_reportFile; 60| |static NSString *g_configFile; 61| |static NSMutableDictionary *> *g_configs; 62| |static NSMutableArray *g_invocations; 63| |static NSDate *g_configRefreshTimestamp; 64| |static NSMutableArray *g_completionBlocks; 65| |static id _requestProvider; 66| | 67| |@implementation FBSDKAEMReporter 68| | 69| |static char *const dispatchQueueLabel = "com.facebook.appevents.AEM.FBSDKAEMReporter"; 70| | 71| |+ (void)configureWithRequestProvider:(id)requestProvider 72| 0|{ 73| 0| if (self == [FBSDKAEMReporter class]) { 74| 0| _requestProvider = requestProvider; 75| 0| } 76| 0|} 77| | 78| |+ (id)requestProvider 79| 0|{ 80| 0| return _requestProvider; 81| 0|} 82| | 83| |+ (void)enable 84| 0|{ 85| 0| if (@available(iOS 14.0, *)) { 86| 0| static dispatch_once_t onceToken; 87| 0| dispatch_once(&onceToken, ^{ 88| 0| [FBSDKAEMConfiguration configureWithRuleProvider:[FBSDKAEMAdvertiserRuleFactory new]]; 89| 0| g_reportFile = [FBSDKBasicUtility persistenceFilePath:FBSDKAEMReporterFileName]; 90| 0| g_configFile = [FBSDKBasicUtility persistenceFilePath:FBSDKAEMConfigFileName]; 91| 0| g_completionBlocks = [NSMutableArray new]; 92| 0| if (!g_serialQueue) { 93| 0| g_serialQueue = dispatch_queue_create(dispatchQueueLabel, DISPATCH_QUEUE_SERIAL); 94| 0| } 95| 0| [self dispatchOnQueue:g_serialQueue block:^() { 96| 0| g_configs = [self _loadConfigs]; 97| 0| g_invocations = [self _loadReportData]; 98| 0| }]; 99| 0| [self _loadConfigurationWithBlock:^(NSError *error) { 100| 0| if (error) { 101| 0| return; 102| 0| } 103| 0| [self _sendAggregationRequest]; 104| 0| [self _clearCache]; 105| 0| }]; 106| 0| g_isAEMReportEnabled = YES; 107| 0| }); 108| 0| } 109| 0|} 110| | 111| |+ (void)handleURL:(NSURL *)url 112| 0|{ 113| 0| if (!g_isAEMReportEnabled) { 114| 0| return; 115| 0| } 116| | 117| 0| FBSDKAEMInvocation *invocation = [self parseURL:url]; 118| 0| if (!invocation) { 119| 0| return; 120| 0| } 121| | 122| 0| [self _appendAndSaveInvocation:invocation]; 123| 0|} 124| | 125| |+ (nullable FBSDKAEMInvocation *)parseURL:(NSURL *)url 126| 0|{ 127| 0| if (!url) { 128| 0| return nil; 129| 0| } 130| | 131| 0| NSDictionary *params = [FBSDKBasicUtility dictionaryWithQueryString:url.query]; 132| 0| NSString *applinkDataString = params[AL_APPLINK_DATA_KEY]; 133| 0| if (!applinkDataString) { 134| 0| return nil; 135| 0| } 136| | 137| 0| NSDictionary *applinkData = [FBSDKTypeUtility dictionaryValue:[FBSDKBasicUtility objectForJSONString:applinkDataString error:NULL]]; 138| 0| if (!applinkData) { 139| 0| return nil; 140| 0| } 141| | 142| 0| return [FBSDKAEMInvocation invocationWithAppLinkData:applinkData]; 143| 0|} 144| | 145| |+ (void)recordAndUpdateEvent:(NSString *)event 146| | currency:(nullable NSString *)currency 147| | value:(nullable NSNumber *)value 148| | parameters:(nullable NSDictionary *)parameters 149| 0|{ 150| 0| if (@available(iOS 14.0, *)) { 151| 0| if (!g_isAEMReportEnabled || 0 == event.length) { 152| 0| return; 153| 0| } 154| 0| [self _loadConfigurationWithBlock:^(NSError *error) { 155| 0| if (0 == g_configs.count || 0 == g_invocations.count) { 156| 0| return; 157| 0| } 158| | 159| 0| FBSDKAEMInvocation *attributedInvocation = [self _attributedInvocation:g_invocations Event:event currency:currency value:value parameters:parameters configs:g_configs]; 160| 0| if (attributedInvocation) { 161| 0| if ([attributedInvocation updateConversionValueWithConfigs:g_configs]) { 162| 0| [self _sendAggregationRequest]; 163| 0| } 164| 0| [self _saveReportData]; 165| 0| } 166| 0| }]; 167| 0| } 168| 0|} 169| | 170| |+ (nullable FBSDKAEMInvocation *)_attributedInvocation:(NSArray *)invocations 171| | Event:(NSString *)event 172| | currency:(nullable NSString *)currency 173| | value:(nullable NSNumber *)value 174| | parameters:(nullable NSDictionary *)parameters 175| | configs:(NSDictionary *> *)configs 176| 0|{ 177| 0| BOOL isGeneralInvocationVisited = NO; 178| 0| FBSDKAEMInvocation *attributedInvocation = nil; 179| 0| for (FBSDKAEMInvocation *invocation in [invocations reverseObjectEnumerator]) { 180| 0| if (!invocation.businessID && isGeneralInvocationVisited) { 181| 0| continue; 182| 0| } 183| | 184| 0| if ([invocation attributeEvent:event currency:currency value:value parameters:parameters configs:configs]) { 185| 0| attributedInvocation = invocation; 186| 0| break; 187| 0| } 188| 0| if (!invocation.businessID) { 189| 0| isGeneralInvocationVisited = YES; 190| 0| } 191| 0| } 192| 0| return attributedInvocation; 193| 0|} 194| | 195| |+ (void)_appendAndSaveInvocation:(FBSDKAEMInvocation *)invocation 196| 0|{ 197| 0| [self dispatchOnQueue:g_serialQueue block:^() { 198| 0| [FBSDKTypeUtility array:g_invocations addObject:invocation]; 199| 0| [self _saveReportData]; 200| 0| }]; 201| 0|} 202| | 203| |+ (void)_loadConfigurationWithBlock:(FBSDKAEMReporterBlock)block 204| 0|{ 205| 0| [self dispatchOnQueue:g_serialQueue block:^() { 206| 0| [FBSDKTypeUtility array:g_completionBlocks addObject:block]; 207| | // Executes blocks if there is cache 208| 0| if (![self _shouldRefresh]) { 209| 0| for (FBSDKAEMReporterBlock executionBlock in g_completionBlocks) { 210| 0| executionBlock(nil); 211| 0| } 212| 0| [g_completionBlocks removeAllObjects]; 213| 0| return; 214| 0| } 215| 0| if (g_isLoadingConfiguration) { 216| 0| return; 217| 0| } 218| 0| g_isLoadingConfiguration = YES; 219| 0| id request = [self.requestProvider createGraphRequestWithGraphPath:[NSString stringWithFormat:@"%@/aem_conversion_configs", [FBSDKSettings appID]] 220| 0| parameters:[self _requestParameters] 221| 0| tokenString:nil 222| 0| HTTPMethod:FBSDKHTTPMethodGET 223| 0| flags:FBSDKGraphRequestFlagSkipClientToken | FBSDKGraphRequestFlagDisableErrorRecovery]; 224| 0| [request startWithCompletion:^(id connection, id result, NSError *error) { 225| 0| [self dispatchOnQueue:g_serialQueue block:^() { 226| 0| if (error) { 227| 0| for (FBSDKAEMReporterBlock executionBlock in g_completionBlocks) { 228| 0| executionBlock(error); 229| 0| } 230| 0| [g_completionBlocks removeAllObjects]; 231| 0| g_isLoadingConfiguration = NO; 232| 0| return; 233| 0| } 234| 0| NSDictionary *json = [FBSDKTypeUtility dictionaryValue:result]; 235| 0| if (json) { 236| 0| g_configRefreshTimestamp = [NSDate date]; 237| 0| [self _addConfigs:[FBSDKTypeUtility dictionary:json objectForKey:@"data" ofType:NSArray.class]]; 238| 0| for (FBSDKAEMReporterBlock executionBlock in g_completionBlocks) { 239| 0| executionBlock(nil); 240| 0| } 241| 0| [g_completionBlocks removeAllObjects]; 242| 0| } else { 243| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Received invalid AEM config"]; 244| 0| } 245| 0| g_isLoadingConfiguration = NO; 246| 0| }]; 247| 0| }]; 248| 0| }]; 249| 0|} 250| | 251| |+ (NSDictionary *)_requestParameters 252| 0|{ 253| 0| NSMutableDictionary *params = [NSMutableDictionary new]; 254| | // append business ids to the request params 255| 0| NSMutableArray *businessIDs = [NSMutableArray new]; 256| 0| for (FBSDKAEMInvocation *invocation in g_invocations) { 257| 0| [FBSDKTypeUtility array:businessIDs addObject:invocation.businessID]; 258| 0| } 259| 0| NSString *businessIDsString = [FBSDKBasicUtility JSONStringForObject:businessIDs error:nil invalidObjectHandler:nil]; 260| 0| [FBSDKTypeUtility dictionary:params setObject:businessIDsString forKey:BUSINESS_IDS_KEY]; 261| 0| return [params copy]; 262| 0|} 263| | 264| |+ (BOOL)_isConfigRefreshTimestampValid 265| 0|{ 266| 0| return g_configRefreshTimestamp && [[NSDate date] timeIntervalSinceDate:g_configRefreshTimestamp] < FBSDK_AEM_CONFIG_TIME_OUT; 267| 0|} 268| | 269| |+ (BOOL)_shouldRefresh 270| 0|{ 271| | // Refresh if there exists invocation which has business ID 272| 0| for (FBSDKAEMInvocation *invocation in g_invocations) { 273| 0| if (invocation.businessID) { 274| 0| return YES; 275| 0| } 276| 0| } 277| | // Refresh if timestamp is expired or cached config is empty 278| 0| return (![self _isConfigRefreshTimestampValid]) || (0 == g_configs.count); 279| 0|} 280| | 281| | #pragma mark - Background methods 282| | 283| |+ (NSMutableDictionary *> *)_loadConfigs 284| 0|{ 285| 0| if (@available(iOS 11.0, *)) { 286| 0| NSData *cachedConfig = [NSData dataWithContentsOfFile:g_configFile options:NSDataReadingMappedIfSafe error:nil]; 287| 0| if ([cachedConfig isKindOfClass:NSData.class]) { 288| 0| NSSet *classes = [NSSet setWithArray:@[ 289| 0| NSMutableDictionary.class, 290| 0| NSMutableArray.class, 291| 0| FBSDKAEMConfiguration.class, 292| 0| FBSDKAEMRule.class, 293| 0| FBSDKAEMEvent.class]]; 294| 0| NSDictionary *> *cache = [FBSDKTypeUtility dictionaryValue:[NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:cachedConfig error:nil]]; 295| 0| if (cache) { 296| 0| return [cache mutableCopy]; 297| 0| } 298| 0| } 299| 0| } 300| 0| return [NSMutableDictionary new]; 301| 0|} 302| | 303| |+ (void)_saveConfigs 304| 0|{ 305| 0| if (!g_configs) { 306| 0| return; 307| 0| } 308| 0| if (@available(iOS 11.0, *)) { 309| 0| NSData *cache = [NSKeyedArchiver archivedDataWithRootObject:g_configs requiringSecureCoding:NO error:nil]; 310| 0| if (cache && g_configFile) { 311| 0| [cache writeToFile:g_configFile atomically:YES]; 312| 0| } 313| 0| } 314| 0|} 315| | 316| |+ (void)_addConfigs:(nullable NSArray *)configs 317| 0|{ 318| 0| if (0 == configs.count) { 319| 0| return; 320| 0| } 321| 0| for (NSDictionary *config in configs) { 322| 0| [self _addConfig:[[FBSDKAEMConfiguration alloc] initWithJSON:config]]; 323| 0| } 324| 0| [self _saveConfigs]; 325| 0|} 326| | 327| |+ (void)_addConfig:(nullable FBSDKAEMConfiguration *)config 328| 0|{ 329| 0| if (!config.configMode) { 330| 0| return; 331| 0| } 332| 0| NSMutableArray *configs = [FBSDKTypeUtility dictionary:g_configs objectForKey:config.configMode ofType:NSMutableArray.class]; 333| | // Remove the config in the array that has the same "validFrom" and "businessID" as the added config 334| 0| NSMutableArray *res = [NSMutableArray new]; 335| 0| for (FBSDKAEMConfiguration *c in configs) { 336| 0| if ([config isSameValidFrom:c.validFrom businessID:c.businessID]) { 337| 0| continue; 338| 0| } 339| 0| [FBSDKTypeUtility array:res addObject:c]; 340| 0| } 341| 0| [FBSDKTypeUtility array:res addObject:config]; 342| 0| [FBSDKTypeUtility dictionary:g_configs setObject:res forKey:config.configMode]; 343| | // Sort the configs via "validFrom" 344| 0| [res sortUsingComparator:^NSComparisonResult (FBSDKAEMConfiguration *obj1, FBSDKAEMConfiguration *obj2) { 345| 0| if (obj1.validFrom > obj2.validFrom) { 346| 0| return NSOrderedDescending; 347| 0| } 348| 0| if (obj1.validFrom < obj2.validFrom) { 349| 0| return NSOrderedAscending; 350| 0| } 351| 0| return NSOrderedSame; 352| 0| }]; 353| 0|} 354| | 355| |+ (NSMutableArray *)_loadReportData 356| 0|{ 357| 0| if (@available(iOS 11.0, *)) { 358| 0| NSData *cachedReportData = [NSData dataWithContentsOfFile:g_reportFile options:NSDataReadingMappedIfSafe error:nil]; 359| 0| if ([cachedReportData isKindOfClass:NSData.class]) { 360| 0| NSArray *cache = [FBSDKTypeUtility arrayValue:[NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[NSArray.class, FBSDKAEMInvocation.class]] fromData:cachedReportData error:nil]]; 361| 0| if (cache) { 362| 0| return [cache mutableCopy]; 363| 0| } 364| 0| } 365| 0| } 366| 0| return [NSMutableArray new]; 367| 0|} 368| | 369| |+ (void)_saveReportData 370| 0|{ 371| 0| if (@available(iOS 11.0, *)) { 372| 0| NSData *cache = [NSKeyedArchiver archivedDataWithRootObject:g_invocations requiringSecureCoding:NO error:nil]; 373| 0| if (cache && g_reportFile) { 374| 0| [cache writeToFile:g_reportFile atomically:YES]; 375| 0| } 376| 0| } 377| 0|} 378| | 379| |+ (void)_sendAggregationRequest 380| 0|{ 381| 0| NSMutableArray *params = [NSMutableArray new]; 382| 0| NSMutableArray *aggregatedInvocations = [NSMutableArray new]; 383| 0| for (FBSDKAEMInvocation *invocation in g_invocations) { 384| 0| if (!invocation.isAggregated) { 385| 0| [FBSDKTypeUtility array:params addObject:[self _aggregationRequestParameters:invocation]]; 386| 0| [FBSDKTypeUtility array:aggregatedInvocations addObject:invocation]; 387| 0| } 388| 0| } 389| 0| if (0 == params.count) { 390| 0| return; 391| 0| } 392| 0| @try { 393| 0| NSData *jsonData = [FBSDKTypeUtility dataWithJSONObject:params options:0 error:nil]; 394| 0| if (jsonData) { 395| 0| NSString *reports = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 396| 0| id request = [self.requestProvider createGraphRequestWithGraphPath:[NSString stringWithFormat:@"%@/aem_conversions", FBSDKSettings.appID] 397| 0| parameters:@{@"aem_conversions" : reports} 398| 0| tokenString:nil 399| 0| HTTPMethod:FBSDKHTTPMethodPOST 400| 0| flags:FBSDKGraphRequestFlagSkipClientToken | FBSDKGraphRequestFlagDisableErrorRecovery]; 401| 0| [request startWithCompletion:^(id connection, id result, NSError *error) { 402| 0| if (error) { 403| 0| return; 404| 0| } 405| | 406| 0| [self dispatchOnQueue:g_serialQueue block:^() { 407| 0| for (FBSDKAEMInvocation *invocation in aggregatedInvocations) { 408| 0| invocation.isAggregated = YES; 409| 0| } 410| 0| [self _saveReportData]; 411| 0| }]; 412| 0| }]; 413| 0| } 414| 0| } @catch (NSException *exception) { 415| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents logEntry:@"Fail to send AEM reports"]; 416| 0| } 417| 0|} 418| | 419| |+ (NSDictionary *)_aggregationRequestParameters:(FBSDKAEMInvocation *)invocation 420| 0|{ 421| 0| NSInteger delay = 24 + arc4random_uniform(24); 422| 0| NSMutableDictionary *conversionParams = [NSMutableDictionary new]; 423| 0| [FBSDKTypeUtility dictionary:conversionParams setObject:invocation.campaignID forKey:CAMPAIGN_ID_KEY]; 424| 0| [FBSDKTypeUtility dictionary:conversionParams setObject:@(invocation.conversionValue) forKey:CONVERSION_DATA_KEY]; 425| 0| [FBSDKTypeUtility dictionary:conversionParams setObject:@(delay) forKey:CONSUMPTION_HOUR_KEY]; 426| 0| [FBSDKTypeUtility dictionary:conversionParams setObject:invocation.ACSToken forKey:TOKEN_KEY]; 427| 0| [FBSDKTypeUtility dictionary:conversionParams setObject:@"server" forKey:DELAY_FLOW_KEY]; 428| 0| [FBSDKTypeUtility dictionary:conversionParams setObject:invocation.ACSConfigID forKey:CONFIG_ID_KEY]; 429| 0| [FBSDKTypeUtility dictionary:conversionParams setObject:[invocation getHMAC:delay] forKey:HMAC_KEY]; 430| 0| [FBSDKTypeUtility dictionary:conversionParams setObject:invocation.businessID forKey:BUSINESS_ID_KEY]; 431| | 432| 0| return [conversionParams copy]; 433| 0|} 434| | 435| |+ (void)dispatchOnQueue:(dispatch_queue_t)queue block:(dispatch_block_t)block 436| 0|{ 437| 0| if (block != nil) { 438| 0| if (strcmp(dispatch_queue_get_label(queue), dispatchQueueLabel) == 0) { 439| 0| dispatch_async(queue, block); 440| 0| } else { 441| 0| block(); 442| 0| } 443| 0| } 444| 0|} 445| | 446| |+ (void)_clearCache 447| 0|{ 448| | // step 1: clear aggregated invocations that are outside attribution window 449| 0| [self _clearInvocations]; 450| | // step 2: clear old configs that are not used anymore and keep the most recent config 451| 0| [self _clearConfigs]; 452| 0|} 453| | 454| |+ (void)_clearConfigs 455| 0|{ 456| 0| BOOL shouldSaveCache = NO; 457| 0| if (g_configs.count > 0) { 458| 0| NSMutableDictionary *> *configs = [NSMutableDictionary new]; 459| 0| for (NSString *key in g_configs) { 460| 0| NSMutableArray *oldConfigurations = [FBSDKTypeUtility dictionary:g_configs objectForKey:key ofType:NSMutableArray.class]; 461| 0| NSMutableArray *newConfigurations = [NSMutableArray new]; 462| | 463| | // Removes the last of the old configurations and stores it so it can be 464| | // added to the array-to-save 465| 0| FBSDKAEMConfiguration *lastConfiguration = oldConfigurations.lastObject; 466| 0| [oldConfigurations removeLastObject]; 467| | 468| 0| for (FBSDKAEMConfiguration *oldConfiguration in oldConfigurations) { 469| 0| if (![self _isUsingConfig:oldConfiguration forInvocations:g_invocations]) { 470| 0| shouldSaveCache = YES; 471| 0| continue; 472| 0| } 473| 0| [FBSDKTypeUtility array:newConfigurations addObject:oldConfiguration]; 474| 0| } 475| | 476| 0| [FBSDKTypeUtility array:newConfigurations addObject:lastConfiguration]; 477| 0| [FBSDKTypeUtility dictionary:configs setObject:newConfigurations forKey:key]; 478| 0| } 479| 0| g_configs = configs; 480| 0| } 481| 0| if (shouldSaveCache) { 482| 0| [self _saveConfigs]; 483| 0| } 484| 0|} 485| | 486| |+ (void)_clearInvocations 487| 0|{ 488| 0| BOOL isInvocationCacheUpdated = NO; 489| 0| if (g_invocations.count > 0) { 490| 0| NSMutableArray *res = [NSMutableArray new]; 491| 0| for (FBSDKAEMInvocation *invocation in g_invocations) { 492| 0| if ([invocation isOutOfWindowWithConfigs:g_configs] && invocation.isAggregated) { 493| 0| isInvocationCacheUpdated = YES; 494| 0| continue; 495| 0| } 496| 0| [FBSDKTypeUtility array:res addObject:invocation]; 497| 0| } 498| 0| g_invocations = res; 499| 0| } 500| 0| if (isInvocationCacheUpdated) { 501| 0| [self _saveReportData]; 502| 0| } 503| 0|} 504| | 505| |+ (BOOL)_isUsingConfig:(FBSDKAEMConfiguration *)config 506| | forInvocations:(NSArray *)invocations 507| 0|{ 508| 0| for (FBSDKAEMInvocation *invocation in invocations) { 509| 0| if ([config isSameValidFrom:invocation.configID businessID:invocation.businessID]) { 510| 0| return YES; 511| 0| } 512| 0| } 513| 0| return NO; 514| 0|} 515| | 516| | #pragma mark - Testability 517| | 518| | #if DEBUG 519| | #if FBSDKTEST 520| | 521| |+ (NSMutableDictionary *> *)configs 522| 0|{ 523| 0| return g_configs; 524| 0|} 525| | 526| |+ (void)setConfigs:(NSMutableDictionary *> *)configs 527| 0|{ 528| 0| g_configs = configs; 529| 0|} 530| | 531| |+ (void)setInvocations:(NSMutableArray *)invocations 532| 0|{ 533| 0| g_invocations = invocations; 534| 0|} 535| | 536| |+ (NSMutableArray *)invocations 537| 0|{ 538| 0| return g_invocations; 539| 0|} 540| | 541| |+ (void)setIsEnabled:(BOOL)enabled 542| 0|{ 543| 0| g_isAEMReportEnabled = enabled; 544| 0|} 545| | 546| |+ (BOOL)isEnabled 547| 0|{ 548| 0| return g_isAEMReportEnabled; 549| 0|} 550| | 551| |+ (void)setCompletionBlocks:(NSMutableArray *)completionBlocks 552| 0|{ 553| 0| g_completionBlocks = completionBlocks; 554| 0|} 555| | 556| |+ (void)setQueue:(nullable dispatch_queue_t)queue 557| 0|{ 558| 0| g_serialQueue = queue; 559| 0|} 560| | 561| |+ (void)setTimestamp:(NSDate *)timestamp 562| 0|{ 563| 0| g_configRefreshTimestamp = timestamp; 564| 0|} 565| | 566| |+ (void)setIsLoadingConfiguration:(BOOL)loading 567| 0|{ 568| 0| g_isLoadingConfiguration = loading; 569| 0|} 570| | 571| |+ (NSString *)reportFilePath 572| 0|{ 573| 0| return g_reportFile; 574| 0|} 575| | 576| |+ (void)setReportFilePath:(NSString *)path 577| 0|{ 578| 0| g_reportFile = path; 579| 0|} 580| | 581| | #endif 582| | #endif 583| | 584| |@end 585| | 586| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AEM/FBSDKAEMRule.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKAEMRule.h" 24| | 25| | #import "FBSDKCoreKitBasicsImport.h" 26| | 27| |static NSString *const CONVERSION_VALUE_KEY = @"conversion_value"; 28| |static NSString *const PRIORITY_KEY = @"priority"; 29| |static NSString *const EVENTS_KEY = @"events"; 30| | 31| |@implementation FBSDKAEMRule 32| | 33| |- (nullable instancetype)initWithJSON:(nullable NSDictionary *)dict 34| 0|{ 35| 0| if ((self = [super init])) { 36| 0| dict = [FBSDKTypeUtility dictionaryValue:dict]; 37| 0| if (!dict) { 38| 0| return nil; 39| 0| } 40| 0| NSNumber *conversionValue = [FBSDKTypeUtility dictionary:dict objectForKey:CONVERSION_VALUE_KEY ofType:NSNumber.class]; 41| 0| NSNumber *priority = [FBSDKTypeUtility dictionary:dict objectForKey:PRIORITY_KEY ofType:NSNumber.class]; 42| 0| NSArray *events = [FBSDKAEMRule parseEvents:[FBSDKTypeUtility dictionary:dict objectForKey:EVENTS_KEY ofType:NSArray.class]]; 43| 0| if (conversionValue == nil || priority == nil || 0 == events.count) { 44| 0| return nil; 45| 0| } 46| 0| _conversionValue = conversionValue.integerValue; 47| 0| _priority = priority.integerValue; 48| 0| _events = events; 49| 0| } 50| 0| return self; 51| 0|} 52| | 53| |- (instancetype)initWithConversionValue:(NSInteger)conversionValue 54| | priority:(NSInteger)priority 55| | events:(NSArray *)events 56| 0|{ 57| 0| if ((self = [super init])) { 58| 0| _conversionValue = conversionValue; 59| 0| _priority = priority; 60| 0| _events = events; 61| 0| } 62| 0| return self; 63| 0|} 64| | 65| |- (BOOL)isMatchedWithRecordedEvents:(nullable NSSet *)recordedEvents 66| | recordedValues:(nullable NSDictionary *)recordedValues 67| 0|{ 68| 0| for (FBSDKAEMEvent *event in self.events) { 69| | // Check if event name matches 70| 0| if (![recordedEvents containsObject:event.eventName]) { 71| 0| return NO; 72| 0| } 73| | // Check if event value matches when values is not nil 74| 0| if (event.values) { 75| 0| NSDictionary *recordedEventValues = [FBSDKTypeUtility dictionary:recordedValues objectForKey:event.eventName ofType:NSDictionary.class]; 76| 0| if (![self _isMatchedWithValues:event.values recordedEventValues:recordedEventValues]) { 77| 0| return NO; 78| 0| } 79| 0| } 80| 0| } 81| 0| return YES; 82| 0|} 83| | 84| |- (BOOL)_isMatchedWithValues:(NSDictionary *)values 85| | recordedEventValues:(nullable NSDictionary *)recordedEventValues 86| 0|{ 87| 0| for (NSString *currency in values) { 88| 0| NSNumber *valueInMapping = [FBSDKTypeUtility dictionary:values objectForKey:currency ofType:NSNumber.class]; 89| 0| NSNumber *value = [FBSDKTypeUtility dictionary:recordedEventValues objectForKey:currency ofType:NSNumber.class]; 90| 0| if (value.doubleValue >= valueInMapping.doubleValue) { 91| 0| return YES; 92| 0| } 93| 0| } 94| 0| return NO; 95| 0|} 96| | 97| |+ (nullable NSArray *)parseEvents:(nullable NSArray *> *)events 98| 0|{ 99| 0| if (0 == events.count) { 100| 0| return nil; 101| 0| } 102| 0| NSMutableArray *parsedEvents = [NSMutableArray new]; 103| 0| for (NSDictionary *eventEntry in events) { 104| 0| FBSDKAEMEvent *event = [[FBSDKAEMEvent alloc] initWithJSON:eventEntry]; 105| 0| if (!event) { 106| 0| return nil; 107| 0| } 108| 0| [FBSDKTypeUtility array:parsedEvents addObject:event]; 109| 0| } 110| 0| return [parsedEvents copy]; 111| 0|} 112| | 113| | #pragma mark - NSCoding 114| | 115| |+ (BOOL)supportsSecureCoding 116| 0|{ 117| 0| return YES; 118| 0|} 119| | 120| |- (instancetype)initWithCoder:(NSCoder *)decoder 121| 0|{ 122| 0| NSInteger conversionValue = [decoder decodeIntegerForKey:CONVERSION_VALUE_KEY]; 123| 0| NSInteger priority = [decoder decodeIntegerForKey:PRIORITY_KEY]; 124| 0| NSArray *events = [decoder decodeObjectOfClasses:[NSSet setWithArray:@[NSArray.class, FBSDKAEMEvent.class]] forKey:EVENTS_KEY]; 125| 0| return [self initWithConversionValue:conversionValue priority:priority events:events]; 126| 0|} 127| | 128| |- (void)encodeWithCoder:(NSCoder *)encoder 129| 0|{ 130| 0| [encoder encodeInteger:_conversionValue forKey:CONVERSION_VALUE_KEY]; 131| 0| [encoder encodeInteger:_priority forKey:PRIORITY_KEY]; 132| 0| [encoder encodeObject:_events forKey:EVENTS_KEY]; 133| 0|} 134| | 135| | #pragma mark - NSCopying 136| | 137| |- (instancetype)copyWithZone:(NSZone *)zone 138| 0|{ 139| 0| return self; 140| 0|} 141| | 142| |@end 143| | 144| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/Codeless/FBSDKCodelessIndexer.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKCodelessIndexer.h" 24| | 25| | #import 26| | 27| | #import 28| | #import 29| | #import 30| | 31| | #import "FBSDKAdvertiserIDProviding.h" 32| | #import "FBSDKAppEventsUtility.h" 33| | #import "FBSDKCoreKitBasicsImport.h" 34| | #import "FBSDKDataPersisting.h" 35| | #import "FBSDKGraphRequestConnecting.h" 36| | #import "FBSDKGraphRequestConnectionProviding.h" 37| | #import "FBSDKGraphRequestHTTPMethod.h" 38| | #import "FBSDKGraphRequestProtocol.h" 39| | #import "FBSDKGraphRequestProviding.h" 40| | #import "FBSDKInternalUtility.h" 41| | #import "FBSDKObjectDecoding.h" 42| | #import "FBSDKServerConfiguration.h" 43| | #import "FBSDKServerConfigurationManager.h" 44| | #import "FBSDKServerConfigurationProviding.h" 45| | #import "FBSDKSettings+Internal.h" 46| | #import "FBSDKSettingsProtocol.h" 47| | #import "FBSDKSwizzling.h" 48| | #import "FBSDKUnarchiverProvider.h" 49| | #import "FBSDKUtility.h" 50| | #import "FBSDKViewHierarchy.h" 51| | #import "FBSDKViewHierarchyMacros.h" 52| | 53| |@interface FBSDKCodelessIndexer () 54| | 55| |@property (class, nullable, nonatomic, readonly) id requestProvider; 56| |@property (class, nullable, nonatomic, readonly) Class serverConfigurationProvider; 57| |@property (class, nullable, nonatomic, readonly) id store; 58| |@property (class, nullable, nonatomic, readonly, copy) id connectionProvider; 59| |@property (class, nullable, nonatomic, readonly, copy) Class swizzler; 60| |@property (class, nullable, nonatomic, readonly) id settings; 61| |@property (class, nullable, nonatomic, readonly) id advertiserIDProvider; 62| | 63| |@end 64| | 65| |@implementation FBSDKCodelessIndexer 66| | 67| |static BOOL _isCodelessIndexing; 68| |static BOOL _isCheckingSession; 69| |static BOOL _isCodelessIndexingEnabled; 70| |static BOOL _isGestureSet; 71| | 72| |static NSMutableDictionary *_codelessSetting; 73| |static const NSTimeInterval kTimeout = 4.0; 74| | 75| |static NSString *_deviceSessionID; 76| |static NSTimer *_appIndexingTimer; 77| |static NSString *_lastTreeHash; 78| |static id _requestProvider; 79| |static Class _serverConfigurationProvider; 80| |static id _store; 81| |static id _connectionProvider; 82| |static Class _swizzler; 83| |static id _settings; 84| |static id _advertiserIDProvider; 85| |static id _settings; 86| | 87| |+ (void)configureWithRequestProvider:(id)requestProvider 88| | serverConfigurationProvider:(Class)serverConfigurationProvider 89| | store:(id)store 90| | connectionProvider:(id)connectionProvider 91| | swizzler:(Class)swizzler 92| | settings:(id)settings 93| | advertiserIDProvider:(id)advertiserIDProvider 94| 0|{ 95| 0| if (self == [FBSDKCodelessIndexer class]) { 96| 0| _requestProvider = requestProvider; 97| 0| _serverConfigurationProvider = serverConfigurationProvider; 98| 0| _store = store; 99| 0| _connectionProvider = connectionProvider; 100| 0| _swizzler = swizzler; 101| 0| _settings = settings; 102| 0| _advertiserIDProvider = advertiserIDProvider; 103| 0| } 104| 0|} 105| | 106| |+ (id)requestProvider 107| 0|{ 108| 0| return _requestProvider; 109| 0|} 110| | 111| |+ (Class)serverConfigurationProvider 112| 0|{ 113| 0| return _serverConfigurationProvider; 114| 0|} 115| | 116| |+ (id)store 117| 0|{ 118| 0| return _store; 119| 0|} 120| | 121| |+ (id)connectionProvider 122| 0|{ 123| 0| return _connectionProvider; 124| 0|} 125| | 126| |+ (Class)swizzler 127| 0|{ 128| 0| return _swizzler; 129| 0|} 130| | 131| |+ (id)settings 132| 0|{ 133| 0| return _settings; 134| 0|} 135| | 136| |+ (id)advertiserIDProvider 137| 0|{ 138| 0| return _advertiserIDProvider; 139| 0|} 140| | 141| |+ (void)enable 142| 0|{ 143| 0| if (_isGestureSet) { 144| 0| return; 145| 0| } 146| | 147| 0| static dispatch_once_t onceToken; 148| 0| dispatch_once(&onceToken, ^{ 149| 0| #if TARGET_OS_SIMULATOR 150| 0| [self setupGesture]; 151| | #else 152| | [self loadCodelessSettingWithCompletionBlock:^(BOOL isCodelessSetupEnabled, NSError *error) { 153| | if (isCodelessSetupEnabled) { 154| | [self setupGesture]; 155| | } 156| | }]; 157| | #endif 158| 0| }); 159| 0|} 160| | 161| | #pragma clang diagnostic push 162| | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 163| |// DO NOT call this function, it is only called once in the enable function 164| |+ (void)loadCodelessSettingWithCompletionBlock:(FBSDKCodelessSettingLoadBlock)completionBlock 165| 0|{ 166| 0| NSString *appID = [self.settings appID]; 167| 0| if (appID == nil) { 168| 0| return; 169| 0| } 170| | 171| 0| [self.serverConfigurationProvider loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *serverConfigurationLoadingError) { 172| 0| if (!serverConfiguration.isCodelessEventsEnabled) { 173| 0| return; 174| 0| } 175| | 176| | // load the defaults 177| 0| NSString *defaultKey = [NSString stringWithFormat:CODELESS_SETTING_KEY, appID]; 178| 0| NSData *data = [self.store objectForKey:defaultKey]; 179| 0| if ([data isKindOfClass:[NSData class]]) { 180| 0| NSMutableDictionary *codelessSetting = nil; 181| 0| id unarchiver = [FBSDKUnarchiverProvider createInsecureUnarchiverFor:data]; 182| 0| @try { 183| 0| codelessSetting = [unarchiver decodeObjectOfClass:NSDictionary.class forKey:NSKeyedArchiveRootObjectKey]; 184| 0| } @catch (NSException *ex) { 185| | // ignore decoding exceptions 186| 0| } 187| 0| if (codelessSetting) { 188| 0| _codelessSetting = codelessSetting; 189| 0| } 190| 0| } 191| | 192| 0| if ( 193| 0| _codelessSetting 194| 0| && [self _codelessSetupTimestampIsValid:[FBSDKTypeUtility dictionary:_codelessSetting objectForKey:CODELESS_SETTING_TIMESTAMP_KEY ofType:NSObject.class]] 195| 0| ) { 196| 0| completionBlock([FBSDKTypeUtility boolValue:[FBSDKTypeUtility dictionary:_codelessSetting objectForKey:CODELESS_SETUP_ENABLED_KEY ofType:NSObject.class]], nil); 197| 0| } else { 198| 0| _codelessSetting = [NSMutableDictionary new]; 199| 0| id request = [self requestToLoadCodelessSetup:appID]; 200| 0| if (request == nil) { 201| 0| return; 202| 0| } 203| 0| id requestConnection = [self.connectionProvider createGraphRequestConnection]; 204| 0| requestConnection.timeout = kTimeout; 205| 0| [requestConnection addRequest:request completion:^(id connection, id result, NSError *codelessLoadingError) { 206| 0| if (codelessLoadingError) { 207| 0| return; 208| 0| } 209| | 210| 0| NSDictionary *resultDictionary = [FBSDKTypeUtility dictionaryValue:result]; 211| 0| if (resultDictionary) { 212| 0| BOOL isCodelessSetupEnabled = [FBSDKTypeUtility boolValue:resultDictionary[CODELESS_SETUP_ENABLED_FIELD]]; 213| 0| [FBSDKTypeUtility dictionary:_codelessSetting setObject:@(isCodelessSetupEnabled) forKey:CODELESS_SETUP_ENABLED_KEY]; 214| 0| [FBSDKTypeUtility dictionary:_codelessSetting setObject:[NSDate date] forKey:CODELESS_SETTING_TIMESTAMP_KEY]; 215| | // update the cached copy in user defaults 216| 0| [self.store setObject:[NSKeyedArchiver archivedDataWithRootObject:_codelessSetting] forKey:defaultKey]; 217| 0| completionBlock(isCodelessSetupEnabled, codelessLoadingError); 218| 0| } 219| 0| }]; 220| 0| [requestConnection start]; 221| 0| } 222| 0| }]; 223| 0|} 224| | 225| | #pragma clang diagnostic pop 226| | 227| |+ (id)requestToLoadCodelessSetup:(NSString *)appID 228| 0|{ 229| 0| NSString *advertiserID = self.advertiserIDProvider.advertiserID; 230| 0| if (!advertiserID) { 231| 0| return nil; 232| 0| } 233| | 234| 0| NSDictionary *parameters = @{ 235| 0| @"fields" : CODELESS_SETUP_ENABLED_FIELD, 236| 0| @"advertiser_id" : advertiserID 237| 0| }; 238| 0| id request = [self.requestProvider createGraphRequestWithGraphPath:appID 239| 0| parameters:parameters 240| 0| tokenString:nil 241| 0| HTTPMethod:nil 242| 0| flags:FBSDKGraphRequestFlagSkipClientToken | FBSDKGraphRequestFlagDisableErrorRecovery]; 243| 0| return request; 244| 0|} 245| | 246| |+ (BOOL)_codelessSetupTimestampIsValid:(NSDate *)timestamp 247| 0|{ 248| 0| return (timestamp != nil && [[NSDate date] timeIntervalSinceDate:timestamp] < CODELESS_SETTING_CACHE_TIMEOUT); 249| 0|} 250| | 251| |+ (void)setupGesture 252| 0|{ 253| 0| _isGestureSet = YES; 254| 0| [UIApplication sharedApplication].applicationSupportsShakeToEdit = YES; 255| 0| Class class = [UIApplication class]; 256| | 257| 0| [self.swizzler swizzleSelector:@selector(motionBegan:withEvent:) 258| 0| onClass:class 259| 0| withBlock:^{ 260| 0| if ([FBSDKServerConfigurationManager cachedServerConfiguration].isCodelessEventsEnabled) { 261| 0| [self checkCodelessIndexingSession]; 262| 0| } 263| 0| } 264| 0| named:@"motionBegan"]; 265| 0|} 266| | 267| |+ (void)checkCodelessIndexingSession 268| 0|{ 269| 0| if (_isCheckingSession) { 270| 0| return; 271| 0| } 272| | 273| 0| _isCheckingSession = YES; 274| 0| NSDictionary *parameters = @{ 275| 0| CODELESS_INDEXING_SESSION_ID_KEY : [self currentSessionDeviceID], 276| 0| CODELESS_INDEXING_EXT_INFO_KEY : [self extInfo] 277| 0| }; 278| 0| id request = [_requestProvider createGraphRequestWithGraphPath:[NSString stringWithFormat:@"%@/%@", 279| 0| [self.settings appID], 280| 0| CODELESS_INDEXING_SESSION_ENDPOINT] 281| 0| parameters:parameters 282| 0| HTTPMethod:FBSDKHTTPMethodPOST]; 283| 0| [request startWithCompletion:^(id connection, id result, NSError *error) { 284| 0| _isCheckingSession = NO; 285| 0| if ([result isKindOfClass:[NSDictionary class]]) { 286| 0| _isCodelessIndexingEnabled = [((NSDictionary *)result)[CODELESS_INDEXING_STATUS_KEY] boolValue]; 287| 0| if (_isCodelessIndexingEnabled) { 288| 0| _lastTreeHash = nil; 289| 0| if (!_appIndexingTimer) { 290| 0| _appIndexingTimer = [NSTimer timerWithTimeInterval:CODELESS_INDEXING_UPLOAD_INTERVAL_IN_SECONDS 291| 0| target:self 292| 0| selector:@selector(startIndexing) 293| 0| userInfo:nil 294| 0| repeats:YES]; 295| 0| [[NSRunLoop mainRunLoop] addTimer:_appIndexingTimer forMode:NSDefaultRunLoopMode]; 296| 0| } 297| 0| } else { 298| 0| _deviceSessionID = nil; 299| 0| } 300| 0| } 301| 0| }]; 302| 0|} 303| | 304| |+ (NSString *)currentSessionDeviceID 305| 0|{ 306| 0| if (!_deviceSessionID) { 307| 0| _deviceSessionID = [NSUUID UUID].UUIDString; 308| 0| } 309| 0| return _deviceSessionID; 310| 0|} 311| | 312| |+ (NSString *)extInfo 313| 0|{ 314| 0| struct utsname systemInfo; 315| 0| uname(&systemInfo); 316| 0| NSString *machine = @(systemInfo.machine); 317| 0| NSString *advertiserID = [FBSDKAppEventsUtility.shared advertiserID] ?: @""; 318| 0| machine = machine ?: @""; 319| 0| NSString *debugStatus = [FBSDKAppEventsUtility isDebugBuild] ? @"1" : @"0"; 320| 0|#if TARGET_OS_SIMULATOR 321| 0| NSString *isSimulator = @"1"; 322| |#else 323| | NSString *isSimulator = @"0"; 324| |#endif 325| 0| NSLocale *locale = [NSLocale currentLocale]; 326| 0| NSString *languageCode = [locale objectForKey:NSLocaleLanguageCode]; 327| 0| NSString *countryCode = [locale objectForKey:NSLocaleCountryCode]; 328| 0| NSString *localeString = locale.localeIdentifier; 329| 0| if (languageCode && countryCode) { 330| 0| localeString = [NSString stringWithFormat:@"%@_%@", languageCode, countryCode]; 331| 0| } 332| | 333| 0| NSString *extinfo = [FBSDKBasicUtility JSONStringForObject:@[machine, 334| 0| advertiserID, 335| 0| debugStatus, 336| 0| isSimulator, 337| 0| localeString] 338| 0| error:NULL 339| 0| invalidObjectHandler:NULL]; 340| | 341| 0| return extinfo ?: @""; 342| 0|} 343| | 344| |+ (void)startIndexing 345| 0|{ 346| 0| if (!_isCodelessIndexingEnabled) { 347| 0| return; 348| 0| } 349| | 350| 0| if (UIApplicationStateActive != [UIApplication sharedApplication].applicationState) { 351| 0| return; 352| 0| } 353| | 354| | // If userAgentSuffix begins with Unity, trigger unity code to upload view hierarchy 355| 0| NSString *userAgentSuffix = [FBSDKSettings userAgentSuffix]; 356| 0| if (userAgentSuffix != nil && [userAgentSuffix hasPrefix:@"Unity"]) { 357| 0| Class FBUnityUtility = objc_lookUpClass("FBUnityUtility"); 358| 0| SEL selector = NSSelectorFromString(@"triggerUploadViewHierarchy"); 359| 0| if (FBUnityUtility && selector && [FBUnityUtility respondsToSelector:selector]) { 360| 0| #pragma clang diagnostic push 361| 0| #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 362| 0| [FBUnityUtility performSelector:selector]; 363| 0| #pragma clang diagnostic pop 364| 0| } 365| 0| } else { 366| 0| [self uploadIndexing]; 367| 0| } 368| 0|} 369| | 370| |+ (void)uploadIndexing 371| 0|{ 372| 0| if (_isCodelessIndexing) { 373| 0| return; 374| 0| } 375| | 376| 0| NSString *tree = [FBSDKCodelessIndexer currentViewTree]; 377| | 378| 0| [self uploadIndexing:tree]; 379| 0|} 380| | 381| |+ (void)uploadIndexing:(NSString *)tree 382| 0|{ 383| 0| if (_isCodelessIndexing) { 384| 0| return; 385| 0| } 386| | 387| 0| if (!tree) { 388| 0| return; 389| 0| } 390| | 391| 0| NSString *currentTreeHash = [FBSDKUtility SHA256Hash:tree]; 392| 0| if (_lastTreeHash && [_lastTreeHash isEqualToString:currentTreeHash]) { 393| 0| return; 394| 0| } 395| | 396| 0| _lastTreeHash = currentTreeHash; 397| | 398| 0| NSBundle *mainBundle = [NSBundle mainBundle]; 399| 0| NSString *version = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; 400| 0| id request = [_requestProvider createGraphRequestWithGraphPath:[NSString stringWithFormat:@"%@/%@", 401| 0| [self.settings appID], 402| 0| CODELESS_INDEXING_ENDPOINT] 403| 0| parameters:@{ 404| 0| CODELESS_INDEXING_TREE_KEY : tree, 405| 0| CODELESS_INDEXING_APP_VERSION_KEY : version ?: @"", 406| 0| CODELESS_INDEXING_PLATFORM_KEY : @"iOS", 407| 0| CODELESS_INDEXING_SESSION_ID_KEY : [self currentSessionDeviceID] 408| 0| } 409| 0| HTTPMethod:FBSDKHTTPMethodPOST]; 410| 0| _isCodelessIndexing = YES; 411| 0| [request startWithCompletion:^(id connection, id result, NSError *error) { 412| 0| _isCodelessIndexing = NO; 413| 0| if ([result isKindOfClass:[NSDictionary class]]) { 414| 0| _isCodelessIndexingEnabled = [result[CODELESS_INDEXING_STATUS_KEY] boolValue]; 415| 0| if (!_isCodelessIndexingEnabled) { 416| 0| _deviceSessionID = nil; 417| 0| } 418| 0| } 419| 0| }]; 420| 0|} 421| | 422| |+ (NSString *)currentViewTree 423| 0|{ 424| 0| NSMutableArray *trees = [NSMutableArray array]; 425| | 426| 0| NSArray *windows = [UIApplication sharedApplication].windows; 427| 0| for (UIWindow *window in windows) { 428| 0| NSDictionary *tree = [FBSDKViewHierarchy recursiveCaptureTreeWithCurrentNode:window 429| 0| targetNode:nil 430| 0| objAddressSet:nil 431| 0| hash:YES]; 432| 0| if (tree) { 433| 0| if (window.isKeyWindow) { 434| 0| [trees insertObject:tree atIndex:0]; 435| 0| } else { 436| 0| [FBSDKTypeUtility array:trees addObject:tree]; 437| 0| } 438| 0| } 439| 0| } 440| | 441| 0| if (0 == trees.count) { 442| 0| return nil; 443| 0| } 444| | 445| 0| NSArray *viewTrees = [trees reverseObjectEnumerator].allObjects; 446| | 447| 0| NSData *data = UIImageJPEGRepresentation([FBSDKCodelessIndexer screenshot], 0.5); 448| 0| NSString *screenshot = [data base64EncodedStringWithOptions:0]; 449| | 450| 0| NSMutableDictionary *treeInfo = [NSMutableDictionary dictionary]; 451| | 452| 0| [FBSDKTypeUtility dictionary:treeInfo setObject:viewTrees forKey:@"view"]; 453| 0| [FBSDKTypeUtility dictionary:treeInfo setObject:screenshot ?: @"" forKey:@"screenshot"]; 454| | 455| 0| NSString *tree = nil; 456| 0| data = [FBSDKTypeUtility dataWithJSONObject:treeInfo options:0 error:nil]; 457| 0| if (data) { 458| 0| tree = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 459| 0| } 460| | 461| 0| return tree; 462| 0|} 463| | 464| |+ (UIImage *)screenshot 465| 0|{ 466| 0| UIWindow *window = [FBSDKInternalUtility.sharedUtility findWindow]; 467| 0| if (!window) { 468| 0| return nil; 469| 0| } 470| | 471| 0| UIGraphicsBeginImageContext(window.bounds.size); 472| 0| [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES]; 473| 0| UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 474| 0| UIGraphicsEndImageContext(); 475| | 476| 0| return image; 477| 0|} 478| | 479| |+ (NSDictionary *)dimensionOf:(NSObject *)obj 480| 0|{ 481| 0| UIView *view = nil; 482| | 483| 0| if ([obj isKindOfClass:[UIView class]]) { 484| 0| view = (UIView *)obj; 485| 0| } else if ([obj isKindOfClass:[UIViewController class]]) { 486| 0| view = ((UIViewController *)obj).view; 487| 0| } 488| | 489| 0| CGRect frame = view.frame; 490| 0| CGPoint offset = CGPointZero; 491| | 492| 0| if ([view isKindOfClass:[UIScrollView class]]) { 493| 0| offset = ((UIScrollView *)view).contentOffset; 494| 0| } 495| | 496| 0| return @{ 497| 0| CODELESS_VIEW_TREE_TOP_KEY : @((int)frame.origin.y), 498| 0| CODELESS_VIEW_TREE_LEFT_KEY : @((int)frame.origin.x), 499| 0| CODELESS_VIEW_TREE_WIDTH_KEY : @((int)frame.size.width), 500| 0| CODELESS_VIEW_TREE_HEIGHT_KEY : @((int)frame.size.height), 501| 0| CODELESS_VIEW_TREE_OFFSET_X_KEY : @((int)offset.x), 502| 0| CODELESS_VIEW_TREE_OFFSET_Y_KEY : @((int)offset.y), 503| 0| CODELESS_VIEW_TREE_VISIBILITY_KEY : view.isHidden ? @4 : @0 504| 0| }; 505| 0|} 506| | 507| | #if DEBUG 508| | #if FBSDKTEST 509| | 510| |+ (void)reset 511| 0|{ 512| 0| _isCheckingSession = NO; 513| 0| _isCodelessIndexing = NO; 514| 0| _isCodelessIndexingEnabled = NO; 515| 0| _isGestureSet = NO; 516| 0| _codelessSetting = nil; 517| 0| _requestProvider = nil; 518| 0| _serverConfigurationProvider = nil; 519| 0| _store = nil; 520| 0| _connectionProvider = nil; 521| 0| _swizzler = nil; 522| 0| _settings = nil; 523| 0| _advertiserIDProvider = nil; 524| 0| _deviceSessionID = nil; 525| 0| _lastTreeHash = nil; 526| 0|} 527| | 528| |+ (void)resetIsCodelessIndexing 529| 0|{ 530| 0| _isCodelessIndexing = NO; 531| 0|} 532| | 533| |+ (BOOL)isCheckingSession 534| 0|{ 535| 0| return _isCheckingSession; 536| 0|} 537| | 538| |+ (NSTimer *)appIndexingTimer 539| 0|{ 540| 0| return _appIndexingTimer; 541| 0|} 542| | 543| | #endif 544| | #endif 545| | 546| |@end 547| | 548| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/Codeless/FBSDKCodelessParameterComponent.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKCodelessParameterComponent.h" 24| | 25| | #import "FBSDKCodelessPathComponent.h" 26| | #import "FBSDKCoreKitBasicsImport.h" 27| | #import "FBSDKViewHierarchyMacros.h" 28| | 29| |@implementation FBSDKCodelessParameterComponent 30| | 31| |- (instancetype)initWithJSON:(NSDictionary *)dict 32| 0|{ 33| 0| if (self = [super init]) { 34| 0| _name = [dict[CODELESS_MAPPING_PARAMETER_NAME_KEY] copy]; 35| 0| _value = [dict[CODELESS_MAPPING_PARAMETER_VALUE_KEY] copy]; 36| 0| _pathType = [dict[CODELESS_MAPPING_PATH_TYPE_KEY] copy]; 37| | 38| 0| NSArray *ary = dict[CODELESS_MAPPING_PATH_KEY]; 39| 0| NSMutableArray *mut = [NSMutableArray array]; 40| 0| for (NSDictionary *info in ary) { 41| 0| FBSDKCodelessPathComponent *component = [[FBSDKCodelessPathComponent alloc] initWithJSON:info]; 42| 0| [FBSDKTypeUtility array:mut addObject:component]; 43| 0| } 44| 0| _path = [mut copy]; 45| 0| } 46| | 47| 0| return self; 48| 0|} 49| | 50| |- (BOOL)isEqualToParameter:(FBSDKCodelessParameterComponent *)parameter 51| 0|{ 52| 0| if (_path.count != parameter.path.count) { 53| 0| return NO; 54| 0| } 55| | 56| 0| NSString *current = [NSString stringWithFormat:@"%@|%@|%@", 57| 0| _name ?: @"", 58| 0| _value ?: @"", 59| 0| _pathType ?: @""]; 60| 0| NSString *compared = [NSString stringWithFormat:@"%@|%@|%@", 61| 0| parameter.name ?: @"", 62| 0| parameter.value ?: @"", 63| 0| parameter.pathType ?: @""]; 64| | 65| 0| if (![current isEqualToString:compared]) { 66| 0| return NO; 67| 0| } 68| | 69| 0| for (int i = 0; i < _path.count; i++) { 70| 0| if (![[FBSDKTypeUtility array:_path objectAtIndex:i] isEqualToPath:[FBSDKTypeUtility array:parameter.path objectAtIndex:i]]) { 71| 0| return NO; 72| 0| } 73| 0| } 74| | 75| 0| return YES; 76| 0|} 77| | 78| |@end 79| | 80| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/Codeless/FBSDKCodelessPathComponent.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKCodelessPathComponent.h" 24| | 25| | #import "FBSDKViewHierarchyMacros.h" 26| | 27| |@implementation FBSDKCodelessPathComponent 28| | 29| |- (instancetype)initWithJSON:(NSDictionary *)dict 30| 0|{ 31| 0| if (self = [super init]) { 32| 0| _className = [dict[CODELESS_MAPPING_CLASS_NAME_KEY] copy]; 33| 0| _text = [dict[CODELESS_MAPPING_TEXT_KEY] copy]; 34| 0| _hint = [dict[CODELESS_MAPPING_HINT_KEY] copy]; 35| 0| _desc = [dict[CODELESS_MAPPING_DESC_KEY] copy]; 36| | 37| 0| if (dict[CODELESS_MAPPING_INDEX_KEY]) { 38| 0| _index = [dict[CODELESS_MAPPING_INDEX_KEY] intValue]; 39| 0| } else { 40| 0| _index = -1; 41| 0| } 42| | 43| 0| if (dict[CODELESS_MAPPING_SECTION_KEY]) { 44| 0| _section = [dict[CODELESS_MAPPING_SECTION_KEY] intValue]; 45| 0| } else { 46| 0| _section = -1; 47| 0| } 48| | 49| 0| if (dict[CODELESS_MAPPING_ROW_KEY]) { 50| 0| _row = [dict[CODELESS_MAPPING_ROW_KEY] intValue]; 51| 0| } else { 52| 0| _row = -1; 53| 0| } 54| | 55| 0| _tag = [dict[CODELESS_MAPPING_TAG_KEY] intValue]; 56| 0| _matchBitmask = [dict[CODELESS_MAPPING_MATCH_BITMASK_KEY] intValue]; 57| 0| } 58| | 59| 0| return self; 60| 0|} 61| | 62| |- (BOOL)isEqualToPath:(FBSDKCodelessPathComponent *)path 63| 0|{ 64| 0| NSString *current = [NSString stringWithFormat:@"%@|%@|%@|%@|%d|%d|%d|%d|%d", 65| 0| _className ?: @"", 66| 0| _text ?: @"", 67| 0| _hint ?: @"", 68| 0| _desc ?: @"", 69| 0| _index, _section, _row, _tag, _matchBitmask]; 70| 0| NSString *compared = [NSString stringWithFormat:@"%@|%@|%@|%@|%d|%d|%d|%d|%d", 71| 0| path.className ?: @"", 72| 0| path.text ?: @"", 73| 0| path.hint ?: @"", 74| 0| path.desc ?: @"", 75| 0| path.index, path.section, path.row, path.tag, path.matchBitmask]; 76| 0| return [current isEqualToString:compared]; 77| 0|} 78| | 79| |@end 80| | 81| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/Codeless/FBSDKEventBinding.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKEventBinding.h" 24| | 25| | #import "FBSDKCodelessPathComponent.h" 26| | #import "FBSDKCoreKitBasicsImport.h" 27| | #import "FBSDKEventLogging.h" 28| | #import "FBSDKInternalUtility.h" 29| | #import "FBSDKSwizzler.h" 30| | #import "FBSDKUtility.h" 31| | #import "FBSDKViewHierarchy.h" 32| | #import "FBSDKViewHierarchyMacros.h" 33| | 34| | #define CODELESS_PATH_TYPE_ABSOLUTE @"absolute" 35| 0| #define CODELESS_PATH_TYPE_RELATIVE @"relative" 36| 0| #define CODELESS_CODELESS_EVENT_KEY @"_is_fb_codeless" 37| 0| #define PARAMETER_NAME_PRICE @"_valueToSum" 38| | 39| |@interface FBSDKEventBinding () 40| | 41| |@property (nonnull, nonatomic) id eventLogger; 42| | 43| |@end 44| | 45| |@implementation FBSDKEventBinding 46| | 47| |static id _numberParser; 48| | 49| |+ (id)numberParser 50| 0|{ 51| 0| return _numberParser; 52| 0|} 53| | 54| |+ (void)setNumberParser:(id)numberParser 55| 0|{ 56| 0| _numberParser = numberParser; 57| 0|} 58| | 59| |+ (void)initialize 60| 0|{ 61| 0| _numberParser = [[FBSDKAppEventsNumberParser alloc] initWithLocale:NSLocale.currentLocale]; 62| 0|} 63| | 64| |- (FBSDKEventBinding *)initWithJSON:(NSDictionary *)dict 65| | eventLogger:(id)eventLogger 66| 0|{ 67| 0| if ((self = [super init])) { 68| 0| _eventLogger = eventLogger; 69| | 70| 0| _eventName = [dict[CODELESS_MAPPING_EVENT_NAME_KEY] copy]; 71| 0| _eventType = [dict[CODELESS_MAPPING_EVENT_TYPE_KEY] copy]; 72| 0| _appVersion = [dict[CODELESS_MAPPING_APP_VERSION_KEY] copy]; 73| 0| _pathType = [dict[CODELESS_MAPPING_PATH_TYPE_KEY] copy]; 74| | 75| 0| NSArray *pathComponents = dict[CODELESS_MAPPING_PATH_KEY]; 76| 0| NSMutableArray *mut = [NSMutableArray array]; 77| 0| for (NSDictionary *info in pathComponents) { 78| 0| FBSDKCodelessPathComponent *component = [[FBSDKCodelessPathComponent alloc] initWithJSON:info]; 79| 0| [FBSDKTypeUtility array:mut addObject:component]; 80| 0| } 81| 0| _path = [mut copy]; 82| | 83| 0| NSArray *parameters = dict[CODELESS_MAPPING_PARAMETERS_KEY]; 84| 0| mut = [NSMutableArray array]; 85| 0| for (NSDictionary *info in parameters) { 86| 0| FBSDKCodelessParameterComponent *component = [[FBSDKCodelessParameterComponent alloc] initWithJSON:info]; 87| 0| [FBSDKTypeUtility array:mut addObject:component]; 88| 0| } 89| 0| _parameters = [mut copy]; 90| 0| } 91| 0| return self; 92| 0|} 93| | 94| |- (void)trackEvent:(id)sender 95| 0|{ 96| 0| UIView *sourceView = [sender isKindOfClass:[UIView class]] ? (UIView *)sender : nil; 97| 0| NSMutableDictionary *params = [NSMutableDictionary dictionary]; 98| 0| [FBSDKTypeUtility dictionary:params setObject:@"1" forKey:CODELESS_CODELESS_EVENT_KEY]; 99| 0| for (FBSDKCodelessParameterComponent *component in self.parameters) { 100| 0| NSString *text = component.value; 101| 0| if (!text || text.length == 0) { 102| 0| text = [FBSDKEventBinding findParameterOfPath:component.path 103| 0| pathType:component.pathType 104| 0| sourceView:sourceView]; 105| 0| } 106| 0| if (text.length > 0) { 107| 0| if ([component.name isEqualToString:PARAMETER_NAME_PRICE]) { 108| 0| NSNumber *value = [self.class.numberParser parseNumberFrom:text]; 109| 0| [FBSDKTypeUtility dictionary:params setObject:value forKey:component.name]; 110| 0| } else { 111| 0| [FBSDKTypeUtility dictionary:params setObject:text forKey:component.name]; 112| 0| } 113| 0| } 114| 0| } 115| | 116| 0| [self.eventLogger logEvent:_eventName parameters:[params copy]]; 117| 0|} 118| | 119| |+ (BOOL)matchAnyView:(NSArray *)views 120| | pathComponent:(FBSDKCodelessPathComponent *)component 121| 0|{ 122| 0| for (NSObject *view in views) { 123| 0| if ([self match:view pathComponent:component]) { 124| 0| return YES; 125| 0| } 126| 0| } 127| 0| return NO; 128| 0|} 129| | 130| |+ (BOOL) match:(NSObject *)view 131| | pathComponent:(FBSDKCodelessPathComponent *)component 132| 0|{ 133| 0| NSString *className = NSStringFromClass([view class]); 134| 0| if (![className isEqualToString:component.className]) { 135| 0| return NO; 136| 0| } 137| | 138| 0| if (component.index >= 0) { 139| 0| NSObject *parent = [FBSDKViewHierarchy getParent:view]; 140| 0| if (parent) { 141| 0| NSArray *children = [FBSDKViewHierarchy getChildren:[FBSDKViewHierarchy getParent:view]]; 142| 0| NSUInteger index = [children indexOfObject:view]; 143| 0| if (index == NSNotFound || index != component.index) { 144| 0| return NO; 145| 0| } 146| 0| } else { 147| 0| if (0 != component.index) { 148| 0| return NO; 149| 0| } 150| 0| } 151| 0| } 152| | 153| 0| if ((component.matchBitmask & FBSDKCodelessMatchBitmaskFieldText) > 0) { 154| 0| NSString *text = [FBSDKViewHierarchy getText:view]; 155| 0| BOOL match = ((text.length == 0 && component.text.length == 0) 156| 0| || [text isEqualToString:component.text]); 157| 0| if (!match) { 158| 0| return NO; 159| 0| } 160| 0| } 161| | 162| 0| if ((component.matchBitmask & FBSDKCodelessMatchBitmaskFieldTag) > 0 163| 0| && [view isKindOfClass:[UIView class]] 164| 0| && component.tag != ((UIView *)view).tag) { 165| 0| return NO; 166| 0| } 167| | 168| 0| if ((component.matchBitmask & FBSDKCodelessMatchBitmaskFieldHint) > 0) { 169| 0| NSString *hint = [FBSDKViewHierarchy getHint:view]; 170| 0| BOOL match = ((hint.length == 0 && component.hint.length == 0) 171| 0| || [hint isEqualToString:component.hint]); 172| 0| if (!match) { 173| 0| return NO; 174| 0| } 175| 0| } 176| | 177| 0| return YES; 178| 0|} 179| | 180| |+ (BOOL)isViewMatchPath:(UIView *)view path:(NSArray *)path 181| 0|{ 182| 0| NSArray *viewPath = [FBSDKViewHierarchy getPath:view]; 183| 0| BOOL isMatch = [self isPath:path matchViewPath:viewPath]; 184| | 185| 0| return isMatch; 186| 0|} 187| | 188| |+ (BOOL)isPath:(NSArray *)path matchViewPath:(NSArray *)viewPath 189| 0|{ 190| 0| if ((path.count == 0) || (viewPath.count == 0)) { 191| 0| return NO; 192| 0| } 193| | 194| 0| for (NSInteger i = 0; i < MIN(path.count, viewPath.count); i++) { 195| 0| NSInteger idxPath = path.count - i - 1; 196| 0| NSInteger idxViewPath = viewPath.count - i - 1; 197| | 198| 0| FBSDKCodelessPathComponent *pathComponent = [FBSDKTypeUtility array:path objectAtIndex:idxPath]; 199| 0| FBSDKCodelessPathComponent *viewPathComponent = [FBSDKTypeUtility array:viewPath objectAtIndex:idxViewPath]; 200| | 201| 0| if (![pathComponent.className isEqualToString:viewPathComponent.className]) { 202| 0| return NO; 203| 0| } 204| | 205| 0| if (pathComponent.index >= 0 206| 0| && pathComponent.index != viewPathComponent.index) { 207| 0| return NO; 208| 0| } 209| | 210| 0| if ((pathComponent.matchBitmask & FBSDKCodelessMatchBitmaskFieldText) > 0) { 211| 0| NSString *text = viewPathComponent.text; 212| 0| BOOL match = ((text.length == 0 && pathComponent.text.length == 0) 213| 0| || [text isEqualToString:pathComponent.text] 214| 0| || [[FBSDKUtility SHA256Hash:text] isEqualToString:pathComponent.text]); 215| 0| if (!match) { 216| 0| return NO; 217| 0| } 218| 0| } 219| | 220| 0| if ((pathComponent.matchBitmask & FBSDKCodelessMatchBitmaskFieldTag) > 0 221| 0| && pathComponent.tag != viewPathComponent.tag) { 222| 0| return NO; 223| 0| } 224| | 225| 0| if ((pathComponent.matchBitmask & FBSDKCodelessMatchBitmaskFieldHint) > 0) { 226| 0| NSString *hint = viewPathComponent.hint; 227| 0| BOOL match = ((hint.length == 0 && pathComponent.hint.length == 0) 228| 0| || [hint isEqualToString:pathComponent.hint] 229| 0| || [[FBSDKUtility SHA256Hash:hint] isEqualToString:pathComponent.hint]); 230| 0| if (!match) { 231| 0| return NO; 232| 0| } 233| 0| } 234| 0| } 235| | 236| 0| return YES; 237| 0|} 238| | 239| |+ (NSObject *)findViewByPath:(NSArray *)path parent:(NSObject *)parent level:(int)level 240| 0|{ 241| 0| if (level >= path.count) { 242| 0| return nil; 243| 0| } 244| | 245| 0| FBSDKCodelessPathComponent *pathComponent = [FBSDKTypeUtility array:path objectAtIndex:level]; 246| | 247| | // If found parent, skip to next level 248| 0| if ([pathComponent.className isEqualToString:CODELESS_MAPPING_PARENT_CLASS_NAME]) { 249| 0| NSObject *nextParent = [FBSDKViewHierarchy getParent:parent]; 250| | 251| 0| return [FBSDKEventBinding findViewByPath:path parent:nextParent level:level + 1]; 252| 0| } else if ([pathComponent.className isEqualToString:CODELESS_MAPPING_CURRENT_CLASS_NAME]) { 253| 0| return parent; 254| 0| } 255| | 256| 0| NSArray *children; 257| 0| if (parent) { 258| 0| children = [FBSDKViewHierarchy getChildren:parent]; 259| 0| } else { 260| 0| UIWindow *window = [FBSDKInternalUtility.sharedUtility findWindow]; 261| 0| if (window) { 262| 0| children = @[window]; 263| 0| } else { 264| 0| return nil; 265| 0| } 266| 0| } 267| | 268| 0| if (path.count - 1 == level) { 269| 0| int index = pathComponent.index; 270| 0| if (index >= 0) { 271| 0| NSObject *child = index < children.count ? [FBSDKTypeUtility array:children objectAtIndex:index] : nil; 272| 0| if ([self match:child pathComponent:pathComponent]) { 273| 0| return child; 274| 0| } 275| 0| } else { 276| 0| for (NSObject *child in children) { 277| 0| if ([self match:child pathComponent:pathComponent]) { 278| 0| return child; 279| 0| } 280| 0| } 281| 0| } 282| 0| } else { 283| 0| for (NSObject *child in children) { 284| 0| NSObject *result = [self findViewByPath:path parent:child level:level + 1]; 285| 0| if (result) { 286| 0| return result; 287| 0| } 288| 0| } 289| 0| } 290| | 291| 0| return nil; 292| 0|} 293| | 294| |- (BOOL)isEqualToBinding:(FBSDKEventBinding *)binding 295| 0|{ 296| 0| if (_path.count != binding.path.count 297| 0| || _parameters.count != binding.parameters.count) { 298| 0| return NO; 299| 0| } 300| | 301| 0| NSString *current = [NSString stringWithFormat:@"%@|%@|%@|%@", 302| 0| _eventName ?: @"", 303| 0| _eventType ?: @"", 304| 0| _appVersion ?: @"", 305| 0| _pathType ?: @""]; 306| 0| NSString *compared = [NSString stringWithFormat:@"%@|%@|%@|%@", 307| 0| binding.eventName ?: @"", 308| 0| binding.eventType ?: @"", 309| 0| binding.appVersion ?: @"", 310| 0| binding.pathType ?: @""]; 311| 0| if (![current isEqualToString:compared]) { 312| 0| return NO; 313| 0| } 314| | 315| 0| for (int i = 0; i < _path.count; i++) { 316| 0| if (![[FBSDKTypeUtility array:_path objectAtIndex:i] isEqualToPath:[FBSDKTypeUtility array:binding.path objectAtIndex:i]]) { 317| 0| return NO; 318| 0| } 319| 0| } 320| | 321| 0| for (int i = 0; i < _parameters.count; i++) { 322| 0| if (![[FBSDKTypeUtility array:_parameters objectAtIndex:i] isEqualToParameter:[FBSDKTypeUtility array:binding.parameters objectAtIndex:i]]) { 323| 0| return NO; 324| 0| } 325| 0| } 326| | 327| 0| return YES; 328| 0|} 329| | 330| |// MARK: - find event parameters via relative path 331| |+ (NSString *)findParameterOfPath:(NSArray *)path 332| | pathType:(NSString *)pathType 333| | sourceView:(UIView *)sourceView 334| 0|{ 335| 0| if (0 == path.count) { 336| 0| return nil; 337| 0| } 338| | 339| 0| UIView *rootView = sourceView; 340| 0| if (![pathType isEqualToString:CODELESS_PATH_TYPE_RELATIVE]) { 341| 0| rootView = nil; 342| 0| } 343| | 344| 0| NSObject *foundObj = [self findViewByPath:path parent:rootView level:0]; 345| | 346| 0| return [FBSDKViewHierarchy getText:foundObj]; 347| 0|} 348| | 349| |@end 350| | 351| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/Codeless/FBSDKEventBindingManager.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKEventBindingManager.h" 24| | 25| | #import 26| | 27| | #import 28| | 29| | #import "FBSDKCodelessPathComponent.h" 30| | #import "FBSDKCoreKitBasicsImport.h" 31| | #import "FBSDKEventBinding.h" 32| | #import "FBSDKEventLogging.h" 33| | #import "FBSDKSwizzling.h" 34| | #import "FBSDKViewHierarchy.h" 35| | #import "FBSDKViewHierarchyMacros.h" 36| | 37| | #define ReactNativeTargetKey @"target" 38| 0| #define ReactNativeTouchEndEventName @"touchEnd" 39| | 40| 0| #define ReactNativeClassRCTTextView "RCTTextView" 41| 0| #define ReactNativeClassRCTImageView "RCTImageView" 42| | #define ReactNativeClassRCTTouchEvent "RCTTouchEvent" 43| 0| #define ReactNativeClassRCTTouchHandler "RCTTouchHandler" 44| | 45| |@interface FBSDKEventBindingManager () 46| | 47| |@property (nonnull, nonatomic) id eventLogger; 48| |@property (nonnull, nonatomic) Class swizzler; 49| |@property (nonatomic) BOOL isStarted; 50| |@property (nullable, nonatomic) NSMutableDictionary *reactBindings; 51| |@property (nonnull, nonatomic) NSSet *validClasses; 52| |@property (nonatomic) BOOL hasReactNative; 53| |@property (nullable, nonatomic) NSArray *eventBindings; 54| | 55| |@end 56| | 57| |@implementation FBSDKEventBindingManager 58| | 59| |- (instancetype)initWithSwizzler:(Class)swizzling 60| | eventLogger:(id)eventLogger; 61| 0|{ 62| 0| if ((self = [super init])) { 63| 0| _swizzler = swizzling; 64| 0| _eventLogger = eventLogger; 65| 0| _hasReactNative = NO; 66| 0| _isStarted = NO; 67| 0| _reactBindings = [NSMutableDictionary dictionary]; 68| | 69| 0| NSMutableSet *classes = [NSMutableSet set]; 70| 0| [classes addObject:[UIControl class]]; 71| 0| [classes addObject:[UITableView class]]; 72| 0| [classes addObject:[UICollectionView class]]; 73| | // ReactNative 74| 0| Class classRCTRootView = objc_lookUpClass(ReactNativeClassRCTRootView); 75| 0| if (classRCTRootView != nil) { 76| 0| _hasReactNative = YES; 77| 0| Class classRCTView = objc_lookUpClass(ReactNativeClassRCTView); 78| 0| Class classRCTTextView = objc_lookUpClass(ReactNativeClassRCTTextView); 79| 0| Class classRCTImageView = objc_lookUpClass(ReactNativeClassRCTImageView); 80| 0| if (classRCTView) { 81| 0| [classes addObject:classRCTView]; 82| 0| } 83| 0| if (classRCTTextView) { 84| 0| [classes addObject:classRCTTextView]; 85| 0| } 86| 0| if (classRCTImageView) { 87| 0| [classes addObject:classRCTImageView]; 88| 0| } 89| 0| } 90| 0| _validClasses = [NSSet setWithSet:classes]; 91| 0| } 92| 0| return self; 93| 0|} 94| | 95| |- (instancetype)initWithJSON:(NSDictionary *)dict 96| | swizzler:(Class)swizzler 97| | eventLogger:(id)eventLogger 98| 0|{ 99| 0| if ((self = [self initWithSwizzler:swizzler eventLogger:eventLogger])) { 100| 0| NSArray *eventBindingsDict = [FBSDKTypeUtility arrayValue:dict[@"event_bindings"]]; 101| 0| NSMutableArray *bindings = [NSMutableArray array]; 102| 0| for (NSDictionary *d in eventBindingsDict) { 103| 0| FBSDKEventBinding *e = [[FBSDKEventBinding alloc] initWithJSON:d eventLogger:eventLogger]; 104| 0| [FBSDKTypeUtility array:bindings addObject:e]; 105| 0| } 106| 0| _eventBindings = [bindings copy]; 107| 0| } 108| 0| return self; 109| 0|} 110| | 111| |- (NSArray *)parseArray:(NSArray *)array 112| 0|{ 113| 0| NSMutableArray *result = [NSMutableArray array]; 114| | 115| 0| for (NSDictionary *json in array) { 116| 0| FBSDKEventBinding *binding = [[FBSDKEventBinding alloc] initWithJSON:json 117| 0| eventLogger:self.eventLogger]; 118| 0| [FBSDKTypeUtility array:result addObject:binding]; 119| 0| } 120| | 121| 0| return [result copy]; 122| 0|} 123| | 124| | #pragma clang diagnostic push 125| | #pragma clang diagnostic ignored "-Wundeclared-selector" 126| |- (void)start 127| 0|{ 128| 0| if (self.isStarted) { 129| 0| return; 130| 0| } 131| | 132| 0| if (0 == self.eventBindings.count) { 133| 0| return; 134| 0| } 135| | 136| 0| self.isStarted = YES; 137| | 138| 0| void (^blockToWindow)(id view) = ^(id view) { 139| 0| [self matchView:view delegate:nil]; 140| 0| }; 141| | 142| 0| [self.swizzler swizzleSelector:@selector(didMoveToWindow) 143| 0| onClass:[UIControl class] 144| 0| withBlock:blockToWindow 145| 0| named:@"map_control"]; 146| | 147| | // ReactNative 148| 0| if (self.hasReactNative) { // If app is built via ReactNative 149| 0| Class classRCTView = objc_lookUpClass(ReactNativeClassRCTView); 150| 0| Class classRCTTextView = objc_lookUpClass(ReactNativeClassRCTTextView); 151| 0| Class classRCTImageView = objc_lookUpClass(ReactNativeClassRCTImageView); 152| 0| Class classRCTTouchHandler = objc_lookUpClass(ReactNativeClassRCTTouchHandler); 153| | 154| | // All react-native views would be added tp RCTRootView, so no need to check didMoveToWindow 155| 0| [self.swizzler swizzleSelector:@selector(didMoveToWindow) 156| 0| onClass:classRCTView 157| 0| withBlock:blockToWindow 158| 0| named:@"match_react_native"]; 159| 0| [self.swizzler swizzleSelector:@selector(didMoveToWindow) 160| 0| onClass:classRCTTextView 161| 0| withBlock:blockToWindow 162| 0| named:@"match_react_native"]; 163| 0| [self.swizzler swizzleSelector:@selector(didMoveToWindow) 164| 0| onClass:classRCTImageView 165| 0| withBlock:blockToWindow 166| 0| named:@"match_react_native"]; 167| | 168| | // RCTTouchHandler handles with touch events, like touchEnd and uses RCTEventDispather to dispatch events, so we can check _updateAndDispatchTouches to fire events 169| 0| [self.swizzler swizzleSelector:@selector(_updateAndDispatchTouches:eventName:) 170| 0| onClass:classRCTTouchHandler 171| 0| withBlock:^(id touchHandler, SEL command, id touches, id eventName) { 172| 0| [self handleReactNativeTouchesWithHandler:touchHandler command:command touches:touches eventName:eventName]; 173| 0| } 174| 0| named:@"dispatch_rn_event"]; 175| 0| } 176| | 177| | // UITableView 178| 0| void (^tableViewBlock)(UITableView *tableView, 179| 0| SEL cmd, 180| 0| id delegate) = 181| 0| ^(UITableView *tableView, SEL cmd, id delegate) { 182| 0| if (!delegate) { 183| 0| return; 184| 0| } 185| | 186| 0| [self matchView:tableView delegate:delegate]; 187| 0| }; 188| 0| [self.swizzler swizzleSelector:@selector(setDelegate:) 189| 0| onClass:[UITableView class] 190| 0| withBlock:tableViewBlock 191| 0| named:@"match_table_view"]; 192| | // UICollectionView 193| 0| void (^collectionViewBlock)(UICollectionView *collectionView, 194| 0| SEL cmd, 195| 0| id delegate) = 196| 0| ^(UICollectionView *collectionView, SEL cmd, id delegate) { 197| 0| if (nil == delegate) { 198| 0| return; 199| 0| } 200| | 201| 0| [self matchView:collectionView delegate:delegate]; 202| 0| }; 203| 0| [self.swizzler swizzleSelector:@selector(setDelegate:) 204| 0| onClass:[UICollectionView class] 205| 0| withBlock:collectionViewBlock 206| 0| named:@"handle_collection_view"]; 207| 0|} 208| | 209| |- (void)rematchBindings 210| 0|{ 211| 0| if (0 == self.eventBindings.count) { 212| 0| return; 213| 0| } 214| | 215| 0| NSArray *windows = [UIApplication sharedApplication].windows; 216| 0| for (UIWindow *window in windows) { 217| 0| [self matchSubviewsIn:window]; 218| 0| } 219| 0|} 220| | 221| |- (void)matchSubviewsIn:(UIView *)view 222| 0|{ 223| 0| if (!view) { 224| 0| return; 225| 0| } 226| | 227| 0| for (UIView *subview in view.subviews) { 228| 0| BOOL isValidClass = NO; 229| 0| for (Class cls in self.validClasses) { 230| 0| if ([subview isKindOfClass:cls]) { 231| 0| isValidClass = YES; 232| 0| break; 233| 0| } 234| 0| } 235| | 236| 0| if (isValidClass) { 237| 0| if ([subview isKindOfClass:[UITableView class]]) { 238| 0| UITableView *tableView = (UITableView *)subview; 239| 0| if (tableView.delegate) { 240| 0| [self matchView:subview delegate:tableView.delegate]; 241| 0| } 242| 0| } else if ([subview isKindOfClass:[UICollectionView class]]) { 243| 0| UICollectionView *collectionView = (UICollectionView *)subview; 244| 0| if (collectionView.delegate) { 245| 0| [self matchView:subview delegate:collectionView.delegate]; 246| 0| } 247| 0| } else { 248| 0| [self matchView:subview delegate:nil]; 249| 0| } 250| 0| } 251| | 252| 0| if (![subview isKindOfClass:[UIControl class]]) { 253| 0| [self matchSubviewsIn:subview]; 254| 0| } 255| 0| } 256| 0|} 257| | 258| |// check if the view is matched to any event 259| |- (void)matchView:(UIView *)view delegate:(id)delegate 260| 0|{ 261| 0| if (0 == self.eventBindings.count) { 262| 0| return; 263| 0| } 264| | 265| 0| __weak Class weakSwizzler = self.swizzler; 266| 0| __block BOOL hasReactNative = self.hasReactNative; 267| 0| fb_dispatch_on_main_thread(^{ 268| 0| if (![view window]) { 269| 0| return; 270| 0| } 271| | 272| 0| NSArray *path = [FBSDKViewHierarchy getPath:view]; 273| | 274| 0| void (^matchBlock)(void) = ^void () { 275| 0| if ([view isKindOfClass:[UIControl class]]) { 276| 0| UIControl *control = (UIControl *)view; 277| 0| for (FBSDKEventBinding *binding in self->_eventBindings) { 278| 0| if ([FBSDKEventBinding isPath:binding.path matchViewPath:path]) { 279| 0| fb_dispatch_on_main_thread(^{ 280| 0| [control addTarget:binding 281| 0| action:@selector(trackEvent:) 282| 0| forControlEvents:UIControlEventTouchUpInside]; 283| 0| }); 284| 0| break; 285| 0| } 286| 0| } 287| 0| } else if (hasReactNative 288| 0| && [view respondsToSelector:@selector(reactTag)]) { 289| 0| for (FBSDKEventBinding *binding in self->_eventBindings) { 290| 0| if ([FBSDKEventBinding isPath:binding.path matchViewPath:path]) { 291| 0| fb_dispatch_on_main_thread(^{ 292| 0| if (view) { 293| 0| NSNumber *reactTag = [FBSDKViewHierarchy getViewReactTag:view]; 294| 0| if (reactTag != nil) { 295| 0| [FBSDKTypeUtility dictionary:self->_reactBindings setObject:binding forKey:reactTag]; 296| 0| } 297| 0| } 298| 0| }); 299| 0| break; 300| 0| } 301| 0| } 302| 0| } else if ([view isKindOfClass:[UITableView class]] 303| 0| && [delegate conformsToProtocol:@protocol(UITableViewDelegate)]) { 304| 0| void (^tableViewBlock)(void) = ^void () { 305| 0| NSMutableSet *matchedBindings = [NSMutableSet set]; 306| 0| for (FBSDKEventBinding *binding in self->_eventBindings) { 307| 0| if (binding.path.count > 1) { 308| 0| NSArray *shortPath = [binding.path 309| 0| subarrayWithRange:NSMakeRange(0, binding.path.count - 1)]; 310| 0| if ([FBSDKEventBinding isPath:shortPath matchViewPath:path]) { 311| 0| [matchedBindings addObject:binding]; 312| 0| } 313| 0| } 314| 0| } 315| | 316| 0| if (matchedBindings.count > 0) { 317| 0| NSArray *bindings = matchedBindings.allObjects; 318| 0| void (^block)(id, SEL, id, id) = ^(id target, SEL command, UITableView *tableView, NSIndexPath *indexPath) { 319| 0| [self handleDidSelectRowWithBindings:bindings target:target command:command tableView:tableView indexPath:indexPath]; 320| 0| }; 321| 0| [weakSwizzler swizzleSelector:@selector(tableView:didSelectRowAtIndexPath:) 322| 0| onClass:[delegate class] 323| 0| withBlock:block 324| 0| named:@"handle_table_view"]; 325| 0| } 326| 0| }; 327| 0| #if FBSDKTEST 328| 0| tableViewBlock(); 329| | #else 330| | fb_dispatch_on_default_thread(tableViewBlock); 331| | #endif 332| 0| } else if ([view isKindOfClass:[UICollectionView class]] 333| 0| && [delegate conformsToProtocol:@protocol(UICollectionViewDelegate)]) { 334| 0| void (^collectionViewBlock)(void) = ^void () { 335| 0| NSMutableSet *matchedBindings = [NSMutableSet set]; 336| 0| for (FBSDKEventBinding *binding in self->_eventBindings) { 337| 0| if (binding.path.count > 1) { 338| 0| NSArray *shortPath = [binding.path 339| 0| subarrayWithRange:NSMakeRange(0, binding.path.count - 1)]; 340| 0| if ([FBSDKEventBinding isPath:shortPath matchViewPath:path]) { 341| 0| [matchedBindings addObject:binding]; 342| 0| } 343| 0| } 344| 0| } 345| | 346| 0| if (matchedBindings.count > 0) { 347| 0| NSArray *bindings = matchedBindings.allObjects; 348| 0| void (^block)(id, SEL, id, id) = ^(id target, SEL command, UICollectionView *collectionView, NSIndexPath *indexPath) { 349| 0| [self handleDidSelectItemWithBindings:bindings target:target command:command collectionView:collectionView indexPath:indexPath]; 350| 0| }; 351| 0| [weakSwizzler swizzleSelector:@selector(collectionView:didSelectItemAtIndexPath:) 352| 0| onClass:[delegate class] 353| 0| withBlock:block 354| 0| named:@"handle_collection_view"]; 355| 0| } 356| 0| }; 357| 0| #if FBSDKTEST 358| 0| collectionViewBlock(); 359| | #else 360| | fb_dispatch_on_default_thread(collectionViewBlock); 361| | #endif 362| 0| } 363| 0| }; 364| | 365| 0| #if FBSDKTEST 366| 0| matchBlock(); 367| | #else 368| | fb_dispatch_on_default_thread(matchBlock); 369| | #endif 370| 0| }); 371| 0|} 372| | 373| | #pragma clang diagnostic pop 374| |- (void)updateBindings:(NSArray *)bindings 375| 0|{ 376| 0| if (self.eventBindings.count > 0 && self.eventBindings.count == bindings.count) { 377| | // Check whether event bindings are the same 378| 0| BOOL isSame = YES; 379| 0| for (int i = 0; i < self.eventBindings.count; i++) { 380| 0| if (![[FBSDKTypeUtility array:self.eventBindings objectAtIndex:i] isEqualToBinding:[FBSDKTypeUtility array:bindings objectAtIndex:i]]) { 381| 0| isSame = NO; 382| 0| break; 383| 0| } 384| 0| } 385| | 386| 0| if (isSame) { 387| 0| return; 388| 0| } 389| 0| } 390| | 391| 0| self.eventBindings = bindings; 392| 0| [self.reactBindings removeAllObjects]; 393| 0| if (!self.isStarted) { 394| 0| [self start]; 395| 0| } 396| | 397| 0| fb_dispatch_on_main_thread(^{ 398| 0| [self rematchBindings]; 399| 0| }); 400| 0|} 401| | 402| |// MARK: Method Replacements 403| | 404| |- (void)handleReactNativeTouchesWithHandler:(id)handler 405| | command:(SEL)command 406| | touches:(id)touches 407| | eventName:(id)eventName 408| 0|{ 409| 0| if ([touches isKindOfClass:[NSSet class]] && [eventName isKindOfClass:[NSString class]]) { 410| 0| @try { 411| 0| NSString *reactEventName = (NSString *)eventName; 412| 0| NSSet *reactTouches = (NSSet *)touches; 413| 0| if ([reactEventName isEqualToString:ReactNativeTouchEndEventName]) { 414| 0| for (UITouch *touch in reactTouches) { 415| 0| UIView *targetView = ((UITouch *)touch).view.superview; 416| 0| NSNumber *reactTag = nil; 417| | // Find the closest React-managed touchable view like RCTTouchHandler 418| 0| while (targetView) { 419| 0| reactTag = [FBSDKViewHierarchy getViewReactTag:targetView]; 420| 0| if (reactTag != nil && targetView.userInteractionEnabled) { 421| 0| break; 422| 0| } 423| 0| targetView = targetView.superview; 424| 0| } 425| 0| FBSDKEventBinding *eventBinding = self->_reactBindings[reactTag]; 426| 0| if (reactTag != nil && eventBinding != nil) { 427| 0| [eventBinding trackEvent:nil]; 428| 0| } 429| 0| } 430| 0| } 431| 0| } @catch (NSException *exception) { 432| | // Catch exception here to prevent LytroKit from crashing app 433| 0| } 434| 0| } 435| 0|}; 436| | 437| |- (void)handleDidSelectRowWithBindings:(NSArray *)bindings 438| | target:(nullable id)target 439| | command:(nullable SEL)command 440| | tableView:(UITableView *)tableView 441| | indexPath:(NSIndexPath *)indexPath 442| 0|{ 443| 0| fb_dispatch_on_main_thread(^{ 444| 0| for (FBSDKEventBinding *binding in bindings) { 445| 0| FBSDKCodelessPathComponent *component = binding.path.lastObject; 446| 0| if ((component.section == -1 || component.section == indexPath.section) 447| 0| && (component.row == -1 || component.row == indexPath.row)) { 448| 0| UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 449| 0| if (cell) { 450| 0| [binding trackEvent:cell]; 451| 0| } 452| 0| } 453| 0| } 454| 0| }); 455| 0|} 456| | 457| |- (void)handleDidSelectItemWithBindings:(NSArray *)bindings 458| | target:(nullable id)target 459| | command:(nullable SEL)command 460| | collectionView:(UICollectionView *)collectionView 461| | indexPath:(NSIndexPath *)indexPath 462| 0|{ 463| 0| fb_dispatch_on_main_thread(^{ 464| 0| for (FBSDKEventBinding *binding in bindings) { 465| 0| FBSDKCodelessPathComponent *component = binding.path.lastObject; 466| 0| if ((component.section == -1 || component.section == indexPath.section) 467| 0| && (component.row == -1 || component.row == indexPath.row)) { 468| 0| UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; 469| 0| if (cell) { 470| 0| [binding trackEvent:cell]; 471| 0| } 472| 0| } 473| 0| } 474| 0| }); 475| 0|} 476| | 477| |- (NSSet *)validClasses 478| 0|{ 479| 0| return _validClasses; 480| 0|} 481| | 482| | #if DEBUG 483| | #if FBSDKTEST 484| | 485| |- (void)setReactBindings:(NSMutableDictionary *)bindings 486| 0|{ 487| 0| _reactBindings = bindings; 488| 0|} 489| | 490| | #endif 491| | #endif 492| | 493| |@end 494| | 495| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/EventDeactivation/FBSDKEventDeactivationManager.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKEventDeactivationManager.h" 20| | 21| |#import "FBSDKCoreKitBasicsImport.h" 22| |#import "FBSDKServerConfigurationManager.h" 23| | 24| |static NSString *const DEPRECATED_PARAM_KEY = @"deprecated_param"; 25| |static NSString *const DEPRECATED_EVENT_KEY = @"is_deprecated_event"; 26| | 27| |@interface FBSDKDeactivatedEvent : NSObject 28| | 29| |@property (nonatomic, readonly, copy) NSString *eventName; 30| |@property (nullable, nonatomic, readonly, copy) NSSet *deactivatedParams; 31| | 32| |- (instancetype)initWithEventName:(NSString *)eventName 33| | deactivatedParams:(NSSet *)deactivatedParams; 34| | 35| |@end 36| | 37| |@implementation FBSDKDeactivatedEvent 38| | 39| |- (instancetype)initWithEventName:(NSString *)eventName 40| | deactivatedParams:(NSSet *)deactivatedParams 41| 0|{ 42| 0| self = [super init]; 43| 0| if (self) { 44| 0| _eventName = eventName; 45| 0| _deactivatedParams = deactivatedParams; 46| 0| } 47| | 48| 0| return self; 49| 0|} 50| | 51| |@end 52| | 53| |@interface FBSDKEventDeactivationManager () 54| | 55| |@property BOOL isEventDeactivationEnabled; 56| |@property (nonatomic, strong) NSMutableSet *deactivatedEvents; 57| |@property (nonatomic, strong) NSMutableArray *eventsWithDeactivatedParams; 58| |@property (nonatomic) Class serverConfigurationProvider; 59| | 60| |@end 61| | 62| |@implementation FBSDKEventDeactivationManager 63| |+ (instancetype)shared 64| 0|{ 65| 0| static FBSDKEventDeactivationManager *instance; 66| 0| static dispatch_once_t nonce; 67| 0| dispatch_once(&nonce, ^{ 68| 0| instance = [[self alloc] initWithServerConfigurationProvider:FBSDKServerConfigurationManager.class]; 69| 0| }); 70| 0| return instance; 71| 0|} 72| | 73| |- (instancetype)initWithServerConfigurationProvider:(Class)serverConfigurationProvider 74| 0|{ 75| 0| self.isEventDeactivationEnabled = NO; 76| 0| self.serverConfigurationProvider = serverConfigurationProvider; 77| 0| return self; 78| 0|} 79| | 80| |- (void)enable 81| 0|{ 82| 0| @try { 83| 0| static dispatch_once_t onceToken; 84| 0| dispatch_once(&onceToken, ^{ 85| 0| NSDictionary *restrictiveParams = [self.serverConfigurationProvider cachedServerConfiguration].restrictiveParams; 86| 0| if (restrictiveParams) { 87| 0| [self _updateDeactivatedEvents:restrictiveParams]; 88| 0| self.isEventDeactivationEnabled = YES; 89| 0| } 90| 0| }); 91| 0| } @catch (NSException *exception) {} 92| 0|} 93| | 94| |- (void)processEvents:(NSMutableArray *> *)events 95| 0|{ 96| 0| @try { 97| 0| if (!self.isEventDeactivationEnabled) { 98| 0| return; 99| 0| } 100| 0| NSArray *> *eventArray = [events copy]; 101| 0| for (NSDictionary *> *event in eventArray) { 102| 0| if ([self.deactivatedEvents containsObject:event[@"event"][@"_eventName"]]) { 103| 0| [events removeObject:event]; 104| 0| } 105| 0| } 106| 0| } @catch (NSException *exception) {} 107| 0|} 108| | 109| |- (nullable NSDictionary *)processParameters:(nullable NSDictionary *)parameters 110| | eventName:(NSString *)eventName 111| 0|{ 112| 0| @try { 113| 0| if (!self.isEventDeactivationEnabled || parameters.count == 0 || self.eventsWithDeactivatedParams.count == 0) { 114| 0| return parameters; 115| 0| } 116| 0| NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:parameters]; 117| 0| for (NSString *key in [parameters keyEnumerator]) { 118| 0| for (FBSDKDeactivatedEvent *event in self.eventsWithDeactivatedParams) { 119| 0| if ([event.eventName isEqualToString:eventName] && [event.deactivatedParams containsObject:key]) { 120| 0| [params removeObjectForKey:key]; 121| 0| } 122| 0| } 123| 0| } 124| 0| return [params copy]; 125| 0| } @catch (NSException *exception) { 126| 0| return parameters; 127| 0| } 128| 0|} 129| | 130| |#pragma mark - Private Method 131| | 132| |- (void)_updateDeactivatedEvents:(nullable NSDictionary *)events 133| 0|{ 134| 0| events = [FBSDKTypeUtility dictionaryValue:events]; 135| 0| if (events.count == 0) { 136| 0| return; 137| 0| } 138| 0| [self.deactivatedEvents removeAllObjects]; 139| 0| [self.eventsWithDeactivatedParams removeAllObjects]; 140| 0| NSMutableArray *deactivatedParamsArray = [NSMutableArray array]; 141| 0| NSMutableSet *deactivatedEventSet = [NSMutableSet set]; 142| 0| for (NSString *eventName in events.allKeys) { 143| 0| NSDictionary *eventInfo = [FBSDKTypeUtility dictionary:events objectForKey:eventName ofType:NSDictionary.class]; 144| 0| if (!eventInfo) { 145| 0| continue; 146| 0| } 147| 0| if (eventInfo[DEPRECATED_EVENT_KEY]) { 148| 0| [deactivatedEventSet addObject:eventName]; 149| 0| } 150| 0| if (eventInfo[DEPRECATED_PARAM_KEY]) { 151| 0| FBSDKDeactivatedEvent *eventWithDeactivatedParams = [[FBSDKDeactivatedEvent alloc] initWithEventName:eventName 152| 0| deactivatedParams:[NSSet setWithArray:eventInfo[DEPRECATED_PARAM_KEY]]]; 153| 0| [FBSDKTypeUtility array:deactivatedParamsArray addObject:eventWithDeactivatedParams]; 154| 0| } 155| 0| } 156| 0| self.deactivatedEvents = deactivatedEventSet; 157| 0| self.eventsWithDeactivatedParams = deactivatedParamsArray; 158| 0|} 159| | 160| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsAtePublisher.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAppEventsAtePublisher.h" 20| | 21| |#if FBSDK_SWIFT_PACKAGE 22| | #import "FBSDKGraphRequestFlags.h" 23| | #import "FBSDKGraphRequestHTTPMethod.h" 24| |#else 25| | #import 26| | #import 27| |#endif 28| | 29| |#import "FBSDKAppEventsDeviceInfo.h" 30| |#import "FBSDKCoreKitBasicsImport.h" 31| |#import "FBSDKDataPersisting.h" 32| |#import "FBSDKGraphRequestConnecting.h" 33| |#import "FBSDKGraphRequestProtocol.h" 34| |#import "FBSDKGraphRequestProviding.h" 35| |#import "FBSDKInternalUtility.h" 36| |#import "FBSDKLogger.h" 37| |#import "FBSDKSettingsProtocol.h" 38| | 39| |@interface FBSDKAppEventsAtePublisher () 40| | 41| |@property (nullable, nonatomic) id graphRequestFactory; 42| |@property (nullable, nonatomic) id settings; 43| |@property (nullable, nonatomic) id store; 44| |@property (nonatomic) BOOL isProcessing; 45| | 46| |@end 47| | 48| |@implementation FBSDKAppEventsAtePublisher 49| | 50| |- (nullable instancetype)initWithAppIdentifier:(NSString *)appIdentifier 51| | graphRequestFactory:(id)graphRequestFactory 52| | settings:(id)settings 53| | store:(id)store 54| 0|{ 55| 0| if ((self = [self init])) { 56| 0| NSString *identifier = [FBSDKTypeUtility coercedToStringValue:appIdentifier]; 57| 0| if (identifier.length == 0) { 58| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Missing [FBSDKAppEvents appID] for [FBSDKAppEvents publishATE:]"]; 59| 0| return nil; 60| 0| } 61| 0| _appIdentifier = identifier; 62| 0| _graphRequestFactory = graphRequestFactory; 63| 0| _settings = settings; 64| 0| _store = store; 65| 0| } 66| 0| return self; 67| 0|} 68| | 69| |- (void)publishATE 70| 0|{ 71| 0| if (self.isProcessing) { 72| 0| return; 73| 0| } 74| 0| self.isProcessing = YES; 75| 0| NSString *lastATEPingString = [NSString stringWithFormat:@"com.facebook.sdk:lastATEPing%@", self.appIdentifier]; 76| 0| id lastPublishDate = [self.store objectForKey:lastATEPingString]; 77| 0| if ([lastPublishDate isKindOfClass:[NSDate class]] && [(NSDate *)lastPublishDate timeIntervalSinceNow] * -1 < 24 * 60 * 60) { 78| 0| self.isProcessing = NO; 79| 0| return; 80| 0| } 81| | 82| 0| NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; 83| 0| [FBSDKTypeUtility dictionary:parameters setObject:@"CUSTOM_APP_EVENTS" forKey:@"event"]; 84| | 85| 0| NSOperatingSystemVersion operatingSystemVersion = [FBSDKInternalUtility operatingSystemVersion]; 86| 0| NSString *osVersion = [NSString stringWithFormat:@"%ti.%ti.%ti", 87| 0| operatingSystemVersion.majorVersion, 88| 0| operatingSystemVersion.minorVersion, 89| 0| operatingSystemVersion.patchVersion]; 90| | 91| 0| NSArray *event = @[ 92| 0| @{ 93| 0| @"_eventName" : @"fb_mobile_ate_status", 94| 0| @"ate_status" : @(self.settings.advertisingTrackingStatus).stringValue, 95| 0| @"os_version" : osVersion, 96| 0| } 97| 0| ]; 98| 0| [FBSDKTypeUtility dictionary:parameters setObject:[FBSDKBasicUtility JSONStringForObject:event error:NULL invalidObjectHandler:NULL] forKey:@"custom_events"]; 99| | 100| 0| [FBSDKAppEventsDeviceInfo extendDictionaryWithDeviceInfo:parameters]; 101| | 102| 0| NSString *path = [NSString stringWithFormat:@"%@/activities", self.appIdentifier]; 103| 0| id request = [self.graphRequestFactory createGraphRequestWithGraphPath:path 104| 0| parameters:parameters 105| 0| tokenString:nil 106| 0| HTTPMethod:FBSDKHTTPMethodPOST 107| 0| flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; 108| 0| __block id weakStore = self.store; 109| 0| [request startWithCompletion:^(id connection, id result, NSError *error) { 110| 0| if (!error) { 111| 0| [weakStore setObject:[NSDate date] forKey:lastATEPingString]; 112| 0| } 113| 0| self.isProcessing = NO; 114| 0| }]; 115| | 116| 0|#if FBSDKTEST 117| 0| self.isProcessing = NO; 118| 0|#endif 119| 0|} 120| | 121| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsConfiguration.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAppEventsConfiguration.h" 20| | 21| |#import "FBSDKCoreKitBasicsImport.h" 22| | 23| 0|#define FBSDK_APP_EVENTS_CONFIGURATION_DEFAULT_ATE_STATUS_KEY @"default_ate_status" 24| 0|#define FBSDK_APP_EVENTS_CONFIGURATION_ADVERTISER_ID_TRACKING_ENABLED_KEY @"advertiser_id_collection_enabled" 25| 0|#define FBSDK_APP_EVENTS_CONFIGURATION_EVENT_COLLECTION_ENABLED_KEY @"event_collection_enabled" 26| | 27| |@implementation FBSDKAppEventsConfiguration 28| | 29| |- (instancetype)initWithJSON:(nullable NSDictionary *)dict 30| 0|{ 31| 0| if ((self = [super init])) { 32| 0| @try { 33| 0| dict = [FBSDKTypeUtility dictionaryValue:dict]; 34| 0| if (!dict) { 35| 0| return FBSDKAppEventsConfiguration.defaultConfiguration; 36| 0| } 37| 0| NSDictionary *configs = [FBSDKTypeUtility dictionary:dict objectForKey:@"app_events_config" ofType:NSDictionary.class]; 38| 0| if (!configs) { 39| 0| return FBSDKAppEventsConfiguration.defaultConfiguration; 40| 0| } 41| 0| NSNumber *defaultATEStatus = [FBSDKTypeUtility numberValue:configs[FBSDK_APP_EVENTS_CONFIGURATION_DEFAULT_ATE_STATUS_KEY]] ?: @(FBSDKAdvertisingTrackingUnspecified); 42| 0| NSNumber *advertiserIDCollectionEnabled = [FBSDKTypeUtility numberValue:configs[FBSDK_APP_EVENTS_CONFIGURATION_ADVERTISER_ID_TRACKING_ENABLED_KEY]] ?: @(YES); 43| 0| NSNumber *eventCollectionEnabled = [FBSDKTypeUtility numberValue:configs[FBSDK_APP_EVENTS_CONFIGURATION_EVENT_COLLECTION_ENABLED_KEY]] ?: @(NO); 44| 0| _defaultATEStatus = [defaultATEStatus integerValue]; 45| 0| _advertiserIDCollectionEnabled = [advertiserIDCollectionEnabled boolValue]; 46| 0| _eventCollectionEnabled = [eventCollectionEnabled boolValue]; 47| 0| } @catch (NSException *exception) { 48| 0| return FBSDKAppEventsConfiguration.defaultConfiguration; 49| 0| } 50| 0| } 51| 0| return self; 52| 0|} 53| | 54| |- (instancetype)initWithDefaultATEStatus:(FBSDKAdvertisingTrackingStatus)defaultATEStatus 55| | advertiserIDCollectionEnabled:(BOOL)advertiserIDCollectionEnabled 56| | eventCollectionEnabled:(BOOL)eventCollectionEnabled 57| 0|{ 58| 0| if ((self = [super init])) { 59| 0| _defaultATEStatus = defaultATEStatus; 60| 0| _advertiserIDCollectionEnabled = advertiserIDCollectionEnabled; 61| 0| _eventCollectionEnabled = eventCollectionEnabled; 62| 0| } 63| 0| return self; 64| 0|} 65| | 66| |+ (instancetype)defaultConfiguration 67| 0|{ 68| 0| FBSDKAppEventsConfiguration *config = [[FBSDKAppEventsConfiguration alloc] initWithDefaultATEStatus:FBSDKAdvertisingTrackingUnspecified 69| 0| advertiserIDCollectionEnabled:YES 70| 0| eventCollectionEnabled:NO]; 71| 0| return config; 72| 0|} 73| | 74| |#pragma mark - NSCoding 75| | 76| |+ (BOOL)supportsSecureCoding 77| 0|{ 78| 0| return YES; 79| 0|} 80| | 81| |- (instancetype)initWithCoder:(NSCoder *)decoder 82| 0|{ 83| 0| FBSDKAdvertisingTrackingStatus defaultATEStatus = [decoder decodeIntegerForKey:FBSDK_APP_EVENTS_CONFIGURATION_DEFAULT_ATE_STATUS_KEY]; 84| 0| BOOL advertisingIDCollectionEnabled = [decoder decodeBoolForKey:FBSDK_APP_EVENTS_CONFIGURATION_ADVERTISER_ID_TRACKING_ENABLED_KEY]; 85| 0| BOOL eventCollectionEnabled = [decoder decodeBoolForKey:FBSDK_APP_EVENTS_CONFIGURATION_EVENT_COLLECTION_ENABLED_KEY]; 86| 0| return [[FBSDKAppEventsConfiguration alloc] initWithDefaultATEStatus:defaultATEStatus 87| 0| advertiserIDCollectionEnabled:advertisingIDCollectionEnabled 88| 0| eventCollectionEnabled:eventCollectionEnabled]; 89| 0|} 90| | 91| |- (void)encodeWithCoder:(NSCoder *)encoder 92| 0|{ 93| 0| [encoder encodeInteger:_defaultATEStatus forKey:FBSDK_APP_EVENTS_CONFIGURATION_DEFAULT_ATE_STATUS_KEY]; 94| 0| [encoder encodeBool:_advertiserIDCollectionEnabled forKey:FBSDK_APP_EVENTS_CONFIGURATION_ADVERTISER_ID_TRACKING_ENABLED_KEY]; 95| 0| [encoder encodeBool:_eventCollectionEnabled forKey:FBSDK_APP_EVENTS_CONFIGURATION_EVENT_COLLECTION_ENABLED_KEY]; 96| 0|} 97| | 98| |#pragma mark - NSCopying 99| | 100| |- (instancetype)copyWithZone:(NSZone *)zone 101| 0|{ 102| 0| return self; 103| 0|} 104| | 105| |#pragma mark - Testability 106| | 107| |#if DEBUG 108| | #if FBSDKTEST 109| | 110| |- (void)setDefaultATEStatus:(FBSDKAdvertisingTrackingStatus)status 111| 0|{ 112| 0| _defaultATEStatus = status; 113| 0|} 114| | 115| | #endif 116| |#endif 117| | 118| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsConfigurationManager.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAppEventsConfigurationManager.h" 20| | 21| |#import "FBSDKCoreKitBasicsImport.h" 22| |#import "FBSDKDataPersisting.h" 23| |#import "FBSDKGraphRequestConnecting.h" 24| |#import "FBSDKGraphRequestConnectionProviding.h" 25| |#import "FBSDKGraphRequestProviding.h" 26| |#import "FBSDKSettingsProtocol.h" 27| | 28| |static NSString *const FBSDKAppEventsConfigurationKey = @"com.facebook.sdk:FBSDKAppEventsConfiguration"; 29| |static NSString *const FBSDKAppEventsConfigurationTimestampKey = @"com.facebook.sdk:FBSDKAppEventsConfigurationTimestamp"; 30| |static const NSTimeInterval kTimeout = 4.0; 31| | 32| |@interface FBSDKAppEventsConfigurationManager () 33| | 34| |@property (nullable, nonatomic) id store; 35| |@property (nullable, nonatomic) id settings; 36| |@property (nullable, nonatomic) id requestFactory; 37| |@property (nullable, nonatomic) id connectionFactory; 38| |@property (nonnull, nonatomic) FBSDKAppEventsConfiguration *configuration; 39| |@property (nonatomic) BOOL isLoadingConfiguration; 40| |@property (nonatomic) BOOL hasRequeryFinishedForAppStart; 41| |@property (nullable, nonatomic) NSDate *timestamp; 42| |@property (nullable, nonatomic) NSMutableArray *completionBlocks; 43| | 44| |@end 45| | 46| |@implementation FBSDKAppEventsConfigurationManager 47| | 48| |static dispatch_once_t sharedConfigurationManagerNonce; 49| | 50| |// Transitional singleton introduced as a way to change the usage semantics 51| |// from a type-based interface to an instance-based interface. 52| |// The goal of the refactor is to move callsites from: 53| |// ClassWithoutUnderlyingInstance -> ClassRelyingOnUnderlyingInstance -> Instance 54| |+ (FBSDKAppEventsConfigurationManager *)shared 55| 0|{ 56| 0| static id instance; 57| 0| dispatch_once(&sharedConfigurationManagerNonce, ^{ 58| 0| instance = [self new]; 59| 0| }); 60| 0| return instance; 61| 0|} 62| | 63| |+ (void) configureWithStore:(id)store 64| | settings:(id)settings 65| | graphRequestFactory:(id)graphRequestFactory 66| | graphRequestConnectionFactory:(id)graphRequestConnectionFactory 67| 0|{ 68| 0| [self.shared configureWithStore:store 69| 0| settings:settings 70| 0| graphRequestFactory:graphRequestFactory 71| 0| graphRequestConnectionFactory:graphRequestConnectionFactory]; 72| 0|} 73| | 74| |#pragma clang diagnostic push 75| |#pragma clang diagnostic ignored "-Wdeprecated-declarations" 76| |- (void) configureWithStore:(id)store 77| | settings:(id)settings 78| | graphRequestFactory:(id)graphRequestFactory 79| | graphRequestConnectionFactory:(id)graphRequestConnectionFactory 80| 0|{ 81| 0| self.store = store; 82| 0| self.settings = settings; 83| 0| self.requestFactory = graphRequestFactory; 84| 0| self.connectionFactory = graphRequestConnectionFactory; 85| 0| id data = [self.store objectForKey:FBSDKAppEventsConfigurationKey]; 86| 0| if ([data isKindOfClass:NSData.class]) { 87| 0| if (@available(iOS 11.0, tvOS 11.0, *)) { 88| 0| self.configuration = [NSKeyedUnarchiver unarchivedObjectOfClass:FBSDKAppEventsConfiguration.class fromData:data error:nil]; 89| 0| } else { 90| 0| self.configuration = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 91| 0| } 92| 0| } 93| 0| if (!self.configuration) { 94| 0| self.configuration = [FBSDKAppEventsConfiguration defaultConfiguration]; 95| 0| } 96| 0| self.completionBlocks = [NSMutableArray new]; 97| 0| self.timestamp = [self.store objectForKey:FBSDKAppEventsConfigurationTimestampKey]; 98| 0|} 99| | 100| |#pragma clang diagnostic pop 101| | 102| |+ (FBSDKAppEventsConfiguration *)cachedAppEventsConfiguration 103| 0|{ 104| 0| return self.shared.cachedAppEventsConfiguration; 105| 0|} 106| | 107| |- (FBSDKAppEventsConfiguration *)cachedAppEventsConfiguration 108| 0|{ 109| 0| return self.configuration; 110| 0|} 111| | 112| |+ (void)loadAppEventsConfigurationWithBlock:(FBSDKAppEventsConfigurationManagerBlock)block 113| 0|{ 114| 0| [self.shared loadAppEventsConfigurationWithBlock:block]; 115| 0|} 116| | 117| |- (void)loadAppEventsConfigurationWithBlock:(FBSDKAppEventsConfigurationManagerBlock)block 118| 0|{ 119| 0| NSString *appID = self.settings.appID; 120| 0| @synchronized(self) { 121| 0| [FBSDKTypeUtility array:self.completionBlocks addObject:block]; 122| 0| if (!appID || (self.hasRequeryFinishedForAppStart && [self _isTimestampValid])) { 123| 0| for (FBSDKAppEventsConfigurationManagerBlock completionBlock in self.completionBlocks) { 124| 0| completionBlock(); 125| 0| } 126| 0| [self.completionBlocks removeAllObjects]; 127| 0| return; 128| 0| } 129| 0| if (self.isLoadingConfiguration) { 130| 0| return; 131| 0| } 132| 0| self.isLoadingConfiguration = true; 133| 0| id request = [self.requestFactory createGraphRequestWithGraphPath:appID 134| 0| parameters:@{ 135| 0| @"fields" : [NSString stringWithFormat:@"app_events_config.os_version(%@)", [UIDevice currentDevice].systemVersion] 136| 0| }]; 137| 0| id requestConnection = [self.connectionFactory createGraphRequestConnection]; 138| 0| requestConnection.timeout = kTimeout; 139| 0| [requestConnection addRequest:request completion:^(id connection, id result, NSError *error) { 140| 0| [self _processResponse:result error:error]; 141| 0| }]; 142| 0| [requestConnection start]; 143| 0| } 144| 0|} 145| | 146| |#pragma clang diagnostic push 147| |#pragma clang diagnostic ignored "-Wdeprecated-declarations" 148| |+ (void)_processResponse:(id)response 149| | error:(NSError *)error 150| 0|{ 151| 0| [self.shared _processResponse:response error:error]; 152| 0|} 153| | 154| |- (void)_processResponse:(id)response 155| | error:(NSError *)error 156| 0|{ 157| 0| NSDate *date = [NSDate date]; 158| 0| @synchronized(self) { 159| 0| self.isLoadingConfiguration = NO; 160| 0| self.hasRequeryFinishedForAppStart = YES; 161| 0| if (error) { 162| 0| return; 163| 0| } 164| 0| self.configuration = [[FBSDKAppEventsConfiguration alloc] initWithJSON:response]; 165| 0| self.timestamp = date; 166| 0| for (FBSDKAppEventsConfigurationManagerBlock completionBlock in self.completionBlocks) { 167| 0| completionBlock(); 168| 0| } 169| 0| [self.completionBlocks removeAllObjects]; 170| 0| } 171| 0| NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.configuration]; 172| 0| [self.store setObject:data forKey:FBSDKAppEventsConfigurationKey]; 173| 0| [self.store setObject:date forKey:FBSDKAppEventsConfigurationTimestampKey]; 174| 0|} 175| | 176| |#pragma clang diagnostic pop 177| | 178| |- (BOOL)_isTimestampValid 179| 0|{ 180| 0| return self.timestamp && [[NSDate date] timeIntervalSinceDate:self.timestamp] < 3600; 181| 0|} 182| | 183| |#if DEBUG 184| | #if FBSDKTEST 185| | 186| |+ (void)reset 187| 0|{ 188| 0| [self.shared reset]; 189| 0|} 190| | 191| |- (void)reset 192| 0|{ 193| | // Reset the nonce so that a new instance will be created. 194| 0| if (sharedConfigurationManagerNonce) { 195| 0| sharedConfigurationManagerNonce = 0; 196| 0| } 197| 0|} 198| | 199| | #endif 200| |#endif 201| | 202| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsDeviceInfo.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAppEventsDeviceInfo.h" 20| | 21| |#import 22| |#import 23| | 24| |#if !TARGET_OS_TV 25| | #import 26| | #import 27| |#endif 28| | 29| |#import 30| |#import 31| | 32| |#import "FBSDKAppEventsUtility.h" 33| |#import "FBSDKCoreKitBasicsImport.h" 34| |#import "FBSDKDynamicFrameworkLoader.h" 35| |#import "FBSDKInternalUtility.h" 36| |#import "FBSDKSettings+Internal.h" 37| | 38| 0|#define FB_ARRAY_COUNT(x) sizeof(x) / sizeof(x[0]) 39| | 40| |static const u_int FB_GROUP1_RECHECK_DURATION = 30 * 60; // seconds 41| | 42| |// Apple reports storage in binary gigabytes (1024^3) in their About menus, etc. 43| |static const u_int FB_GIGABYTE = 1024 * 1024 * 1024; // bytes 44| | 45| |@implementation FBSDKAppEventsDeviceInfo 46| |{ 47| | // Ephemeral data, may change during the lifetime of an app. We collect them in different 48| | // 'group' frequencies - group1 may gets collected once every 30 minutes. 49| | 50| | // group1 51| | NSString *_carrierName; 52| | NSString *_timeZoneAbbrev; 53| | unsigned long long _remainingDiskSpaceGB; 54| | NSString *_timeZoneName; 55| | 56| | // Persistent data, but we maintain it to make rebuilding the device info as fast as possible. 57| | NSString *_bundleIdentifier; 58| | NSString *_longVersion; 59| | NSString *_shortVersion; 60| | NSString *_sysVersion; 61| | NSString *_machine; 62| | NSString *_language; 63| | unsigned long long _totalDiskSpaceGB; 64| | unsigned long long _coreCount; 65| | CGFloat _width; 66| | CGFloat _height; 67| | CGFloat _density; 68| | 69| | // Other state 70| | long _lastGroup1CheckTime; 71| | BOOL _isEncodingDirty; 72| | NSString *_encodedDeviceInfo; 73| |} 74| | 75| |#pragma mark - Public Methods 76| | 77| |+ (void)extendDictionaryWithDeviceInfo:(NSMutableDictionary *)dictionary 78| 0|{ 79| 0| [FBSDKTypeUtility dictionary:dictionary setObject:[[self sharedDeviceInfo] encodedDeviceInfo] forKey:@"extinfo"]; 80| 0|} 81| | 82| |#pragma mark - Internal Methods 83| | 84| |+ (void)initialize 85| 0|{ 86| 0| if (self == [FBSDKAppEventsDeviceInfo class]) { 87| 0| [[self sharedDeviceInfo] _collectPersistentData]; 88| 0| } 89| 0|} 90| | 91| |+ (instancetype)sharedDeviceInfo 92| 0|{ 93| 0| static FBSDKAppEventsDeviceInfo *_sharedDeviceInfo = nil; 94| 0| if (_sharedDeviceInfo == nil) { 95| 0| _sharedDeviceInfo = [FBSDKAppEventsDeviceInfo new]; 96| 0| } 97| 0| return _sharedDeviceInfo; 98| 0|} 99| | 100| |- (instancetype)init 101| 0|{ 102| 0| if ((self = [super init])) { 103| 0| _isEncodingDirty = YES; 104| 0| } 105| 0| return self; 106| 0|} 107| | 108| |- (NSString *)encodedDeviceInfo 109| 0|{ 110| 0| @synchronized(self) { 111| 0| BOOL isGroup1Expired = [self _isGroup1Expired]; 112| 0| BOOL isEncodingExpired = isGroup1Expired; // Can || other groups in if we add them 113| | 114| | // As long as group1 hasn't expired, we can just return the last generated value 115| 0| if (_encodedDeviceInfo && !isEncodingExpired) { 116| 0| return _encodedDeviceInfo; 117| 0| } 118| | 119| 0| if (isGroup1Expired) { 120| 0| [self _collectGroup1Data]; 121| 0| } 122| | 123| 0| if (_isEncodingDirty) { 124| 0| self.encodedDeviceInfo = [self _generateEncoding]; 125| 0| _isEncodingDirty = NO; 126| 0| } 127| | 128| 0| return _encodedDeviceInfo; 129| 0| } 130| 0|} 131| | 132| |- (void)setEncodedDeviceInfo:(NSString *)encodedDeviceInfo 133| 0|{ 134| 0| @synchronized(self) { 135| 0| if (![_encodedDeviceInfo isEqualToString:encodedDeviceInfo]) { 136| 0| _encodedDeviceInfo = [encodedDeviceInfo copy]; 137| 0| } 138| 0| } 139| 0|} 140| | 141| |// This data need only be collected once. 142| |- (void)_collectPersistentData 143| 0|{ 144| | // Bundle stuff 145| 0| NSBundle *mainBundle = [NSBundle mainBundle]; 146| 0| _bundleIdentifier = mainBundle.bundleIdentifier; 147| 0| _longVersion = [mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; 148| 0| _shortVersion = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; 149| | 150| | // Locale stuff 151| 0| _language = [NSLocale currentLocale].localeIdentifier; 152| | 153| | // Device stuff 154| 0| UIDevice *device = [UIDevice currentDevice]; 155| 0| _sysVersion = device.systemVersion; 156| 0| _coreCount = [FBSDKAppEventsDeviceInfo _coreCount]; 157| | 158| 0| UIScreen *sc = [UIScreen mainScreen]; 159| 0| CGRect sr = sc.bounds; 160| 0| _width = sr.size.width; 161| 0| _height = sr.size.height; 162| 0| _density = sc.scale; 163| | 164| 0| struct utsname systemInfo; 165| 0| uname(&systemInfo); 166| 0| _machine = @(systemInfo.machine); 167| | 168| | // Disk space stuff 169| 0| float totalDiskSpace = [FBSDKAppEventsDeviceInfo _getTotalDiskSpace].floatValue; 170| 0| _totalDiskSpaceGB = (unsigned long long)round(totalDiskSpace / FB_GIGABYTE); 171| 0|} 172| | 173| |- (BOOL)_isGroup1Expired 174| 0|{ 175| 0| return ([self unixTimeNow] - _lastGroup1CheckTime) > FB_GROUP1_RECHECK_DURATION; 176| 0|} 177| | 178| |// This data is collected only once every GROUP1_RECHECK_DURATION. 179| |- (void)_collectGroup1Data 180| 0|{ 181| 0| const BOOL shouldUseCachedValues = [FBSDKSettings shouldUseCachedValuesForExpensiveMetadata]; 182| | 183| 0| if (!_carrierName || !shouldUseCachedValues) { 184| 0| NSString *newCarrierName = [FBSDKAppEventsDeviceInfo _getCarrier]; 185| 0| if (!_carrierName || ![newCarrierName isEqualToString:_carrierName]) { 186| 0| _carrierName = newCarrierName; 187| 0| _isEncodingDirty = YES; 188| 0| } 189| 0| } 190| | 191| 0| if (!_timeZoneName || !_timeZoneAbbrev || !shouldUseCachedValues) { 192| 0| NSTimeZone *timeZone = [NSTimeZone systemTimeZone]; 193| 0| NSString *timeZoneName = timeZone.name; 194| 0| if (!_timeZoneName || ![timeZoneName isEqualToString:_timeZoneName]) { 195| 0| _timeZoneName = timeZoneName; 196| 0| _timeZoneAbbrev = timeZone.abbreviation; 197| 0| _isEncodingDirty = YES; 198| 0| } 199| 0| } 200| | 201| | // Remaining disk space 202| 0| float remainingDiskSpace = [FBSDKAppEventsDeviceInfo _getRemainingDiskSpace].floatValue; 203| 0| unsigned long long newRemainingDiskSpaceGB = (unsigned long long)round(remainingDiskSpace / FB_GIGABYTE); 204| 0| if (_remainingDiskSpaceGB != newRemainingDiskSpaceGB) { 205| 0| _remainingDiskSpaceGB = newRemainingDiskSpaceGB; 206| 0| _isEncodingDirty = YES; 207| 0| } 208| | 209| 0| _lastGroup1CheckTime = [self unixTimeNow]; 210| 0|} 211| | 212| |- (NSString *)_generateEncoding 213| 0|{ 214| | // Keep a bit of precision on density as it's the most likely to become non-integer. 215| 0| NSString *densityString = _density ? [NSString stringWithFormat:@"%.02f", _density] : @""; 216| | 217| 0| NSArray *arr = @[ 218| 0| @"i2", // version - starts with 'i' for iOS, we'll use 'a' for Android 219| 0| _bundleIdentifier ?: @"", 220| 0| _longVersion ?: @"", 221| 0| _shortVersion ?: @"", 222| 0| _sysVersion ?: @"", 223| 0| _machine ?: @"", 224| 0| _language ?: @"", 225| 0| _timeZoneAbbrev ?: @"", 226| 0| _carrierName ?: @"", 227| 0| _width ? @((unsigned long)_width) : @"", 228| 0| _height ? @((unsigned long)_height) : @"", 229| 0| densityString, 230| 0| @(_coreCount) ?: @"", 231| 0| @(_totalDiskSpaceGB) ?: @"", 232| 0| @(_remainingDiskSpaceGB) ?: @"", 233| 0| _timeZoneName ?: @"" 234| 0| ]; 235| | 236| 0| return [FBSDKBasicUtility JSONStringForObject:arr error:NULL invalidObjectHandler:NULL]; 237| 0|} 238| | 239| |#pragma mark - Helper Methods 240| | 241| |- (NSTimeInterval)unixTimeNow 242| 0|{ 243| 0| return round([NSDate date].timeIntervalSince1970); 244| 0|} 245| | 246| |+ (NSNumber *)_getTotalDiskSpace 247| 0|{ 248| 0| NSDictionary *attrs = [[NSFileManager new] attributesOfFileSystemForPath:NSHomeDirectory() 249| 0| error:nil]; 250| 0| return attrs[NSFileSystemSize]; 251| 0|} 252| | 253| |+ (NSNumber *)_getRemainingDiskSpace 254| 0|{ 255| 0| NSDictionary *attrs = [[NSFileManager new] attributesOfFileSystemForPath:NSHomeDirectory() 256| 0| error:nil]; 257| 0| return attrs[NSFileSystemFreeSize]; 258| 0|} 259| | 260| |+ (uint)_coreCount 261| 0|{ 262| 0| return [FBSDKAppEventsDeviceInfo _readSysCtlUInt:CTL_HW type:HW_AVAILCPU]; 263| 0|} 264| | 265| |+ (uint)_readSysCtlUInt:(int)ctl type:(int)type 266| 0|{ 267| 0| int mib[2] = {ctl, type}; 268| 0| uint value; 269| 0| size_t size = sizeof value; 270| 0| if (0 != sysctl(mib, FB_ARRAY_COUNT(mib), &value, &size, NULL, 0)) { 271| 0| return 0; 272| 0| } 273| 0| return value; 274| 0|} 275| | 276| |#pragma clang diagnostic push 277| |#pragma clang diagnostic ignored "-Wdeprecated-declarations" 278| |+ (NSString *)_getCarrier 279| 0|{ 280| 0|#if TARGET_OS_TV || TARGET_OS_SIMULATOR 281| 0| return @"NoCarrier"; 282| |#else 283| | // Dynamically load class for this so calling app doesn't need to link framework in. 284| | CTTelephonyNetworkInfo *networkInfo = [[fbsdkdfl_CTTelephonyNetworkInfoClass() alloc] init]; 285| | CTCarrier *carrier = networkInfo.subscriberCellularProvider; 286| | return carrier.carrierName ?: @"NoCarrier"; 287| |#endif 288| 0|} 289| | 290| |#pragma clang diagnostic pop 291| | 292| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsNumberParser.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAppEventsNumberParser.h" 20| | 21| |@implementation FBSDKAppEventsNumberParser 22| |{ 23| | NSLocale *_locale; 24| |} 25| | 26| |- (instancetype)initWithLocale:(NSLocale *)locale 27| 0|{ 28| 0| if ((self = [self init])) { 29| 0| _locale = locale; 30| 0| } 31| 0| return self; 32| 0|} 33| | 34| |- (NSNumber *)parseNumberFrom:(NSString *)string 35| 0|{ 36| 0| NSNumber *value = @0; 37| | 38| 0| NSString *ds = [_locale objectForKey:NSLocaleDecimalSeparator] ?: @"."; 39| 0| NSString *gs = [_locale objectForKey:NSLocaleGroupingSeparator] ?: @","; 40| 0| NSString *separators = [ds stringByAppendingString:gs]; 41| | 42| 0| NSString *regex = [NSString stringWithFormat:@"[+-]?([0-9]+[%1$@]?)?[%1$@]?([0-9]+[%1$@]?)+", separators]; 43| 0| NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:regex 44| 0| options:0 45| 0| error:nil]; 46| 0| NSTextCheckingResult *match = [re firstMatchInString:string 47| 0| options:0 48| 0| range:NSMakeRange(0, string.length)]; 49| 0| if (match) { 50| 0| NSString *validText = [string substringWithRange:match.range]; 51| 0| NSNumberFormatter *formatter = [NSNumberFormatter new]; 52| 0| formatter.locale = _locale; 53| 0| formatter.numberStyle = NSNumberFormatterDecimalStyle; 54| | 55| 0| value = [formatter numberFromString:validText]; 56| 0| if (nil == value) { 57| 0| value = @(validText.floatValue); 58| 0| } 59| 0| } 60| | 61| 0| return value; 62| 0|} 63| | 64| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsState.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAppEventsState.h" 20| | 21| |#import "FBSDKCoreKitBasicsImport.h" 22| | 23| 0|#define FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY @"isImplicit" 24| | 25| 0|#define FBSDK_APPEVENTSSTATE_MAX_EVENTS 1000 26| | 27| 0|#define FBSDK_APPEVENTSSTATE_APPID_KEY @"appID" 28| 0|#define FBSDK_APPEVENTSSTATE_EVENTS_KEY @"events" 29| 0|#define FBSDK_APPEVENTSSTATE_NUMSKIPPED_KEY @"numSkipped" 30| 0|#define FBSDK_APPEVENTSSTATE_TOKENSTRING_KEY @"tokenString" 31| 0|#define FBSDK_APPEVENTSTATE_RECEIPTDATA_KEY @"receipt_data" 32| 0|#define FBSDK_APPEVENTSTATE_RECEIPTID_KEY @"receipt_id" 33| | 34| |static NSArray> *_eventProcessors; 35| | 36| |@implementation FBSDKAppEventsState 37| |{ 38| | NSMutableArray *_mutableEvents; 39| |} 40| | 41| |+ (void)configureWithEventProcessors:(nonnull NSArray> *)eventProcessors 42| 0|{ 43| 0| _eventProcessors = eventProcessors; 44| 0|} 45| | 46| |- (instancetype)initWithToken:(NSString *)tokenString appID:(NSString *)appID 47| 0|{ 48| 0| if ((self = [super init])) { 49| 0| _tokenString = [tokenString copy]; 50| 0| _appID = [appID copy]; 51| 0| _mutableEvents = [NSMutableArray array]; 52| 0| } 53| 0| return self; 54| 0|} 55| | 56| |- (instancetype)copyWithZone:(NSZone *)zone 57| 0|{ 58| 0| FBSDKAppEventsState *copy = [[FBSDKAppEventsState allocWithZone:zone] initWithToken:_tokenString appID:_appID]; 59| 0| if (copy) { 60| 0| [copy->_mutableEvents addObjectsFromArray:_mutableEvents]; 61| 0| copy->_numSkipped = _numSkipped; 62| 0| } 63| 0| return copy; 64| 0|} 65| | 66| |#pragma mark - NSCoding 67| | 68| |+ (BOOL)supportsSecureCoding 69| 0|{ 70| 0| return YES; 71| 0|} 72| | 73| |- (id)initWithCoder:(NSCoder *)decoder 74| 0|{ 75| 0| NSString *appID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APPEVENTSSTATE_APPID_KEY]; 76| 0| NSString *tokenString = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APPEVENTSSTATE_TOKENSTRING_KEY]; 77| 0| NSArray *events = [FBSDKTypeUtility arrayValue:[decoder decodeObjectOfClasses: 78| 0| [NSSet setWithArray:@[NSArray.class, NSDictionary.class]] 79| 0| forKey:FBSDK_APPEVENTSSTATE_EVENTS_KEY]]; 80| 0| NSUInteger numSkipped = [[decoder decodeObjectOfClass:[NSNumber class] forKey:FBSDK_APPEVENTSSTATE_NUMSKIPPED_KEY] unsignedIntegerValue]; 81| | 82| 0| if ((self = [self initWithToken:tokenString appID:appID])) { 83| 0| _mutableEvents = [NSMutableArray arrayWithArray:events]; 84| 0| _numSkipped = numSkipped; 85| 0| } 86| 0| return self; 87| 0|} 88| | 89| |- (void)encodeWithCoder:(NSCoder *)encoder 90| 0|{ 91| 0| [encoder encodeObject:_appID forKey:FBSDK_APPEVENTSSTATE_APPID_KEY]; 92| 0| [encoder encodeObject:_tokenString forKey:FBSDK_APPEVENTSSTATE_TOKENSTRING_KEY]; 93| 0| [encoder encodeObject:@(_numSkipped) forKey:FBSDK_APPEVENTSSTATE_NUMSKIPPED_KEY]; 94| 0| [encoder encodeObject:_mutableEvents forKey:FBSDK_APPEVENTSSTATE_EVENTS_KEY]; 95| 0|} 96| | 97| |#pragma mark - Implementation 98| | 99| |- (NSArray *)events 100| 0|{ 101| 0| return [_mutableEvents copy]; 102| 0|} 103| | 104| |- (void)addEventsFromAppEventState:(FBSDKAppEventsState *)appEventsState 105| 0|{ 106| 0| NSArray *toAdd = appEventsState->_mutableEvents; 107| 0| NSInteger excess = _mutableEvents.count + toAdd.count - FBSDK_APPEVENTSSTATE_MAX_EVENTS; 108| 0| if (excess > 0) { 109| 0| NSInteger range = FBSDK_APPEVENTSSTATE_MAX_EVENTS - _mutableEvents.count; 110| 0| toAdd = [toAdd subarrayWithRange:NSMakeRange(0, range)]; 111| 0| _numSkipped += excess; 112| 0| } 113| | 114| 0| [_mutableEvents addObjectsFromArray:toAdd]; 115| 0|} 116| | 117| |- (void)addEvent:(NSDictionary *)eventDictionary 118| | isImplicit:(BOOL)isImplicit 119| 0|{ 120| 0| if (_mutableEvents.count >= FBSDK_APPEVENTSSTATE_MAX_EVENTS) { 121| 0| _numSkipped++; 122| 0| } else { 123| 0| [FBSDKTypeUtility array:_mutableEvents addObject:@{ 124| 0| @"event" : [eventDictionary mutableCopy], 125| 0| FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY : @(isImplicit) 126| 0| }]; 127| 0| } 128| 0|} 129| | 130| |- (NSString *)extractReceiptData 131| 0|{ 132| 0| NSMutableString *receipts_string = [NSMutableString string]; 133| 0| NSInteger transactionId = 1; 134| 0| for (NSMutableDictionary *events in _mutableEvents) { 135| 0| NSMutableDictionary *event = events[@"event"]; 136| | 137| 0| NSString *receipt = event[@"receipt_data"]; 138| | // Add receipt id as the identifier for receipt data in event parameter. 139| | // Receipt data will be sent as post parameter rather than the event parameter 140| 0| if (receipt) { 141| 0| NSString *idKey = [NSString stringWithFormat:@"receipt_%ld", (long)transactionId]; 142| 0| [FBSDKTypeUtility dictionary:event setObject:idKey forKey:FBSDK_APPEVENTSTATE_RECEIPTID_KEY]; 143| 0| NSString *receiptWithId = [NSString stringWithFormat:@"%@::%@;;;", idKey, receipt]; 144| 0| [receipts_string appendString:receiptWithId]; 145| 0| transactionId++; 146| 0| } 147| 0| } 148| 0| return receipts_string; 149| 0|} 150| | 151| |- (BOOL)areAllEventsImplicit 152| 0|{ 153| 0| for (NSDictionary *event in _mutableEvents) { 154| 0| if (![[event valueForKey:FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY] boolValue]) { 155| 0| return NO; 156| 0| } 157| 0| } 158| 0| return YES; 159| 0|} 160| | 161| |- (BOOL)isCompatibleWithAppEventsState:(FBSDKAppEventsState *)appEventsState 162| 0|{ 163| 0| return ([self isCompatibleWithTokenString:appEventsState.tokenString appID:appEventsState.appID]); 164| 0|} 165| | 166| |- (BOOL)isCompatibleWithTokenString:(NSString *)tokenString appID:(NSString *)appID 167| 0|{ 168| | // token strings can be nil (e.g., no user token) but appIDs should not. 169| 0| BOOL tokenCompatible = ([self.tokenString isEqualToString:tokenString] 170| 0| || (self.tokenString == nil && tokenString == nil)); 171| 0| return (tokenCompatible 172| 0| && [self.appID isEqualToString:appID]); 173| 0|} 174| | 175| |- (NSString *)JSONStringForEventsIncludingImplicitEvents:(BOOL)includeImplicitEvents 176| 0|{ 177| 0| if (_eventProcessors != nil) { 178| 0| for (id processor in _eventProcessors) { 179| 0| [processor processEvents:_mutableEvents]; 180| 0| } 181| 0| } 182| 0| NSMutableArray *events = [[NSMutableArray alloc] initWithCapacity:_mutableEvents.count]; 183| 0| for (NSDictionary *eventAndImplicitFlag in _mutableEvents) { 184| 0| const BOOL isImplicitEvent = [eventAndImplicitFlag[FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY] boolValue]; 185| 0| if (!includeImplicitEvents && isImplicitEvent) { 186| 0| continue; 187| 0| } 188| 0| NSMutableDictionary *event = eventAndImplicitFlag[@"event"]; 189| 0| NSAssert(event != nil, @"event cannot be nil"); 190| 0| [event removeObjectForKey:FBSDK_APPEVENTSTATE_RECEIPTDATA_KEY]; 191| | 192| 0| [FBSDKTypeUtility array:events addObject:event]; 193| 0| } 194| | 195| 0| return [FBSDKBasicUtility JSONStringForObject:events error:NULL invalidObjectHandler:NULL]; 196| 0|} 197| | 198| |#ifdef DEBUG 199| | #ifdef FBSDKTEST 200| |+ (NSArray> *)eventProcessors 201| 0|{ 202| 0| return _eventProcessors; 203| 0|} 204| | 205| | #endif 206| |#endif 207| | 208| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsStateFactory.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAppEventsStateFactory.h" 20| | 21| |#import 22| | 23| |#import "FBSDKAppEventsState.h" 24| | 25| |@implementation FBSDKAppEventsStateFactory 26| | 27| |- (FBSDKAppEventsState *)createStateWithToken:(NSString *)tokenString appID:(NSString *)appID 28| 0|{ 29| 0| return [[FBSDKAppEventsState alloc] initWithToken:tokenString appID:appID]; 30| 0|} 31| | 32| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsStateManager.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAppEventsStateManager.h" 20| | 21| |#import 22| | 23| |#import "FBSDKAppEventsState.h" 24| |#import "FBSDKAppEventsUtility.h" 25| |#import "FBSDKCoreKitBasicsImport.h" 26| |#import "FBSDKLogger.h" 27| |#import "FBSDKSettings.h" 28| |#import "FBSDKUnarchiverProvider.h" 29| | 30| |@interface FBSDKAppEventsStateManager (Internal) 31| |// A quick optimization to allow returning empty array if we know there are no persisted events. 32| |@property (nonatomic, readwrite, assign) BOOL canSkipDiskCheck; 33| |@end 34| | 35| |@implementation FBSDKAppEventsStateManager 36| |{ 37| | BOOL _canSkipDiskCheck; 38| |} 39| | 40| |- (instancetype)init 41| 0|{ 42| 0| self.canSkipDiskCheck = NO; 43| 0| return self; 44| 0|} 45| | 46| |- (void)setCanSkipDiskCheck:(BOOL)canSkipDiskCheck 47| 0|{ 48| 0| _canSkipDiskCheck = canSkipDiskCheck; 49| 0|} 50| | 51| |- (BOOL)canSkipDiskCheck 52| 0|{ 53| 0| return _canSkipDiskCheck; 54| 0|} 55| | 56| |+ (FBSDKAppEventsStateManager *)shared 57| 0|{ 58| 0| static dispatch_once_t nonce; 59| 0| static FBSDKAppEventsStateManager *instance = nil; 60| | 61| 0| dispatch_once(&nonce, ^{ 62| 0| instance = [FBSDKAppEventsStateManager new]; 63| 0| }); 64| 0| return instance; 65| 0|} 66| | 67| |- (void)clearPersistedAppEventsStates 68| 0|{ 69| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents 70| 0| logEntry:@"FBSDKAppEvents Persist: Clearing"]; 71| 0| [[NSFileManager defaultManager] removeItemAtPath:[self filePath] 72| 0| error:NULL]; 73| 0| self.canSkipDiskCheck = YES; 74| 0|} 75| | 76| |#pragma clang diagnostic push 77| |#pragma clang diagnostic ignored "-Wdeprecated-declarations" 78| |- (void)persistAppEventsData:(FBSDKAppEventsState *)appEventsState 79| 0|{ 80| 0| NSString *msg = [NSString stringWithFormat:@"FBSDKAppEvents Persist: Writing %lu events", (unsigned long)appEventsState.events.count]; 81| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents 82| 0| logEntry:msg]; 83| | 84| 0| if (!appEventsState.events.count) { 85| 0| return; 86| 0| } 87| 0| NSMutableArray *existingEvents = [NSMutableArray arrayWithArray:[self retrievePersistedAppEventsStates]]; 88| 0| [FBSDKTypeUtility array:existingEvents addObject:appEventsState]; 89| | 90| 0| [NSKeyedArchiver archiveRootObject:existingEvents toFile:[self filePath]]; 91| 0| self.canSkipDiskCheck = NO; 92| 0|} 93| | 94| |- (NSArray *)retrievePersistedAppEventsStates 95| 0|{ 96| 0| NSMutableArray *eventsStates = [NSMutableArray array]; 97| 0| if (!self.canSkipDiskCheck) { 98| 0| NSData *data = [[NSData alloc] initWithContentsOfFile:[self filePath] options:NSDataReadingMappedIfSafe error:NULL]; 99| 0| id unarchiver = [FBSDKUnarchiverProvider createSecureUnarchiverFor:data]; 100| 0| @try { 101| 0| NSArray *retrievedEvents = [unarchiver decodeObjectOfClasses: 102| 0| [NSSet setWithObjects:NSArray.class, FBSDKAppEventsState.class, NSDictionary.class, nil] 103| 0| forKey:NSKeyedArchiveRootObjectKey]; 104| 0| [eventsStates addObjectsFromArray:[FBSDKTypeUtility arrayValue:retrievedEvents]]; 105| 0| } @catch (NSException *ex) { 106| | // ignore decoding exceptions from previous versions of the archive, etc 107| 0| } 108| | 109| 0| NSString *msg = [NSString stringWithFormat:@"FBSDKAppEvents Persist: Read %lu event states. First state has %lu events", 110| 0| (unsigned long)eventsStates.count, 111| 0| (unsigned long)(eventsStates.count > 0 ? ((FBSDKAppEventsState *)[FBSDKTypeUtility array:eventsStates objectAtIndex:0]).events.count : 0)]; 112| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents 113| 0| logEntry:msg]; 114| 0| [self clearPersistedAppEventsStates]; 115| 0| } 116| 0| return eventsStates; 117| 0|} 118| | 119| |#pragma clang diagnostic pop 120| | 121| |#pragma mark - Private Helpers 122| | 123| |- (NSString *)filePath 124| 0|{ 125| 0| return [FBSDKBasicUtility persistenceFilePath:@"com-facebook-sdk-AppEventsPersistedEvents.json"]; 126| 0|} 127| | 128| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKAppEventsUtility.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAppEventsUtility.h" 20| | 21| |#import 22| | 23| |#import 24| | 25| |#import "FBSDKAccessToken.h" 26| |#import "FBSDKAppEvents.h" 27| |#import "FBSDKAppEventsConfiguration.h" 28| |#import "FBSDKAppEventsConfigurationManager.h" 29| |#import "FBSDKAppEventsDeviceInfo.h" 30| |#import "FBSDKConstants.h" 31| |#import "FBSDKCoreKitBasicsImport.h" 32| |#import "FBSDKDynamicFrameworkLoader.h" 33| |#import "FBSDKError.h" 34| |#import "FBSDKInternalUtility.h" 35| |#import "FBSDKLogger.h" 36| |#import "FBSDKSettings.h" 37| |#import "FBSDKSettings+Internal.h" 38| | 39| 0|#define FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME @"com-facebook-sdk-PersistedAnonymousID.json" 40| 0|#define FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY @"anon_id" 41| 0|#define FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH 40 42| | 43| |static NSArray *standardEvents; 44| |static ASIdentifierManager *_cachedAdvertiserIdentifierManager; 45| | 46| |@implementation FBSDKAppEventsUtility 47| | 48| |+ (void)initialize 49| 0|{ 50| 0| standardEvents = @[ 51| 0| FBSDKAppEventNameCompletedRegistration, 52| 0| FBSDKAppEventNameViewedContent, 53| 0| FBSDKAppEventNameSearched, 54| 0| FBSDKAppEventNameRated, 55| 0| FBSDKAppEventNameCompletedTutorial, 56| 0| FBSDKAppEventNameAddedToCart, 57| 0| FBSDKAppEventNameAddedToWishlist, 58| 0| FBSDKAppEventNameInitiatedCheckout, 59| 0| FBSDKAppEventNameAddedPaymentInfo, 60| 0| FBSDKAppEventNamePurchased, 61| 0| FBSDKAppEventNameAchievedLevel, 62| 0| FBSDKAppEventNameUnlockedAchievement, 63| 0| FBSDKAppEventNameSpentCredits, 64| 0| FBSDKAppEventNameContact, 65| 0| FBSDKAppEventNameCustomizeProduct, 66| 0| FBSDKAppEventNameDonate, 67| 0| FBSDKAppEventNameFindLocation, 68| 0| FBSDKAppEventNameSchedule, 69| 0| FBSDKAppEventNameStartTrial, 70| 0| FBSDKAppEventNameSubmitApplication, 71| 0| FBSDKAppEventNameSubscribe, 72| 0| FBSDKAppEventNameAdImpression, 73| 0| FBSDKAppEventNameAdClick 74| 0| ]; 75| 0|} 76| | 77| |// Transitional singleton introduced as a way to change the usage semantics 78| |// from a type-based interface to an instance-based interface. 79| |// The goal is to move from: 80| |// ClassWithoutUnderlyingInstance -> ClassRelyingOnUnderlyingInstance -> Instance 81| |+ (instancetype)shared 82| 0|{ 83| 0| static dispatch_once_t nonce; 84| 0| static id instance; 85| 0| dispatch_once(&nonce, ^{ 86| 0| instance = [self new]; 87| 0| }); 88| 0| return instance; 89| 0|} 90| | 91| |+ (NSMutableDictionary *)activityParametersDictionaryForEvent:(NSString *)eventCategory 92| | shouldAccessAdvertisingID:(BOOL)shouldAccessAdvertisingID 93| 0|{ 94| 0| NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; 95| 0| [FBSDKTypeUtility dictionary:parameters setObject:eventCategory forKey:@"event"]; 96| | 97| 0| if (shouldAccessAdvertisingID) { 98| 0| NSString *advertiserID = [self.shared advertiserID]; 99| 0| [FBSDKTypeUtility dictionary:parameters setObject:advertiserID forKey:@"advertiser_id"]; 100| 0| } 101| | 102| 0| [FBSDKTypeUtility dictionary:parameters setObject:[FBSDKBasicUtility anonymousID] forKey:FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY]; 103| | 104| 0| FBSDKAdvertisingTrackingStatus advertisingTrackingStatus = [FBSDKSettings advertisingTrackingStatus]; 105| 0| if (advertisingTrackingStatus != FBSDKAdvertisingTrackingUnspecified) { 106| 0| [FBSDKTypeUtility dictionary:parameters setObject:@([FBSDKSettings isAdvertiserTrackingEnabled]).stringValue forKey:@"advertiser_tracking_enabled"]; 107| 0| } 108| | 109| 0| NSString *userData = [FBSDKAppEvents getUserData]; 110| 0| if (userData) { 111| 0| [FBSDKTypeUtility dictionary:parameters setObject:userData forKey:@"ud"]; 112| 0| } 113| | 114| 0| [FBSDKTypeUtility dictionary:parameters setObject:@(!FBSDKSettings.limitEventAndDataUsage).stringValue forKey:@"application_tracking_enabled"]; 115| 0| [FBSDKTypeUtility dictionary:parameters setObject:@(FBSDKSettings.advertiserIDCollectionEnabled).stringValue forKey:@"advertiser_id_collection_enabled"]; 116| | 117| 0| NSString *userID = [FBSDKAppEvents userID]; 118| 0| if (userID) { 119| 0| [FBSDKTypeUtility dictionary:parameters setObject:userID forKey:@"app_user_id"]; 120| 0| } 121| | 122| 0| NSDictionary *dataProcessingOptions = [FBSDKSettings dataProcessingOptions]; 123| 0| if (dataProcessingOptions) { 124| 0| NSArray *options = (NSArray *)dataProcessingOptions[DATA_PROCESSING_OPTIONS]; 125| 0| if (options && [options isKindOfClass:NSArray.class]) { 126| 0| NSString *optionsString = [FBSDKBasicUtility JSONStringForObject:options error:nil invalidObjectHandler:nil]; 127| 0| [FBSDKTypeUtility dictionary:parameters 128| 0| setObject:optionsString 129| 0| forKey:DATA_PROCESSING_OPTIONS]; 130| 0| } 131| 0| [FBSDKTypeUtility dictionary:parameters 132| 0| setObject:dataProcessingOptions[DATA_PROCESSING_OPTIONS_COUNTRY] 133| 0| forKey:DATA_PROCESSING_OPTIONS_COUNTRY]; 134| 0| [FBSDKTypeUtility dictionary:parameters 135| 0| setObject:dataProcessingOptions[DATA_PROCESSING_OPTIONS_STATE] 136| 0| forKey:DATA_PROCESSING_OPTIONS_STATE]; 137| 0| } 138| | 139| 0| [FBSDKAppEventsDeviceInfo extendDictionaryWithDeviceInfo:parameters]; 140| | 141| 0| static dispatch_once_t fetchBundleOnce; 142| 0| static NSMutableArray *urlSchemes; 143| | 144| 0| dispatch_once(&fetchBundleOnce, ^{ 145| 0| NSBundle *mainBundle = [NSBundle mainBundle]; 146| 0| urlSchemes = [NSMutableArray new]; 147| 0| for (NSDictionary *fields in [mainBundle objectForInfoDictionaryKey:@"CFBundleURLTypes"]) { 148| 0| NSArray *schemesForType = fields[@"CFBundleURLSchemes"]; 149| 0| if (schemesForType) { 150| 0| [urlSchemes addObjectsFromArray:schemesForType]; 151| 0| } 152| 0| } 153| 0| }); 154| | 155| 0| if (urlSchemes.count > 0) { 156| 0| [FBSDKTypeUtility dictionary:parameters setObject:[FBSDKBasicUtility JSONStringForObject:urlSchemes error:NULL invalidObjectHandler:NULL] forKey:@"url_schemes"]; 157| 0| } 158| | 159| 0| return parameters; 160| 0|} 161| | 162| |- (NSString *)advertiserID 163| 0|{ 164| 0| BOOL shouldUseCachedManagerIfAvailable = [FBSDKSettings shouldUseCachedValuesForExpensiveMetadata]; 165| 0| id dynamicFrameworkResolver = FBSDKDynamicFrameworkLoader.shared; 166| 0| return [self _advertiserIDFromDynamicFrameworkResolver:dynamicFrameworkResolver 167| 0| shouldUseCachedManager:shouldUseCachedManagerIfAvailable]; 168| 0|} 169| | 170| |- (NSString *)_advertiserIDFromDynamicFrameworkResolver:(id)dynamicFrameworkResolver 171| | shouldUseCachedManager:(BOOL)shouldUseCachedManager 172| 0|{ 173| 0| if (!FBSDKSettings.isAdvertiserIDCollectionEnabled) { 174| 0| return nil; 175| 0| } 176| | 177| 0| if (@available(iOS 14.0, *)) { 178| 0| if (![FBSDKAppEventsConfigurationManager cachedAppEventsConfiguration].advertiserIDCollectionEnabled) { 179| 0| return nil; 180| 0| } 181| 0| } 182| | 183| 0| ASIdentifierManager *manager = [self _asIdentifierManagerWithShouldUseCachedManager:shouldUseCachedManager 184| 0| dynamicFrameworkResolver:dynamicFrameworkResolver]; 185| 0| return manager.advertisingIdentifier.UUIDString; 186| 0|} 187| | 188| |- (ASIdentifierManager *)_asIdentifierManagerWithShouldUseCachedManager:(BOOL)shouldUseCachedManager 189| | dynamicFrameworkResolver:(id)dynamicFrameworkResolver 190| 0|{ 191| 0| if (shouldUseCachedManager && _cachedAdvertiserIdentifierManager) { 192| 0| return _cachedAdvertiserIdentifierManager; 193| 0| } 194| | 195| 0| Class ASIdentifierManagerClass = [dynamicFrameworkResolver asIdentifierManagerClass]; 196| 0| ASIdentifierManager *manager = [ASIdentifierManagerClass sharedManager]; 197| 0| if (shouldUseCachedManager) { 198| 0| _cachedAdvertiserIdentifierManager = manager; 199| 0| } else { 200| 0| _cachedAdvertiserIdentifierManager = nil; 201| 0| } 202| 0| return manager; 203| 0|} 204| | 205| |+ (BOOL)isStandardEvent:(nullable NSString *)event 206| 0|{ 207| 0| if (!event) { 208| 0| return NO; 209| 0| } 210| 0| return [standardEvents containsObject:event]; 211| 0|} 212| | 213| |#pragma mark - Internal, for testing 214| | 215| |+ (void)clearLibraryFiles 216| 0|{ 217| 0| [[NSFileManager defaultManager] removeItemAtPath:[[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME] 218| 0| error:NULL]; 219| 0| [[NSFileManager defaultManager] removeItemAtPath:[[self class] persistenceFilePath:@"com-facebook-sdk-AppEventsTimeSpent.json"] 220| 0| error:NULL]; 221| 0|} 222| | 223| |+ (void)ensureOnMainThread:(NSString *)methodName className:(NSString *)className 224| 0|{ 225| 0| FBSDKConditionalLog( 226| 0| [NSThread isMainThread], 227| 0| FBSDKLoggingBehaviorDeveloperErrors, 228| 0| @"*** <%@, %@> is not called on the main thread. This can lead to errors.", 229| 0| methodName, 230| 0| className 231| 0| ); 232| 0|} 233| | 234| |+ (NSString *)flushReasonToString:(FBSDKAppEventsFlushReason)flushReason 235| 0|{ 236| 0| NSString *result = @"Unknown"; 237| 0| switch (flushReason) { 238| 0| case FBSDKAppEventsFlushReasonExplicit: 239| 0| result = @"Explicit"; 240| 0| break; 241| 0| case FBSDKAppEventsFlushReasonTimer: 242| 0| result = @"Timer"; 243| 0| break; 244| 0| case FBSDKAppEventsFlushReasonSessionChange: 245| 0| result = @"SessionChange"; 246| 0| break; 247| 0| case FBSDKAppEventsFlushReasonPersistedEvents: 248| 0| result = @"PersistedEvents"; 249| 0| break; 250| 0| case FBSDKAppEventsFlushReasonEventThreshold: 251| 0| result = @"EventCountThreshold"; 252| 0| break; 253| 0| case FBSDKAppEventsFlushReasonEagerlyFlushingEvent: 254| 0| result = @"EagerlyFlushingEvent"; 255| 0| break; 256| 0| } 257| 0| return result; 258| 0|} 259| | 260| |+ (void)logAndNotify:(NSString *)msg 261| 0|{ 262| 0| [[self class] logAndNotify:msg allowLogAsDeveloperError:YES]; 263| 0|} 264| | 265| |+ (void)logAndNotify:(NSString *)msg allowLogAsDeveloperError:(BOOL)allowLogAsDeveloperError 266| 0|{ 267| 0| NSString *behaviorToLog = FBSDKLoggingBehaviorAppEvents; 268| 0| if (allowLogAsDeveloperError) { 269| 0| if ([FBSDKSettings.loggingBehaviors containsObject:FBSDKLoggingBehaviorDeveloperErrors]) { 270| | // Rather than log twice, prefer 'DeveloperErrors' if it's set over AppEvents. 271| 0| behaviorToLog = FBSDKLoggingBehaviorDeveloperErrors; 272| 0| } 273| 0| } 274| | 275| 0| [FBSDKLogger singleShotLogEntry:behaviorToLog logEntry:msg]; 276| 0| NSError *error = [FBSDKError errorWithCode:FBSDKErrorAppEventsFlush message:msg]; 277| 0| [[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAppEventsLoggingResultNotification object:error]; 278| 0|} 279| | 280| |+ (BOOL) matchString:(NSString *)string 281| | firstCharacterSet:(NSCharacterSet *)firstCharacterSet 282| | restOfStringCharacterSet:(NSCharacterSet *)restOfStringCharacterSet 283| 0|{ 284| 0| if (string.length == 0) { 285| 0| return NO; 286| 0| } 287| 0| for (NSUInteger i = 0; i < string.length; i++) { 288| 0| const unichar c = [string characterAtIndex:i]; 289| 0| if (i == 0) { 290| 0| if (![firstCharacterSet characterIsMember:c]) { 291| 0| return NO; 292| 0| } 293| 0| } else { 294| 0| if (![restOfStringCharacterSet characterIsMember:c]) { 295| 0| return NO; 296| 0| } 297| 0| } 298| 0| } 299| 0| return YES; 300| 0|} 301| | 302| |+ (BOOL)regexValidateIdentifier:(NSString *)identifier 303| 0|{ 304| 0| static NSCharacterSet *firstCharacterSet; 305| 0| static NSCharacterSet *restOfStringCharacterSet; 306| 0| static dispatch_once_t onceToken; 307| 0| static NSMutableSet *cachedIdentifiers; 308| 0| dispatch_once(&onceToken, ^{ 309| 0| NSMutableCharacterSet *mutableSet = [NSMutableCharacterSet alphanumericCharacterSet]; 310| 0| [mutableSet addCharactersInString:@"_"]; 311| 0| firstCharacterSet = [mutableSet copy]; 312| | 313| 0| [mutableSet addCharactersInString:@"- "]; 314| 0| restOfStringCharacterSet = [mutableSet copy]; 315| 0| cachedIdentifiers = [NSMutableSet new]; 316| 0| }); 317| | 318| 0| @synchronized(self) { 319| 0| if (![cachedIdentifiers containsObject:identifier]) { 320| 0| if ([self matchString:identifier 321| 0| firstCharacterSet:firstCharacterSet 322| 0| restOfStringCharacterSet:restOfStringCharacterSet]) { 323| 0| [cachedIdentifiers addObject:identifier]; 324| 0| } else { 325| 0| return NO; 326| 0| } 327| 0| } 328| 0| } 329| 0| return YES; 330| 0|} 331| | 332| |+ (BOOL)validateIdentifier:(NSString *)identifier 333| 0|{ 334| 0| if (identifier == nil || identifier.length == 0 || identifier.length > FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH || ![[self class] regexValidateIdentifier:identifier]) { 335| 0| [[self class] logAndNotify:[NSString stringWithFormat:@"Invalid identifier: '%@'. Must be between 1 and %d characters, and must be contain only alphanumerics, _, - or spaces, starting with alphanumeric or _.", 336| 0| identifier, FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH]]; 337| 0| return NO; 338| 0| } 339| | 340| 0| return YES; 341| 0|} 342| | 343| |// Given a candidate token (which may be nil), find the real token to string to use. 344| |// Precedence: 1) provided token, 2) current token, 3) app | client token, 4) fully anonymous session. 345| |+ (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token 346| 0|{ 347| 0| if (!token) { 348| 0| token = [FBSDKAccessToken currentAccessToken]; 349| 0| } 350| | 351| 0| NSString *loggingOverrideAppID = [FBSDKAppEvents loggingOverrideAppID]; 352| | 353| 0| NSString *appID = loggingOverrideAppID ?: token.appID ?: [FBSDKSettings appID]; 354| 0| NSString *tokenString = token.tokenString; 355| 0| NSString *clientTokenString = [FBSDKSettings clientToken]; 356| | 357| 0| if (![appID isEqualToString:token.appID]) { 358| | // If there's a logging override app id present 359| | // then we don't want to use the client token since the client token 360| | // is intended to match up with the primary app id 361| | // and AppEvents doesn't require a client token. 362| 0| if (clientTokenString && loggingOverrideAppID) { 363| 0| tokenString = nil; 364| 0| } else if (clientTokenString && appID && ([appID isEqualToString:token.appID] || token == nil)) { 365| 0| tokenString = [NSString stringWithFormat:@"%@|%@", appID, clientTokenString]; 366| 0| } else if (appID) { 367| 0| tokenString = nil; 368| 0| } 369| 0| } 370| 0| return tokenString; 371| 0|} 372| | 373| |+ (NSTimeInterval)unixTimeNow 374| 0|{ 375| 0| return round([NSDate date].timeIntervalSince1970); 376| 0|} 377| | 378| |+ (NSTimeInterval)convertToUnixTime:(NSDate *)date 379| 0|{ 380| 0| return round([date timeIntervalSince1970]); 381| 0|} 382| | 383| |+ (BOOL)isDebugBuild 384| 0|{ 385| 0|#if TARGET_OS_SIMULATOR 386| 0| return YES; 387| |#else 388| | BOOL isDevelopment = NO; 389| | 390| | // There is no provisioning profile in AppStore Apps. 391| | @try { 392| | NSData *data = [NSData dataWithContentsOfFile:[NSBundle.mainBundle pathForResource:@"embedded" ofType:@"mobileprovision"]]; 393| | if (data) { 394| | const char *bytes = [data bytes]; 395| | NSMutableString *profile = [[NSMutableString alloc] initWithCapacity:data.length]; 396| | for (NSUInteger i = 0; i < data.length; i++) { 397| | [profile appendFormat:@"%c", bytes[i]]; 398| | } 399| | // Look for debug value, if detected we're in a development build. 400| | NSString *cleared = [[profile componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet] componentsJoinedByString:@""]; 401| | isDevelopment = ([cleared rangeOfString:@"get-task-allow"].length > 0); 402| | } 403| | 404| | return isDevelopment; 405| | } @catch (NSException *exception) {} 406| | 407| | return NO; 408| |#endif 409| 0|} 410| | 411| |+ (BOOL)shouldDropAppEvent 412| 0|{ 413| 0| if (@available(iOS 14.0, *)) { 414| 0| if ([FBSDKSettings advertisingTrackingStatus] == FBSDKAdvertisingTrackingDisallowed && ![FBSDKAppEventsConfigurationManager cachedAppEventsConfiguration].eventCollectionEnabled) { 415| 0| return YES; 416| 0| } 417| 0| } 418| 0| return NO; 419| 0|} 420| | 421| |+ (BOOL)isSensitiveUserData:(NSString *)text 422| 0|{ 423| 0| if (0 == text.length) { 424| 0| return NO; 425| 0| } 426| | 427| 0| return [self isEmailAddress:text] || [self isCreditCardNumber:text]; 428| 0|} 429| | 430| |+ (BOOL)isCreditCardNumber:(NSString *)text 431| 0|{ 432| 0| text = [[text componentsSeparatedByCharactersInSet:[NSCharacterSet.decimalDigitCharacterSet invertedSet]] componentsJoinedByString:@""]; 433| | 434| 0| if (text.doubleValue == 0) { 435| 0| return NO; 436| 0| } 437| | 438| 0| if (text.length < 9 || text.length > 21) { 439| 0| return NO; 440| 0| } 441| | 442| 0| const char *chars = [text cStringUsingEncoding:NSUTF8StringEncoding]; 443| 0| if (NULL == chars) { 444| 0| return NO; 445| 0| } 446| | 447| 0| BOOL isOdd = YES; 448| 0| int oddSum = 0; 449| 0| int evenSum = 0; 450| | 451| 0| for (int i = (int)text.length - 1; i >= 0; i--) { 452| 0| int digit = chars[i] - '0'; 453| | 454| 0| if (isOdd) { 455| 0| oddSum += digit; 456| 0| } else { 457| 0| evenSum += digit / 5 + (2 * digit) % 10; 458| 0| } 459| | 460| 0| isOdd = !isOdd; 461| 0| } 462| | 463| 0| return ((oddSum + evenSum) % 10 == 0); 464| 0|} 465| | 466| |+ (BOOL)isEmailAddress:(NSString *)text 467| 0|{ 468| 0| NSString *pattern = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"; 469| 0| NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:nil]; 470| 0| NSUInteger matches = [regex numberOfMatchesInString:text options:0 range:NSMakeRange(0, [text length])]; 471| 0| return matches > 0; 472| 0|} 473| | 474| |#if DEBUG 475| | #if FBSDKTEST 476| | 477| |+ (ASIdentifierManager *)cachedAdvertiserIdentifierManager 478| 0|{ 479| 0| return _cachedAdvertiserIdentifierManager; 480| 0|} 481| | 482| |+ (void)setCachedAdvertiserIdentifierManager:(ASIdentifierManager *)manager 483| 0|{ 484| 0| _cachedAdvertiserIdentifierManager = manager; 485| 0|} 486| | 487| | #endif 488| |#endif 489| | 490| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKAtePublisherFactory.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKAtePublisherFactory.h" 20| | 21| |#import "FBSDKAppEventsAtePublisher.h" 22| |#import "FBSDKDataPersisting.h" 23| | 24| |NS_ASSUME_NONNULL_BEGIN 25| | 26| |@interface FBSDKAtePublisherFactory () 27| | 28| |@property (nonnull, nonatomic, readonly) id graphRequestFactory; 29| |@property (nonnull, nonatomic, readonly) id settings; 30| |@property (nonnull, nonatomic, readonly) id store; 31| | 32| |@end 33| | 34| |@implementation FBSDKAtePublisherFactory 35| | 36| |- (instancetype)initWithStore:(id)store 37| | graphRequestFactory:(id)graphRequestFactory 38| | settings:(id)settings 39| 0|{ 40| 0| if ((self = [super init])) { 41| 0| _store = store; 42| 0| _graphRequestFactory = graphRequestFactory; 43| 0| _settings = settings; 44| 0| } 45| 0| return self; 46| 0|} 47| | 48| |- (id)createPublisherWithAppID:(NSString *)appID 49| 0|{ 50| 0| return [[FBSDKAppEventsAtePublisher alloc] initWithAppIdentifier:appID 51| 0| graphRequestFactory:self.graphRequestFactory 52| 0| settings:self.settings 53| 0| store:self.store]; 54| 0|} 55| | 56| |@end 57| | 58| |NS_ASSUME_NONNULL_END /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKHybridAppEventsScriptMessageHandler.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKHybridAppEventsScriptMessageHandler.h" 24| | 25| | #import "FBSDKAppEvents+EventLogging.h" 26| | #import "FBSDKAppEvents+Internal.h" 27| | #import "FBSDKCoreKitBasicsImport.h" 28| | #import "FBSDKEventLogging.h" 29| | 30| |NSString *const FBSDKAppEventsWKWebViewMessagesPixelReferralParamKey = @"_fb_pixel_referral_id"; 31| | 32| |@protocol FBSDKEventLogging; 33| |@class WKUserContentController; 34| | 35| |@interface FBSDKHybridAppEventsScriptMessageHandler () 36| | 37| |@property (nonatomic) id eventLogger; 38| | 39| |@end 40| | 41| |@implementation FBSDKHybridAppEventsScriptMessageHandler 42| | 43| |- (instancetype)init 44| 0|{ 45| 0| return [self initWithEventLogger:FBSDKAppEvents.singleton]; 46| 0|} 47| | 48| |- (instancetype)initWithEventLogger:(id)eventLogger 49| 0|{ 50| 0| if ((self = [super init])) { 51| 0| _eventLogger = eventLogger; 52| 0| } 53| 0| return self; 54| 0|} 55| | 56| |- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message 57| 0|{ 58| 0| if ([message.name isEqualToString:FBSDKAppEventsWKWebViewMessagesHandlerKey]) { 59| 0| NSDictionary *body = [FBSDKTypeUtility dictionaryValue:message.body]; 60| 0| if (!body) { 61| 0| return; 62| 0| } 63| 0| NSString *event = body[FBSDKAppEventsWKWebViewMessagesEventKey]; 64| 0| if ([event isKindOfClass:NSString.class] && (event.length > 0)) { 65| 0| NSString *stringedParams = [FBSDKTypeUtility stringValueOrNil:body[FBSDKAppEventsWKWebViewMessagesParamsKey]]; 66| 0| NSMutableDictionary *params = nil; 67| 0| NSError *jsonParseError = nil; 68| 0| if (stringedParams) { 69| 0| params = [FBSDKTypeUtility JSONObjectWithData:[stringedParams dataUsingEncoding:NSUTF8StringEncoding] 70| 0| options:NSJSONReadingMutableContainers 71| 0| error:&jsonParseError 72| 0| ]; 73| 0| } 74| 0| NSString *pixelID = body[FBSDKAppEventsWKWebViewMessagesPixelIDKey]; 75| 0| if (pixelID == nil) { 76| 0| [FBSDKAppEventsUtility logAndNotify:@"Can't bridge an event without a referral Pixel ID. Check your webview Pixel configuration."]; 77| 0| return; 78| 0| } 79| 0| if (jsonParseError != nil || ![params isKindOfClass:[NSDictionary class]] || params == nil) { 80| 0| [FBSDKAppEventsUtility logAndNotify:@"Could not find parameters for your Pixel request. Check your webview Pixel configuration."]; 81| 0| params = [[NSMutableDictionary alloc] initWithObjectsAndKeys:pixelID, FBSDKAppEventsWKWebViewMessagesPixelReferralParamKey, nil]; 82| 0| } else { 83| 0| [FBSDKTypeUtility dictionary:params setObject:pixelID forKey:FBSDKAppEventsWKWebViewMessagesPixelReferralParamKey]; 84| 0| } 85| 0| [self.eventLogger logInternalEvent:event 86| 0| parameters:params 87| 0| isImplicitlyLogged:NO]; 88| 0| } 89| 0| } 90| 0|} 91| | 92| |@end 93| | 94| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKPaymentObserver.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKPaymentObserver.h" 20| | 21| |#import 22| | 23| |#import "FBSDKCoreKit+Internal.h" 24| |#import "FBSDKPaymentProductRequestor.h" 25| |#import "FBSDKPaymentProductRequestorCreating.h" 26| |#import "FBSDKPaymentProductRequestorFactory.h" 27| | 28| |@interface FBSDKPaymentObserver () 29| | 30| |@property (nonatomic, readonly) SKPaymentQueue *paymentQueue; 31| |@property (nonatomic, readonly) id requestorFactory; 32| |@property (nonatomic) BOOL isObservingTransactions; 33| | 34| |@end 35| | 36| |@implementation FBSDKPaymentObserver 37| | 38| |- (instancetype)initWithPaymentQueue:(SKPaymentQueue *)paymentQueue 39| | paymentProductRequestorFactory:(id)paymentProductRequestorFactory 40| 0|{ 41| 0| if ((self = [super init])) { 42| 0| _paymentQueue = paymentQueue; 43| 0| _requestorFactory = paymentProductRequestorFactory; 44| 0| } 45| | 46| 0| return self; 47| 0|} 48| | 49| |#pragma mark - Internal Methods 50| | 51| |+ (FBSDKPaymentObserver *)shared 52| 0|{ 53| 0| static FBSDKPaymentObserver *shared = nil; 54| 0| static dispatch_once_t nonce; 55| 0| dispatch_once(&nonce, ^{ 56| 0| shared = [[FBSDKPaymentObserver alloc] initWithPaymentQueue:SKPaymentQueue.defaultQueue 57| 0| paymentProductRequestorFactory:[FBSDKPaymentProductRequestorFactory new]]; 58| 0| }); 59| 0| return shared; 60| 0|} 61| | 62| |- (void)startObservingTransactions 63| 0|{ 64| 0| @synchronized(self) { 65| 0| if (!self.isObservingTransactions) { 66| 0| [self.paymentQueue addTransactionObserver:self]; 67| 0| self.isObservingTransactions = YES; 68| 0| } 69| 0| } 70| 0|} 71| | 72| |- (void)stopObservingTransactions 73| 0|{ 74| 0| @synchronized(self) { 75| 0| if (self.isObservingTransactions) { 76| 0| [self.paymentQueue removeTransactionObserver:self]; 77| 0| self.isObservingTransactions = NO; 78| 0| } 79| 0| } 80| 0|} 81| | 82| |- (void) paymentQueue:(SKPaymentQueue *)queue 83| | updatedTransactions:(NSArray *)transactions 84| 0|{ 85| 0| for (SKPaymentTransaction *transaction in transactions) { 86| 0| switch (transaction.transactionState) { 87| 0| case SKPaymentTransactionStatePurchasing: 88| 0| case SKPaymentTransactionStatePurchased: 89| 0| case SKPaymentTransactionStateFailed: 90| 0| case SKPaymentTransactionStateRestored: 91| 0| [self handleTransaction:transaction]; 92| 0| break; 93| 0| case SKPaymentTransactionStateDeferred: 94| 0| break; 95| 0| } 96| 0| } 97| 0|} 98| | 99| |- (void)handleTransaction:(SKPaymentTransaction *)transaction 100| 0|{ 101| 0| FBSDKPaymentProductRequestor *productRequestor = [self.requestorFactory createRequestorWithTransaction:transaction]; 102| 0| [productRequestor resolveProducts]; 103| 0|} 104| | 105| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKPaymentProductRequestor.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKPaymentProductRequestor.h" 20| | 21| |#import 22| | 23| |#import "FBSDKAppEventName.h" 24| |#import "FBSDKAppEventParameterName.h" 25| |#import "FBSDKAppEventsFlushReason.h" 26| |#import "FBSDKAppStoreReceiptProviding.h" 27| |#import "FBSDKCoreKitBasicsImport.h" 28| |#import "FBSDKDataPersisting.h" 29| |#import "FBSDKEventLogging.h" 30| |#import "FBSDKGateKeeperManaging.h" 31| |#import "FBSDKLoggingCreating.h" 32| |#import "FBSDKProductsRequestProtocols.h" 33| |#import "FBSDKSettingsProtocol.h" 34| | 35| |static NSString *const FBSDKPaymentObserverOriginalTransactionKey = @"com.facebook.appevents.PaymentObserver.originalTransaction"; 36| |static NSString *const FBSDKPaymentObserverDelimiter = @","; 37| | 38| |static NSString *const FBSDKAppEventParameterImplicitlyLoggedPurchase = @"_implicitlyLogged"; 39| |static NSString *const FBSDKAppEventNamePurchaseFailed = @"fb_mobile_purchase_failed"; 40| |static NSString *const FBSDKAppEventNamePurchaseRestored = @"fb_mobile_purchase_restored"; 41| |static NSString *const FBSDKAppEventParameterNameInAppPurchaseType = @"fb_iap_product_type"; 42| |static NSString *const FBSDKAppEventParameterNameProductTitle = @"fb_content_title"; 43| |static NSString *const FBSDKAppEventParameterNameOriginalTransactionID = @"fb_original_transaction_id"; 44| |static NSString *const FBSDKAppEventParameterNameTransactionID = @"fb_transaction_id"; 45| |static NSString *const FBSDKAppEventParameterNameTransactionDate = @"fb_transaction_date"; 46| |static NSString *const FBSDKAppEventParameterNameSubscriptionPeriod = @"fb_iap_subs_period"; 47| |static NSString *const FBSDKAppEventParameterNameIsStartTrial = @"fb_iap_is_start_trial"; 48| |static NSString *const FBSDKAppEventParameterNameHasFreeTrial = @"fb_iap_has_free_trial"; 49| |static NSString *const FBSDKAppEventParameterNameTrialPeriod = @"fb_iap_trial_period"; 50| |static NSString *const FBSDKAppEventParameterNameTrialPrice = @"fb_iap_trial_price"; 51| | 52| |static NSString *const FBSDKGateKeeperAppEventsIfAutoLogSubs = @"app_events_if_auto_log_subs"; 53| |static int const FBSDKMaxParameterValueLength = 100; 54| | 55| |@interface FBSDKPaymentProductRequestor () 56| | 57| |@property (class, nonatomic, readonly) NSMutableArray *pendingRequestors; 58| |@property (nonatomic, retain) SKPaymentTransaction *transaction; 59| |@property (nonatomic, readonly) id appStoreReceiptProvider; 60| |@property (nonatomic, retain) id productsRequest; 61| |@property (nonatomic, readonly) id productRequestFactory; 62| |@property (nonatomic, readonly) id settings; 63| |@property (nonatomic, readonly) id eventLogger; 64| |@property (nonatomic, readonly) Class gateKeeperManager; 65| |@property (nonatomic, readonly) id store; 66| |@property (nonatomic, readonly) id loggerFactory; 67| |@property (nonatomic) NSMutableSet *originalTransactionSet; 68| |@property (nonatomic) NSSet *eventsWithReceipt; 69| |@property (nonatomic, readonly) NSDateFormatter *formatter; 70| | 71| |@end 72| | 73| |@implementation FBSDKPaymentProductRequestor 74| | 75| |static NSMutableArray *_pendingRequestors; 76| | 77| |+ (void)initialize 78| 0|{ 79| 0| if ([self class] == [FBSDKPaymentProductRequestor class]) { 80| 0| _pendingRequestors = [NSMutableArray new]; 81| 0| } 82| 0|} 83| | 84| |- (instancetype)initWithTransaction:(SKPaymentTransaction *)transaction 85| | settings:(id)settings 86| | eventLogger:(id)eventLogger 87| | gateKeeperManager:(Class)gateKeeperManager 88| | store:(id)store 89| | loggerFactory:(id)loggerFactory 90| | productsRequestFactory:(id)productRequestFactory 91| | appStoreReceiptProvider:(id)receiptProvider 92| 0|{ 93| 0| if ((self = [super init])) { 94| 0| _settings = settings; 95| 0| _eventLogger = eventLogger; 96| 0| _gateKeeperManager = gateKeeperManager; 97| 0| _store = store; 98| 0| _loggerFactory = loggerFactory; 99| 0| _productRequestFactory = productRequestFactory; 100| 0| _appStoreReceiptProvider = receiptProvider; 101| 0| _transaction = transaction; 102| 0| _formatter = [NSDateFormatter new]; 103| 0| _formatter.dateFormat = @"yyyy-MM-dd HH:mm:ssZ"; 104| 0| NSString *data = [_store stringForKey:FBSDKPaymentObserverOriginalTransactionKey]; 105| 0| _eventsWithReceipt = [NSSet setWithArray:@[FBSDKAppEventNamePurchased, FBSDKAppEventNameSubscribe, 106| 0| FBSDKAppEventNameStartTrial]]; 107| 0| if (data) { 108| 0| _originalTransactionSet = [NSMutableSet setWithArray:[data componentsSeparatedByString:FBSDKPaymentObserverDelimiter]]; 109| 0| } else { 110| 0| _originalTransactionSet = [NSMutableSet new]; 111| 0| } 112| 0| } 113| 0| return self; 114| 0|} 115| | 116| |+ (NSMutableArray *)pendingRequestors 117| 0|{ 118| 0| return _pendingRequestors; 119| 0|} 120| | 121| |- (void)setProductsRequest:(id)productsRequest 122| 0|{ 123| 0| if (productsRequest != _productsRequest) { 124| 0| if (_productsRequest) { 125| 0| _productsRequest.delegate = nil; 126| 0| } 127| 0| _productsRequest = productsRequest; 128| 0| } 129| 0|} 130| | 131| |- (void)resolveProducts 132| 0|{ 133| 0| NSString *productId = self.transaction.payment.productIdentifier; 134| 0| NSSet *productIdentifiers = [NSSet setWithObjects:productId, nil]; 135| 0| self.productsRequest = [self.productRequestFactory createWithProductIdentifiers:productIdentifiers]; 136| 0| self.productsRequest.delegate = self; 137| 0| @synchronized(self.class.pendingRequestors) { 138| 0| [FBSDKTypeUtility array:self.class.pendingRequestors addObject:self]; 139| 0| } 140| 0| [self.productsRequest start]; 141| 0|} 142| | 143| |- (NSString *)getTruncatedString:(NSString *)inputString 144| 0|{ 145| 0| if (!inputString) { 146| 0| return @""; 147| 0| } 148| | 149| 0| return inputString.length <= FBSDKMaxParameterValueLength ? inputString : [inputString substringToIndex:FBSDKMaxParameterValueLength]; 150| 0|} 151| | 152| |- (void)logTransactionEvent:(SKProduct *)product 153| 0|{ 154| 0| if ([self isSubscription:product] 155| 0| && [self.gateKeeperManager boolForKey:FBSDKGateKeeperAppEventsIfAutoLogSubs 156| 0| defaultValue:NO]) { 157| 0| [self logImplicitSubscribeTransaction:self.transaction ofProduct:product]; 158| 0| } else { 159| 0| [self logImplicitPurchaseTransaction:self.transaction ofProduct:product]; 160| 0| } 161| 0|} 162| | 163| |- (BOOL)isSubscription:(SKProduct *)product 164| 0|{ 165| 0|#if !TARGET_OS_TV 166| 0|#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_1 167| 0| if (@available(iOS 11.2, *)) { 168| 0| return (product.subscriptionPeriod != nil) && ((unsigned long)product.subscriptionPeriod.numberOfUnits > 0); 169| 0| } 170| 0|#endif 171| 0|#endif 172| 0| return NO; 173| 0|} 174| | 175| |- (NSMutableDictionary *)getEventParametersOfProduct:(SKProduct *)product 176| | withTransaction:(SKPaymentTransaction *)transaction 177| 0|{ 178| 0| NSString *transactionID = nil; 179| 0| NSString *transactionDate = nil; 180| 0| switch (transaction.transactionState) { 181| 0| case SKPaymentTransactionStatePurchasing: 182| 0| break; 183| 0| case SKPaymentTransactionStatePurchased: 184| 0| transactionID = transaction.transactionIdentifier; 185| 0| transactionDate = [_formatter stringFromDate:transaction.transactionDate]; 186| 0| break; 187| 0| case SKPaymentTransactionStateFailed: 188| 0| break; 189| 0| case SKPaymentTransactionStateRestored: 190| 0| transactionDate = [_formatter stringFromDate:transaction.transactionDate]; 191| 0| break; 192| 0| default: break; 193| 0| } 194| 0| SKPayment *payment = transaction.payment; 195| 0| NSMutableDictionary *eventParameters = [NSMutableDictionary dictionaryWithDictionary:@{ 196| 0| FBSDKAppEventParameterNameContentID : payment.productIdentifier ?: @"", 197| 0| FBSDKAppEventParameterNameNumItems : @(payment.quantity), 198| 0| FBSDKAppEventParameterNameTransactionDate : transactionDate ?: @"", 199| 0| }]; 200| 0| if (product) { 201| 0| [eventParameters addEntriesFromDictionary:@{ 202| 0| FBSDKAppEventParameterNameCurrency : [product.priceLocale objectForKey:NSLocaleCurrencyCode], 203| 0| FBSDKAppEventParameterNameNumItems : @(payment.quantity), 204| 0| FBSDKAppEventParameterNameProductTitle : [self getTruncatedString:product.localizedTitle], 205| 0| FBSDKAppEventParameterNameDescription : [self getTruncatedString:product.localizedDescription], 206| 0| }]; 207| 0| if (transactionID) { 208| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:transactionID forKey:FBSDKAppEventParameterNameTransactionID]; 209| 0| } 210| 0| } 211| | 212| 0|#if !TARGET_OS_TV 213| 0|#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_1 214| 0| if (@available(iOS 11.2, *)) { 215| 0| if ([self isSubscription:product]) { 216| | // subs inapp 217| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:[self durationOfSubscriptionPeriod:product.subscriptionPeriod] forKey:FBSDKAppEventParameterNameSubscriptionPeriod]; 218| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:@"subs" forKey:FBSDKAppEventParameterNameInAppPurchaseType]; 219| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:[self isStartTrial:transaction ofProduct:product] ? @"1" : @"0" forKey:FBSDKAppEventParameterNameIsStartTrial]; 220| | // trial information for subs 221| 0| SKProductDiscount *discount = product.introductoryPrice; 222| 0| if (discount) { 223| 0| if (discount.paymentMode == SKProductDiscountPaymentModeFreeTrial) { 224| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:@"1" forKey:FBSDKAppEventParameterNameHasFreeTrial]; 225| 0| } else { 226| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:@"0" forKey:FBSDKAppEventParameterNameHasFreeTrial]; 227| 0| } 228| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:[self durationOfSubscriptionPeriod:discount.subscriptionPeriod] forKey:FBSDKAppEventParameterNameTrialPeriod]; 229| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:discount.price forKey:FBSDKAppEventParameterNameTrialPrice]; 230| 0| } 231| 0| } else { 232| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:@"inapp" forKey:FBSDKAppEventParameterNameInAppPurchaseType]; 233| 0| } 234| 0| } 235| 0|#endif 236| 0|#endif 237| 0| return eventParameters; 238| 0|} 239| | 240| |- (void)appendOriginalTransactionID:(NSString *)transactionID 241| 0|{ 242| 0| if (!transactionID) { 243| 0| return; 244| 0| } 245| 0| [self.originalTransactionSet addObject:transactionID]; 246| 0| [self.store setObject:[[self.originalTransactionSet allObjects] componentsJoinedByString:FBSDKPaymentObserverDelimiter] 247| 0| forKey:FBSDKPaymentObserverOriginalTransactionKey]; 248| 0|} 249| | 250| |- (void)clearOriginalTransactionID:(NSString *)transactionID 251| 0|{ 252| 0| if (!transactionID) { 253| 0| return; 254| 0| } 255| 0| [self.originalTransactionSet removeObject:transactionID]; 256| 0| [self.store setObject:[[self.originalTransactionSet allObjects] componentsJoinedByString:FBSDKPaymentObserverDelimiter] 257| 0| forKey:FBSDKPaymentObserverOriginalTransactionKey]; 258| 0|} 259| | 260| |- (BOOL)isStartTrial:(SKPaymentTransaction *)transaction 261| | ofProduct:(SKProduct *)product 262| 0|{ 263| 0|#if !TARGET_OS_TV 264| 0|#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_1 265| 0|#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_4 266| 0|#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_12_1 267| | // promotional offer starting from iOS 12.2 268| 0| if (@available(iOS 12.2, *)) { 269| 0| SKPaymentDiscount *paymentDiscount = transaction.payment.paymentDiscount; 270| 0| if (paymentDiscount) { 271| 0| NSArray *discounts = product.discounts; 272| 0| for (SKProductDiscount *discount in discounts) { 273| 0| if (discount.paymentMode == SKProductDiscountPaymentModeFreeTrial 274| 0| && [paymentDiscount.identifier isEqualToString:discount.identifier]) { 275| 0| return YES; 276| 0| } 277| 0| } 278| 0| } 279| 0| } 280| 0|#endif 281| 0|#endif 282| | // introductory offer starting from iOS 11.2 283| 0| if (@available(iOS 11.2, *)) { 284| 0| if (product.introductoryPrice 285| 0| && product.introductoryPrice.paymentMode == SKProductDiscountPaymentModeFreeTrial) { 286| 0| NSString *originalTransactionID = transaction.originalTransaction.transactionIdentifier; 287| | // only consider the very first trial transaction as start trial 288| 0| if (!originalTransactionID) { 289| 0| return YES; 290| 0| } 291| 0| } 292| 0| } 293| 0|#endif 294| 0|#endif 295| 0| return NO; 296| 0|} 297| | 298| |- (NSString *)durationOfSubscriptionPeriod:(id)subcriptionPeriod 299| 0|{ 300| 0|#if !TARGET_OS_TV 301| 0|#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_1 302| 0| if (@available(iOS 11.2, *)) { 303| 0| if (subcriptionPeriod && [subcriptionPeriod isKindOfClass:[SKProductSubscriptionPeriod class]]) { 304| 0| SKProductSubscriptionPeriod *period = (SKProductSubscriptionPeriod *)subcriptionPeriod; 305| 0| NSString *unit = nil; 306| 0| switch (period.unit) { 307| 0| case SKProductPeriodUnitDay: unit = @"D"; break; 308| 0| case SKProductPeriodUnitWeek: unit = @"W"; break; 309| 0| case SKProductPeriodUnitMonth: unit = @"M"; break; 310| 0| case SKProductPeriodUnitYear: unit = @"Y"; break; 311| 0| } 312| 0| return [NSString stringWithFormat:@"P%lu%@", (unsigned long)period.numberOfUnits, unit]; 313| 0| } 314| 0| } 315| 0|#endif 316| 0|#endif 317| 0| return nil; 318| 0|} 319| | 320| |- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response 321| 0|{ 322| 0| NSArray *products = response.products; 323| 0| NSArray *invalidProductIdentifiers = response.invalidProductIdentifiers; 324| 0| if (products.count + invalidProductIdentifiers.count != 1) { 325| 0| id logger = [self.loggerFactory createLoggerWithLoggingBehavior:FBSDKLoggingBehaviorAppEvents]; 326| 0| [logger logEntry:@"FBSDKPaymentObserver: Expect to resolve one product per request"]; 327| 0| } 328| 0| SKProduct *product = nil; 329| 0| if (products.count) { 330| 0| product = [FBSDKTypeUtility array:products objectAtIndex:0]; 331| 0| } 332| 0| [self logTransactionEvent:product]; 333| 0|} 334| | 335| |- (void)requestDidFinish:(SKRequest *)request 336| 0|{ 337| 0| [self cleanUp]; 338| 0|} 339| | 340| |- (void)request:(SKRequest *)request didFailWithError:(NSError *)error 341| 0|{ 342| 0| [self logTransactionEvent:nil]; 343| 0| [self cleanUp]; 344| 0|} 345| | 346| |- (void)cleanUp 347| 0|{ 348| 0| @synchronized(self.class.pendingRequestors) { 349| 0| [self.class.pendingRequestors removeObject:self]; 350| 0| } 351| 0|} 352| | 353| |- (void)logImplicitSubscribeTransaction:(SKPaymentTransaction *)transaction 354| | ofProduct:(SKProduct *)product 355| 0|{ 356| 0| NSString *eventName = nil; 357| 0| NSString *originalTransactionID = transaction.originalTransaction.transactionIdentifier; 358| 0| switch (transaction.transactionState) { 359| 0| case SKPaymentTransactionStatePurchasing: 360| 0| eventName = @"SubscriptionInitiatedCheckout"; 361| 0| break; 362| 0| case SKPaymentTransactionStatePurchased: 363| 0| if ([self isStartTrial:transaction ofProduct:product]) { 364| 0| eventName = FBSDKAppEventNameStartTrial; 365| 0| [self clearOriginalTransactionID:originalTransactionID]; 366| 0| } else { 367| 0| if (originalTransactionID && [self.originalTransactionSet containsObject:originalTransactionID]) { 368| 0| return; 369| 0| } 370| 0| eventName = FBSDKAppEventNameSubscribe; 371| 0| [self appendOriginalTransactionID:(originalTransactionID ?: transaction.transactionIdentifier)]; 372| 0| } 373| 0| break; 374| 0| case SKPaymentTransactionStateFailed: 375| 0| eventName = @"SubscriptionFailed"; 376| 0| break; 377| 0| case SKPaymentTransactionStateRestored: 378| 0| eventName = @"SubscriptionRestore"; 379| 0| break; 380| 0| case SKPaymentTransactionStateDeferred: 381| 0| return; 382| 0| } 383| | 384| 0| double totalAmount = 0; 385| 0| if (product) { 386| 0| totalAmount = transaction.payment.quantity * product.price.doubleValue; 387| 0| } 388| | 389| 0| [self logImplicitTransactionEvent:eventName 390| 0| valueToSum:totalAmount 391| 0| parameters:[self getEventParametersOfProduct:product withTransaction:transaction]]; 392| 0|} 393| | 394| |- (void)logImplicitPurchaseTransaction:(SKPaymentTransaction *)transaction 395| | ofProduct:(SKProduct *)product 396| 0|{ 397| 0| NSString *eventName = nil; 398| 0| switch (transaction.transactionState) { 399| 0| case SKPaymentTransactionStatePurchasing: 400| 0| eventName = FBSDKAppEventNameInitiatedCheckout; 401| 0| break; 402| 0| case SKPaymentTransactionStatePurchased: 403| 0| eventName = FBSDKAppEventNamePurchased; 404| 0| break; 405| 0| case SKPaymentTransactionStateFailed: 406| 0| eventName = FBSDKAppEventNamePurchaseFailed; 407| 0| break; 408| 0| case SKPaymentTransactionStateRestored: 409| 0| eventName = FBSDKAppEventNamePurchaseRestored; 410| 0| break; 411| 0| case SKPaymentTransactionStateDeferred: 412| 0| return; 413| 0| } 414| | 415| 0| double totalAmount = 0; 416| 0| if (product) { 417| 0| totalAmount = transaction.payment.quantity * product.price.doubleValue; 418| 0| } 419| | 420| 0| [self logImplicitTransactionEvent:eventName 421| 0| valueToSum:totalAmount 422| 0| parameters:[self getEventParametersOfProduct:product withTransaction:transaction]]; 423| 0|} 424| | 425| |- (void)logImplicitTransactionEvent:(NSString *)eventName 426| | valueToSum:(double)valueToSum 427| | parameters:(NSDictionary *)parameters 428| 0|{ 429| 0| NSMutableDictionary *eventParameters = [NSMutableDictionary dictionaryWithDictionary:parameters]; 430| | 431| 0| if ([_eventsWithReceipt containsObject:eventName]) { 432| 0| NSData *receipt = [self fetchDeviceReceipt]; 433| 0| if (receipt) { 434| 0| NSString *base64encodedReceipt = [receipt base64EncodedStringWithOptions:0]; 435| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:base64encodedReceipt forKey:@"receipt_data"]; 436| 0| } 437| 0| } 438| | 439| 0| [FBSDKTypeUtility dictionary:eventParameters setObject:@"1" forKey:FBSDKAppEventParameterImplicitlyLoggedPurchase]; 440| 0| [self.eventLogger logEvent:eventName 441| 0| valueToSum:valueToSum 442| 0| parameters:eventParameters]; 443| | 444| | // Unless the behavior is set to only allow explicit flushing, we go ahead and flush, since purchase events 445| | // are relatively rare and relatively high value and worth getting across on wire right away. 446| 0| if ([self.eventLogger flushBehavior] != FBSDKAppEventsFlushBehaviorExplicitOnly) { 447| 0| [self.eventLogger flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent]; 448| 0| } 449| 0|} 450| | 451| |// Fetch the current receipt for this application. 452| |- (NSData *)fetchDeviceReceipt 453| 0|{ 454| 0| NSURL *receiptURL = self.appStoreReceiptProvider.appStoreReceiptURL; 455| 0| NSData *receipt = [NSData dataWithContentsOfURL:receiptURL]; 456| 0| return receipt; 457| 0|} 458| | 459| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKPaymentProductRequestorFactory.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKPaymentProductRequestorFactory.h" 20| | 21| |#import "FBSDKAppEvents+EventLogging.h" 22| |#import "FBSDKAppStoreReceiptProviding.h" 23| |#import "FBSDKGateKeeperManager.h" 24| |#import "FBSDKGateKeeperManaging.h" 25| |#import "FBSDKLoggerFactory.h" 26| |#import "FBSDKPaymentProductRequestor.h" 27| |#import "FBSDKProductRequestFactory.h" 28| |#import "FBSDKProductsRequestProtocols.h" 29| |#import "FBSDKSettings+Internal.h" 30| |#import "FBSDKSettings+SettingsProtocols.h" 31| |#import "NSUserDefaults+FBSDKDataPersisting.h" 32| | 33| |@interface FBSDKPaymentProductRequestorFactory () 34| | 35| |@property (nonatomic, readonly) id settings; 36| |@property (nonatomic, readonly) id eventLogger; 37| |@property (nullable, nonatomic) Class gateKeeperManager; 38| |@property (nullable, nonatomic) id store; 39| |@property (nullable, nonatomic) id loggerFactory; 40| |@property (nonatomic, readonly) id productsRequestFactory; 41| |@property (nonatomic, readonly) id appStoreReceiptProvider; 42| | 43| |@end 44| | 45| |@implementation FBSDKPaymentProductRequestorFactory 46| | 47| |- (instancetype)init 48| 0|{ 49| 0| return [self initWithSettings:FBSDKSettings.sharedSettings 50| 0| eventLogger:FBSDKAppEvents.singleton 51| 0| gateKeeperManager:FBSDKGateKeeperManager.class 52| 0| store:NSUserDefaults.standardUserDefaults 53| 0| loggerFactory:[FBSDKLoggerFactory new] 54| 0| productsRequestFactory:[FBSDKProductRequestFactory new] 55| 0| appStoreReceiptProvider:[NSBundle bundleForClass:self.class]]; 56| 0|} 57| | 58| |- (instancetype)initWithSettings:(id)settings 59| | eventLogger:(id)eventLogger 60| | gateKeeperManager:(Class)gateKeeperManager 61| | store:(id)store 62| | loggerFactory:(id)loggerFactory 63| | productsRequestFactory:(id)productsRequestFactory 64| | appStoreReceiptProvider:(id)receiptProvider 65| 0|{ 66| 0| if ((self = [super init])) { 67| 0| _settings = settings; 68| 0| _eventLogger = eventLogger; 69| 0| _gateKeeperManager = gateKeeperManager; 70| 0| _store = store; 71| 0| _loggerFactory = loggerFactory; 72| 0| _productsRequestFactory = productsRequestFactory; 73| 0| _appStoreReceiptProvider = receiptProvider; 74| 0| } 75| | 76| 0| return self; 77| 0|} 78| | 79| |- (nonnull FBSDKPaymentProductRequestor *)createRequestorWithTransaction:(SKPaymentTransaction *)transaction 80| 0|{ 81| 0| return [[FBSDKPaymentProductRequestor alloc] initWithTransaction:transaction 82| 0| settings:self.settings 83| 0| eventLogger:self.eventLogger 84| 0| gateKeeperManager:self.gateKeeperManager 85| 0| store:self.store 86| 0| loggerFactory:self.loggerFactory 87| 0| productsRequestFactory:self.productsRequestFactory 88| 0| appStoreReceiptProvider:self.appStoreReceiptProvider]; 89| 0|} 90| | 91| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKProductRequestFactory.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKProductRequestFactory.h" 20| | 21| |#import "SKProductsRequest+FBSDKProductsRequest.h" 22| | 23| |@implementation FBSDKProductRequestFactory 24| | 25| |- (nonnull id)createWithProductIdentifiers:(nonnull NSSet *)identifiers 26| 0|{ 27| 0| return [[SKProductsRequest alloc] initWithProductIdentifiers:identifiers]; 28| 0|} 29| | 30| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKTimeSpentData.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKTimeSpentData.h" 20| | 21| |#import "FBSDKAppEventParameterName.h" 22| |#import "FBSDKAppEventsFlushReason.h" 23| |#import "FBSDKCoreKitBasicsImport.h" 24| |#import "FBSDKEventLogging.h" 25| |#import "FBSDKInternalUtility.h" 26| |#import "FBSDKLogger.h" 27| |#import "FBSDKServerConfiguration.h" 28| |#import "FBSDKServerConfigurationProviding.h" 29| | 30| |// Filename and keys for session length 31| |NSString *const FBSDKTimeSpentFilename = @"com-facebook-sdk-AppEventsTimeSpent.json"; 32| |static NSString *const FBSDKTimeSpentPersistKeySessionSecondsSpent = @"secondsSpentInCurrentSession"; 33| |static NSString *const FBSDKTimeSpentPersistKeySessionNumInterruptions = @"numInterruptions"; 34| |static NSString *const FBSDKTimeSpentPersistKeyLastSuspendTime = @"lastSuspendTime"; 35| |static NSString *const FBSDKTimeSpentPersistKeySessionID = @"sessionID"; 36| | 37| |static NSString *const FBSDKAppEventNameActivatedApp = @"fb_mobile_activate_app"; 38| |static NSString *const FBSDKAppEventNameDeactivatedApp = @"fb_mobile_deactivate_app"; 39| |static NSString *const FBSDKAppEventParameterNameSessionInterruptions = @"fb_mobile_app_interruptions"; 40| |static NSString *const FBSDKAppEventParameterNameTimeBetweenSessions = @"fb_mobile_time_between_sessions"; 41| |static NSString *const FBSDKAppEventParameterNameSessionID = @"_session_id"; 42| | 43| |FBSDKAppEventParameterName FBSDKAppEventParameterLaunchSource = @"fb_mobile_launch_source"; 44| | 45| |static const int SECS_PER_MIN = 60; 46| |static const int SECS_PER_HOUR = 60 * SECS_PER_MIN; 47| |static const int SECS_PER_DAY = 24 * SECS_PER_HOUR; 48| | 49| |// Will be translated and displayed in App Insights. Need to maintain same number and value of quanta on the server. 50| |static const long INACTIVE_SECONDS_QUANTA[] = 51| |{ 52| | 5 * SECS_PER_MIN, 53| | 15 * SECS_PER_MIN, 54| | 30 * SECS_PER_MIN, 55| | 1 * SECS_PER_HOUR, 56| | 6 * SECS_PER_HOUR, 57| | 12 * SECS_PER_HOUR, 58| | 1 * SECS_PER_DAY, 59| | 2 * SECS_PER_DAY, 60| | 3 * SECS_PER_DAY, 61| | 7 * SECS_PER_DAY, 62| | 14 * SECS_PER_DAY, 63| | 21 * SECS_PER_DAY, 64| | 28 * SECS_PER_DAY, 65| | 60 * SECS_PER_DAY, 66| | 90 * SECS_PER_DAY, 67| | 120 * SECS_PER_DAY, 68| | 150 * SECS_PER_DAY, 69| | 180 * SECS_PER_DAY, 70| | 365 * SECS_PER_DAY, 71| | LONG_MAX, // keep as LONG_MAX to guarantee loop will terminate 72| |}; 73| | 74| |@interface FBSDKTimeSpentData () 75| | 76| |@property (nonatomic, weak) id eventLogger; 77| |@property (nonnull, nonatomic) Class serverConfigurationProvider; 78| |@property (nonatomic) NSString *sourceApplication; 79| |@property (nonatomic) BOOL isOpenedFromAppLink; 80| | 81| |@end 82| | 83| |/** 84| | * This class encapsulates the notion of an app 'session' - the length of time that the user has 85| | * spent in the app that can be considered a single usage of the app. Apps may be frequently interrupted 86| | * do to other device activity, like a text message, so this class allows those interruptions to be smoothed 87| | * out and the time actually spent in the app excluding this interruption time to be accumulated. Also, 88| | * once a certain amount of time has gone by where the app is not in the foreground, we consider the 89| | * session to be complete, and a new session beginning. When this occurs, we log a 'deactivate app' event 90| | * with the duration of the previous session as the 'value' of this event, along with the number of 91| | * interruptions from that previous session as an event parameter. 92| | */ 93| |@implementation FBSDKTimeSpentData 94| |{ 95| | BOOL _isCurrentlyLoaded; 96| | BOOL _shouldLogActivateEvent; 97| | BOOL _shouldLogDeactivateEvent; 98| | NSTimeInterval _secondsSpentInCurrentSession; 99| | NSTimeInterval _timeSinceLastSuspend; 100| | int _numInterruptionsInCurrentSession; 101| | NSTimeInterval _lastRestoreTime; 102| | NSTimeInterval _lastSuspendTime; 103| | NSString *_sessionID; 104| |} 105| | 106| |- (instancetype)initWithEventLogger:(id)eventLogger 107| | serverConfigurationProvider:(Class)serverConfigurationProvider 108| 0|{ 109| 0| if ((self = [super init])) { 110| 0| _eventLogger = eventLogger; 111| 0| _serverConfigurationProvider = serverConfigurationProvider; 112| 0| } 113| | 114| 0| return self; 115| 0|} 116| | 117| |- (void)ensureOnMainThread:(NSString *)methodName className:(NSString *)className 118| 0|{ 119| 0| if (!NSThread.isMainThread) { 120| 0| NSString *msg = [NSString stringWithFormat:@"*** <%@, %@> is not called on the main thread. This can lead to errors.", methodName, className]; 121| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:msg]; 122| 0| } 123| 0|} 124| | 125| |// Calculate and persist time spent data for this instance of the app activation. 126| |- (void)suspend 127| 0|{ 128| 0| [self ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])]; 129| 0| if (!_isCurrentlyLoaded) { 130| 0| FBSDKConditionalLog(YES, FBSDKLoggingBehaviorInformational, @"[FBSDKTimeSpentData suspend] invoked without corresponding restore"); 131| 0| return; 132| 0| } 133| | 134| 0| NSTimeInterval now = round([NSDate date].timeIntervalSince1970); 135| 0| NSTimeInterval timeSinceRestore = now - _lastRestoreTime; 136| | 137| | // Can happen if the clock on the device is changed 138| 0| if (timeSinceRestore < 0) { 139| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents 140| 0| logEntry:@"Clock skew detected"]; 141| 0| timeSinceRestore = 0; 142| 0| } 143| | 144| 0| _secondsSpentInCurrentSession += timeSinceRestore; 145| | 146| 0| NSDictionary *timeSpentData = 147| 0| @{ 148| 0| FBSDKTimeSpentPersistKeySessionSecondsSpent : @(_secondsSpentInCurrentSession), 149| 0| FBSDKTimeSpentPersistKeySessionNumInterruptions : @(_numInterruptionsInCurrentSession), 150| 0| FBSDKTimeSpentPersistKeyLastSuspendTime : @(now), 151| 0| FBSDKTimeSpentPersistKeySessionID : _sessionID, 152| 0| }; 153| | 154| 0| NSString *content = [FBSDKBasicUtility JSONStringForObject:timeSpentData error:NULL invalidObjectHandler:NULL]; 155| | 156| 0| [content writeToFile:[FBSDKBasicUtility persistenceFilePath:FBSDKTimeSpentFilename] 157| 0| atomically:YES 158| 0| encoding:NSASCIIStringEncoding 159| 0| error:nil]; 160| | 161| 0| NSString *msg = [NSString stringWithFormat:@"FBSDKTimeSpentData Persist: %@", content]; 162| 0| [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents 163| 0| logEntry:msg]; 164| | 165| 0| _isCurrentlyLoaded = NO; 166| 0|} 167| | 168| |// Called during activation - either through an explicit 'activateApp' call or implicitly when the app is foregrounded. 169| |// In both cases, we restore the persisted event data. In the case of the activateApp, we log an 'app activated' 170| |// event if there's been enough time between the last deactivation and now. 171| |- (void)restore:(BOOL)calledFromActivateApp 172| 0|{ 173| 0| [self ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])]; 174| | 175| | // It's possible to call this multiple times during the time the app is in the foreground. If this is the case, 176| | // just restore persisted data the first time. 177| 0| if (!_isCurrentlyLoaded) { 178| 0| NSTimeInterval now = round([NSDate date].timeIntervalSince1970); 179| 0| NSString *content = 180| 0| [[NSString alloc] initWithContentsOfFile:[FBSDKBasicUtility persistenceFilePath:FBSDKTimeSpentFilename] 181| 0| usedEncoding:nil 182| 0| error:nil]; 183| | 184| 0| if (!content) { 185| | // Nothing persisted, so this is the first launch. 186| 0| _sessionID = [NSUUID UUID].UUIDString; 187| 0| _secondsSpentInCurrentSession = 0; 188| 0| _numInterruptionsInCurrentSession = 0; 189| 0| _lastSuspendTime = 0; 190| | 191| | // We want to log the app activation event on the first launch, but not the deactivate event 192| 0| _shouldLogActivateEvent = YES; 193| 0| _shouldLogDeactivateEvent = NO; 194| 0| } else { 195| 0| NSDictionary *results = [FBSDKBasicUtility objectForJSONString:content error:NULL]; 196| | 197| 0| _lastSuspendTime = [results[FBSDKTimeSpentPersistKeyLastSuspendTime] longValue]; 198| | 199| 0| _timeSinceLastSuspend = now - _lastSuspendTime; 200| 0| _secondsSpentInCurrentSession = [results[FBSDKTimeSpentPersistKeySessionSecondsSpent] intValue]; 201| 0| _sessionID = results[FBSDKTimeSpentPersistKeySessionID] ?: [NSUUID UUID].UUIDString; 202| 0| _numInterruptionsInCurrentSession = [results[FBSDKTimeSpentPersistKeySessionNumInterruptions] intValue]; 203| 0| _shouldLogActivateEvent = (_timeSinceLastSuspend > [[self.serverConfigurationProvider cachedServerConfiguration] sessionTimoutInterval]); 204| | 205| | // Other than the first launch, we always log the last session's deactivate with this session's activate. 206| 0| _shouldLogDeactivateEvent = _shouldLogActivateEvent; 207| | 208| 0| if (!_shouldLogDeactivateEvent) { 209| | // If we're not logging, then the time we spent deactivated is considered another interruption. But cap it 210| | // so errant or test uses doesn't blow out the cardinality on the backend processing 211| 0| _numInterruptionsInCurrentSession = MIN(_numInterruptionsInCurrentSession + 1, 200); 212| 0| } 213| 0| } 214| | 215| 0| _lastRestoreTime = now; 216| 0| _isCurrentlyLoaded = YES; 217| | 218| 0| if (calledFromActivateApp) { 219| | // It's important to log deactivate first to reset sessionID 220| 0| if (_shouldLogDeactivateEvent) { 221| 0| [self.eventLogger logEvent:FBSDKAppEventNameDeactivatedApp 222| 0| valueToSum:_secondsSpentInCurrentSession 223| 0| parameters:[self appEventsParametersForDeactivate]]; 224| | 225| | // We've logged the session stats, now reset. 226| 0| _secondsSpentInCurrentSession = 0; 227| 0| _numInterruptionsInCurrentSession = 0; 228| 0| _sessionID = [NSUUID UUID].UUIDString; 229| 0| } 230| | 231| 0| if (_shouldLogActivateEvent) { 232| 0| [self.eventLogger logEvent:FBSDKAppEventNameActivatedApp 233| 0| parameters:[self appEventsParametersForActivate]]; 234| | // Unless the behavior is set to only allow explicit flushing, we go ahead and flush. App launch 235| | // events are critical to Analytics so we don't want to lose them. 236| 0| if (self.eventLogger.flushBehavior != FBSDKAppEventsFlushBehaviorExplicitOnly) { 237| 0| [self.eventLogger flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent]; 238| 0| } 239| 0| } 240| 0| } 241| 0| } 242| 0|} 243| | 244| |- (NSDictionary *)appEventsParametersForActivate 245| 0|{ 246| 0| return @{ 247| 0| FBSDKAppEventParameterLaunchSource : [self getSourceApplication], 248| 0| FBSDKAppEventParameterNameSessionID : _sessionID, 249| 0| }; 250| 0|} 251| | 252| |- (NSDictionary *)appEventsParametersForDeactivate 253| 0|{ 254| 0| int quantaIndex = 0; 255| 0| while (_timeSinceLastSuspend > INACTIVE_SECONDS_QUANTA[quantaIndex]) { 256| 0| quantaIndex++; 257| 0| } 258| | 259| 0| NSMutableDictionary *params = [@{ FBSDKAppEventParameterNameSessionInterruptions : @(_numInterruptionsInCurrentSession), 260| 0| FBSDKAppEventParameterNameTimeBetweenSessions : [NSString stringWithFormat:@"session_quanta_%d", quantaIndex], 261| 0| FBSDKAppEventParameterLaunchSource : [self getSourceApplication], 262| 0| FBSDKAppEventParameterNameSessionID : _sessionID ?: @"", } mutableCopy]; 263| 0| if (_lastSuspendTime) { 264| 0| [FBSDKTypeUtility dictionary:params setObject:@(_lastSuspendTime) forKey:@"_logTime"]; 265| 0| } 266| 0| return [params copy]; 267| 0|} 268| | 269| |- (void)setSourceApplication:(nullable NSString *)sourceApplication openURL:(NSURL *)url 270| 0|{ 271| 0| [self setSourceApplication:sourceApplication 272| 0| isFromAppLink:[FBSDKInternalUtility parametersFromFBURL:url][@"al_applink_data"] != nil]; 273| 0|} 274| | 275| |- (void)setSourceApplication:(nullable NSString *)sourceApplication isFromAppLink:(BOOL)isFromAppLink 276| 0|{ 277| 0| self.isOpenedFromAppLink = isFromAppLink; 278| 0| self.sourceApplication = sourceApplication; 279| 0|} 280| | 281| |- (NSString *)getSourceApplication 282| 0|{ 283| 0| NSString *openType = @"Unclassified"; 284| 0| if (self.isOpenedFromAppLink) { 285| 0| openType = @"AppLink"; 286| 0| } 287| 0| return (self.sourceApplication 288| 0| ? [NSString stringWithFormat:@"%@(%@)", openType, self.sourceApplication] 289| 0| : openType); 290| 0|} 291| | 292| |- (void)resetSourceApplication 293| 0|{ 294| 0| self.sourceApplication = nil; 295| 0| self.isOpenedFromAppLink = NO; 296| 0|} 297| | 298| |- (void)registerAutoResetSourceApplication 299| 0|{ 300| 0| [[NSNotificationCenter defaultCenter] addObserver:self 301| 0| selector:@selector(resetSourceApplication) 302| 0| name:UIApplicationDidEnterBackgroundNotification 303| 0| object:nil]; 304| 0|} 305| | 306| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKTimeSpentRecordingFactory.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKTimeSpentRecordingFactory.h" 20| | 21| |#import "FBSDKEventLogging.h" 22| |#import "FBSDKServerConfigurationProviding.h" 23| |#import "FBSDKTimeSpentData.h" 24| |#import "FBSDKTimeSpentData+SourceApplicationTracking.h" 25| |#import "FBSDKTimeSpentData+TimeSpentRecording.h" 26| | 27| |NS_ASSUME_NONNULL_BEGIN 28| | 29| |@interface FBSDKTimeSpentRecordingFactory () 30| | 31| |@property (nonnull, nonatomic, readonly) Class serverConfigurationProvider; 32| |@property (nonnull, nonatomic, readonly) id eventLogger; 33| | 34| |@end 35| | 36| |@implementation FBSDKTimeSpentRecordingFactory 37| | 38| |- (instancetype)initWithEventLogger:(id)eventLogger 39| | serverConfigurationProvider:(Class)serverConfigurationProvider 40| 0|{ 41| 0| if ((self = [super init])) { 42| 0| _eventLogger = eventLogger; 43| 0| _serverConfigurationProvider = serverConfigurationProvider; 44| 0| } 45| 0| return self; 46| 0|} 47| | 48| |- (id)createTimeSpentRecorder 49| 0|{ 50| 0| return [[FBSDKTimeSpentData alloc] initWithEventLogger:self.eventLogger 51| 0| serverConfigurationProvider:self.serverConfigurationProvider]; 52| 0|} 53| | 54| |@end 55| | 56| |NS_ASSUME_NONNULL_END /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/Integrity/FBSDKIntegrityManager.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKIntegrityManager.h" 24| | 25| | #import "FBSDKCoreKitBasicsImport.h" 26| | #import "FBSDKGateKeeperManaging.h" 27| | #import "FBSDKIntegrityProcessing.h" 28| | 29| |@interface FBSDKIntegrityManager () 30| | 31| |@property (nonatomic) Class gateKeeperManager; 32| |@property (nonatomic, weak) id integrityProcessor; 33| |@property (nonatomic) BOOL isIntegrityEnabled; 34| |@property (nonatomic) BOOL isSampleEnabled; 35| | 36| |@end 37| | 38| |@implementation FBSDKIntegrityManager 39| | 40| |- (instancetype)initWithGateKeeperManager:(Class)gateKeeperManager 41| | integrityProcessor:(id)integrityProcessor 42| 0|{ 43| 0| if ((self = [super init])) { 44| 0| _gateKeeperManager = gateKeeperManager; 45| 0| _integrityProcessor = integrityProcessor; 46| 0| } 47| 0| return self; 48| 0|} 49| | 50| |- (void)enable 51| 0|{ 52| 0| self.isIntegrityEnabled = YES; 53| 0| self.isSampleEnabled = [self.gateKeeperManager boolForKey:@"FBSDKFeatureIntegritySample" defaultValue:false]; 54| 0|} 55| | 56| |// Unused parameter eventName is required for conformance to shared protocol for processing app events. 57| |- (nullable NSDictionary *)processParameters:(nullable NSDictionary *)parameters 58| | eventName:(NSString *)eventName 59| 0|{ 60| 0| if (!self.isIntegrityEnabled || parameters.count == 0) { 61| 0| return parameters; 62| 0| } 63| 0| NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:parameters]; 64| 0| NSMutableDictionary *restrictiveParams = [NSMutableDictionary dictionary]; 65| | 66| 0| for (NSString *key in [parameters keyEnumerator]) { 67| 0| NSString *valueString = [FBSDKTypeUtility coercedToStringValue:parameters[key]]; 68| 0| BOOL shouldFilter = [self.integrityProcessor processIntegrity:key] || [self.integrityProcessor processIntegrity:valueString]; 69| 0| if (shouldFilter) { 70| 0| [FBSDKTypeUtility dictionary:restrictiveParams setObject:self.isSampleEnabled ? valueString : @"" forKey:key]; 71| 0| [params removeObjectForKey:key]; 72| 0| } 73| 0| } 74| 0| if ([restrictiveParams count] > 0) { 75| 0| NSString *restrictiveParamsJSONString = [FBSDKBasicUtility JSONStringForObject:restrictiveParams 76| 0| error:NULL 77| 0| invalidObjectHandler:NULL]; 78| 0| [FBSDKTypeUtility dictionary:params setObject:restrictiveParamsJSONString forKey:@"_onDeviceParams"]; 79| 0| } 80| 0| return [params copy]; 81| 0|} 82| | 83| |@end 84| | 85| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/Integrity/FBSDKRestrictiveDataFilterManager.m: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "FBSDKRestrictiveDataFilterManager.h" 20| | 21| |#import "FBSDKCoreKitBasicsImport.h" 22| |#import "FBSDKServerConfigurationManager.h" 23| |#import "FBSDKServerConfigurationProviding.h" 24| | 25| |@interface FBSDKRestrictiveEventFilter : NSObject 26| | 27| |@property (nonatomic, readonly, copy) NSString *eventName; 28| |@property (nonatomic, readonly, copy) NSDictionary *restrictiveParams; 29| | 30| |- (instancetype)init NS_UNAVAILABLE; 31| |+ (instancetype)new NS_UNAVAILABLE; 32| | 33| |- (instancetype)initWithEventName:(NSString *)eventName 34| | restrictiveParams:(NSDictionary *)restrictiveParams; 35| | 36| |@end 37| | 38| |@implementation FBSDKRestrictiveEventFilter 39| | 40| |- (instancetype)initWithEventName:(NSString *)eventName 41| | restrictiveParams:(NSDictionary *)restrictiveParams 42| 0|{ 43| 0| self = [super init]; 44| 0| if (self) { 45| 0| _eventName = [eventName copy]; 46| 0| _restrictiveParams = [restrictiveParams copy]; 47| 0| } 48| | 49| 0| return self; 50| 0|} 51| | 52| |@end 53| | 54| |static FBSDKRestrictiveDataFilterManager *_instance; 55| | 56| |@interface FBSDKRestrictiveDataFilterManager () 57| | 58| |@property BOOL isRestrictiveEventFilterEnabled; 59| |@property (nonatomic) NSMutableArray *params; 60| |@property (nonatomic) NSMutableSet *restrictedEvents; 61| |@property (nonatomic) Class serverConfigurationProvider; 62| | 63| |@end 64| | 65| |@implementation FBSDKRestrictiveDataFilterManager 66| | 67| |- (instancetype)initWithServerConfigurationProvider:(Class)serverConfigurationProvider 68| 0|{ 69| 0| self.serverConfigurationProvider = serverConfigurationProvider; 70| 0| return self; 71| 0|} 72| | 73| |- (void)enable 74| 0|{ 75| 0| @synchronized(self) { 76| 0| @try { 77| 0| if (!self.isRestrictiveEventFilterEnabled) { 78| 0| NSDictionary *restrictiveParams = [self.serverConfigurationProvider cachedServerConfiguration].restrictiveParams; 79| 0| if (restrictiveParams) { 80| 0| [self updateFilters:restrictiveParams]; 81| 0| self.isRestrictiveEventFilterEnabled = YES; 82| 0| } 83| 0| } 84| 0| } @catch (NSException *exception) {} 85| 0| } 86| 0|} 87| | 88| |- (NSDictionary *)processParameters:(NSDictionary *)parameters 89| | eventName:(NSString *)eventName 90| 0|{ 91| 0| if (!self.isRestrictiveEventFilterEnabled) { 92| 0| return parameters; 93| 0| } 94| 0| if (parameters) { 95| 0| @try { 96| 0| NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:parameters]; 97| 0| NSMutableDictionary *restrictedParams = [NSMutableDictionary dictionary]; 98| | 99| 0| for (NSString *key in [parameters keyEnumerator]) { 100| 0| NSString *type = [self getMatchedDataTypeWithEventName:eventName paramKey:key]; 101| 0| if (type) { 102| 0| [FBSDKTypeUtility dictionary:restrictedParams setObject:type forKey:key]; 103| 0| [params removeObjectForKey:key]; 104| 0| } 105| 0| } 106| | 107| 0| if ([[restrictedParams allKeys] count] > 0) { 108| 0| NSString *restrictedParamsJSONString = [FBSDKBasicUtility JSONStringForObject:restrictedParams 109| 0| error:NULL 110| 0| invalidObjectHandler:NULL]; 111| 0| [FBSDKTypeUtility dictionary:params setObject:restrictedParamsJSONString forKey:@"_restrictedParams"]; 112| 0| } 113| | 114| 0| return [params copy]; 115| 0| } @catch (NSException *exception) { 116| 0| return parameters; 117| 0| } 118| 0| } 119| | 120| 0| return nil; 121| 0|} 122| | 123| |- (void)processEvents:(NSMutableArray *> *)events 124| 0|{ 125| 0| @try { 126| 0| if (!self.isRestrictiveEventFilterEnabled) { 127| 0| return; 128| 0| } 129| | 130| 0| static NSString *const REPLACEMENT_STRING = @"_removed_"; 131| | 132| 0| for (NSDictionary *> *event in events) { 133| 0| if ([self isRestrictedEvent:event[@"event"][@"_eventName"]]) { 134| 0| [FBSDKTypeUtility dictionary:event[@"event"] setObject:REPLACEMENT_STRING forKey:@"_eventName"]; 135| 0| } 136| 0| } 137| 0| } @catch (NSException *exception) {} 138| 0|} 139| | 140| |#pragma mark - Private Methods 141| | 142| |- (BOOL)isRestrictedEvent:(NSString *)eventName 143| 0|{ 144| 0| @synchronized(self) { 145| 0| return [self.restrictedEvents containsObject:eventName]; 146| 0| } 147| 0|} 148| | 149| |- (nullable NSString *)getMatchedDataTypeWithEventName:(NSString *)eventName 150| | paramKey:(NSString *)paramKey 151| 0|{ 152| | // match by params in custom events with event name 153| 0| for (FBSDKRestrictiveEventFilter *filter in self.params) { 154| 0| if ([filter.eventName isEqualToString:eventName]) { 155| 0| NSString *type = [FBSDKTypeUtility coercedToStringValue:filter.restrictiveParams[paramKey]]; 156| 0| if (type) { 157| 0| return type; 158| 0| } 159| 0| } 160| 0| } 161| 0| return nil; 162| 0|} 163| | 164| |- (void)updateFilters:(nullable NSDictionary *)restrictiveParams 165| 0|{ 166| 0| static NSString *const RESTRICTIVE_PARAM_KEY = @"restrictive_param"; 167| 0| static NSString *const PROCESS_EVENT_NAME_KEY = @"process_event_name"; 168| | 169| 0| restrictiveParams = [FBSDKTypeUtility dictionaryValue:restrictiveParams]; 170| 0| if (restrictiveParams.count > 0) { 171| 0| @synchronized(self) { 172| 0| [self.params removeAllObjects]; 173| 0| [self.restrictedEvents removeAllObjects]; 174| 0| NSMutableArray *eventFilterArray = [NSMutableArray array]; 175| 0| NSMutableSet *restrictedEventSet = [NSMutableSet set]; 176| 0| for (NSString *eventName in restrictiveParams.allKeys) { 177| 0| NSDictionary *eventInfo = restrictiveParams[eventName]; 178| 0| if (!eventInfo) { 179| 0| continue; 180| 0| } 181| 0| if (eventInfo[RESTRICTIVE_PARAM_KEY]) { 182| 0| FBSDKRestrictiveEventFilter *restrictiveEventFilter = [[FBSDKRestrictiveEventFilter alloc] initWithEventName:eventName 183| 0| restrictiveParams:eventInfo[RESTRICTIVE_PARAM_KEY]]; 184| 0| [FBSDKTypeUtility array:eventFilterArray addObject:restrictiveEventFilter]; 185| 0| } 186| 0| if (restrictiveParams[eventName][PROCESS_EVENT_NAME_KEY]) { 187| 0| [restrictedEventSet addObject:eventName]; 188| 0| } 189| 0| } 190| 0| self.params = eventFilterArray; 191| 0| self.restrictedEvents = restrictedEventSet; 192| 0| } 193| 0| } 194| 0|} 195| | 196| |@end /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/ML/FBSDKMLMacros.h: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#ifndef FBSDKMLMacros_h 20| |#define FBSDKMLMacros_h 21| | 22| |// keys for ML 23| 0|#define MODEL_REQUEST_INTERVAL (60 * 60 * 24 * 3) 24| 0|#define MODEL_REQUEST_TIMESTAMP_KEY @"com.facebook.sdk:FBSDKModelRequestTimestamp" 25| | 26| 0|#define FBSDK_ML_MODEL_PATH @"models" 27| 0|#define MODEL_INFO_KEY @"com.facebook.sdk:FBSDKModelInfo" 28| 0|#define ASSET_URI_KEY @"asset_uri" 29| 0|#define RULES_URI_KEY @"rules_uri" 30| 0|#define THRESHOLDS_KEY @"thresholds" 31| 0|#define USE_CASE_KEY @"use_case" 32| 0|#define VERSION_ID_KEY @"version_id" 33| 0|#define MODEL_DATA_KEY @"data" 34| | 35| 0|#define MTMLKey @"MTML" 36| 0|#define MTMLTaskAppEventPredKey @"MTML_APP_EVENT_PRED" 37| 0|#define MTMLTaskIntegrityDetectKey @"MTML_INTEGRITY_DETECT" 38| | 39| |// keys for Suggested Event 40| |#define SUGGEST_EVENT_KEY @"SUGGEST_EVENT" 41| |#define DENSE_FEATURE_KEY @"DENSE_FEATURE" 42| 0|#define SUGGESTED_EVENT_OTHER @"other" 43| | 44| |#endif /* FBSDKMLMacros_h */ /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/ML/FBSDKModelManager.mm: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKModelManager.h" 24| | #import "FBSDKModelManager+IntegrityProcessing.h" 25| | 26| | #import "FBSDKAppEvents+Internal.h" 27| | #import "FBSDKAppEventsParameterProcessing.h" 28| | #import "FBSDKCoreKitBasicsImport.h" 29| | #import "FBSDKDataPersisting.h" 30| | #import "FBSDKFeatureChecking.h" 31| | #import "FBSDKFeatureExtractor.h" 32| | #import "FBSDKGateKeeperManager.h" 33| | #import "FBSDKGraphRequestProviding.h" 34| | #import "FBSDKIntegrityManager+AppEventsParametersProcessing.h" 35| | #import "FBSDKMLMacros.h" 36| | #import "FBSDKModelParser.h" 37| | #import "FBSDKModelRuntime.hpp" 38| | #import "FBSDKModelUtility.h" 39| | #import "FBSDKSettingsProtocol.h" 40| | #import "FBSDKSuggestedEventsIndexer.h" 41| | 42| |static NSString *const INTEGRITY_NONE = @"none"; 43| |static NSString *const INTEGRITY_ADDRESS = @"address"; 44| |static NSString *const INTEGRITY_HEALTH = @"health"; 45| | 46| |extern FBSDKAppEventName FBSDKAppEventNameCompletedRegistration; 47| |extern FBSDKAppEventName FBSDKAppEventNameAddedToCart; 48| |extern FBSDKAppEventName FBSDKAppEventNamePurchased; 49| |extern FBSDKAppEventName FBSDKAppEventNameInitiatedCheckout; 50| | 51| |static NSString *_directoryPath; 52| |static NSMutableDictionary *_modelInfo; 53| |static std::unordered_map _MTMLWeights; 54| | 55| |NS_ASSUME_NONNULL_BEGIN 56| | 57| |@interface FBSDKModelManager () 58| | 59| |@property (nonatomic) id integrityParametersProcessor; 60| |@property (nullable, nonatomic) id featureChecker; 61| |@property (nullable, nonatomic) id graphRequestFactory; 62| |@property (nullable, nonatomic) id fileManager; 63| |@property (nullable, nonatomic) id store; 64| |@property (nullable, nonatomic) id settings; 65| |@property (nullable, nonatomic) Class dataExtractor; 66| | 67| |@end 68| | 69| |@implementation FBSDKModelManager 70| | 71| |typedef void (^FBSDKDownloadCompletionBlock)(void); 72| | 73| |// Transitional singleton introduced as a way to change the usage semantics 74| |// from a type-based interface to an instance-based interface. 75| |+ (instancetype)shared 76| 0|{ 77| 0| static dispatch_once_t nonce; 78| 0| static id instance; 79| 0| dispatch_once(&nonce, ^{ 80| 0| instance = [self new]; 81| 0| }); 82| 0| return instance; 83| 0|} 84| | 85| | #pragma mark - Dependency Management 86| | 87| |- (void)configureWithFeatureChecker:(id)featureChecker 88| | graphRequestFactory:(id)graphRequestFactory 89| | fileManager:(id)fileManager 90| | store:(id)store 91| | settings:(id)settings 92| | dataExtractor:(Class)dataExtractor 93| 0|{ 94| 0| _featureChecker = featureChecker; 95| 0| _graphRequestFactory = graphRequestFactory; 96| 0| _fileManager = fileManager; 97| 0| _store = store; 98| 0| _settings = settings; 99| 0| _dataExtractor = dataExtractor; 100| 0|} 101| | 102| | #pragma mark - Public methods 103| | 104| |static dispatch_once_t enableNonce; 105| | 106| |- (void)enable 107| 0|{ 108| 0| @try { 109| 0| dispatch_once(&enableNonce, ^{ 110| 0| NSString *languageCode = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]; 111| | // If the languageCode could not be fetched successfully, it's regarded as "en" by default. 112| 0| if (languageCode && ![languageCode isEqualToString:@"en"]) { 113| 0| return; 114| 0| } 115| | 116| 0| _directoryPath = [NSTemporaryDirectory() stringByAppendingPathComponent:FBSDK_ML_MODEL_PATH]; 117| 0| if (![self.fileManager fileExistsAtPath:_directoryPath]) { 118| 0| [self.fileManager createDirectoryAtPath:_directoryPath withIntermediateDirectories:YES attributes:NULL error:NULL]; 119| 0| } 120| 0| _modelInfo = [self.store objectForKey:MODEL_INFO_KEY]; 121| 0| NSDate *timestamp = [self.store objectForKey:MODEL_REQUEST_TIMESTAMP_KEY]; 122| 0| if ([_modelInfo count] == 0 || ![self.featureChecker isEnabled:FBSDKFeatureModelRequest] || ![self.class isValidTimestamp:timestamp]) { 123| | // fetch api 124| 0| NSString *graphPath = [NSString stringWithFormat:@"%@/model_asset", self.settings.appID]; 125| 0| id request = [self.graphRequestFactory createGraphRequestWithGraphPath:graphPath]; 126| 0| __weak FBSDKModelManager *weakSelf = self; 127| 0| [request startWithCompletion:^(id connection, id result, NSError *error) { 128| 0| if (!error) { 129| 0| NSDictionary *resultDictionary = [FBSDKTypeUtility dictionaryValue:result]; 130| 0| NSArray *rawModels = resultDictionary[MODEL_DATA_KEY]; 131| 0| if ([rawModels isKindOfClass:NSArray.class]) { 132| 0| NSDictionary *modelInfo = [weakSelf.class convertToDictionary:rawModels]; 133| 0| if (modelInfo) { 134| 0| _modelInfo = [modelInfo mutableCopy]; 135| 0| [weakSelf.class processMTML]; 136| | // update cache for model info and timestamp 137| 0| [weakSelf.store setObject:_modelInfo forKey:MODEL_INFO_KEY]; 138| 0| [weakSelf.store setObject:[NSDate date] forKey:MODEL_REQUEST_TIMESTAMP_KEY]; 139| 0| } 140| 0| } 141| 0| } 142| 0| [self checkFeaturesAndExecuteForMTML]; 143| 0| }]; 144| 0| } else { 145| 0| [self checkFeaturesAndExecuteForMTML]; 146| 0| } 147| 0| }); 148| 0| } @catch (NSException *exception) { 149| 0| NSLog(@"Fail to enable model manager, exception reason: %@", exception.reason); 150| 0| } 151| 0|} 152| | 153| |- (nullable NSDictionary *)getRulesForKey:(NSString *)useCase 154| 0|{ 155| 0| @try { 156| 0| NSDictionary *model = [FBSDKTypeUtility dictionary:_modelInfo objectForKey:useCase ofType:NSObject.class]; 157| 0| if (model && model[VERSION_ID_KEY]) { 158| 0| NSString *filePath = [_directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%@.rules", useCase, model[VERSION_ID_KEY]]]; 159| 0| if (filePath) { 160| 0| NSData *rulesData = [self.dataExtractor dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:nil]; 161| 0| NSDictionary *rules = [FBSDKTypeUtility JSONObjectWithData:rulesData options:0 error:nil]; 162| 0| return rules; 163| 0| } 164| 0| } 165| 0| } @catch (NSException *exception) { 166| 0| NSLog(@"Fail to get rules for usecase %@ from ml model, exception reason: %@", useCase, exception.reason); 167| 0| } 168| 0| return nil; 169| 0|} 170| | 171| |- (nullable NSData *)getWeightsForKey:(NSString *)useCase 172| 0|{ 173| 0| if (!_modelInfo || !_directoryPath) { 174| 0| return nil; 175| 0| } 176| 0| if ([useCase hasPrefix:MTMLKey]) { 177| 0| useCase = MTMLKey; 178| 0| } 179| 0| NSDictionary *model = [FBSDKTypeUtility dictionary:_modelInfo objectForKey:useCase ofType:NSObject.class]; 180| 0| if (model && model[VERSION_ID_KEY]) { 181| 0| NSString *path = [_directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%@.weights", useCase, model[VERSION_ID_KEY]]]; 182| 0| if (!path) { 183| 0| return nil; 184| 0| } 185| 0| return [NSData dataWithContentsOfFile:path 186| 0| options:NSDataReadingMappedIfSafe 187| 0| error:nil]; 188| 0| } 189| 0| return nil; 190| 0|} 191| | 192| |- (nullable NSArray *)getThresholdsForKey:(NSString *)useCase 193| 0|{ 194| 0| if (!_modelInfo) { 195| 0| return nil; 196| 0| } 197| 0| NSDictionary *modelInfo = _modelInfo[useCase]; 198| 0| if (!modelInfo) { 199| 0| return nil; 200| 0| } 201| 0| return modelInfo[THRESHOLDS_KEY]; 202| 0|} 203| | 204| | #pragma mark - Integrity Inferencer method 205| | 206| |// Used by the `integrityParametersProcessor` which holds a weak reference to this instance 207| |- (BOOL)processIntegrity:(nullable NSString *)param 208| 0|{ 209| 0| NSString *integrityType = INTEGRITY_NONE; 210| 0| @try { 211| 0| if (param.length == 0 || _MTMLWeights.size() == 0) { 212| 0| return false; 213| 0| } 214| 0| NSArray *integrityMapping = [self.class getIntegrityMapping]; 215| 0| NSString *text = [FBSDKModelUtility normalizedText:param]; 216| 0| const char *bytes = [text UTF8String]; 217| 0| if ((int)strlen(bytes) == 0) { 218| 0| return false; 219| 0| } 220| 0| NSArray *thresholds = [FBSDKModelManager.shared getThresholdsForKey:MTMLTaskIntegrityDetectKey]; 221| 0| if (thresholds.count != integrityMapping.count) { 222| 0| return false; 223| 0| } 224| 0| const fbsdk::MTensor &res = fbsdk::predictOnMTML("integrity_detect", bytes, _MTMLWeights, nullptr); 225| 0| const float *res_data = res.data(); 226| 0| for (int i = 0; i < thresholds.count; i++) { 227| 0| if ((float)res_data[i] >= (float)[[FBSDKTypeUtility array:thresholds objectAtIndex:i] floatValue]) { 228| 0| integrityType = [FBSDKTypeUtility array:integrityMapping objectAtIndex:i]; 229| 0| break; 230| 0| } 231| 0| } 232| 0| } @catch (NSException *exception) { 233| 0| NSLog(@"Fail to process parameter for integrity usecase, exception reason: %@", exception.reason); 234| 0| } 235| 0| return ![integrityType isEqualToString:INTEGRITY_NONE]; 236| 0|} 237| | 238| | #pragma mark - SuggestedEvents Inferencer method 239| | 240| |- (NSString *)processSuggestedEvents:(NSString *)textFeature denseData:(nullable float *)denseData 241| 0|{ 242| 0| @try { 243| 0| NSArray *eventMapping = [FBSDKModelManager getSuggestedEventsMapping]; 244| 0| if (textFeature.length == 0 || _MTMLWeights.size() == 0 || !denseData) { 245| 0| return SUGGESTED_EVENT_OTHER; 246| 0| } 247| 0| const char *bytes = [textFeature UTF8String]; 248| 0| if ((int)strlen(bytes) == 0) { 249| 0| return SUGGESTED_EVENT_OTHER; 250| 0| } 251| | 252| 0| NSArray *thresholds = [FBSDKModelManager.shared getThresholdsForKey:MTMLTaskAppEventPredKey]; 253| 0| if (thresholds.count != eventMapping.count) { 254| 0| return SUGGESTED_EVENT_OTHER; 255| 0| } 256| | 257| 0| const fbsdk::MTensor &res = fbsdk::predictOnMTML("app_event_pred", bytes, _MTMLWeights, denseData); 258| 0| const float *res_data = res.data(); 259| 0| for (int i = 0; i < thresholds.count; i++) { 260| 0| if ((float)res_data[i] >= (float)[[FBSDKTypeUtility array:thresholds objectAtIndex:i] floatValue]) { 261| 0| return [FBSDKTypeUtility array:eventMapping objectAtIndex:i]; 262| 0| } 263| 0| } 264| 0| } @catch (NSException *exception) { 265| 0| NSLog(@"Fail to process suggested events, exception reason: %@", exception.reason); 266| 0| } 267| 0| return SUGGESTED_EVENT_OTHER; 268| 0|} 269| | 270| | #pragma mark - Private methods 271| | 272| |+ (BOOL)isValidTimestamp:(NSDate *)timestamp 273| 0|{ 274| 0| if (!timestamp) { 275| 0| return NO; 276| 0| } 277| 0| return ([[NSDate date] timeIntervalSinceDate:timestamp] < MODEL_REQUEST_INTERVAL); 278| 0|} 279| | 280| |+ (void)processMTML 281| 0|{ 282| 0| NSString *mtmlAssetUri = nil; 283| 0| long mtmlVersionId = 0; 284| 0| for (NSString *useCase in _modelInfo) { 285| 0| if (![useCase isKindOfClass:NSString.class]) { 286| 0| continue; 287| 0| } 288| 0| NSDictionary *model = _modelInfo[useCase]; 289| 0| if ([useCase hasPrefix:MTMLKey]) { 290| 0| if (![model[ASSET_URI_KEY] isKindOfClass:NSString.class] 291| 0| || ![model[VERSION_ID_KEY] isKindOfClass:NSNumber.class]) { 292| 0| continue; 293| 0| } 294| 0| mtmlAssetUri = model[ASSET_URI_KEY]; 295| 0| long thisVersionId = [model[VERSION_ID_KEY] longValue]; 296| 0| mtmlVersionId = thisVersionId > mtmlVersionId ? thisVersionId : mtmlVersionId; 297| 0| } 298| 0| } 299| 0| if (mtmlAssetUri && mtmlVersionId > 0) { 300| 0| [FBSDKTypeUtility dictionary:_modelInfo setObject:@{ 301| 0| USE_CASE_KEY : MTMLKey, 302| 0| ASSET_URI_KEY : mtmlAssetUri, 303| 0| VERSION_ID_KEY : [NSNumber numberWithLong:mtmlVersionId], 304| 0| } forKey:MTMLKey]; 305| 0| } 306| 0|} 307| | 308| |- (void)checkFeaturesAndExecuteForMTML 309| 0|{ 310| 0| [self getModelAndRules:MTMLKey onSuccess:^() { 311| 0| NSData *data = [FBSDKModelManager.shared getWeightsForKey:MTMLKey]; 312| 0| _MTMLWeights = [FBSDKModelParser parseWeightsData:data]; 313| 0| if (![FBSDKModelParser validateWeights:_MTMLWeights forKey:MTMLKey]) { 314| 0| return; 315| 0| } 316| | 317| 0| if ([self.featureChecker isEnabled:FBSDKFeatureSuggestedEvents]) { 318| 0| [self getModelAndRules:MTMLTaskAppEventPredKey onSuccess:^() { 319| 0| [FBSDKFeatureExtractor loadRulesForKey:MTMLTaskAppEventPredKey]; 320| 0| [FBSDKSuggestedEventsIndexer.shared enable]; 321| 0| }]; 322| 0| } 323| | 324| 0| if ([self.featureChecker isEnabled:FBSDKFeatureIntelligentIntegrity]) { 325| 0| [self getModelAndRules:MTMLTaskIntegrityDetectKey onSuccess:^() { 326| 0| [self setIntegrityParametersProcessor:[[FBSDKIntegrityManager alloc] initWithGateKeeperManager:FBSDKGateKeeperManager.class 327| 0| integrityProcessor:self]]; 328| 0| [[self integrityParametersProcessor] enable]; 329| 0| }]; 330| 0| } 331| 0| }]; 332| 0|} 333| | 334| |- (void)getModelAndRules:(NSString *)useCaseKey 335| | onSuccess:(FBSDKDownloadCompletionBlock)handler 336| 0|{ 337| 0| dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 338| 0| dispatch_group_t group = dispatch_group_create(); 339| | 340| 0| NSDictionary *model = [FBSDKTypeUtility dictionary:_modelInfo objectForKey:useCaseKey ofType:NSObject.class]; 341| 0| if (!model || !_directoryPath) { 342| 0| return; 343| 0| } 344| | 345| 0| NSFileManager *fileManager = [NSFileManager defaultManager]; 346| | // download model asset only if not exist before 347| 0| NSString *assetUrlString = [FBSDKTypeUtility dictionary:model objectForKey:ASSET_URI_KEY ofType:NSObject.class]; 348| 0| NSString *assetFilePath; 349| 0| if (assetUrlString.length > 0) { 350| 0| [self clearCacheForModel:model suffix:@".weights"]; 351| 0| NSString *fileName = useCaseKey; 352| 0| if ([useCaseKey hasPrefix:MTMLKey]) { 353| | // all mtml tasks share the same weights file 354| 0| fileName = MTMLKey; 355| 0| } 356| 0| assetFilePath = [_directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%@.weights", fileName, model[VERSION_ID_KEY]]]; 357| 0| [self download:assetUrlString filePath:assetFilePath queue:queue group:group]; 358| 0| } 359| | 360| | // download rules 361| 0| NSString *rulesUrlString = [FBSDKTypeUtility dictionary:model objectForKey:RULES_URI_KEY ofType:NSObject.class]; 362| 0| NSString *rulesFilePath = nil; 363| | // rules are optional and rulesUrlString may be empty 364| 0| if (rulesUrlString.length > 0) { 365| 0| [self clearCacheForModel:model suffix:@".rules"]; 366| 0| rulesFilePath = [_directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%@.rules", useCaseKey, model[VERSION_ID_KEY]]]; 367| 0| [self download:rulesUrlString filePath:rulesFilePath queue:queue group:group]; 368| 0| } 369| 0| dispatch_group_notify(group, 370| 0| dispatch_get_main_queue(), ^{ 371| 0| if (handler) { 372| 0| if ([fileManager fileExistsAtPath:assetFilePath] && (!rulesFilePath || [fileManager fileExistsAtPath:rulesFilePath])) { 373| 0| handler(); 374| 0| } 375| 0| } 376| 0| }); 377| 0|} 378| | 379| |- (void)clearCacheForModel:(NSDictionary *)model 380| | suffix:(NSString *)suffix 381| 0|{ 382| 0| NSFileManager *fileManager = [NSFileManager defaultManager]; 383| 0| NSString *useCase = model[USE_CASE_KEY]; 384| 0| NSString *version = model[VERSION_ID_KEY]; 385| 0| NSArray *files = [fileManager contentsOfDirectoryAtPath:_directoryPath error:nil]; 386| 0| NSString *prefixWithVersion = [NSString stringWithFormat:@"%@_%@", useCase, version]; 387| 0| for (NSString *file in files) { 388| 0| if ([file hasSuffix:suffix] && [file hasPrefix:useCase] && ![file hasPrefix:prefixWithVersion]) { 389| 0| [fileManager removeItemAtPath:[_directoryPath stringByAppendingPathComponent:file] error:nil]; 390| 0| } 391| 0| } 392| 0|} 393| | 394| |- (void)download:(NSString *)urlString 395| | filePath:(NSString *)filePath 396| | queue:(dispatch_queue_t)queue 397| | group:(dispatch_group_t)group 398| 0|{ 399| 0| if (!filePath || [[NSFileManager defaultManager] fileExistsAtPath:filePath]) { 400| 0| return; 401| 0| } 402| 0| dispatch_group_async(group, 403| 0| queue, ^{ 404| 0| NSURL *url = [NSURL URLWithString:urlString]; 405| 0| NSData *urlData = [NSData dataWithContentsOfURL:url]; 406| 0| if (urlData) { 407| 0| [urlData writeToFile:filePath atomically:YES]; 408| 0| } 409| 0| }); 410| 0|} 411| | 412| |+ (nullable NSMutableDictionary *)convertToDictionary:(NSArray *> *)models 413| 0|{ 414| 0| if ([models count] == 0) { 415| 0| return nil; 416| 0| } 417| 0| NSMutableDictionary *modelInfo = [NSMutableDictionary dictionary]; 418| 0| for (NSDictionary *model in models) { 419| 0| if ([model isKindOfClass:NSDictionary.class] 420| 0| && [model[USE_CASE_KEY] isKindOfClass:NSString.class] 421| 0| && [self isPlistFormatDictionary:model]) { 422| 0| [modelInfo addEntriesFromDictionary:@{model[USE_CASE_KEY] : model}]; 423| 0| } 424| 0| } 425| | 426| 0| if (modelInfo.allKeys.count > 0) { 427| 0| return modelInfo; 428| 0| } else { 429| 0| return nil; 430| 0| } 431| 0|} 432| | 433| |+ (BOOL)isPlistFormatDictionary:(NSDictionary *)dictionary 434| 0|{ 435| 0| __block BOOL isPlistFormat = YES; 436| 0| [dictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL *_Nonnull stop) { 437| 0| if (![key isKindOfClass:NSString.class]) { 438| 0| isPlistFormat = NO; 439| 0| *stop = YES; 440| 0| } 441| 0| if (![obj isKindOfClass:NSArray.class] 442| 0| && ![obj isKindOfClass:NSDictionary.class] 443| 0| && ![obj isKindOfClass:NSData.class] 444| 0| && ![obj isKindOfClass:NSDate.class] 445| 0| && ![obj isKindOfClass:NSNumber.class] 446| 0| && ![obj isKindOfClass:NSString.class]) { 447| 0| isPlistFormat = NO; 448| 0| *stop = YES; 449| 0| } 450| 0| }]; 451| | 452| 0| return isPlistFormat; 453| 0|} 454| | 455| |+ (NSArray *)getIntegrityMapping 456| 0|{ 457| 0| return @[INTEGRITY_NONE, INTEGRITY_ADDRESS, INTEGRITY_HEALTH]; 458| 0|} 459| | 460| |+ (NSArray *)getSuggestedEventsMapping 461| 0|{ 462| 0| return 463| 0| @[SUGGESTED_EVENT_OTHER, 464| 0| FBSDKAppEventNameCompletedRegistration, 465| 0| FBSDKAppEventNameAddedToCart, 466| 0| FBSDKAppEventNamePurchased, 467| 0| FBSDKAppEventNameInitiatedCheckout]; 468| 0|} 469| | 470| | #if DEBUG && FBSDKTEST 471| | 472| |+ (void)reset 473| 0|{ 474| 0| if (enableNonce) { 475| 0| enableNonce = 0; 476| 0| } 477| 0| _directoryPath = nil; 478| 0| _modelInfo = nil; 479| | 480| 0| self.shared.featureChecker = nil; 481| 0| self.shared.graphRequestFactory = nil; 482| 0| self.shared.fileManager = nil; 483| 0| self.shared.store = nil; 484| 0| self.shared.settings = nil; 485| 0| self.shared.dataExtractor = nil; 486| 0|} 487| | 488| |+ (void)setModelInfo:(NSDictionary *)modelInfo 489| 0|{ 490| 0| _modelInfo = [NSMutableDictionary dictionaryWithDictionary:modelInfo]; 491| 0|} 492| | 493| |+ (void)setDirectoryPath:(NSString *)directoryPath 494| 0|{ 495| 0| _directoryPath = directoryPath; 496| 0|} 497| | 498| | #endif 499| | 500| |@end 501| | 502| |NS_ASSUME_NONNULL_END 503| | 504| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/ML/FBSDKModelParser.mm: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #import "FBSDKModelParser.h" 24| | 25| | #import "FBSDKCoreKitBasicsImport.h" 26| | #import "FBSDKMLMacros.h" 27| | 28| |NS_ASSUME_NONNULL_BEGIN 29| | 30| |@implementation FBSDKModelParser 31| | 32| |+ (std::unordered_map)parseWeightsData:(NSData *)weightsData 33| 0|{ 34| 0| std::unordered_map weights; 35| 0| if (!weightsData) { 36| 0| return weights; 37| 0| } 38| | 39| 0| const void *data = weightsData.bytes; 40| 0| NSUInteger totalLength = weightsData.length; 41| | 42| 0| if (totalLength < 4) { 43| | // Make sure data length is valid 44| 0| return weights; 45| 0| } 46| 0| try { 47| 0| int length; 48| 0| memcpy(&length, data, 4); 49| 0| if (length + 4 > totalLength) { 50| | // Make sure data length is valid 51| 0| return weights; 52| 0| } 53| | 54| 0| char *json = (char *)data + 4; 55| 0| NSDictionary *info = [FBSDKTypeUtility JSONObjectWithData:[NSData dataWithBytes:json length:length] 56| 0| options:0 57| 0| error:nil]; 58| 0| NSArray *keys = [[info allKeys] sortedArrayUsingComparator:^NSComparisonResult (NSString *key1, NSString *key2) { 59| 0| return [key1 compare:key2]; 60| 0| }]; 61| | 62| 0| int totalFloats = 0; 63| 0| float *floats = (float *)(json + length); 64| 0| NSDictionary *keysMapping = [self getKeysMapping]; 65| 0| for (NSString *key in keys) { 66| 0| NSString *finalKey = key; 67| 0| NSString *mapping = [FBSDKTypeUtility dictionary:keysMapping objectForKey:key ofType:NSObject.class]; 68| 0| if (mapping) { 69| 0| finalKey = mapping; 70| 0| } 71| 0| std::string s_name([finalKey UTF8String]); 72| | 73| 0| std::vector v_shape; 74| 0| NSArray *shape = [FBSDKTypeUtility dictionary:info objectForKey:key ofType:NSObject.class]; 75| 0| int count = 1; 76| 0| for (NSNumber *_s in shape) { 77| 0| int i = [_s intValue]; 78| 0| v_shape.push_back(i); 79| 0| count *= i; 80| 0| } 81| | 82| 0| totalFloats += count; 83| | 84| 0| if ((4 + length + totalFloats * 4) > totalLength) { 85| | // Make sure data length is valid 86| 0| break; 87| 0| } 88| 0| fbsdk::MTensor tensor(v_shape); 89| 0| memcpy(tensor.mutable_data(), floats, sizeof(float) * count); 90| 0| floats += count; 91| | 92| 0| weights[s_name] = tensor; 93| 0| } 94| 0| } catch (const std::exception &e) {} 95| | 96| 0| return weights; 97| 0|} 98| | 99| |+ (bool)validateWeights:(std::unordered_map)weights forKey:(NSString *)key 100| 0|{ 101| 0| NSMutableDictionary *weightsInfoDict = [NSMutableDictionary new]; 102| 0| if ([key hasPrefix:MTMLKey]) { 103| 0| [weightsInfoDict addEntriesFromDictionary:[self getMTMLWeightsInfo]]; 104| 0| } 105| 0| return [self checkWeights:weights withExpectedInfo:weightsInfoDict]; 106| 0|} 107| | 108| | #pragma mark - private methods 109| | 110| |+ (NSDictionary *)getKeysMapping 111| 0|{ 112| 0| return @{ 113| 0| @"embedding.weight" : @"embed.weight", 114| 0| @"dense1.weight" : @"fc1.weight", 115| 0| @"dense2.weight" : @"fc2.weight", 116| 0| @"dense3.weight" : @"fc3.weight", 117| 0| @"dense1.bias" : @"fc1.bias", 118| 0| @"dense2.bias" : @"fc2.bias", 119| 0| @"dense3.bias" : @"fc3.bias" 120| 0| }; 121| 0|} 122| | 123| |+ (NSDictionary *)getMTMLWeightsInfo 124| 0|{ 125| 0| return @{ 126| 0| @"embed.weight" : @[@256, @32], 127| 0| @"convs.0.weight" : @[@32, @32, @3], 128| 0| @"convs.0.bias" : @[@32], 129| 0| @"convs.1.weight" : @[@64, @32, @3], 130| 0| @"convs.1.bias" : @[@64], 131| 0| @"convs.2.weight" : @[@64, @64, @3], 132| 0| @"convs.2.bias" : @[@64], 133| 0| @"fc1.weight" : @[@128, @190], 134| 0| @"fc1.bias" : @[@128], 135| 0| @"fc2.weight" : @[@64, @128], 136| 0| @"fc2.bias" : @[@64], 137| 0| @"integrity_detect.weight" : @[@3, @64], 138| 0| @"integrity_detect.bias" : @[@3], 139| 0| @"app_event_pred.weight" : @[@5, @64], 140| 0| @"app_event_pred.bias" : @[@5] 141| 0| }; 142| 0|} 143| | 144| |+ (bool)checkWeights:(std::unordered_map)weights 145| | withExpectedInfo:(NSDictionary *)weightsInfoDict 146| 0|{ 147| 0| if (weightsInfoDict.count != weights.size()) { 148| 0| return false; 149| 0| } 150| 0| try { 151| 0| for (NSString *key in weightsInfoDict) { 152| 0| if (weights.count(std::string([key UTF8String])) == 0) { 153| 0| return false; 154| 0| } 155| 0| fbsdk::MTensor tensor = weights[std::string([key UTF8String])]; 156| 0| const std::vector &actualSize = tensor.sizes(); 157| 0| NSArray *expectedSize = weightsInfoDict[key]; 158| 0| if (actualSize.size() != expectedSize.count) { 159| 0| return false; 160| 0| } 161| 0| for (int i = 0; i < expectedSize.count; i++) { 162| 0| if ((int)actualSize[i] != (int)[[FBSDKTypeUtility array:expectedSize objectAtIndex:i] intValue]) { 163| 0| return false; 164| 0| } 165| 0| } 166| 0| } 167| 0| } catch (const std::exception &e) { 168| 0| return false; 169| 0| } 170| 0| return true; 171| 0|} 172| | 173| |@end 174| | 175| |NS_ASSUME_NONNULL_END 176| | 177| |#endif /Users/runner/work/Parse-SDK-iOS-OSX/Parse-SDK-iOS-OSX/Carthage/Checkouts/facebook-ios-sdk/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/ML/FBSDKModelRuntime.hpp: 1| |// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 2| |// 3| |// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4| |// copy, modify, and distribute this software in source code or binary form for use 5| |// in connection with the web services and APIs provided by Facebook. 6| |// 7| |// As with any software that integrates with the Facebook platform, your use of 8| |// this software is subject to the Facebook Developer Principles and Policies 9| |// [http://developers.facebook.com/policy/]. This copyright notice shall be 10| |// included in all copies or substantial portions of the software. 11| |// 12| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14| |// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15| |// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16| |// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17| |// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18| | 19| |#import "TargetConditionals.h" 20| | 21| |#if !TARGET_OS_TV 22| | 23| | #include 24| | 25| | #include 26| | #include 27| | #include 28| | 29| | #import 30| | 31| | #include "FBSDKTensor.hpp" 32| | 33| 0| #define SEQ_LEN 128 34| 0| #define DENSE_FEATURE_LEN 30 35| | 36| |namespace fbsdk { 37| | static void relu(MTensor &x) 38| 0| { 39| 0| float min = 0; 40| 0| float max = FLT_MAX; 41| 0| float *x_data = x.mutable_data(); 42| 0| vDSP_vclip(x_data, 1, &min, &max, x_data, 1, x.count()); 43| 0| } 44| | 45| | static void flatten(MTensor &x, int start_dim) 46| 0| { 47| 0| const std::vector &shape = x.sizes(); 48| 0| std::vector new_shape; 49| 0| for (int i = 0; i < start_dim; i++) { 50| 0| new_shape.push_back(shape[i]); 51| 0| } 52| 0| int count = 1; 53| 0| for (int i = start_dim; i < shape.size(); i++) { 54| 0| count *= shape[i]; 55| 0| } 56| 0| new_shape.push_back(count); 57| 0| x.Reshape(new_shape); 58| 0| } 59| | 60| | static MTensor concatenate(std::vector &tensors) 61| 0| { 62| 0| int n_examples = tensors[0]->size(0); 63| 0| int count = 0; 64| 0| for (int i = 0; i < tensors.size(); i++) { 65| 0| count += tensors[i]->size(1); 66| 0| } 67| 0| MTensor y({n_examples, count}); 68| 0| float *y_data = y.mutable_data(); 69| 0| for (int i = 0; i < tensors.size(); i++) { 70| 0| int this_count = (int)tensors[i]->size(1); 71| 0| const float *this_data = tensors[i]->data(); 72| 0| for (int n = 0; n < n_examples; n++) { 73| 0| memcpy(y_data + n * count, this_data + n * this_count, this_count * sizeof(float)); 74| 0| } 75| 0| y_data += this_count; 76| 0| } 77| 0| return y; 78| 0| } 79| | 80| | static void softmax(MTensor &x) 81| 0| { 82| 0| int n_examples = x.size(0); 83| 0| int n_channel = x.size(1); 84| 0| float *x_data = x.mutable_data(); 85| 0| float max; 86| 0| float sum; 87| 0| for (int n = 0; n < n_examples; n++) { 88| 0| vDSP_maxv(x_data, 1, &max, n_channel); 89| 0| max = -max; 90| 0| vDSP_vsadd(x_data, 1, &max, x_data, 1, n_channel); 91| 0| vvexpf(x_data, x_data, &n_channel); 92| 0| vDSP_sve(x_data, 1, &sum, n_channel); 93| 0| vDSP_vsdiv(x_data, 1, &sum, x_data, 1, n_channel); 94| 0| x_data += n_channel; 95| 0| } 96| 0| } 97| | 98| | static std::vector vectorize(const char *texts, const int seq_length) 99| 0| { 100| 0| int str_len = (int)strlen(texts); 101| 0| std::vector vec(seq_length, 0); 102| 0| for (int i = 0; i < seq_length; i++) { 103| 0| if (i < str_len) { 104| 0| vec[i] = static_cast(texts[i]); 105| 0| } 106| 0| } 107| 0| return vec; 108| 0| } 109| | 110| | static MTensor embedding(const char *texts, const int seq_length, const MTensor &w) 111| 0| { 112| | // TODO: T65152708 support batch prediction 113| 0| const std::vector &vec = vectorize(texts, seq_length); 114| 0| int n_examples = 1; 115| 0| int embedding_size = w.size(1); 116| 0| MTensor y({n_examples, seq_length, embedding_size}); 117| 0| const float *w_data = w.data(); 118| 0| float *y_data = y.mutable_data(); 119| 0| for (int i = 0; i < n_examples; i++) { 120| 0| for (int j = 0; j < seq_length; j++) { 121| 0| memcpy(y_data, w_data + vec[i * seq_length + j] * embedding_size, (size_t)(embedding_size * sizeof(float))); 122| 0| y_data += embedding_size; 123| 0| } 124| 0| } 125| 0| return y; 126| 0| } 127| | 128| | /* 129| | x shape: n_examples, in_vector_size 130| | w shape: in_vector_size, out_vector_size 131| | b shape: out_vector_size 132| | return shape: n_examples, out_vector_size 133| | */ 134| | static MTensor dense(const MTensor &x, const MTensor &w, const MTensor &b) 135| 0| { 136| 0| int n_examples = x.size(0); 137| 0| int in_vector_size = x.size(1); 138| 0| int out_vector_size = w.size(1); 139| 0| MTensor y({n_examples, out_vector_size}); 140| 0| float *y_data = y.mutable_data(); 141| 0| const float *b_data = b.data(); 142| 0| vDSP_mmul(x.data(), 1, w.data(), 1, y_data, 1, n_examples, out_vector_size, in_vector_size); 143| 0| for (int i = 0; i < out_vector_size; i++) { 144| 0| vDSP_vsadd(y_data + i, out_vector_size, b_data + i, y_data + i, out_vector_size, n_examples); 145| 0| } 146| 0| return y; 147| 0| } 148| | 149| | /* 150| | x shape: n_examples, seq_len, input_size 151| | w shape: kernel_size, input_size, output_size 152| | return shape: n_examples, seq_len - kernel_size + 1, output_size 153| | */ 154| | static MTensor conv1D(const MTensor &x, const MTensor &w) 155| 0| { 156| 0| int n_examples = x.size(0); 157| 0| int seq_len = x.size(1); 158| 0| int input_size = x.size(2); 159| 0| int kernel_size = w.size(0); 160| 0| int output_size = w.size(2); 161| 0| MTensor y({n_examples, seq_len - kernel_size + 1, output_size}); 162| 0| MTensor temp_x({kernel_size, input_size}); 163| 0| MTensor temp_w({kernel_size, input_size}); 164| 0| const float *x_data = x.data(); 165| 0| const float *w_data = w.data(); 166| 0| float *y_data = y.mutable_data(); 167| 0| float *temp_x_data = temp_x.mutable_data(); 168| 0| float *temp_w_data = temp_w.mutable_data(); 169| 0| float sum; 170| 0| for (int n = 0; n < n_examples; n++) { 171| 0| for (int o = 0; o < output_size; o++) { 172| 0| for (int i = 0; i < seq_len - kernel_size + 1; i++) { 173| 0| for (int m = 0; m < kernel_size; m++) { 174| 0| for (int k = 0; k < input_size; k++) { 175| 0| temp_x_data[m * input_size + k] = x_data[n * (seq_len * input_size) + (m + i) * input_size + k]; 176| 0| temp_w_data[m * input_size + k] = w_data[(m * input_size + k) * output_size + o]; 177| 0| } 178| 0| } 179| 0| vDSP_dotpr(temp_x_data, 1, temp_w_data, 1, &sum, (size_t)(kernel_size * input_size)); 180| 0| y_data[(n * (output_size * (seq_len - kernel_size + 1)) + i * output_size + o)] = sum; 181| 0| } 182| 0| } 183| 0| } 184| 0| return y; 185| 0| } 186| | 187| | /* 188| | input shape: n_examples, len, n_channel 189| | return shape: n_examples, len - pool_size + 1, n_channel 190| | */ 191| | static MTensor maxPool1D(const MTensor &x, const int pool_size) 192| 0| { 193| 0| int n_examples = x.size(0); 194| 0| int input_len = x.size(1); 195| 0| int n_channel = x.size(2); 196| 0| int output_len = input_len - pool_size + 1; 197| 0| MTensor y({n_examples, output_len, n_channel}); 198| 0| const float *x_data = x.data(); 199| 0| float *y_data = y.mutable_data(); 200| 0| for (int n = 0; n < n_examples; n++) { 201| 0| for (int c = 0; c < n_channel; c++) { 202| 0| for (int i = 0; i < output_len; i++) { 203| 0| float this_max = -FLT_MAX; 204| 0| for (int r = i; r < i + pool_size; r++) { 205| 0| this_max = fmax(this_max, x_data[n * (n_channel * input_len) + r * n_channel + c]); 206| 0| } 207| 0| y_data[n * (n_channel * output_len) + i * n_channel + c] = this_max; 208| 0| } 209| 0| } 210| 0| } 211| 0| return y; 212| 0| } 213| | 214| | /* 215| | input shape: m, n 216| | return shape: n, m 217| | */ 218| | static MTensor transpose2D(const MTensor &x) 219| 0| { 220| 0| int m = x.size(0); 221| 0| int n = x.size(1); 222| 0| MTensor y({n, m}); 223| 0| float *y_data = y.mutable_data(); 224| 0| const float *x_data = x.data(); 225| 0| for (int i = 0; i < m; i++) { 226| 0| for (int j = 0; j < n; j++) { 227| 0| y_data[j * m + i] = x_data[i * n + j]; 228| 0| } 229| 0| } 230| 0| return y; 231| 0| } 232| | 233| | /* 234| | input shape: m, n, p 235| | return shape: p, n, m 236| | */ 237| | static MTensor transpose3D(const MTensor &x) 238| 0| { 239| 0| int m = x.size(0); 240| 0| int n = x.size(1); 241| 0| int p = x.size(2); 242| 0| MTensor y({p, n, m}); 243| 0| float *y_data = y.mutable_data(); 244| 0| const float *x_data = x.data(); 245| 0| for (int i = 0; i < m; i++) { 246| 0| for (int j = 0; j < n; j++) { 247| 0| for (int k = 0; k < p; k++) { 248| 0| y_data[k * m * n + j * m + i] = x_data[i * n * p + j * p + k]; 249| 0| } 250| 0| } 251| 0| } 252| 0| return y; 253| 0| } 254| | 255| | static void addmv(MTensor &y, const MTensor &x) 256| 0| { 257| 0| int m = y.size(0); 258| 0| int n = y.size(1); 259| 0| int p = y.size(2); 260| 0| float *y_data = y.mutable_data(); 261| 0| const float *x_data = x.data(); 262| 0| for (int i = 0; i < p; i++) { 263| 0| vDSP_vsadd(y_data + i, p, x_data + i, y_data + i, p, m * n); 264| 0| } 265| 0| } 266| | 267| | static MTensor getDenseTensor(const float *df) 268| 0| { 269| 0| MTensor dense_tensor({1, DENSE_FEATURE_LEN}); 270| 0| if (df) { 271| 0| memcpy(dense_tensor.mutable_data(), df, DENSE_FEATURE_LEN * sizeof(float)); 272| 0| } else { 273| 0| memset(dense_tensor.mutable_data(), 0, DENSE_FEATURE_LEN * sizeof(float)); 274| 0| } 275| 0| return dense_tensor; 276| 0| } 277| | 278| | static MTensor predictOnMTML(const std::string task, const char *texts, const std::unordered_map &weights, const float *df) 279| 0| { 280| 0| MTensor dense_tensor = getDenseTensor(df); 281| 0| std::string final_layer_weight_key = task + ".weight"; 282| 0| std::string final_layer_bias_key = task + ".bias"; 283| | 284| 0| const MTensor &embed_t = weights.at("embed.weight"); 285| 0| const MTensor &conv0w_t = weights.at("convs.0.weight"); 286| 0| const MTensor &conv1w_t = weights.at("convs.1.weight"); 287| 0| const MTensor &conv2w_t = weights.at("convs.2.weight"); 288| 0| const MTensor &conv0b_t = weights.at("convs.0.bias"); 289| 0| const MTensor &conv1b_t = weights.at("convs.1.bias"); 290| 0| const MTensor &conv2b_t = weights.at("convs.2.bias"); 291| 0| const MTensor &fc1w_t = weights.at("fc1.weight"); // (128, 190) 292| 0| const MTensor &fc1b_t = weights.at("fc1.bias"); // 128 293| 0| const MTensor &fc2w_t = weights.at("fc2.weight"); // (64, 128) 294| 0| const MTensor &fc2b_t = weights.at("fc2.bias"); // 64 295| 0| const MTensor &final_layer_weight_t = weights.at(final_layer_weight_key); // (2, 64) or (5, 64) 296| 0| const MTensor &final_layer_bias_t = weights.at(final_layer_bias_key); // 2 or 5 297| | 298| 0| const MTensor &convs_0_weight = transpose3D(conv0w_t); 299| 0| const MTensor &convs_1_weight = transpose3D(conv1w_t); 300| 0| const MTensor &convs_2_weight = transpose3D(conv2w_t); 301| 0| const MTensor &fc1_weight = transpose2D(fc1w_t); 302| 0| const MTensor &fc2_weight = transpose2D(fc2w_t); 303| 0| const MTensor &final_layer_weight = transpose2D(final_layer_weight_t); 304| | 305| | // embedding 306| 0| const MTensor &embed_x = embedding(texts, SEQ_LEN, embed_t); 307| | 308| | // conv0 309| 0| MTensor c0 = conv1D(embed_x, convs_0_weight); // (1, 126, 32) 310| 0| addmv(c0, conv0b_t); 311| 0| relu(c0); 312| | 313| | // conv1 314| 0| MTensor c1 = conv1D(c0, convs_1_weight); // (1, 124, 64) 315| 0| addmv(c1, conv1b_t); 316| 0| relu(c1); 317| 0| c1 = maxPool1D(c1, 2); // (1, 123, 64) 318| | 319| | // conv2 320| 0| MTensor c2 = conv1D(c1, convs_2_weight); // (1, 121, 64) 321| 0| addmv(c2, conv2b_t); 322| 0| relu(c2); 323| | 324| | // max pooling 325| 0| MTensor ca = maxPool1D(c0, c0.size(1)); 326| 0| MTensor cb = maxPool1D(c1, c1.size(1)); 327| 0| MTensor cc = maxPool1D(c2, c2.size(1)); 328| | 329| | // concate